Fix MCP OAuth callback URL leaking instance name#868
Merged
Conversation
🦋 Changeset detectedLatest commit: 47633ba The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
This comment was marked as resolved.
This comment was marked as resolved.
agents-git-bot Bot
pushed a commit
to cloudflare/cloudflare-docs
that referenced
this pull request
Feb 8, 2026
Add documentation for the new callbackPath parameter in addMcpServer() that allows custom OAuth callback URL paths. This is required when sendIdentityOnConnect is false to prevent instance name leakage. Changes: - Add callbackPath parameter to addMcpServer() API reference - Add security section explaining when and why callbackPath is required - Include example showing how to route custom callback paths with getAgentByName - Note that callback matching uses state parameter, not URL path Relates to cloudflare/agents#868 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
commit: |
4 tasks
threepointone
commented
Feb 8, 2026
threepointone
requested review from
mattzcarey
and removed request for
mattzcarey
February 8, 2026 16:26
elithrar
added a commit
to cloudflare/cloudflare-docs
that referenced
this pull request
Feb 8, 2026
* Document callbackPath option for MCP OAuth callback security Add documentation for the new callbackPath parameter in addMcpServer() that allows custom OAuth callback URL paths. This is required when sendIdentityOnConnect is false to prevent instance name leakage. Changes: - Add callbackPath parameter to addMcpServer() API reference - Add security section explaining when and why callbackPath is required - Include example showing how to route custom callback paths with getAgentByName - Note that callback matching uses state parameter, not URL path Relates to cloudflare/agents#868 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * Fix export and await in code example Co-authored-by: elithrar <elithrar@users.noreply.github.com> --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com> Co-authored-by: opencode-agent[bot] <opencode-agent[bot]@users.noreply.github.com> Co-authored-by: elithrar <elithrar@users.noreply.github.com>
threepointone
force-pushed
the
fix-basepath-mcp-callbacks
branch
from
February 8, 2026 23:01
edd9811 to
9f1a3a8
Compare
Add `callbackPath` option to `addMcpServer` to prevent instance name
leakage in MCP OAuth callback URLs. When `sendIdentityOnConnect` is
`false`, `callbackPath` is now required — the default callback URL would
expose the instance name, undermining the security intent.
Replace the loose `url.includes("/callback")` check in
`isCallbackRequest` with origin + pathname matching against the stored
callback URL, enabling custom callback paths while preventing unrelated
GET requests from being intercepted.
Co-authored-by: Cursor <cursoragent@cursor.com>
agents-git-bot Bot
pushed a commit
to cloudflare/cloudflare-docs
that referenced
this pull request
Feb 8, 2026
Update MCP client API documentation to reflect new security requirements from agents PR #868: - Clarify that callbackPath is required when sendIdentityOnConnect is false - Document that addMcpServer() throws an error without callbackPath - Explain the enhanced callback matching logic (state param + origin/pathname verification) - Add details about callbackPath format requirements (plain path, no query strings) Related to: cloudflare/agents#868 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
threepointone
force-pushed
the
fix-basepath-mcp-callbacks
branch
from
February 8, 2026 23:06
9f1a3a8 to
47633ba
Compare
agents-git-bot Bot
pushed a commit
to cloudflare/cloudflare-docs
that referenced
this pull request
Feb 8, 2026
Update MCP client API documentation to reflect the new security requirement that callbackPath must be provided when sendIdentityOnConnect is false. Changes: - Emphasize that callbackPath is REQUIRED (not optional) when sendIdentityOnConnect is false - Add error behavior information (throws if callbackPath is missing) - Update callback matching explanation (state parameter + origin/pathname verification) - Add example callback URL format for custom callbackPath - Clarify security implications (OAuth provider, browser history, address bar) Related to cloudflare/agents#868 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #854
Problem
When an agent uses
sendIdentityOnConnect: falseto protect sensitive instance names (session IDs, user IDs), the MCP OAuth callback URL still exposes the raw instance name:This URL is sent to the remote OAuth provider as
redirect_uri, displayed in the browser address bar, and saved in browser history — completely undermining the security intent. Additionally, the hardcoded/agents/{class}/{name}/callbackpattern doesn't work for developers usingbasePathrouting withgetAgentByName.Design decisions
callbackPathis required whensendIdentityOnConnect: false.Rather than silently hashing or obfuscating the instance name (which would require complex coordination between the routing layer and DO storage), we make the developer explicitly provide a safe callback path. This is consistent with how
basePathalready works — if you've opted into custom routing to protect instance names, you handle the routing yourself viagetAgentByName. The error message is actionable and tells the developer exactly what to do.callbackPathis optional whensendIdentityOnConnect: true.The default auto-constructed URL (
/agents/{class}/{name}/callback) still works for developers who haven't opted out of identity exposure. This keeps the simple case simple. Developers can still providecallbackPathif they prefer cleaner URLs or a different routing pattern.Callback detection uses
stateparameter with origin + pathname verification.Previously,
isCallbackRequest()checkedurl.includes("/callback")as a loose heuristic — this would break with custom callback paths (e.g.,/mcp-oauth-return). Thestatequery parameter (format:{nonce}.{serverId}) is now the primary mechanism for identifying which server a callback belongs to. As defense-in-depth, we also verify that the request's origin and pathname match the registeredcallback_urlfor that server, preventing unrelated GET requests with astateparam from being intercepted.Changes
AddMcpServerOptionstype — newcallbackPath?: stringfield with JSDoc documenting it should be a plain path (no query strings or fragments)addMcpServer()— resolvescallbackPath, enforces it whensendIdentityOnConnect: false, uses it for URL construction when provided. Also normalizes trailing slashes oncallbackHostto prevent double-slash URLs.isCallbackRequest()— replaced looseurl.includes("/callback")substring check with state-based server ID matching plus origin + pathname verification against the storedcallback_urlclient-manager.test.ts. New integration tests inadd-mcp-server.test.tsverifying thecallbackPathenforcement (throws whensendIdentityOnConnect: falsewithoutcallbackPath, does not throw whencallbackPathis provided).Notes for reviewers
The
isCallbackRequestchange is the subtlest part. The old/callbacksubstring check is replaced by a two-layer approach: (1) extractserverIdfrom thestateparam and confirm it exists in storage, (2) verify the request's origin + pathname match the storedcallback_urlfor that server. This is both more precise and more permissive than before — it works with any callback path while preventing false-positive interception.The runtime enforcement (throw when
sendIdentityOnConnect: falsewithoutcallbackPath) can't be done at the type level sincesendIdentityOnConnectis onstatic optionsandcallbackPathis on theaddMcpServercall — TypeScript can't connect those two. The runtime error is clear and fails fast.