Merged
Conversation
🦋 Changeset detectedLatest commit: d9b6246 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
commit: |
e7a2ae8 to
5273dcd
Compare
6ecc7db to
2fe8497
Compare
2fe8497 to
6e404aa
Compare
whoiskatrin
reviewed
Oct 16, 2025
72d1f7d to
f7da517
Compare
|
How far is this from being merged? |
Contributor
not far, it will go though another round of reviews today |
mattzcarey
commented
Nov 4, 2025
mattzcarey
commented
Nov 4, 2025
mattzcarey
commented
Nov 4, 2025
mattzcarey
commented
Nov 4, 2025
mattzcarey
commented
Nov 4, 2025
mattzcarey
commented
Nov 4, 2025
Resolved conflicts in: - packages/agents/src/index.ts (imports, workflow methods, addMcpServer) - packages/agents/src/mcp/index.ts (transport exports) - packages/agents/src/mcp/client-connection.ts (RPC transport + auth provider) - packages/agents/src/mcp/types.ts (transport type + jurisdiction) - package-lock.json (regenerated from main) Kept RPC transport additions (_resolveRpcBinding, _buildRpcTransportOptions, _buildHttpTransportOptions, _connectToMcpServerInternal) alongside main's refactored addMcpServer, workflow integration, and new MCP handler APIs. Fixed McpAgent generic constraints to use Cloudflare.Env instead of unknown. Co-authored-by: Cursor <cursoragent@cursor.com>
Revamp RPC transport docs and overhaul the mcp-rpc-transport example. Docs: clarify Durable Object binding usage, remove RPC-specific auth wording, simplify examples and explain automatic reconnection and timeout configuration. Example: replace OpenAI usage with Workers AI, add env.d.ts, update package.json (deps, scripts, types), remove legacy normalize.css and utils, migrate styles to Tailwind/Kumo/agents-ui, and rebuild the React client UI with agents-ui/kumo components. Server: simplify McpAgent/McpServer wiring, streamline tool handlers and chat flow, and return UI message streams via Workers AI. Tests: add and update MCP-related tests (including add-rpc-mcp-server.test.ts and other test adjustments). Also include multiple agent package updates to support these changes.
Introduce an RPC transport that lets Agents connect to McpAgent instances in the same Worker using Durable Object bindings (no HTTP). Key changes: - New feature: addMcpServer now accepts string | DurableObjectNamespace with TypeScript overloads so HTTP and RPC paths are type-safe. - RPC connections persist across Durable Object hibernation; binding name and props are stored/restored automatically and duplicate connections are deduplicated. - Rewrote RPCClientTransport/ServerTransport to create DO stubs internally, drop unnecessary session management, and use validated JSONRPC schemas. - Added RPC_DO_PREFIX constant and discriminated AddRpcMcpServerOptions so props are only available for DO binding. - Persist/restore helpers added: getRpcServersFromStorage(), saveRpcServerToStorage(); restoreConnectionsFromStorage now skips RPC servers (Agent restores them with env access). - Fixed MCPClientManager.callTool to strip serverId before calling conn.client.callTool. - Removed several Agent base helpers that leaked RPC logic and reduced rpc/types files significantly. - Updated example to Kumo v1.7.0 and adjusted server example; added tests to verify RPC removal behavior. Also included minor logging cleanup and various refactors to simplify the RPC implementation.
Contributor
|
I took a crack at this and rewrote it all, with tests and such. I also managed to fix some other gnarly stuff along the way (of note, this.name is now available inside alarms, because of enhancements to partyserver). I (and by I I mean cursor) also rewrote the PR description. Quite happy, I think this is ready to land. I might just land it tonight. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

