McpClient·续2

import { useAgent } from "agents/react";
import { useState } from "react";

function Dashboard() {
    const [tools, setTools] = useState([]);
    const [servers, setServers] = useState({});

const agent = useAgent({
        agent: "MyAgent",
        onMcpUpdate: (mcpState) => {
            setTools(mcpState.tools);
            setServers(mcpState.servers);
        },
    });

return (
        <div>
            <h2>Connected Servers</h2>
            {Object.entries(servers).map(([id, server]) => (
                <div key={id}>
                    {server.name}: {server.state}
                </div>
            ))}

<h2>Available Tools ({tools.length})</h2>
            {tools.map((tool) => (
                <div key={`${tool.serverId}-${tool.name}`}>{tool.name}</div>
            ))}
        </div>
    );
}

API reference

addMcpServer()

Add a connection to an MCP server and make its tools available to your agent.

Calling addMcpServer is idempotent when both the server name and URL match an existing active connection — the existing connection is returned without creating a duplicate. This makes it safe to call in onStart() without worrying about duplicate connections on restart.

If you call addMcpServer with the same name but a different URL, a new connection is created. Both connections remain active and their tools are merged in getAITools(). To replace a server, call removeMcpServer(oldId) first.

URLs are normalized before comparison (trailing slashes, default ports, and hostname case are handled), so https://MCP.Example.com and https://mcp.example.com/ are treated as the same URL.

// HTTP transport (Streamable HTTP, SSE)
async addMcpServer(
  serverName: string,
  url: string,
  options?: {
    id?: string;
    callbackHost?: string;
    callbackPath?: string;
    agentsPrefix?: string;
    client?: McpClientOptions;
    transport?: {
      headers?: HeadersInit;
      type?: "sse" | "streamable-http" | "auto";
    };
    retry?: RetryOptions;
  }
): Promise<
  | { id: string; state: "authenticating"; authUrl: string }
  | { id: string; state: "ready" }
>

// RPC transport (Durable Object binding — no HTTP overhead)
async addMcpServer(
  serverName: string,
  binding: DurableObjectNamespace,
  options?: {
    id?: string;
    props?: Record<string, unknown>;
    client?: McpClientOptions;
    retry?: RetryOptions;
  }
): Promise<{ id: string; state: "ready" }>

Parameters (HTTP transport)

  • serverName (string, required) — Display name for the MCP server
  • url (string, required) — URL of the MCP server endpoint
  • options (object, optional) — Connection configuration:
  • id — Optional stable, caller-supplied server ID for connector-style integrations. When provided, it replaces the generated nanoid(8) across storage, listServers(), listTools(), getAITools() (so tool keys become readable, for example tool_github_create_pull_request), and OAuth state. Refer to Stable server IDs
  • callbackHost — Host for OAuth callback URL. Only needed for OAuth-authenticated servers. If omitted, automatically derived from the incoming request or WebSocket connection URI — you typically do not need to set this unless you are using a custom domain that differs from the Worker's hostname
  • callbackPath — Custom callback URL path that bypasses the default /agents/{class}/{name}/callback construction. Required when sendIdentityOnConnect is false to prevent leaking the instance name. When set, the callback URL becomes {callbackHost}/{callbackPath}. You must route this path to the agent instance via getAgentByName
  • agentsPrefix — URL prefix for OAuth callback path. Default: "agents". Ignored when callbackPath is provided
  • client — The Agents-supported McpClientOptions subset from @modelcontextprotocol/client. The default validator supports JSON Schema 2020-12 and legacy draft-07 schemas in Workers
  • transport — Transport layer configuration:
    • headers — Custom HTTP headers for authentication
    • type — Transport type: "auto" (default), "streamable-http", or "sse"
  • retry — Retry options for connection and reconnection attempts. Persisted and used when restoring connections after hibernation or after OAuth completion. Default: 3 attempts, 500ms base delay, 5s max delay. Refer to Retries for details on RetryOptions.

