diff --git a/src/content/docs/agents/api-reference/agents-api.mdx b/src/content/docs/agents/api-reference/agents-api.mdx
index c991b8302e3eab2..8551fbd809745c3 100644
--- a/src/content/docs/agents/api-reference/agents-api.mdx
+++ b/src/content/docs/agents/api-reference/agents-api.mdx
@@ -580,6 +580,40 @@ Visit the [state management API documentation](/agents/api-reference/store-and-s
:::
+### MCP Client API
+
+The Agents SDK allows your Agent to act as an MCP (Model Context Protocol) client, connecting to remote MCP servers and using their tools, resources, and prompts.
+
+
+
+```ts
+class Agent {
+ // Connect to an MCP server
+ async addMcpServer(
+ serverName: string,
+ url: string,
+ callbackHost?: string,
+ agentsPrefix?: string,
+ options?: MCPClientOptions
+ ): Promise<{ id: string; authUrl: string | undefined }>;
+
+ // Disconnect from an MCP server
+ async removeMcpServer(id: string): Promise;
+
+ // Get state of all connected MCP servers
+ getMcpServers(): MCPServersState;
+}
+```
+
+
+
+When your Agent connects to MCP servers, it can dynamically discover and use tools provided by those servers, enabling powerful integrations with external services.
+
+:::note
+
+For complete MCP client API documentation, including OAuth configuration and advanced usage, refer to the [Agent — MCP Client API](/agents/model-context-protocol/mcp-client-api/).
+
+:::
### Client API
diff --git a/src/content/docs/agents/guides/connect-mcp-client.mdx b/src/content/docs/agents/guides/connect-mcp-client.mdx
new file mode 100644
index 000000000000000..2e131959d979d88
--- /dev/null
+++ b/src/content/docs/agents/guides/connect-mcp-client.mdx
@@ -0,0 +1,223 @@
+---
+title: Connect to an MCP server
+pcx_content_type: tutorial
+tags:
+ - MCP
+sidebar:
+ order: 5
+---
+
+import { Render, TypeScriptExample, PackageManagers, Steps } from "~/components";
+
+Your Agent can connect to external [Model Context Protocol (MCP)](https://modelcontextprotocol.io) servers to access their tools and extend your Agent's capabilities. In this tutorial, you'll create an Agent that connects to an MCP server and uses one of its tools.
+
+## What you will build
+
+An Agent with endpoints to:
+- Connect to an MCP server
+- List available tools from connected servers
+- Get the connection status
+
+## Prerequisites
+
+An MCP server to connect to (or use the public example in this tutorial).
+
+## 1. Create a basic Agent
+
+
+
+1. Create a new Agent project using the `hello-world` template:
+
+
+
+2. Move into the project directory:
+
+ ```sh
+ cd my-mcp-client
+ ```
+
+ Your Agent is ready! The template includes a minimal Agent in `src/index.ts`:
+
+
+
+ ```ts title="src/index.ts"
+ import { Agent, type AgentNamespace, routeAgentRequest } from "agents";
+
+ type Env = {
+ HelloAgent: AgentNamespace;
+ };
+
+ export class HelloAgent extends Agent {
+ async onRequest(request: Request): Promise {
+ return new Response("Hello, Agent!", { status: 200 });
+ }
+ }
+
+ export default {
+ async fetch(request: Request, env: Env) {
+ return (
+ (await routeAgentRequest(request, env, { cors: true })) ||
+ new Response("Not found", { status: 404 })
+ );
+ },
+ } satisfies ExportedHandler;
+ ```
+
+
+
+## 2. Add MCP connection endpoint
+
+
+
+1. Add an endpoint to connect to MCP servers. Update your Agent class in `src/index.ts`:
+
+
+
+ ```ts title="src/index.ts"
+ export class HelloAgent extends Agent {
+ async onRequest(request: Request): Promise {
+ const url = new URL(request.url);
+
+ // Connect to an MCP server
+ if (url.pathname.endsWith("add-mcp") && request.method === "POST") {
+ const { serverUrl, name } = (await request.json()) as {
+ serverUrl: string;
+ name: string;
+ };
+
+ const { id, authUrl } = await this.addMcpServer(name, serverUrl);
+
+ if (authUrl) {
+ // OAuth required - return auth URL
+ return new Response(
+ JSON.stringify({ serverId: id, authUrl }),
+ { headers: { "Content-Type": "application/json" } },
+ );
+ }
+
+ return new Response(
+ JSON.stringify({ serverId: id, status: "connected" }),
+ { headers: { "Content-Type": "application/json" } },
+ );
+ }
+
+ return new Response("Not found", { status: 404 });
+ }
+ }
+ ```
+
+
+
+
+The `addMcpServer()` method connects to an MCP server. If the server requires OAuth authentication, it returns an `authUrl` that users must visit to complete authorization.
+
+## 3. Test the connection
+
+
+
+1. Start your development server:
+
+ ```sh
+ npm start
+ ```
+
+2. In a new terminal, connect to an MCP server (using a public example):
+
+ ```sh
+ curl -X POST http://localhost:8788/agents/hello-agent/default/add-mcp \
+ -H "Content-Type: application/json" \
+ -d '{
+ "serverUrl": "https://docs.mcp.cloudflare.com/mcp",
+ "name": "Example Server"
+ }'
+ ```
+
+ You should see a response with the server ID:
+
+ ```json
+ {
+ "serverId": "example-server-id",
+ "status": "connected"
+ }
+ ```
+
+
+
+## 4. List available tools
+
+
+
+1. Add an endpoint to see which tools are available from connected servers:
+
+
+
+ ```ts title="src/index.ts"
+ export class HelloAgent extends Agent {
+ async onRequest(request: Request): Promise {
+ const url = new URL(request.url);
+
+ // ... previous add-mcp endpoint ...
+
+ // List MCP state (servers, tools, etc)
+ if (url.pathname.endsWith("mcp-state") && request.method === "GET") {
+ const mcpState = this.getMcpServers();
+
+ return new Response(JSON.stringify(mcpState, null, 2), {
+ headers: { "Content-Type": "application/json" },
+ });
+ }
+
+ return new Response("Not found", { status: 404 });
+ }
+ }
+ ```
+
+
+2. Test it:
+
+ ```sh
+ curl http://localhost:8788/agents/hello-agent/default/mcp-state
+ ```
+
+ You'll see all connected servers, their connection states, and available tools:
+
+ ```json
+ {
+ "servers": {
+ "example-server-id": {
+ "name": "Example Server",
+ "state": "ready",
+ "server_url": "https://docs.mcp.cloudflare.com/mcp",
+ ...
+ }
+ },
+ "tools": [
+ {
+ "name": "add",
+ "description": "Add two numbers",
+ "serverId": "example-server-id",
+ ...
+ }
+ ]
+ }
+ ```
+
+
+## Summary
+
+You created an Agent that can:
+- Connect to external MCP servers dynamically
+- Handle OAuth authentication flows when required
+- List all available tools from connected servers
+- Monitor connection status
+
+Connections persist in the Agent's [SQL storage](/agents/api-reference/store-and-sync-state/), so they remain active across requests.
+
+## Next steps
+
+- [Handle OAuth flows](/agents/guides/oauth-mcp-client) — Configure OAuth callbacks and error handling
+- [McpClient — API reference](/agents/model-context-protocol/mcp-client-api/) — Complete API documentation
diff --git a/src/content/docs/agents/guides/oauth-mcp-client.mdx b/src/content/docs/agents/guides/oauth-mcp-client.mdx
new file mode 100644
index 000000000000000..914aa34caf8eb64
--- /dev/null
+++ b/src/content/docs/agents/guides/oauth-mcp-client.mdx
@@ -0,0 +1,415 @@
+---
+title: Handle OAuth with MCP servers
+pcx_content_type: how-to
+tags:
+ - MCP
+sidebar:
+ order: 8
+---
+
+import { Render, TypeScriptExample, PackageManagers } from "~/components";
+
+When you build an Agent that connects to OAuth-protected MCP servers (like Slack or Notion), your end users will need to authenticate before the Agent can access their data. This guide shows you how to implement OAuth flows so your users can authorize access seamlessly.
+
+## Understanding the OAuth flow
+
+When your Agent connects to an OAuth-protected MCP server, here's what happens:
+
+1. **Your code calls** `addMcpServer()` with the server URL
+2. **If OAuth is required**, it returns an `authUrl` instead of immediately connecting
+3. **Your application presents** the `authUrl` to your user
+4. **Your user authenticates** on the provider's site (Slack, etc.)
+5. **The provider redirects** back to your Agent's callback URL with an authorization code
+6. **Your Agent completes** the connection automatically
+
+## Connect and initiate OAuth
+
+When you connect to an OAuth-protected server (like Cloudflare Observability), check if `authUrl` is returned. If present, automatically redirect your user to complete authorization:
+
+
+
+```ts title="src/index.ts"
+export class ObservabilityAgent extends Agent {
+ async onRequest(request: Request): Promise {
+ const url = new URL(request.url);
+
+ if (url.pathname.endsWith("connect-observability") && request.method === "POST") {
+ // Attempt to connect to Cloudflare Observability MCP server
+ const { id, authUrl } = await this.addMcpServer(
+ "Cloudflare Observability",
+ "https://observability.mcp.cloudflare.com/mcp",
+ );
+
+ if (authUrl) {
+ // OAuth required - redirect user to authorize
+ return Response.redirect(authUrl, 302);
+ }
+
+ // No OAuth needed - connection complete
+ return new Response(
+ JSON.stringify({ serverId: id, status: "connected" }),
+ { headers: { "Content-Type": "application/json" } },
+ );
+ }
+
+ return new Response("Not found", { status: 404 });
+ }
+}
+```
+
+
+
+Your user is automatically redirected to the provider's OAuth page to authorize access.
+
+### Alternative approaches
+
+Instead of an automatic redirect, you can also present the `authUrl` to your user as a:
+
+- **Popup window**: `window.open(authUrl, '_blank', 'width=600,height=700')` (for dashboard-style apps)
+- **Clickable link**: Display as a button or link (for API documentation or multi-step flows)
+- **Deep link**: Use custom URL schemes for mobile apps
+
+## Configure callback behavior
+
+After your user completes OAuth, the provider redirects back to your Agent's callback URL. Configure what happens next.
+
+### Redirect to your application (recommended)
+
+For the automatic redirect approach, redirect users back to your application after OAuth completes:
+
+
+
+```ts title="src/index.ts"
+export class MyAgent extends Agent {
+ onStart() {
+ this.mcp.configureOAuthCallback({
+ successRedirect: "/dashboard",
+ errorRedirect: "/auth-error",
+ });
+ }
+}
+```
+
+
+
+Users return to `/dashboard` on success or `/auth-error?error=` on failure, maintaining a smooth flow.
+
+### Close popup window
+
+If you used `window.open()` to open OAuth in a popup:
+
+
+
+```ts title="src/index.ts"
+import { Agent } from "agents";
+import type { MCPClientOAuthResult } from "agents/mcp";
+
+export class MyAgent extends Agent {
+ onStart() {
+ this.mcp.configureOAuthCallback({
+ customHandler: (result: MCPClientOAuthResult) => {
+ if (result.authSuccess) {
+ // Success - close the popup
+ return new Response("", {
+ headers: { "content-type": "text/html" },
+ });
+ } else {
+ // Error - show message, then close
+ return new Response(
+ ``,
+ { headers: { "content-type": "text/html" } },
+ );
+ }
+ },
+ });
+ }
+}
+```
+
+
+
+The popup closes automatically, and your main application can detect this and refresh the connection status.
+
+## Monitor connection status
+
+### For React applications (recommended)
+
+Use the `useAgent` hook for automatic state updates:
+
+
+
+```tsx title="src/App.tsx"
+import { useAgent } from "agents/react";
+import type { MCPServersState } from "agents";
+
+function App() {
+ const [mcpState, setMcpState] = useState({
+ prompts: [],
+ resources: [],
+ servers: {},
+ tools: [],
+ });
+
+ const agent = useAgent({
+ agent: "my-agent",
+ name: "session-id",
+ onMcpUpdate: (mcpServers: MCPServersState) => {
+ // Automatically called when MCP state changes!
+ setMcpState(mcpServers);
+ },
+ });
+
+ return (
+