Skip to content

Commit 0aab361

Browse files
docs: Update MCP client API for connection state improvements
Sync documentation for PR #672 which introduces: - MCPConnectionState enum with standardized connection states - Breaking change to addMcpServer() return type (now discriminated union) - New error throwing behavior for connection/discovery failures - New "connected" state between connection and discovery - New discoverIfConnected() function for capability discovery Updated mcp-client-api.mdx with: - Connection state lifecycle documentation - Updated addMcpServer() signature and examples with try-catch - Error handling requirements and examples - Updated getMcpServers() return type with new "connected" state - Breaking change callouts for error handling requirements Added comprehensive changelog entry documenting breaking changes and new features. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 4f17170 commit 0aab361

File tree

2 files changed

+164
-28
lines changed

2 files changed

+164
-28
lines changed
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
---
2+
title: MCP connection state improvements and standardized discovery
3+
description: Introduces MCPConnectionState enum, improved error handling, and separates connection from discovery phases
4+
products:
5+
- agents
6+
- workers
7+
date: 2025-11-26
8+
---
9+
10+
The latest update to [@cloudflare/agents](https://github.com/cloudflare/agents) brings improvements to MCP client connection lifecycle management and error handling. This release standardizes connection states and makes discovery failures more visible.
11+
12+
## Breaking changes
13+
14+
### `addMcpServer()` return type changed
15+
16+
The `addMcpServer()` method now returns a discriminated union that includes the connection state:
17+
18+
```ts
19+
// Before
20+
const { id, authUrl } = await this.addMcpServer("Server", "https://...");
21+
if (authUrl) {
22+
// Handle OAuth
23+
}
24+
25+
// After
26+
const result = await this.addMcpServer("Server", "https://...");
27+
if (result.state === "authenticating") {
28+
// Handle OAuth with result.authUrl
29+
}
30+
```
31+
32+
### Error handling now required
33+
34+
`addMcpServer()` now throws errors when connection or discovery fails. Previously, servers would silently enter the `failed` state. Update your code to handle errors:
35+
36+
```ts
37+
try {
38+
const result = await this.addMcpServer("Server", "https://...");
39+
// Connection succeeded
40+
} catch (error) {
41+
// Handle connection or discovery failure
42+
console.error(`Failed to connect: ${error.message}`);
43+
}
44+
```
45+
46+
### `ClientConnection.init()` no longer discovers automatically
47+
48+
Tool discovery must now be explicitly triggered after initialization. The `MCPClientManager` handles this automatically, but if you are using `ClientConnection` directly, you need to call `discover()` after successful initialization.
49+
50+
## New features
51+
52+
### MCPConnectionState enum
53+
54+
A new `MCPConnectionState` enum standardizes connection states:
55+
56+
- `authenticating` — Waiting for OAuth authorization
57+
- `connecting` — Establishing transport connection
58+
- `connected` — Transport connected but tools not yet discovered
59+
- `discovering` — Discovering server capabilities
60+
- `ready` — Fully connected with all capabilities available
61+
- `failed` — Connection failed
62+
63+
The new `connected` state separates transport connection from capability discovery, providing better visibility into the connection lifecycle.
64+
65+
### `discoverIfConnected()` function
66+
67+
A new convenience function on `MCPClientManager` simplifies capability discovery:
68+
69+
```ts
70+
const result = await this.mcp.discoverIfConnected(serverId);
71+
if (!result.success) {
72+
console.error(`Discovery failed: ${result.error}`);
73+
}
74+
```
75+
76+
## Improvements
77+
78+
### Immediate error reporting
79+
80+
Discovery failures now throw errors immediately using `Promise.all()` instead of continuing with empty arrays. This makes issues visible immediately rather than silently degrading functionality.
81+
82+
### Better connection state visibility
83+
84+
The connection state machine is now formalized with explicit enum values, making it easier to understand and monitor connection lifecycle in `getMcpServers()`.
85+
86+
Learn more in the [MCP Client API documentation](/agents/model-context-protocol/mcp-client-api/).

src/content/docs/agents/model-context-protocol/mcp-client-api.mdx

Lines changed: 78 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,22 @@ export class MyAgent extends Agent<Env, never> {
2525
const url = new URL(request.url);
2626

2727
if (url.pathname === "/connect" && request.method === "POST") {
28-
const { id, authUrl } = await this.addMcpServer(
29-
"Weather API",
30-
"https://weather-mcp.example.com/mcp",
31-
);
32-
33-
if (authUrl) {
34-
return new Response(JSON.stringify({ authUrl }), {
35-
headers: { "Content-Type": "application/json" },
36-
});
28+
try {
29+
const result = await this.addMcpServer(
30+
"Weather API",
31+
"https://weather-mcp.example.com/mcp",
32+
);
33+
34+
if (result.state === "authenticating") {
35+
return new Response(JSON.stringify({ authUrl: result.authUrl }), {
36+
headers: { "Content-Type": "application/json" },
37+
});
38+
}
39+
40+
return new Response(`Connected: ${result.id}`, { status: 200 });
41+
} catch (error) {
42+
return new Response(`Connection failed: ${error}`, { status: 500 });
3743
}
38-
39-
return new Response(`Connected: ${id}`, { status: 200 });
4044
}
4145
}
4246
}
@@ -46,6 +50,27 @@ export class MyAgent extends Agent<Env, never> {
4650

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

53+
## Connection States
54+
55+
When connecting to an MCP server, the connection progresses through different states represented by the `MCPConnectionState` enum:
56+
57+
- **`authenticating`** — Server requires OAuth; waiting for user authentication
58+
- **`connecting`** — Establishing connection to the server
59+
- **`connected`** — Transport connection established, awaiting initialization
60+
- **`discovering`** — Retrieving available tools, prompts, and resources
61+
- **`ready`** — Fully connected and all capabilities available
62+
- **`failed`** — Connection or discovery failed
63+
64+
### Typical Connection Flow
65+
66+
**For servers without OAuth:**
67+
`connecting``connected``discovering``ready`
68+
69+
**For servers with OAuth:**
70+
`authenticating` → (user completes OAuth) → `connecting``connected``discovering``ready`
71+
72+
If any step fails, the state transitions to `failed` and an error is thrown.
73+
4974
## Agent MCP Client Methods
5075

5176
### `addMcpServer()`
@@ -65,7 +90,10 @@ async addMcpServer(
6590
type?: "sse" | "streamable-http" | "auto";
6691
};
6792
}
68-
): Promise<{ id: string; authUrl: string | undefined }>
93+
): Promise<
94+
| { id: string; state: "authenticating"; authUrl: string }
95+
| { id: string; state: "ready"; authUrl?: undefined }
96+
>
6997
```
7098

7199
#### Parameters
@@ -82,10 +110,21 @@ async addMcpServer(
82110

83111
#### Returns
84112

85-
A Promise that resolves to an object containing:
113+
A Promise that resolves to a discriminated union based on the connection state:
86114

115+
**When authentication is required:**
87116
- **`id`** (string) — Unique identifier for this server connection
88-
- **`authUrl`** (string | undefined) — OAuth authorization URL if authentication is required, otherwise `undefined`
117+
- **`state`** (`"authenticating"`) — Indicates OAuth authentication is needed
118+
- **`authUrl`** (string) — OAuth authorization URL for user authentication
119+
120+
**When connection is ready:**
121+
- **`id`** (string) — Unique identifier for this server connection
122+
- **`state`** (`"ready"`) — Indicates the server is fully connected and ready
123+
- **`authUrl`** (undefined) — No authentication URL when ready
124+
125+
#### Throws
126+
127+
Throws an error if the connection or discovery process fails. Always wrap `addMcpServer()` calls in try-catch blocks to handle connection failures gracefully.
89128

90129
#### Example
91130

@@ -94,26 +133,36 @@ A Promise that resolves to an object containing:
94133
```ts title="src/index.ts"
95134
export class MyAgent extends Agent<Env, never> {
96135
async onRequest(request: Request): Promise<Response> {
97-
const { id, authUrl } = await this.addMcpServer(
98-
"Weather API",
99-
"https://weather-mcp.example.com/mcp",
100-
);
101-
102-
if (authUrl) {
103-
// User needs to complete OAuth flow
104-
return new Response(JSON.stringify({ serverId: id, authUrl }), {
105-
headers: { "Content-Type": "application/json" },
106-
});
107-
}
136+
try {
137+
const result = await this.addMcpServer(
138+
"Weather API",
139+
"https://weather-mcp.example.com/mcp",
140+
);
108141

109-
return new Response("Connected", { status: 200 });
142+
if (result.state === "authenticating") {
143+
// User needs to complete OAuth flow
144+
return new Response(JSON.stringify({ serverId: result.id, authUrl: result.authUrl }), {
145+
headers: { "Content-Type": "application/json" },
146+
});
147+
}
148+
149+
return new Response(`Connected: ${result.id}`, { status: 200 });
150+
} catch (error) {
151+
return new Response(`Connection failed: ${error}`, { status: 500 });
152+
}
110153
}
111154
}
112155
```
113156

114157
</TypeScriptExample>
115158

116-
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.
159+
If the MCP server requires OAuth authentication, the response will have `state: "authenticating"` with an `authUrl` for user authentication. Connections persist across requests and the Agent will automatically reconnect if the connection is lost.
160+
161+
:::note[Breaking Change: Error Handling Required]
162+
163+
As of the latest version, `addMcpServer()` now throws errors on connection or discovery failures instead of returning a failed state. Always wrap calls in try-catch blocks to handle errors gracefully. The return type is now a discriminated union based on the connection state.
164+
165+
:::
117166

118167
:::note[Default JSON Schema Validation]
119168

@@ -193,6 +242,7 @@ An `MCPServersState` object containing:
193242
state:
194243
| "authenticating"
195244
| "connecting"
245+
| "connected"
196246
| "ready"
197247
| "discovering"
198248
| "failed";
@@ -228,7 +278,7 @@ export class MyAgent extends Agent<Env, never> {
228278

229279
</TypeScriptExample>
230280

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

233283
## OAuth Configuration
234284

0 commit comments

Comments
 (0)