Parameters (RPC transport)

  • serverName (string, required) — Display name for the MCP server
  • binding ( DurableObjectNamespace, required) — The Durable Object binding for the McpAgent class
  • options (object, optional) — Connection configuration:
  • id — Optional stable, caller-supplied server ID. Refer to Stable server IDs
  • props — Initialization data passed to the McpAgent's onStart(props). Use this to pass user context, configuration, or other data to the MCP server instance
  • client — MCP client configuration options
  • retry — Retry options for the connection

RPC transport connects your Agent directly to an McpAgent via Durable Object bindings without HTTP overhead. Refer to MCP Transport for details on configuring RPC transport.

Returns

A Promise that resolves to a discriminated union based on connection state:

  • When state is "authenticating":
  • id (string) — Unique identifier for this server connection
  • state ( "authenticating") — Server is waiting for OAuth authorization
  • authUrl (string) — OAuth authorization URL for user authentication
  • When state is "ready":
  • id (string) — Unique identifier for this server connection
  • state ( "ready") — Server is fully connected and operational

removeMcpServer()

Disconnect from an MCP server and clean up its resources.

async removeMcpServer(id: string): Promise<void>

Parameters

  • id (string, required) — Server connection ID returned from addMcpServer()

getMcpServers()

Get the current state of all MCP server connections.

getMcpServers(): MCPServersState

Returns

type MCPServersState = {
    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;
            error: string | null;
        }
    >;
    tools: Array<Tool & { serverId: string }>;
    prompts: Array<Prompt & { serverId: string }>;
    resources: Array<Resource & { serverId: string }>;
    resourceTemplates: Array<ResourceTemplate & { serverId: string }>;
};

The state field indicates the connection lifecycle:

  • authenticating — Waiting for OAuth authorization to complete
  • connecting — Establishing transport connection
  • connected — Transport connection established
  • discovering — Discovering server capabilities (tools, resources, prompts)
  • ready — Fully connected and operational
  • failed — Connection failed (see error field for details)

The error field contains an error message when state is "failed". Error messages from external OAuth providers are automatically escaped to prevent XSS attacks, making them safe to display directly in your UI.

configureOAuthCallback()

Configure OAuth callback behavior for MCP servers requiring authentication. This method allows you to customize what happens after a user completes OAuth authorization.

this.mcp.configureOAuthCallback(options: {
  successRedirect?: string;
  errorRedirect?: string;
  customHandler?: () => Response | Promise<Response>;
}): void

Parameters

  • options (object, required) — OAuth callback configuration:
  • successRedirect (string, optional) — URL to redirect to after successful authentication
  • errorRedirect (string, optional) — URL to redirect to after failed authentication. Error message is appended as ?error=<message> query parameter
  • customHandler (function, optional) — Custom handler for complete control over the callback response. Must return a Response

Default behavior

When no configuration is provided:

  • Success: Redirects to your application origin
  • Failure: Displays an HTML error page with the error message

If OAuth fails, the connection state becomes "failed" and the error message is stored in the server.error field for display in your UI.

Usage

Configure in onStart() before any OAuth flows begin:

export class MyAgent extends Agent {
    onStart() {
        // Option 1: Simple redirects
        this.mcp.configureOAuthCallback({
            successRedirect: "/dashboard",
            errorRedirect: "/auth-error",
        });

// Option 2: Custom handler (e.g., for popup windows)
        this.mcp.configureOAuthCallback({
            customHandler: () => {
                return new Response("<script>window.close();</script>", {
                    headers: { "content-type": "text/html" },
                });
            },
        });
    }
}
export class MyAgent extends Agent {
    onStart() {
        // Option 1: Simple redirects
        this.mcp.configureOAuthCallback({
            successRedirect: "/dashboard",
            errorRedirect: "/auth-error",
        });

// Option 2: Custom handler (e.g., for popup windows)
        this.mcp.configureOAuthCallback({
            customHandler: () => {
                return new Response("<script>window.close();</script>", {
                    headers: { "content-type": "text/html" },
                });
            },
        });
    }
}

