Skip to content

Conversation

@mattzcarey
Copy link
Contributor

@mattzcarey mattzcarey commented Oct 13, 2025

Adds custom RPC transport for MCP.

  • Core Implementation (packages/agents/src/mcp/rpc.ts) implements RPCClientTransport and RPCServerTransport with full JSON-RPC 2.0 validation, batch request support, and session management.

  • Agent Integration (packages/agents/src/index.ts) addRpcMcpServer() method to Agent class for connecting to MCP servers via RPC bindings.

  • McpAgent Support (packages/agents/src/mcp/index.ts) implements handleMcpMessage() with automatic transport recreation after hibernation.

  • Example (examples/mcp-rpc-transport/) showing Agent calling McpAgent via RPC with counter tool.

  • Documentation (docs/mcp-transports.md) guide covering all three transports (Streamable HTTP, SSE, RPC) with step-by-step setup.

  • Tests (packages/agents/src/tests/mcp/transports/rpc.test.ts)

Closes #548

@changeset-bot
Copy link

changeset-bot bot commented Oct 13, 2025

⚠️ No Changeset found

Latest commit: b1245a8

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@pkg-pr-new
Copy link

pkg-pr-new bot commented Oct 13, 2025

Open in StackBlitz

npm i https://pkg.pr.new/cloudflare/agents@565

commit: b1245a8

@mattzcarey mattzcarey marked this pull request as ready for review October 14, 2025 09:30
@mattzcarey mattzcarey marked this pull request as draft October 14, 2025 10:23
@mattzcarey mattzcarey marked this pull request as ready for review October 16, 2025 14:29
@mattzcarey mattzcarey marked this pull request as draft October 17, 2025 16:48
@mattzcarey mattzcarey marked this pull request as ready for review October 17, 2025 19:05
@jpm-halfspace
Copy link

How far is this from being merged?

@whoiskatrin
Copy link
Contributor

How far is this from being merged?

not far, it will go though another round of reviews today

Comment on lines +11 to +37
/**
* Validates a JSON-RPC 2.0 batch request
* @see JSON-RPC 2.0 spec section 6
*/
function validateJSONRPCBatch(batch: unknown): batch is JSONRPCMessage[] {
if (!Array.isArray(batch)) {
throw new Error("Invalid JSON-RPC batch: must be an array");
}

// Spec: "an Array with at least one value"
if (batch.length === 0) {
throw new Error("Invalid JSON-RPC batch: array must not be empty");
}

// Validate each message in the batch
for (let i = 0; i < batch.length; i++) {
try {
validateJSONRPCMessage(batch[i]);
} catch (error) {
throw new Error(
`Invalid JSON-RPC batch: message at index ${i} is invalid: ${error instanceof Error ? error.message : String(error)}`
);
}
}

return true;
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should probs be zod schema as MCP sdk does.

Comment on lines +249 to +252
// Set the name if the stub is a DO
if (this._doName && this._stub.setName) {
await this._stub.setName(this._doName);
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I dont want to do this in the transport since it could be a worker to worker binding...

Comment on lines +255 to +258
if (this._props && !this._propsInitialized && this._stub.updateProps) {
await this._stub.updateProps(this._props);
this._propsInitialized = true;
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here. we need a better/first class way to pass props through the transport.

Comment on lines +681 to 696
this._connectToMcpServerInternal({
type: "http",
serverName: server.name,
url: server.server_url,
callbackUrl: server.callback_url,
options: server.server_options
? JSON.parse(server.server_options)
: undefined,
{
reconnect: {
id: server.id,
oauthClientId: server.client_id ?? undefined
}
)
})
.then(() => {
// Broadcast updated MCP servers state after each server connects
this.broadcastMcpServers();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is the biggest change here. I'm not sure I like it.

Why is the main agent class caring about this. it should all be added to the client manager.

* Validates and resolves a Durable Object binding from env
* @returns The namespace and binding name for storage
*/
private _resolveRpcBinding<T extends McpAgent>(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also grim to have this at the top level agent class. this is an implementation detail of the rpc transport. And actually a bad one at that.

* await agent.addMcpServer("my-server", "https://example.com/mcp", "https://my-app.com");
* ```
*/
async addMcpServer<
Copy link
Contributor Author

@mattzcarey mattzcarey Nov 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the lifecycle of calling this needs rethinking. I initially thought ahh we add this to onStart and then all is good. But that means you have v little control on when the mcp server is connected and when the auth happens etc. Also there is almost no error handling.

Need to think about this a bit more but maybe actually we deprecate this addMcpServer and make the lower level McpClientManager easier to use. If we do that then this change is actually not necessary as the example can directly use the client manager.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: define Agent and McpAgent in the same worker

3 participants