Skip to content

Commit af4ee34

Browse files
docs: update OAuth error handling for MCP clients
Updates documentation to reflect security improvements in OAuth error handling: - Remove MCPClientOAuthResult from customHandler signature (no longer receives error info) - Document new `error` field in MCPServer type that stores connection errors - Update examples to display errors from connection state instead of script alerts - Add note that error messages are automatically escaped to prevent XSS attacks - Simplify customHandler examples to only close popup (errors handled separately) Related to cloudflare/agents#841 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent 7596021 commit af4ee34

File tree

2 files changed

+22
-32
lines changed

2 files changed

+22
-32
lines changed

src/content/docs/agents/guides/oauth-mcp-client.mdx

Lines changed: 18 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -96,24 +96,15 @@ If you opened OAuth in a popup, close it automatically when complete:
9696

9797
```ts title="src/index.ts"
9898
import { Agent } from "agents";
99-
import type { MCPClientOAuthResult } from "agents/mcp";
10099

101100
export class MyAgent extends Agent<Env, never> {
102101
onStart() {
103102
this.mcp.configureOAuthCallback({
104-
customHandler: (result: MCPClientOAuthResult) => {
105-
if (result.authSuccess) {
106-
// Success - close the popup
107-
return new Response("<script>window.close();</script>", {
108-
headers: { "content-type": "text/html" },
109-
});
110-
} else {
111-
// Error - show message, then close
112-
return new Response(
113-
`<script>alert('Authorization failed: ${result.authError}'); window.close();</script>`,
114-
{ headers: { "content-type": "text/html" } },
115-
);
116-
}
103+
customHandler: () => {
104+
// Close the popup after OAuth completes
105+
return new Response("<script>window.close();</script>", {
106+
headers: { "content-type": "text/html" },
107+
});
117108
},
118109
});
119110
}
@@ -122,7 +113,7 @@ export class MyAgent extends Agent<Env, never> {
122113

123114
</TypeScriptExample>
124115

125-
Your main application can detect the popup closing and refresh the connection status.
116+
Your main application can detect the popup closing and refresh the connection status. If OAuth fails, the connection state becomes `"failed"` and the error message is stored in `server.error` for display in your UI.
126117

127118
## Monitor connection status
128119

@@ -163,6 +154,9 @@ function App() {
163154
Authorize
164155
</button>
165156
)}
157+
{server.state === "failed" && server.error && (
158+
<p className="error">{server.error}</p>
159+
)}
166160
</div>
167161
))}
168162
</div>
@@ -216,7 +210,7 @@ Connection states flow: `authenticating` (needs OAuth) → `connecting` (complet
216210

217211
## Handle failures
218212

219-
When OAuth fails, the connection state becomes `"failed"`. Detect this in your UI and allow users to retry:
213+
When OAuth fails, the connection state becomes `"failed"` and the error message is stored in the `server.error` field. Display this error in your UI and allow users to retry:
220214

221215
<TypeScriptExample>
222216

@@ -262,7 +256,7 @@ function App() {
262256

263257
{server.state === "failed" && (
264258
<div>
265-
<p>Connection failed. Please try again.</p>
259+
{server.error && <p className="error">{server.error}</p>}
266260
<button onClick={() => handleRetry(id, server.server_url, server.name)}>
267261
Retry Connection
268262
</button>
@@ -284,17 +278,16 @@ Common failure reasons:
284278
- **Permission denied**: User lacks required permissions
285279
- **Expired session**: OAuth session timed out
286280

287-
Failed connections remain in state until removed with `removeMcpServer(serverId)`.
281+
Failed connections remain in state until removed with `removeMcpServer(serverId)`. The error message is automatically escaped to prevent XSS attacks, so it is safe to display directly in your UI.
288282

289283
## Complete example
290284

291-
This example demonstrates a complete OAuth integration with Cloudflare Observability. Users connect, authorize in a popup window, and the connection becomes available.
285+
This example demonstrates a complete OAuth integration with Cloudflare Observability. Users connect, authorize in a popup window, and the connection becomes available. Errors are automatically stored in the connection state for display in your UI.
292286

293287
<TypeScriptExample>
294288

295289
```ts title="src/index.ts"
296290
import { Agent, routeAgentRequest } from "agents";
297-
import type { MCPClientOAuthResult } from "agents/mcp";
298291

299292
type Env = {
300293
MyAgent: DurableObjectNamespace<MyAgent>;
@@ -303,17 +296,11 @@ type Env = {
303296
export class MyAgent extends Agent<Env, never> {
304297
onStart() {
305298
this.mcp.configureOAuthCallback({
306-
customHandler: (result: MCPClientOAuthResult) => {
307-
if (result.authSuccess) {
308-
return new Response("<script>window.close();</script>", {
309-
headers: { "content-type": "text/html" },
310-
});
311-
} else {
312-
return new Response(
313-
`<script>alert('Authorization failed: ${result.authError}'); window.close();</script>`,
314-
{ headers: { "content-type": "text/html" } },
315-
);
316-
}
299+
customHandler: () => {
300+
// Close popup after OAuth completes (success or failure)
301+
return new Response("<script>window.close();</script>", {
302+
headers: { "content-type": "text/html" },
303+
});
317304
},
318305
});
319306
}

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ An `MCPServersState` object containing:
208208
| "failed";
209209
capabilities: ServerCapabilities | null;
210210
instructions: string | null;
211+
error: string | null;
211212
}
212213
>;
213214
tools: Array<Tool & { serverId: string }>;
@@ -245,7 +246,9 @@ The `state` field indicates the connection lifecycle:
245246
- `connected` — Transport connection established
246247
- `discovering` — Discovering server capabilities (tools, resources, prompts)
247248
- `ready` — Fully connected and operational
248-
- `failed` — Connection failed
249+
- `failed` — Connection failed (see `error` field for details)
250+
251+
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.
249252

250253
Use this method to monitor connection status, list available tools, or build UI for connected servers.
251254

0 commit comments

Comments
 (0)