configureElicitationHandlers()

Configure handlers for stateless elicitation and legacy elicitation/create requests. Add a handler for each elicitation mode your Agent supports.

this.mcp.configureElicitationHandlers(handlers?: {
  form?: (
    request: ElicitRequest,
    serverId: string,
    signal?: AbortSignal,
  ) => Promise<ElicitResult>;
  url?: (
    request: ElicitRequest,
    serverId: string,
    signal?: AbortSignal,
  ) => Promise<ElicitResult>;
}): void

Parameters

  • handlers (object, optional) — Elicitation handlers keyed by mode:
  • form (function, optional) — Handles form-mode requests for structured, non-sensitive input.
  • url (function, optional) — Handles URL-mode requests for out-of-band interactions.
  • request ( ElicitRequest) — The MCP elicitation request. Inspect request.params.mode for the mode-specific fields.
  • serverId (string) — The ID of the MCP server connection that sent the request.
  • signal ( AbortSignal, optional) — Aborts when the originating MCP operation is cancelled.

Each handler returns a promise containing an ElicitResult. Return accept, decline, or cancel. Accepted form responses include content that matches requestedSchema. URL responses omit content.

Passing undefined clears all configured handlers.

Capability behavior

The client advertises only modes with configured handlers during legacy negotiation and on stateless requests. Handler changes apply immediately to live connections, but servers receive updated advertised modes after those connections reconnect.

The SDK stores the handler-derived modes with each MCP server registration. Restored connections advertise those modes after Durable Object hibernation, and callbacks reattach when onStart() runs.

Usage

Configure handlers in onStart():

import { Agent } from "agents";

export class MyAgent extends Agent {
    onStart() {
        this.mcp.configureElicitationHandlers({
            form: (request, serverId) =>
                this.forwardElicitationToBrowser(request, serverId),
            url: (request, serverId) =>
                this.forwardElicitationToBrowser(request, serverId),
        });
    }

forwardElicitationToBrowser(request, serverId) {
        // Forward the request to your UI and resolve after the user responds.
        throw new Error(
            `Implement elicitation for ${serverId}: ${request.params.message}`,
        );
    }
}
import { Agent } from "agents";
import type { ElicitRequest, ElicitResult } from "agents/mcp/client";

export class MyAgent extends Agent<Env> {
    onStart() {
        this.mcp.configureElicitationHandlers({
            form: (request, serverId) =>
                this.forwardElicitationToBrowser(request, serverId),
            url: (request, serverId) =>
                this.forwardElicitationToBrowser(request, serverId),
        });
    }

private forwardElicitationToBrowser(
        request: ElicitRequest,
        serverId: string,
    ): Promise<ElicitResult> {
        // Forward the request to your UI and resolve after the user responds.
        throw new Error(
            `Implement elicitation for ${serverId}: ${request.params.message}`,
        );
    }
}

For the complete browser forwarding pattern and mode-specific requirements, refer to Elicitation.

Custom OAuth provider

Override the default OAuth provider used when connecting to MCP servers by implementing createMcpOAuthProvider() on your Agent class. This enables custom authentication strategies such as pre-registered client credentials or mTLS, beyond the built-in dynamic client registration.

The override is used for both new connections (addMcpServer) and restored connections after a Durable Object restart.

import { Agent } from "agents";

export class MyAgent extends Agent {
    createMcpOAuthProvider(callbackUrl) {
        const env = this.env;
        return {
            get redirectUrl() {
                return callbackUrl;
            },
            get clientMetadata() {
                return {
                    client_id: env.MCP_CLIENT_ID,
                    client_secret: env.MCP_CLIENT_SECRET,
                    redirect_uris: [callbackUrl],
                };
            },
            clientInformation() {
                return {
                    client_id: env.MCP_CLIENT_ID,
                    client_secret: env.MCP_CLIENT_SECRET,
                };
            },
        };
    }
}