RPC Transport for MCP
Enables an Agent to connect to an McpAgent via Durable Object RPC bindings — no HTTP, no network overhead. Both can live in the same Worker.
Closes #548
User-facing API
addMcpServernow has proper TypeScript overloads so the RPC and HTTP paths are type-safe.AddRpcMcpServerOptions(withprops) is separate fromAddMcpServerOptions(withcallbackHost,transport, etc.) — you cannot accidentally pass HTTP options to an RPC binding or vice versa.Architecture
Design decisions
RPCClientTransport accepts a namespace, not a stub. It creates the stub internally during
start()viagetServerByNamefrom partyserver, which handlessetName+ props in one call. The transport is a thin wrapper:start()creates the stub,send()callsstub.handleMcpMessage(msg)and routes responses toonmessage.RPCServerTransport is minimal. Dropped session management (unnecessary — RPC within a DO is inherently session-scoped). Dropped 170 lines of hand-written JSON-RPC validation in favor of
JSONRPCMessageSchema.parse()from the MCP SDK. What remains:handle()receives a message, callsonmessage, waits forsend()via a microtask-batched promise, returns the response.Hibernation works automatically. When
addMcpServeris called with an RPC binding, the binding name (looked up by scanningenv) and props are persisted to thecf_agents_mcp_serverstable. On wake-up,_restoreRpcMcpServers()reads these rows, looks upenv[bindingName], and reconnects with the same ID. This matches the existing HTTP restore path. Depends on partyserver 0.3.0 which persiststhis.nameto DO storage so it survives RPC-triggered wake-ups.Deduplication by server name. Calling
addMcpServerwith the same name returns the existing connection instead of creating duplicates. This applies to both RPC and HTTP. Connection IDs are stable across hibernation (passed viareconnect: { id }tomcp.connect()).No changes to the Agent base class beyond
addMcpServer. The original PR added_resolveRpcBinding,_buildRpcTransportOptions,_buildHttpTransportOptions, and_connectToMcpServerInternalto the ~4300-lineindex.ts. All removed. The RPC path inaddMcpServeris ~30 lines that create transport options and delegate tomcp.connect().Files changed
packages/agents/src/mcp/rpc.tsRPCClientTransport(namespace-based), simplifiedRPCServerTransport,RPC_DO_PREFIXconstantpackages/agents/src/index.tsaddMcpServeroverloads for RPC/HTTP,AddRpcMcpServerOptionstype, name-based dedup,_restoreRpcMcpServers(),_findBindingNameForNamespace()packages/agents/src/mcp/client.tsgetRpcServersFromStorage(),saveRpcServerToStorage(),restoreConnectionsFromStorageskipsrpc:URLs, fixedcallToolstrippingserverIdpackages/agents/src/mcp/client-connection.tsMCPTransportOptionsunion,getTransport("rpc"), auth probe rejects RPCpackages/agents/src/mcp/types.tspackages/agents/src/mcp/index.tsRPC_DO_PREFIXexamples/mcp-rpc-transport/docs/mcp-transports.mdTest coverage
Unit tests (
tests/mcp/transports/rpc.test.ts— 21 tests):E2e tests (
tests/mcp/add-rpc-mcp-server.test.ts— 7 tests):Notes for reviewers
as unknown as DurableObjectNamespace<McpAgent>cast inaddMcpServeris needed becauseDurableObjectNamespace<T>whereT extends McpAgentis not directly assignable toDurableObjectNamespace<McpAgent>due to generic variance. The cast is safe sinceTis a subclass.RPCClientTransportOptionshas a generic<T extends McpAgent>for the namespace type, but the class itself storesDurableObjectNamespace<McpAgent>(the base type) to avoid the infinite type recursion thatDurableObjectNamespace<any>causes withgetServerByName.mcp.connect()method is used intentionally for RPC connections becauseregisterServer()saves transport options to storage viaJSON.stringify, andDurableObjectNamespaceis not serializable. RPC persistence is handled separately viasaveRpcServerToStorage.this.nameto DO storage, fixing the "Attempting to read .name before it was set" error on RPC-triggered wake-ups.