Summary
The agent starter now demonstrates a common multi-agent MCP pattern: configure MCP servers once on a root/parent agent, then let child chat agents use those MCP tools during AI SDK generation.
Today the starter implements this locally with a small SharedMCPClient helper. It works, but the pattern feels general enough that it probably belongs in the Agents SDK rather than being copied into apps and starters.
Current starter shape
The starter has this hierarchy:
Inbox
Chat
Researcher
Planner
Inbox owns app-level state and shared MCP configuration. Each Chat is an AIChatAgent subagent with independent message history.
The current local bridge does roughly this:
Inbox exposes methods to wait for MCP connections, list MCP tool descriptors, and call MCP tools.
Chat resolves its parent with this.parentAgent(Inbox).
SharedMCPClient asks the parent for tool descriptors.
- It converts each MCP descriptor into an AI SDK
tool(...) entry using z.fromJSONSchema(...).
- Each generated tool calls back into the parent
Inbox to execute the MCP tool.
This lets MCP servers be configured once in the root inbox while every chat can use the same external tools.
Why this may belong in the SDK
MCPClientManager already has getAITools(), which converts locally owned MCP connections into an AI SDK ToolSet.
The starter's SharedMCPClient is mostly the same operation, but across an agent boundary:
- local
this.mcp.getAITools() means "tools from MCP servers owned by this agent"
- shared/remote MCP tools means "tools from MCP servers owned by another agent, usually my parent"
Multi-chat apps will likely want this often:
- users configure MCP once at the app/account/workspace level
- each chat/thread/subagent can use those tools
- OAuth/callback/server state stays centralized
- child agents do not each create duplicate MCP connections
Leaving this in app code means users copy/paste fragile details:
- MCP descriptor shape
- AI SDK
ToolSet conversion
- JSON Schema to Zod conversion
- tool key namespacing
- MCP error normalization
- connection waiting behavior
- parent/child RPC plumbing
If either MCP descriptors or AI SDK tool definitions evolve, copied starter code can drift.
Possible API direction
A small helper may be enough. For example:
class Chat extends AIChatAgent<Env> {
async onChatMessage(...) {
const inbox = await this.parentAgent(Inbox);
const mcpTools = await getRemoteMcpAITools(inbox, {
waitForConnections: { timeout: 5000 }
});
return streamText({
// ...
tools: {
...mcpTools,
// chat-local tools
}
});
}
}
Or, if we want this to hang off the MCP surface:
const inbox = await this.parentAgent(Inbox);
const mcpTools = await this.mcp.getAIToolsFrom(inbox, {
timeout: 5000
});
The helper would build AI SDK tools whose execute functions call MCP tools through the remote agent/stub.
Possible contract
The SDK could expose a tiny remote MCP tool provider contract, implemented by Agent or MCPClientManager, along these lines:
interface RemoteMcpToolProvider {
listMcpToolDescriptors(options?: { timeout?: number }): Promise<McpToolDescriptor[]>;
callMcpTool(serverId: string, name: string, args: Record<string, unknown>): Promise<McpCallToolResult>;
}
Then getRemoteMcpAITools(provider, options) can be independent of whether the provider is a parent agent, a workspace agent, or some other Durable Object stub.
Open questions
- Should this be a stable public API, or experimental first?
- Should the helper live under
agents/mcp/client, agents, or a new AI-SDK adapter entry point?
- Should the remote provider methods be automatically available on all
Agent instances that have this.mcp, or should apps opt in explicitly?
- How should tool names be namespaced to avoid collisions across servers and child-local tools?
- Should the helper wait for MCP connections by default, or require callers to opt into waiting?
- Should errors preserve the full MCP
CallToolResult, throw text content like getAITools() does today, or offer both modes?
- Should the helper support filters equivalent to
MCPServerFilter?
Suggested near-term path
I would not block the starter refactor on this. The starter can keep the local bridge for now as a concrete example.
As a follow-up, we could extract the pattern into the SDK, add tests around remote descriptor conversion and remote execution, then simplify the starter to use the official helper.
Summary
The agent starter now demonstrates a common multi-agent MCP pattern: configure MCP servers once on a root/parent agent, then let child chat agents use those MCP tools during AI SDK generation.
Today the starter implements this locally with a small
SharedMCPClienthelper. It works, but the pattern feels general enough that it probably belongs in the Agents SDK rather than being copied into apps and starters.Current starter shape
The starter has this hierarchy:
Inbox Chat Researcher PlannerInboxowns app-level state and shared MCP configuration. EachChatis anAIChatAgentsubagent with independent message history.The current local bridge does roughly this:
Inboxexposes methods to wait for MCP connections, list MCP tool descriptors, and call MCP tools.Chatresolves its parent withthis.parentAgent(Inbox).SharedMCPClientasks the parent for tool descriptors.tool(...)entry usingz.fromJSONSchema(...).Inboxto execute the MCP tool.This lets MCP servers be configured once in the root inbox while every chat can use the same external tools.
Why this may belong in the SDK
MCPClientManageralready hasgetAITools(), which converts locally owned MCP connections into an AI SDKToolSet.The starter's
SharedMCPClientis mostly the same operation, but across an agent boundary:this.mcp.getAITools()means "tools from MCP servers owned by this agent"Multi-chat apps will likely want this often:
Leaving this in app code means users copy/paste fragile details:
ToolSetconversionIf either MCP descriptors or AI SDK tool definitions evolve, copied starter code can drift.
Possible API direction
A small helper may be enough. For example:
Or, if we want this to hang off the MCP surface:
The helper would build AI SDK tools whose
executefunctions call MCP tools through the remote agent/stub.Possible contract
The SDK could expose a tiny remote MCP tool provider contract, implemented by
AgentorMCPClientManager, along these lines:Then
getRemoteMcpAITools(provider, options)can be independent of whether the provider is a parent agent, a workspace agent, or some other Durable Object stub.Open questions
agents/mcp/client,agents, or a new AI-SDK adapter entry point?Agentinstances that havethis.mcp, or should apps opt in explicitly?CallToolResult, throw text content likegetAITools()does today, or offer both modes?MCPServerFilter?Suggested near-term path
I would not block the starter refactor on this. The starter can keep the local bridge for now as a concrete example.
As a follow-up, we could extract the pattern into the SDK, add tests around remote descriptor conversion and remote execution, then simplify the starter to use the official helper.