McpClient — API reference
Your Agent can connect to external Model Context Protocol (MCP) ↗ servers to access tools, resources, and prompts. The Agent class provides three methods to manage MCP connections:
import { Agent } from "agents";
export class MyAgent extends Agent { async onRequest(request) { const url = new URL(request.url);
if (url.pathname === "/connect" && request.method === "POST") { const result = await this.addMcpServer( "Weather API", "https://weather-mcp.example.com/mcp", );
if (result.state === "authenticating") { return new Response(JSON.stringify({ authUrl: result.authUrl }), { headers: { "Content-Type": "application/json" }, }); }
return new Response(`Connected: ${result.id}`, { status: 200 }); } }}import { Agent, type AgentNamespace } from "agents";
type Env = { MyAgent: AgentNamespace<MyAgent>;};
export class MyAgent extends Agent<Env, never> { async onRequest(request: Request): Promise<Response> { const url = new URL(request.url);
if (url.pathname === "/connect" && request.method === "POST") { const result = await this.addMcpServer( "Weather API", "https://weather-mcp.example.com/mcp", );
if (result.state === "authenticating") { return new Response(JSON.stringify({ authUrl: result.authUrl }), { headers: { "Content-Type": "application/json" }, }); }
return new Response(`Connected: ${result.id}`, { status: 200 }); } }}Connections persist in the Agent's SQL storage, and when an Agent connects to an MCP server, all tools from that server become available automatically.
Add a connection to an MCP server and make its tools available to your Agent.
async addMcpServer( serverName: string, url: string, callbackHost?: string, agentsPrefix?: string, options?: { client?: ConstructorParameters<typeof Client>[1]; transport?: { headers?: HeadersInit; type?: "sse" | "streamable-http" | "auto"; }; }): Promise< | { id: string; state: "authenticating"; authUrl: string } | { id: string; state: "ready"; authUrl?: undefined }>serverName(string, required) — Display name for the MCP serverurl(string, required) — URL of the MCP server endpointcallbackHost(string, optional) — Host for OAuth callback URL. If omitted, automatically derived from the incoming requestagentsPrefix(string, optional) — URL prefix for OAuth callback path. Default:"agents"options(object, optional) — Connection configuration:client— MCP client configuration options (passed to@modelcontextprotocol/sdkClient constructor). By default, includesCfWorkerJsonSchemaValidatorfor validating tool parameters against JSON schemas.transport— Transport layer configuration:headers— Custom HTTP headers for authenticationtype— Transport type:"sse","streamable-http", or"auto"(tries streamable-http first, falls back to sse)
A Promise that resolves to a discriminated union based on connection state:
-
When
stateis"authenticating":id(string) — Unique identifier for this server connectionstate("authenticating") — Server is waiting for OAuth authorizationauthUrl(string) — OAuth authorization URL for user authentication
-
When
stateis"ready":id(string) — Unique identifier for this server connectionstate("ready") — Server is fully connected and operationalauthUrl(undefined) — Not present when already authenticated
export class MyAgent extends Agent { async onRequest(request) { const result = await this.addMcpServer( "Weather API", "https://weather-mcp.example.com/mcp", );
if (result.state === "authenticating") { // User needs to complete OAuth flow return new Response( JSON.stringify({ serverId: result.id, authUrl: result.authUrl }), { headers: { "Content-Type": "application/json" }, }, ); }
return new Response(`Connected: ${result.id}`, { status: 200 }); }}export class MyAgent extends Agent<Env, never> { async onRequest(request: Request): Promise<Response> { const result = await this.addMcpServer( "Weather API", "https://weather-mcp.example.com/mcp", );
if (result.state === "authenticating") { // User needs to complete OAuth flow return new Response(JSON.stringify({ serverId: result.id, authUrl: result.authUrl }), { headers: { "Content-Type": "application/json" }, }); }
return new Response(`Connected: ${result.id}`, { status: 200 }); }}If the MCP server requires OAuth authentication, authUrl will be returned for user authentication. Connections persist across requests and the Agent will automatically reconnect if the connection is lost.
Related:
Disconnect from an MCP server and clean up its resources.
async removeMcpServer(id: string): Promise<void>id(string, required) — Server connection ID returned fromaddMcpServer()
A Promise that resolves when disconnection is complete.
export class MyAgent extends Agent { async onRequest(request) { const url = new URL(request.url);
if (url.pathname === "/disconnect" && request.method === "POST") { const { serverId } = await request.json(); await this.removeMcpServer(serverId);
return new Response("Disconnected", { status: 200 }); } }}export class MyAgent extends Agent<Env, never> { async onRequest(request: Request): Promise<Response> { const url = new URL(request.url);
if (url.pathname === "/disconnect" && request.method === "POST") { const { serverId } = await request.json(); await this.removeMcpServer(serverId);
return new Response("Disconnected", { status: 200 }); } }}Disconnects from the MCP server, removes all related resources, and deletes the server record from storage.
Get the current state of all MCP server connections.
getMcpServers(): MCPServersStateNone.
An MCPServersState object containing:
{ servers: Record< string, { name: string; server_url: string; auth_url: string | null; state: | "authenticating" | "connecting" | "connected" | "discovering" | "ready" | "failed"; capabilities: ServerCapabilities | null; instructions: string | null; } >; tools: Array<Tool & { serverId: string }>; prompts: Array<Prompt & { serverId: string }>; resources: Array<Resource & { serverId: string }>; resourceTemplates: Array<ResourceTemplate & { serverId: string }>;}export class MyAgent extends Agent { async onRequest(request) { const url = new URL(request.url);
if (url.pathname === "/mcp-state") { const mcpState = this.getMcpServers();
return new Response(JSON.stringify(mcpState, null, 2), { headers: { "Content-Type": "application/json" }, }); } }}export class MyAgent extends Agent<Env, never> { async onRequest(request: Request): Promise<Response> { const url = new URL(request.url);
if (url.pathname === "/mcp-state") { const mcpState = this.getMcpServers();
return new Response(JSON.stringify(mcpState, null, 2), { headers: { "Content-Type": "application/json" }, }); } }}The state field indicates the connection lifecycle:
authenticating— Waiting for OAuth authorization to completeconnecting— Establishing transport connectionconnected— Transport connection establisheddiscovering— Discovering server capabilities (tools, resources, prompts)ready— Fully connected and operationalfailed— Connection failed
Use this method to monitor connection status, list available tools, or build UI for connected servers.
The this.mcp property exposes additional methods for fine-grained control over MCP server connections.
Register a server without immediately connecting. Useful for pre-configuring servers that will be connected later.
async registerServer( id: string, options: { url: string; name: string; callbackUrl: string; clientOptions?: ClientOptions; transportOptions?: TransportOptions; }): Promise<string>id(string, required) — Unique identifier for the serveroptions(object, required) — Server configuration:url— MCP server endpoint URLname— Display name for the servercallbackUrl— OAuth callback URLclientOptions— MCP client configurationtransportOptions— Transport layer settings
A Promise that resolves to the server ID.
Establish a connection to a previously registered server.
async connectToServer(id: string): Promise<MCPConnectionResult>id(string, required) — Server ID fromregisterServer()
A Promise that resolves to an MCPConnectionResult:
type MCPConnectionResult = | { state: "failed"; error: string } | { state: "authenticating"; authUrl: string } | { state: "connected" }Check server capabilities if a connection is active.
async discoverIfConnected( serverId: string, options?: { timeoutMs?: number }): Promise<MCPDiscoverResult | undefined>serverId(string, required) — Server ID to checkoptions(object, optional):timeoutMs— Discovery timeout in milliseconds
A Promise that resolves to MCPDiscoverResult if connected, or undefined if not connected:
type MCPDiscoverResult = { success: boolean; state: MCPConnectionState; error?: string;}Close the connection to a specific server while keeping it registered.
async closeConnection(id: string): Promise<void>Close all active server connections while preserving registrations.
async closeAllConnections(): Promise<void>Get all discovered MCP tools in a format compatible with the AI SDK ↗.
getAITools(): ToolSetA ToolSet object containing all tools from connected MCP servers, ready to use with AI SDK functions like generateText() or streamText().
import { generateText } from "ai";
export class MyAgent extends Agent { async onRequest(request) { // Get all MCP tools as AI SDK compatible tools const tools = this.mcp.getAITools();
const result = await generateText({ model: openai("gpt-4"), prompt: "What's the weather in San Francisco?", tools, });
return new Response(result.text); }}import { generateText } from "ai";
export class MyAgent extends Agent<Env, never> { async onRequest(request: Request): Promise<Response> { // Get all MCP tools as AI SDK compatible tools const tools = this.mcp.getAITools();
const result = await generateText({ model: openai("gpt-4"), prompt: "What's the weather in San Francisco?", tools, });
return new Response(result.text); }}Tools are automatically namespaced by server ID to prevent conflicts when multiple MCP servers expose tools with the same name.
Customize OAuth callback behavior using this.mcp.configureOAuthCallback():
export class MyAgent extends Agent { onStart() { this.mcp.configureOAuthCallback({ successRedirect: "/connected", errorRedirect: "/auth-failed", }); }}export class MyAgent extends Agent<Env, never> { onStart() { this.mcp.configureOAuthCallback({ successRedirect: "/connected", errorRedirect: "/auth-failed", }); }}You can also provide a customHandler function for full control over the callback response. Refer to the OAuth handling guide for details.
Use error detection utilities to handle connection errors:
import { isUnauthorized, isTransportNotImplemented } from "agents/mcp";
export class MyAgent extends Agent { async onRequest(request) { try { await this.addMcpServer("Server", "https://mcp.example.com/mcp"); } catch (error) { if (isUnauthorized(error)) { return new Response("Authentication required", { status: 401 }); } else if (isTransportNotImplemented(error)) { return new Response("Transport not supported", { status: 400 }); } throw error; } }}import { isUnauthorized, isTransportNotImplemented } from "agents/mcp";
export class MyAgent extends Agent<Env, never> { async onRequest(request: Request): Promise<Response> { try { await this.addMcpServer("Server", "https://mcp.example.com/mcp"); } catch (error) { if (isUnauthorized(error)) { return new Response("Authentication required", { status: 401 }); } else if (isTransportNotImplemented(error)) { return new Response("Transport not supported", { status: 400 }); } throw error; } }}- Connect your first MCP server — Tutorial to get started
- Handle OAuth flows — Complete OAuth integration guide
Was this helpful?
- Resources
- API
- New to Cloudflare?
- Directory
- Sponsorships
- Open Source
- Support
- Help Center
- System Status
- Compliance
- GDPR
- Company
- cloudflare.com
- Our team
- Careers
- © 2025 Cloudflare, Inc.
- Privacy Policy
- Terms of Use
- Report Security Issues
- Trademark
-