Skip to content

Conversation

@agents-git-bot
Copy link
Contributor

@agents-git-bot agents-git-bot bot commented Feb 6, 2026

Summary

Updates MCP OAuth client documentation to reflect improved error handling from cloudflare/agents#850.

Changes

  • Updated customHandler examples to properly check result.authSuccess and handle both success and error cases with user-friendly HTML error pages
  • Added configureOAuthCallback() API reference with complete documentation of parameters and MCPClientOAuthResult type
  • Documented default error handling behavior when no callback configuration is provided (displays HTML error page instead of silent redirect)
  • Added error field to MCPServersState type for displaying error messages in failed connection states
  • Updated failure handling examples in React applications to show error messages to users
  • Added important warnings about checking authSuccess to avoid silently swallowing authentication errors

Context

MCP OAuth errors were previously silently swallowed in most configurations. The SDK now:

  1. Properly catches and surfaces errors from handleCallbackRequest through the normal response path (fixes unhandled throws after hibernation)
  2. Returns 400 HTML error pages by default instead of silent redirects when no errorRedirect or customHandler is configured
  3. Provides error details via MCPClientOAuthResult.authError and server.error fields

This documentation update ensures developers understand how to properly handle and display these errors to their users.

Related PR

@github-actions github-actions bot added product:agents Build and deploy AI-powered Agents on Cloudflare that can act autonomously. size/s labels Feb 6, 2026
@github-actions
Copy link
Contributor

github-actions bot commented Feb 6, 2026

This pull request requires reviews from CODEOWNERS as it changes files that match the following patterns:

Pattern Owners
/src/content/docs/agents/ @irvinebroque, @rita3ko, @elithrar, @thomasgauvin, @threepointone, @whoiskatrin, @cloudflare/pcx-technical-writing, @cloudflare/ai-agents, @cloudflare/dev-plat-leads

@elithrar
Copy link
Collaborator

elithrar commented Feb 6, 2026

/bonk review this PR.

@ask-bonk
Copy link
Contributor

ask-bonk bot commented Feb 6, 2026

Now I have full context. Let me review this PR thoroughly.

PR Review: docs: surface MCP OAuth errors to browser instead of silently swallowing

Overview

This PR updates two documentation files to reflect improved error handling from cloudflare/agents#850. The changes are well-scoped and the documentation accurately describes the new behavior.

File-by-file review

src/content/docs/agents/guides/oauth-mcp-client.mdx (+44/-11)

  1. New "Default behavior" section (lines 75-82) - Good addition. Clearly explains what happens out-of-the-box, which is important since the previous behavior silently swallowed errors.

  2. Updated error redirect clarification (line 103) - The note that "errors still show the default HTML error page" when only successRedirect is configured is a useful edge case to document.

  3. Improved popup error handling example (lines 118-141) - Replacing the alert() + immediate window.close() with a styled HTML error page and 3-second delay before closing is a much better UX pattern. The old alert() approach was blocking and crude.

  4. Result object documentation (lines 150-154) - Good to document the shape of MCPClientOAuthResult inline where the customHandler is first introduced.

  5. server.error in failure handling (line 299) - Showing {server.error || "Unknown error"} is the right pattern for displaying error details.

  6. "Connection lost" failure reason (line 322) - Important to document the hibernation scenario.

  7. Note about error surfacing (lines 326-330) - Useful context about hibernation behavior.

Issues found

1. XSS vulnerability in HTML template (medium severity)

At oauth-mcp-client.mdx:132, result.authError is interpolated directly into HTML without escaping:

<p style="color:#666;">${result.authError}</p>

If the error message contains HTML/script tags, this is an XSS vector. The same pattern appears in the "Complete example" at line 356:

`<script>alert('Authorization failed: ${result.authError}'); window.close();</script>`

This second instance (line 356 in the "Complete example") was not updated by this PR - it still uses the old alert() pattern, which is inconsistent with the improved error handling shown in the popup section above. The complete example should be updated to match.

2. Inconsistency between guide and API reference error examples

The guide (oauth-mcp-client.mdx:127-141) shows a full styled HTML error page, while the API reference (mcp-client-api.mdx:221-228) shows a minimal <html><body>Auth failed: ${result.authError}</body></html>. This inconsistency is fine for reference docs being more concise, but the API reference example is also missing <!DOCTYPE html> which the guide includes. Minor, but worth noting for consistency.

3. The complete example at the bottom was not updated

oauth-mcp-client.mdx:354-358 still shows the old alert-based pattern:

return new Response(
    `<script>alert('Authorization failed: ${result.authError}'); window.close();</script>`,
    { headers: { "content-type": "text/html" } },
);

This contradicts the improved error handling documented earlier in the same page. The complete example should be updated to use the HTML error page approach (or at least not use alert()).

src/content/docs/agents/model-context-protocol/mcp-client-api.mdx (+40/-4)

  1. Added MCPClientOAuthResult import and type annotation (lines 200, 212) - Good improvement. The previous untyped (result) parameter was less clear.

  2. New "Default behavior" and "Configuration options" sections (lines 236-259) - Good documentation of the MCPClientOAuthResult type and configuration options directly in the API reference.

  3. Added error?: string to MCPServersState (line 513) - Necessary addition to reflect the new field.

Summary

The PR is a solid documentation update. The main actionable item is the complete example at the bottom of oauth-mcp-client.mdx still uses the old alert() pattern, which directly contradicts the guidance given earlier in the same document. That should be updated to match. The XSS concern in the template literals is worth a mention since these are copy-paste examples developers will use directly, though it may be out of scope for this PR if the SDK itself doesn't escape errors either.

