> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/cloudflare/agents/llms.txt
> Use this file to discover all available pages before exploring further.

# MCPClientManager

> Connect to and manage external MCP servers from Agents

## Overview

`MCPClientManager` allows Agents to connect to external MCP servers and access their tools, prompts, and resources. It's automatically available via `this.mcp` in all Agents.

```typescript theme={null}
class MyAgent extends Agent {
  async onStart() {
    // Register an MCP server
    const serverId = await this.mcp.registerServer("weather-server", {
      url: "https://weather-mcp.example.com",
      name: "Weather Server"
    });

    // Connect to the server
    await this.mcp.connectToServer(serverId);

    // Discover capabilities
    await this.mcp.discoverIfConnected(serverId);
  }

  @callable()
  async getWeather(location: string) {
    const result = await this.mcp.callTool({
      serverId: "weather-server",
      name: "get_weather",
      arguments: { location }
    });
    return result;
  }
}
```

## Registration & Connection

### registerServer()

Register an MCP server without connecting. Creates the connection object, sets up observability, and saves to storage.

<ParamField path="id" type="string" required>
  Unique identifier for the server
</ParamField>

<ParamField path="options" type="RegisterServerOptions" required>
  <ParamField path="url" type="string" required>
    Server URL (http/https for remote, rpc:// for Durable Object)
  </ParamField>

  <ParamField path="name" type="string" required>
    Human-readable server name
  </ParamField>

  <ParamField path="callbackUrl" type="string">
    OAuth callback URL (auto-derived from request if omitted)
  </ParamField>

  <ParamField path="authUrl" type="string">
    OAuth authorization URL
  </ParamField>

  <ParamField path="clientId" type="string">
    OAuth client ID
  </ParamField>

  <ParamField path="client" type="ConstructorParameters<typeof Client>[1]">
    MCP client options
  </ParamField>

  <ParamField path="transport" type="MCPTransportOptions">
    Transport configuration (headers, type)
  </ParamField>

  <ParamField path="retry" type="RetryOptions">
    Retry options for connection attempts
  </ParamField>
</ParamField>

```typescript theme={null}
const serverId = await this.mcp.registerServer("my-server", {
  url: "https://mcp-server.example.com",
  name: "My MCP Server",
  transport: {
    headers: {
      "Authorization": "Bearer token"
    },
    type: "streamable-http"
  },
  retry: {
    maxAttempts: 5,
    baseDelayMs: 200
  }
});
```

**Returns:** `Promise<string>` - Server ID

### connectToServer()

Connect to a registered MCP server and initialize the connection.

<ParamField path="id" type="string" required>
  Server ID (from registerServer)
</ParamField>

```typescript theme={null}
const result = await this.mcp.connectToServer("my-server");

if (result.state === "authenticating") {
  console.log("OAuth required:", result.authUrl);
} else if (result.state === "connected") {
  console.log("Connected!");
} else if (result.state === "failed") {
  console.error("Connection failed:", result.error);
}
```

**Returns:** `Promise<MCPConnectionResult>`

<Expandable title="MCPConnectionResult variants">
  **Connected:**

  ```typescript theme={null}
  { state: "connected" }
  ```

  **Authenticating (OAuth required):**

  ```typescript theme={null}
  {
    state: "authenticating",
    authUrl: string,
    clientId?: string
  }
  ```

  **Failed:**

  ```typescript theme={null}
  {
    state: "failed",
    error: string
  }
  ```
</Expandable>

### discoverIfConnected()

Discover server capabilities if connection is in CONNECTED or READY state.

<ParamField path="serverId" type="string" required>
  Server ID to discover
</ParamField>

<ParamField path="options" type="DiscoverOptions">
  <ParamField path="timeoutMs" type="number" default="30000">
    Timeout in milliseconds
  </ParamField>
</ParamField>

```typescript theme={null}
const result = await this.mcp.discoverIfConnected("my-server");

if (result.success) {
  console.log("Discovery complete!");
  const tools = this.mcp.listTools();
  console.log("Available tools:", tools);
} else {
  console.error("Discovery failed:", result.error);
}
```

**Returns:** `Promise<MCPDiscoverResult | undefined>`

### removeServer()

Remove an MCP server - closes connection if active and removes from storage.

<ParamField path="serverId" type="string" required>
  Server ID to remove
</ParamField>

```typescript theme={null}
await this.mcp.removeServer("my-server");
```

**Returns:** `Promise<void>`

## Listing Resources

### listTools()

Get all available tools from connected MCP servers.

```typescript theme={null}
const tools = this.mcp.listTools();
tools.forEach(tool => {
  console.log(`[${tool.serverId}] ${tool.name}: ${tool.description}`);
});
```

**Returns:** `(Tool & { serverId: string })[]`

### listPrompts()

Get all available prompts from connected MCP servers.

```typescript theme={null}
const prompts = this.mcp.listPrompts();
for (const prompt of prompts) {
  console.log(`${prompt.name}: ${prompt.description}`);
}
```

**Returns:** `(Prompt & { serverId: string })[]`

### listResources()

Get all available resources from connected MCP servers.

```typescript theme={null}
const resources = this.mcp.listResources();
for (const resource of resources) {
  console.log(`${resource.uri}: ${resource.name}`);
}
```

**Returns:** `(Resource & { serverId: string })[]`

### listResourceTemplates()

Get all available resource templates from connected MCP servers.

```typescript theme={null}
const templates = this.mcp.listResourceTemplates();
```

**Returns:** `(ResourceTemplate & { serverId: string })[]`

### listServers()

List all registered MCP servers from storage.

```typescript theme={null}
const servers = this.mcp.listServers();
for (const server of servers) {
  console.log(`${server.name}: ${server.server_url}`);
}
```

**Returns:** `MCPServerRow[]`

## Calling Tools

### callTool()

Call a tool on an MCP server.

<ParamField path="params" type="CallToolParams" required>
  <ParamField path="serverId" type="string" required>
    Server ID
  </ParamField>

  <ParamField path="name" type="string" required>
    Tool name
  </ParamField>

  <ParamField path="arguments" type="Record<string, unknown>" required>
    Tool arguments
  </ParamField>
</ParamField>

```typescript theme={null}
const result = await this.mcp.callTool({
  serverId: "weather-server",
  name: "get_weather",
  arguments: { location: "San Francisco" }
});

console.log("Result:", result);
```

**Returns:** `Promise<CallToolResult>`

### getPrompt()

Get a prompt from an MCP server.

<ParamField path="params" type="GetPromptParams" required>
  <ParamField path="serverId" type="string" required>
    Server ID
  </ParamField>

  <ParamField path="name" type="string" required>
    Prompt name
  </ParamField>

  <ParamField path="arguments" type="Record<string, unknown>">
    Prompt arguments
  </ParamField>
</ParamField>

```typescript theme={null}
const prompt = await this.mcp.getPrompt({
  serverId: "my-server",
  name: "summarize",
  arguments: { text: "Long text to summarize..." }
});
```

**Returns:** `Promise<GetPromptResult>`

### readResource()

Read a resource from an MCP server.

<ParamField path="params" type="ReadResourceParams" required>
  <ParamField path="serverId" type="string" required>
    Server ID
  </ParamField>

  <ParamField path="uri" type="string" required>
    Resource URI
  </ParamField>
</ParamField>

```typescript theme={null}
const resource = await this.mcp.readResource({
  serverId: "my-server",
  uri: "file:///data.json"
});
```

**Returns:** `Promise<ReadResourceResult>`

## AI SDK Integration

### getAITools()

Get all MCP tools as AI SDK tool definitions. Use with `generateText()` or `streamText()`.

```typescript theme={null}
import { generateText } from "ai";

const tools = this.mcp.getAITools();

const result = await generateText({
  model: this.env.AI.run("@cf/meta/llama-3.3-70b-instruct-fp8-fast"),
  messages: [
    { role: "user", content: "What's the weather in SF?" }
  ],
  tools
});
```

**Returns:** `ToolSet`

<Note>
  Call `await this.mcp.ensureJsonSchema()` before using `getAITools()` if you're not using `await this.mcp.waitForConnections()`.
</Note>

## Connection Management

### waitForConnections()

Wait for all in-flight connection and discovery operations to settle.

<ParamField path="options" type="WaitOptions">
  <ParamField path="timeout" type="number">
    Maximum time to wait in milliseconds. `0` returns immediately, `undefined` waits indefinitely.
  </ParamField>
</ParamField>

```typescript theme={null}
// Wait for all connections to complete
await this.mcp.waitForConnections({ timeout: 10000 });

// Now safe to use getAITools()
const tools = this.mcp.getAITools();
```

**Returns:** `Promise<void>`

### closeConnection()

Close a connection to an MCP server (but keep it in storage).

<ParamField path="id" type="string" required>
  Server ID
</ParamField>

```typescript theme={null}
await this.mcp.closeConnection("my-server");
```

**Returns:** `Promise<void>`

### closeAllConnections()

Close all active connections to MCP servers (but keep them in storage).

```typescript theme={null}
await this.mcp.closeAllConnections();
```

**Returns:** `Promise<void>`

## OAuth Flow

### configureOAuthCallback()

Configure OAuth callback handling for MCP servers.

<ParamField path="config" type="MCPClientOAuthCallbackConfig" required>
  <ParamField path="successRedirect" type="string">
    URL to redirect to on successful OAuth
  </ParamField>

  <ParamField path="errorRedirect" type="string">
    URL to redirect to on failed OAuth
  </ParamField>

  <ParamField path="customHandler" type="(result: MCPClientOAuthResult) => Response">
    Custom handler for OAuth callback
  </ParamField>
</ParamField>

```typescript theme={null}
this.mcp.configureOAuthCallback({
  successRedirect: "/dashboard",
  errorRedirect: "/error"
});
```

### isCallbackRequest()

Check if a request is an OAuth callback request.

<ParamField path="req" type="Request" required>
  The request to check
</ParamField>

```typescript theme={null}
async onRequest(request: Request) {
  if (this.mcp.isCallbackRequest(request)) {
    const result = await this.mcp.handleCallbackRequest(request);
    if (result.authSuccess) {
      // OAuth complete, establish connection
      await this.mcp.establishConnection(result.serverId);
      return new Response("Connected!");
    }
    return new Response(result.authError, { status: 400 });
  }
}
```

**Returns:** `boolean`

### handleCallbackRequest()

Handle an OAuth callback request.

<ParamField path="req" type="Request" required>
  The OAuth callback request
</ParamField>

```typescript theme={null}
const result = await this.mcp.handleCallbackRequest(request);

if (result.authSuccess) {
  await this.mcp.establishConnection(result.serverId);
  return new Response("Success!");
} else {
  return new Response(result.authError, { status: 400 });
}
```

**Returns:** `Promise<MCPClientOAuthResult>`

### establishConnection()

Establish connection in the background after OAuth completion.

<ParamField path="serverId" type="string" required>
  Server ID
</ParamField>

```typescript theme={null}
await this.mcp.establishConnection("my-server");
```

**Returns:** `Promise<void>`

## RPC Servers (Durable Objects)

### addRpcMcpServer()

Connect to an MCP server running as a Durable Object.

```typescript theme={null}
// In your Agent
await this.mcp.addRpcMcpServer(
  "internal-server",
  this.env.INTERNAL_MCP_SERVER,
  { props: { config: "value" } }
);

const tools = this.mcp.listTools();
```

See Agent class reference for full signature.

## Full Example

```typescript theme={null}
import { Agent, callable } from "agents";
import { generateText } from "ai";

class WeatherAgent extends Agent {
  async onStart() {
    // Register weather MCP server
    await this.mcp.registerServer("weather", {
      url: "https://weather-mcp.example.com",
      name: "Weather Server"
    });

    // Connect and discover
    const connected = await this.mcp.connectToServer("weather");
    if (connected.state === "connected") {
      await this.mcp.discoverIfConnected("weather");
    }

    // Wait for all connections
    await this.mcp.waitForConnections({ timeout: 5000 });

    // List available tools
    const tools = this.mcp.listTools();
    console.log("Available tools:", tools.map(t => t.name));
  }

  @callable()
  async chat(message: string) {
    const tools = this.mcp.getAITools();

    const result = await generateText({
      model: this.env.AI.run("@cf/meta/llama-3.3-70b-instruct-fp8-fast"),
      messages: [
        { role: "user", content: message }
      ],
      tools,
      maxSteps: 5
    });

    return result.text;
  }
}
```

## Events

### onServerStateChanged

Subscribe to server state changes (registered, connected, removed, etc.).

```typescript theme={null}
const unsubscribe = this.mcp.onServerStateChanged(() => {
  console.log("MCP server state changed!");
  this.broadcastMcpServers();
});

// Clean up
unsubscribe();
```

### onObservabilityEvent

Subscribe to observability events from MCP connections.

```typescript theme={null}
const unsubscribe = this.mcp.onObservabilityEvent((event) => {
  console.log("MCP event:", event.type, event.payload);
});
```

## Related

* [McpAgent](/api/mcp-agent) - Build MCP servers
* [Agent Class](/api/agent-class) - Agent base class
