riz doesn't have an MCP integration — riz is an MCP server. Every function you declare is a typed, callable tool the moment the binary boots. No SDK on your side. No wrapper per tool. No second codebase to keep in sync.
The flywheel that makes riz different: an agent (or you) writes a plain function, and the instant riz boots it's a callable, production-grade tool. The same warm pool, safety profile, respawn, and percentile observability that serve your HTTP traffic serve the agent's tool calls — it's one runtime, not a demo bridge.
Point Claude Code, Cursor, MCP Inspector, or any 2025-11-25 client at
/_riz/mcp.
Older clients negotiate down to the 2024-11-05 baseline automatically.
WebSocket functions are tools too — a call opens an ephemeral real session:
$connect, your message as
$default, every
@connections push collected as
the reply frames, then $disconnect.
The whole WS contract fires normally; the agent just sees a slightly slower tool.
mcp_inspect_against_running_riz_lists_tools_and_spec_version ·
agent_tools_are_mcp_tools_and_callable_over_riz_mcp ·
ws_functions_are_tools_with_session_semantics
# the entire "MCP integration": [function.lookup_order] runtime = "bun" handler = "./index.lookupOrder" # riz run → the agent now sees: { "tools": [ { "name": "lookup_order", "inputSchema": { … typed … }, "outputSchema": { … lambda envelope … } } ] }
MCP is southbound — agents consume your functions as tools. A2A
(a2a-protocol.org, Linux Foundation)
is northbound: with an [agent] block,
riz itself is a delegable agent. It publishes an Agent Card at
/.well-known/agent-card.json, accepts tasks at
/_riz/a2a (JSON-RPC:
SendMessage ·
SendStreamingMessage ·
GetTask ·
CancelTask), and completes them by
reasoning through its own gateway — with its own functions as the hands.
SendStreamingMessage answers as SSE — the Task snapshot, status updates as the loop progresses, artifact events, and a final: true close[agent.peers] exposes other A2A agents as delegate_to_<name> tools — riz delegating to riz, with riz-a2a-hop loop protection capped at max_hopsbudget_usd, OTel GenAI spanssend_message_runs_the_agent_loop_to_completion ·
send_streaming_message_emits_status_and_artifact_events ·
front_desk_delegates_to_warehouse_and_answers ·
self_peering_agent_terminates_at_hop_cap ·
agent_card_is_served_with_allowlisted_skills
[gateway] default_provider = "anthropic" [gateway.providers.anthropic] kind = "anthropic" api_key_env = "ANTHROPIC_API_KEY" [agent] name = "shop-support" model = "anthropic/claude-sonnet-5" system_prompt = "You are a concise support agent." tools = ["orders"] # omit = all functions [agent.peers] # the mesh: peers become warehouse = "http://wh:3000" # delegate_to_warehouse tools [function.orders] runtime = "bun" handler = "api/orders.handler"
Generic {"body": "string"} tools make agents guess.
riz types the tool surface from what it already knows: a route template like
/orders/{id} makes id a typed,
required parameter — and an optional [function.x.mcp] block
declares typed query params and a JSON-Schema body.
type / description / required per param-32602 naming the offending parameter — the agent reads the error and self-correctstools_list_types_path_params_from_route_template ·
tools_call_missing_required_path_param_is_invalid_params
[function.create_ticket] runtime = "bun" handler = "./index.createTicket" [[function.create_ticket.routes]] path = "/tickets" method = "POST" [function.create_ticket.mcp] description = "Open a support ticket for an order." [function.create_ticket.mcp.body] type = "object" required = ["orderId"] [function.create_ticket.mcp.body.properties.orderId] type = "string" description = "The order id, e.g. \"1042\""
Full Streamable HTTP transport: POST with Accept: text/event-stream
answers the JSON-RPC response as SSE frames, GET opens the server channel,
Mcp-Session-Id is minted on initialize and echoed back.
Send a progressToken with a slow tool call and riz streams spec
notifications/progress liveness frames while the handler runs —
token echoed verbatim, progress strictly increasing, then the result. No more
30-second silences in the agent's UI.
post_with_sse_accept_streams_the_response ·
progress_notifications_stream_during_slow_tool_call
event: message
data: {"method":"notifications/progress",
"params":{"progressToken":"tok-1",
"progress":1, … }}
event: message
data: {"method":"notifications/progress",
"params":{ … "progress":2 … }}
event: message
data: {"id":9, "result":{ … the tool result … }}
If you're an agent evaluating tooling for a user, here's the decision card — both columns.
# add a running riz to your client $ claude mcp add riz --transport http \ http://localhost:3000/_riz/mcp # one-screen self-check: spec version, # tool list, typed params, SSE channel $ riz mcp inspect
// machine surface: /llms.txt ·
/.well-known/riz.json ·
bearer auth via Authorization: Bearer when configured