RPC transport for MCP; OAuth now opt-in
v0.6.0
The latest release of the Agents SDK ↗ lets you define an Agent and an McpAgent in the same Worker and connect them over RPC — no HTTP, no network overhead. It also makes OAuth opt-in for simple MCP connections, hardens the schema converter for production workloads, and ships a batch of @cloudflare/ai-chat reliability fixes.
RPC transport for MCP
You can now connect an Agent to an McpAgent in the same Worker using a Durable Object binding instead of an HTTP URL. The connection stays entirely within the Cloudflare runtime — no network round-trips, no serialization overhead.
Pass the Durable Object namespace directly to addMcpServer:
<span class="line"><span class="nb-shiki-1itgoe">import</span><span class="nb-shiki-140thh"> { Agent } </span><span class="nb-shiki-1itgoe">from</span><span class="nb-shiki-mdbnqw"> "agents"</span><span class="nb-shiki-140thh">;</span></span>
<span class="line"></span>
<span class="line"><span class="nb-shiki-1itgoe">export</span><span class="nb-shiki-1itgoe"> class</span><span class="nb-shiki-1t8gfj"> MyAgent</span><span class="nb-shiki-1itgoe"> extends</span><span class="nb-shiki-1t8gfj"> Agent</span><span class="nb-shiki-140thh"> {</span></span>
<span class="line"><span class="nb-shiki-1itgoe"> async</span><span class="nb-shiki-1t8gfj"> onStart</span><span class="nb-shiki-140thh">() {</span></span>
<span class="line"><span class="nb-shiki-21nrsd"> // Connect via DO binding — no HTTP, no network overhead</span></span>
<span class="line"><span class="nb-shiki-1itgoe"> await</span><span class="nb-shiki-dzsirb"> this</span><span class="nb-shiki-140thh">.</span><span class="nb-shiki-1t8gfj">addMcpServer</span><span class="nb-shiki-140thh">(</span><span class="nb-shiki-mdbnqw">"counter"</span><span class="nb-shiki-140thh">, env.</span><span class="nb-shiki-dzsirb">MY_MCP</span><span class="nb-shiki-140thh">);</span></span>
<span class="line"></span>
<span class="line"><span class="nb-shiki-21nrsd"> // With props for per-user context</span></span>
<span class="line"><span class="nb-shiki-1itgoe"> await</span><span class="nb-shiki-dzsirb"> this</span><span class="nb-shiki-140thh">.</span><span class="nb-shiki-1t8gfj">addMcpServer</span><span class="nb-shiki-140thh">(</span><span class="nb-shiki-mdbnqw">"counter"</span><span class="nb-shiki-140thh">, env.</span><span class="nb-shiki-dzsirb">MY_MCP</span><span class="nb-shiki-140thh">, {</span></span>
<span class="line"><span class="nb-shiki-140thh"> props: { userId: </span><span class="nb-shiki-mdbnqw">"user-123"</span><span class="nb-shiki-140thh">, role: </span><span class="nb-shiki-mdbnqw">"admin"</span><span class="nb-shiki-140thh"> },</span></span>
<span class="line"><span class="nb-shiki-140thh"> });</span></span>
<span class="line"><span class="nb-shiki-140thh"> }</span></span>
<span class="line"><span class="nb-shiki-140thh">}</span></span>
<span class="line"><span class="nb-shiki-1itgoe">import</span><span class="nb-shiki-140thh"> { Agent } </span><span class="nb-shiki-1itgoe">from</span><span class="nb-shiki-mdbnqw"> "agents"</span><span class="nb-shiki-140thh">;</span></span>
<span class="line"></span>
<span class="line"><span class="nb-shiki-1itgoe">export</span><span class="nb-shiki-1itgoe"> class</span><span class="nb-shiki-1t8gfj"> MyAgent</span><span class="nb-shiki-1itgoe"> extends</span><span class="nb-shiki-1t8gfj"> Agent</span><span class="nb-shiki-140thh"> {</span></span>
<span class="line"><span class="nb-shiki-1itgoe"> async</span><span class="nb-shiki-1t8gfj"> onStart</span><span class="nb-shiki-140thh">() {</span></span>
<span class="line"><span class="nb-shiki-21nrsd"> // Connect via DO binding — no HTTP, no network overhead</span></span>
<span class="line"><span class="nb-shiki-1itgoe"> await</span><span class="nb-shiki-dzsirb"> this</span><span class="nb-shiki-140thh">.</span><span class="nb-shiki-1t8gfj">addMcpServer</span><span class="nb-shiki-140thh">(</span><span class="nb-shiki-mdbnqw">"counter"</span><span class="nb-shiki-140thh">, env.</span><span class="nb-shiki-dzsirb">MY_MCP</span><span class="nb-shiki-140thh">);</span></span>
<span class="line"></span>
<span class="line"><span class="nb-shiki-21nrsd"> // With props for per-user context</span></span>
<span class="line"><span class="nb-shiki-1itgoe"> await</span><span class="nb-shiki-dzsirb"> this</span><span class="nb-shiki-140thh">.</span><span class="nb-shiki-1t8gfj">addMcpServer</span><span class="nb-shiki-140thh">(</span><span class="nb-shiki-mdbnqw">"counter"</span><span class="nb-shiki-140thh">, env.</span><span class="nb-shiki-dzsirb">MY_MCP</span><span class="nb-shiki-140thh">, {</span></span>
<span class="line"><span class="nb-shiki-140thh"> props: { userId: </span><span class="nb-shiki-mdbnqw">"user-123"</span><span class="nb-shiki-140thh">, role: </span><span class="nb-shiki-mdbnqw">"admin"</span><span class="nb-shiki-140thh"> },</span></span>
<span class="line"><span class="nb-shiki-140thh"> });</span></span>
<span class="line"><span class="nb-shiki-140thh"> }</span></span>
<span class="line"><span class="nb-shiki-140thh">}</span></span>
The addMcpServer method now accepts string | DurableObjectNamespace as the second parameter with full TypeScript overloads, so HTTP and RPC paths are type-safe and cannot be mixed.
Key capabilities:
- Hibernation support — RPC connections survive Durable Object hibernation automatically. The binding name and props are persisted to storage and restored on wake-up, matching the behavior of HTTP MCP connections.
- Deduplication — Calling
addMcpServerwith the same server name returns the existing connection instead of creating duplicates. Connection IDs are stable across hibernation restore. - Smaller surface area — The RPC transport internals have been rewritten and reduced from 609 lines to 245 lines.
RPCServerTransportnow usesJSONRPCMessageSchemafrom the MCP SDK for validation instead of hand-written checks.
Note
RPC transport is experimental. The API may change based on feedback. Refer to the tracking issue ↗ for updates.
Optional OAuth for MCP connections
addMcpServer() no longer eagerly creates an OAuth provider for every connection. For servers that do not require authentication, a simple call is all you need:
<span class="line"><span class="nb-shiki-21nrsd">// No callbackHost, no OAuth config — just works</span></span>
<span class="line"><span class="nb-shiki-1itgoe">await</span><span class="nb-shiki-dzsirb"> this</span><span class="nb-shiki-140thh">.</span><span class="nb-shiki-1t8gfj">addMcpServer</span><span class="nb-shiki-140thh">(</span><span class="nb-shiki-mdbnqw">"my-server"</span><span class="nb-shiki-140thh">, </span><span class="nb-shiki-mdbnqw">"https://mcp.example.com"</span><span class="nb-shiki-140thh">);</span></span>
<span class="line"><span class="nb-shiki-21nrsd">// No callbackHost, no OAuth config — just works</span></span>
<span class="line"><span class="nb-shiki-1itgoe">await</span><span class="nb-shiki-dzsirb"> this</span><span class="nb-shiki-140thh">.</span><span class="nb-shiki-1t8gfj">addMcpServer</span><span class="nb-shiki-140thh">(</span><span class="nb-shiki-mdbnqw">"my-server"</span><span class="nb-shiki-140thh">, </span><span class="nb-shiki-mdbnqw">"https://mcp.example.com"</span><span class="nb-shiki-140thh">);</span></span>
If the server responds with a 401, the SDK throws a clear error: "This MCP server requires OAuth authentication. Provide callbackHost in addMcpServer options to enable the OAuth flow." The restore-from-storage flow also handles missing callback URLs gracefully, skipping auth provider creation for non-OAuth servers.
Hardened JSON Schema to TypeScript converter
The schema converter used by generateTypes() and getAITools() now handles edge cases that previously caused crashes in production:
- Depth and circular reference guards — Prevents stack overflows on recursive or deeply nested schemas
$refresolution — Supports internal JSON Pointers (#/definitions/...,#/$defs/...,#)- Tuple support —
prefixItems(JSON Schema 2020-12) and arrayitems(draft-07) - OpenAPI 3.0
nullable: true— Supported across all schema branches - Per-tool error isolation — One malformed schema cannot crash the full pipeline in
generateTypes()orgetAITools() - Missing
inputSchemafallback —getAITools()falls back to{ type: "object" }instead of throwing
@cloudflare/ai-chat fixes
- Tool denial flow — Denied tool approvals (
approved: false) now transition tooutput-deniedwith atool_result, fixing Anthropic provider compatibility. Custom denial messages are supported viastate: "output-error"anderrorText. - Abort/cancel support — Streaming responses now properly cancel the reader loop when the abort signal fires and send a done signal to the client.
- Duplicate message persistence —
persistMessages()now reconciles assistant messages by content and order, preventing duplicate rows when clients resend full history. requestIdinOnChatMessageOptions— Handlers can now send properly-tagged error responses for pre-stream failures.redacted_thinkingpreservation — The message sanitizer no longer strips Anthropicredacted_thinkingblocks./get-messagesreliability — Endpoint handling moved from a prototypeonRequest()override to a constructor wrapper, so it works even when users overrideonRequestwithout callingsuper.onRequest().- Client tool APIs undeprecated —
createToolsFromClientSchemas,clientTools,AITool,extractClientToolSchemas, and thetoolsoption onuseAgentChatare restored for SDK use cases where tools are defined dynamically at runtime. jsonSchemainitialization — FixedjsonSchema not initializederror when callinggetAITools()inonChatMessage.
Upgrade
To update to the latest version:
<span class="line"><span class="nb-shiki-1t8gfj">npm</span><span class="nb-shiki-mdbnqw"> i</span><span class="nb-shiki-mdbnqw"> agents@latest</span><span class="nb-shiki-mdbnqw"> @cloudflare/ai-chat@latest</span></span>Fetched July 22, 2026


