---
title: McpClient — API reference · Cloudflare Agents docs
description: "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:"
lastUpdated: 2025-11-04T18:23:20.000Z
chatbotDeprioritize: false
tags: MCP
source_url:
  html: https://developers.cloudflare.com/agents/model-context-protocol/mcp-client-api/
  md: https://developers.cloudflare.com/agents/model-context-protocol/mcp-client-api/index.md
---

Your Agent can connect to external [Model Context Protocol (MCP)](https://modelcontextprotocol.io) servers to access tools, resources, and prompts. The `Agent` class provides three methods to manage MCP connections:

* JavaScript

  ```js
  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 { id, authUrl } = await this.addMcpServer(
          "Weather API",
          "https://weather-mcp.example.com/mcp",
        );


        if (authUrl) {
          return new Response(JSON.stringify({ authUrl }), {
            headers: { "Content-Type": "application/json" },
          });
        }


        return new Response(`Connected: ${id}`, { status: 200 });
      }
    }
  }
  ```

* TypeScript

  ```ts
  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 { id, authUrl } = await this.addMcpServer(
          "Weather API",
          "https://weather-mcp.example.com/mcp",
        );


        if (authUrl) {
          return new Response(JSON.stringify({ authUrl }), {
            headers: { "Content-Type": "application/json" },
          });
        }


        return new Response(`Connected: ${id}`, { status: 200 });
      }
    }
  }
  ```

Connections persist in the Agent's [SQL storage](https://developers.cloudflare.com/agents/api-reference/store-and-sync-state), and when an Agent connects to an MCP server, all tools from that server become available automatically.

## Agent MCP Client Methods

### `addMcpServer()`

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

```ts
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; authUrl: string | undefined }>
```

#### Parameters

* **`serverName`** (string, required) — Display name for the MCP server

* **`url`** (string, required) — URL of the MCP server endpoint

* **`callbackHost`** (string, optional) — Host for OAuth callback URL. If omitted, automatically derived from the incoming request

* **`agentsPrefix`** (string, optional) — URL prefix for OAuth callback path. Default: `"agents"`

* **`options`** (object, optional) — Connection configuration:

  * **`client`** — MCP client configuration options (passed to `@modelcontextprotocol/sdk` Client constructor)

  * **`transport`** — Transport layer configuration:

    * **`headers`** — Custom HTTP headers for authentication
    * **`type`** — Transport type: `"sse"`, `"streamable-http"`, or `"auto"` (tries streamable-http first, falls back to sse)

#### Returns

A Promise that resolves to an object containing:

* **`id`** (string) — Unique identifier for this server connection
* **`authUrl`** (string | undefined) — OAuth authorization URL if authentication is required, otherwise `undefined`

#### Example

* JavaScript

  ```js
  export class MyAgent extends Agent {
    async onRequest(request) {
      const { id, authUrl } = await this.addMcpServer(
        "Weather API",
        "https://weather-mcp.example.com/mcp",
      );


      if (authUrl) {
        // User needs to complete OAuth flow
        return new Response(JSON.stringify({ serverId: id, authUrl }), {
          headers: { "Content-Type": "application/json" },
        });
      }


      return new Response("Connected", { status: 200 });
    }
  }
  ```

* TypeScript

  ```ts
  export class MyAgent extends Agent<Env, never> {
    async onRequest(request: Request): Promise<Response> {
      const { id, authUrl } = await this.addMcpServer(
        "Weather API",
        "https://weather-mcp.example.com/mcp",
      );


      if (authUrl) {
        // User needs to complete OAuth flow
        return new Response(JSON.stringify({ serverId: id, authUrl }), {
          headers: { "Content-Type": "application/json" },
        });
      }


      return new Response("Connected", { 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:**

* [OAuth handling guide](https://developers.cloudflare.com/agents/guides/oauth-mcp-client)
* [Transport options](https://developers.cloudflare.com/agents/model-context-protocol/transport)
* [removeMcpServer()](#removemcpserver)

### `removeMcpServer()`

Disconnect from an MCP server and clean up its resources.

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

#### Parameters

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

#### Returns

A Promise that resolves when disconnection is complete.

#### Example

* JavaScript

  ```js
  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 });
      }
    }
  }
  ```

* TypeScript

  ```ts
  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.

### `getMcpServers()`

Get the current state of all MCP server connections.

```ts
getMcpServers(): MCPServersState
```

#### Parameters

None.

#### Returns

An `MCPServersState` object containing:

```ts
{
  servers: Record<
    string,
    {
      name: string;
      server_url: string;
      auth_url: string | null;
      state:
        | "authenticating"
        | "connecting"
        | "ready"
        | "discovering"
        | "failed";
      capabilities: ServerCapabilities | null;
      instructions: string | null;
    }
  >;
  tools: Array<Tool & { serverId: string }>;
  prompts: Array<Prompt & { serverId: string }>;
  resources: Array<Resource & { serverId: string }>;
}
```

#### Example

* JavaScript

  ```js
  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" },
        });
      }
    }
  }
  ```

* TypeScript

  ```ts
  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 can be: `authenticating`, `connecting`, `ready`, `discovering`, or `failed`. Use this method to monitor connection status, list available tools, or build UI for connected servers.

## OAuth Configuration

Customize OAuth callback behavior using `this.mcp.configureOAuthCallback()`:

* JavaScript

  ```js
  export class MyAgent extends Agent {
    onStart() {
      this.mcp.configureOAuthCallback({
        successRedirect: "/connected",
        errorRedirect: "/auth-failed",
      });
    }
  }
  ```

* TypeScript

  ```ts
  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](https://developers.cloudflare.com/agents/guides/oauth-mcp-client) for details.

## Error Handling

Use error detection utilities to handle connection errors:

* JavaScript

  ```js
  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;
      }
    }
  }
  ```

* TypeScript

  ```ts
  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;
      }
    }
  }
  ```

## Next Steps

* [Connect your first MCP server](https://developers.cloudflare.com/agents/guides/connect-mcp-client) — Tutorial to get started
* [Handle OAuth flows](https://developers.cloudflare.com/agents/guides/oauth-mcp-client) — Complete OAuth integration guide
