Skip to content

Commit 49492cf

Browse files
docs: Update MCP OAuth security documentation
Update OAuth documentation to reflect security improvements from PR #841: - Remove vulnerable pattern of displaying errors via script tags - Document new error field on MCPServer type for safe error display - Update custom OAuth handler examples to use secure pattern - Add note about XSS prevention in popup OAuth flows Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent 201258a commit 49492cf

File tree

2 files changed

+22
-29
lines changed

2 files changed

+22
-29
lines changed

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

Lines changed: 18 additions & 28 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 popup on both success and failure
105+
return new Response("<script>window.close();</script>", {
106+
headers: { "content-type": "text/html" },
107+
});
117108
},
118109
});
119110
}
@@ -124,6 +115,12 @@ export class MyAgent extends Agent<Env, never> {
124115

125116
Your main application can detect the popup closing and refresh the connection status.
126117

118+
:::note[Error handling in popup flow]
119+
120+
When using the popup approach, authentication errors are automatically stored in the connection state with the `error` field on the `MCPServer` object. Display these errors in your main application UI rather than in the popup window. This approach prevents XSS vulnerabilities and provides better user experience.
121+
122+
:::
123+
127124
## Monitor connection status
128125

129126
### React applications
@@ -216,7 +213,7 @@ Connection states flow: `authenticating` (needs OAuth) → `connecting` (complet
216213

217214
## Handle failures
218215

219-
When OAuth fails, the connection state becomes `"failed"`. Detect this in your UI and allow users to retry:
216+
When OAuth fails, the connection state becomes `"failed"`. The `error` field on the server object contains details about the failure. Detect this in your UI and allow users to retry:
220217

221218
<TypeScriptExample>
222219

@@ -262,7 +259,7 @@ function App() {
262259

263260
{server.state === "failed" && (
264261
<div>
265-
<p>Connection failed. Please try again.</p>
262+
<p>Connection failed: {server.error || "Unknown error"}</p>
266263
<button onClick={() => handleRetry(id, server.server_url, server.name)}>
267264
Retry Connection
268265
</button>
@@ -294,7 +291,6 @@ This example demonstrates a complete OAuth integration with Cloudflare Observabi
294291

295292
```ts title="src/index.ts"
296293
import { Agent, routeAgentRequest } from "agents";
297-
import type { MCPClientOAuthResult } from "agents/mcp";
298294

299295
type Env = {
300296
MyAgent: DurableObjectNamespace<MyAgent>;
@@ -303,17 +299,10 @@ type Env = {
303299
export class MyAgent extends Agent<Env, never> {
304300
onStart() {
305301
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-
}
302+
customHandler: () => {
303+
return new Response("<script>window.close();</script>", {
304+
headers: { "content-type": "text/html" },
305+
});
317306
},
318307
});
319308
}
@@ -348,6 +337,7 @@ export class MyAgent extends Agent<Env, never> {
348337
name: server.name,
349338
state: server.state,
350339
authUrl: server.auth_url,
340+
error: server.error,
351341
}),
352342
);
353343
return Response.json(connections);

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
@@ -206,6 +206,7 @@ An `MCPServersState` object containing:
206206
| "discovering"
207207
| "ready"
208208
| "failed";
209+
error: string | null;
209210
capabilities: ServerCapabilities | null;
210211
instructions: string | null;
211212
}
@@ -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 (check `error` field for details)
250+
251+
The `error` field contains a human-readable error message when `state` is `"failed"`. Error messages are automatically sanitized to prevent XSS vulnerabilities. This field is `null` for all other states.
249252

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

0 commit comments

Comments
 (0)