github run

@elithrar
Copy link
Collaborator

elithrar commented Feb 6, 2026

/bonk fix the examples. be precise. validate they are issues, but examples should be "safe by default" for users.

@ask-bonk
Copy link
Contributor

ask-bonk bot commented Feb 6, 2026

Three fixes applied across 2 files:

What was fixed

XSS in all customHandler examples -- result.authError comes from external OAuth providers and was interpolated directly into HTML template literals without escaping. A malicious or misconfigured provider returning <script>...</script> as an error message would get executed in the user's browser.

File Location Fix
oauth-mcp-client.mdx Popup error example (~line 132) Added escapeHtml() helper, use safeError in template
oauth-mcp-client.mdx Complete example (~line 356) Replaced alert() pattern entirely with safe HTML error page + escapeHtml()
mcp-client-api.mdx Custom OAuth callback (~line 222) Added escapeHtml() helper, use safeError in template, added <!DOCTYPE html>

Why this matters: These are copy-paste examples. Developers will use them as-is. The examples should be safe by default rather than requiring readers to notice they need to add escaping themselves.

github run

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/bonk consider more reliable ways to handle HTML escaping. don't leave users at risk when they copy our examples.

@ask-bonk
Copy link
Contributor

ask-bonk bot commented Feb 6, 2026

Here's what I changed and why:

Problem with escapeHtml()

The hand-rolled regex chain had several weaknesses:

  1. Missing characters -- didn't encode ' (single quote → &#39;), which matters in attribute contexts
  2. Order-dependent -- the & replacement must come first or it double-encodes; easy to get wrong when someone copies and modifies the function
  3. Incomplete coverage -- no handling for backticks, null bytes, or other injection vectors in template literal contexts
  4. Duplicated 3 times -- each copy is a maintenance risk

New approach: JSON.stringify + textContent

Instead of trying to escape for HTML, avoid HTML parsing of the untrusted string entirely:

const errorJson = JSON.stringify(result.authError ?? "Unknown error");
// ...
<p id="err"></p>
<script>
  document.getElementById("err").textContent = ${errorJson};
</script>

Why this is strictly safer:

  • JSON.stringify is a platform primitive (not hand-rolled) that correctly handles all Unicode, quotes, angle brackets, backslashes, null bytes, etc.
  • textContent never interprets its input as HTML -- it's a text-only DOM setter. Even if the error string contains <script>alert(1)</script>, it renders as literal text.
  • The error string never passes through the HTML parser at all. There is no escaping to get wrong.

Applied consistently to all 3 customHandler examples across both files (oauth-mcp-client.mdx:128-140, oauth-mcp-client.mdx:363-378, mcp-client-api.mdx:221-227).

github run

Updates documentation to reflect improved OAuth error handling from
cloudflare/agents#850.

Changes:
- Update customHandler examples to properly check result.authSuccess
- Document MCPClientOAuthResult type with authSuccess and authError fields
- Add configureOAuthCallback() API reference documentation
- Document default error page behavior when no callback config is provided
- Add error field to MCPServersState type for failed connections
- Add examples showing proper error handling in React applications

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@agents-git-bot agents-git-bot bot changed the title docs: surface MCP OAuth errors to browser instead of silently swallowing docs: update MCP OAuth error handling documentation Feb 6, 2026
@elithrar
Copy link
Collaborator

elithrar commented Feb 6, 2026

/bonk re-review and make sure the latest commit didn't break our changes

Use JSON.stringify + textContent for HTML examples to avoid injecting
untrusted authError strings into the DOM via innerHTML. Add explicit
content-type: text/plain to API reference plain-text error responses
to prevent browser content sniffing.
@ask-bonk
Copy link
Contributor

ask-bonk bot commented Feb 6, 2026

Summary

The latest commit (a85e174) did not include the XSS safety fixes that were discussed and agreed upon in the review thread. All four customHandler examples were still interpolating result.authError directly into HTML/response bodies without any escaping.

What I fixed

File Location Issue Fix
oauth-mcp-client.mdx Popup example (~line 117) ${error} interpolated directly into HTML <p> tag JSON.stringify() + textContent
oauth-mcp-client.mdx Complete example (~line 346) Same raw interpolation Same JSON.stringify() + textContent fix
mcp-client-api.mdx Inline example (~line 224) Raw interpolation, no explicit content-type Added ?? "Unknown error" fallback + content-type: text/plain header
mcp-client-api.mdx Usage example (~line 580) Same pattern Same fix

Why this matters

result.authError comes from external OAuth providers. A malicious or misconfigured provider returning <script>...</script> as an error message would get executed in the user's browser. Since these are copy-paste documentation examples, they need to be safe by default.

The JSON.stringify + textContent approach is strictly safer than hand-rolled escapeHtml() because:

  • JSON.stringify is a platform primitive that correctly handles all Unicode, quotes, angle brackets, etc.
  • textContent is a text-only DOM setter that never interprets input as HTML
  • The error string never passes through the HTML parser at all

github run

Copy link
Collaborator

@elithrar elithrar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is good now.

@elithrar elithrar enabled auto-merge (squash) February 6, 2026 17:19
@elithrar elithrar merged commit 475fdde into production Feb 6, 2026
9 checks passed
@elithrar elithrar deleted the sync-docs-pr-850 branch February 6, 2026 17:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

product:agents Build and deploy AI-powered Agents on Cloudflare that can act autonomously. size/s

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants