Skip to content

fix(mcp): FastMCP-compatible redirect-URI patterns for DCR allow-list#34

Open
hunzlahmalik wants to merge 1 commit into
foss-sandboxfrom
fix/mcp-redirect-uri-patterns
Open

fix(mcp): FastMCP-compatible redirect-URI patterns for DCR allow-list#34
hunzlahmalik wants to merge 1 commit into
foss-sandboxfrom
fix/mcp-redirect-uri-patterns

Conversation

@hunzlahmalik

Copy link
Copy Markdown

What

Fixes the DCR redirect-URI allow-list matcher so the shared MCP_ALLOWED_CLIENT_REDIRECT_URIS value parses the same way in the Penpot MCP gate as it does for surfsense-mcp / plane-mcp. Follow-up to #33.

Problem

MCP_ALLOWED_CLIENT_REDIRECT_URIS is one value shared across all three MCP servers, written in FastMCP's pattern syntax (http://localhost:*, https://claude.ai/*). The origin-equality matcher merged in #33 can't satisfy a port wildcard: http://localhost:* has no port in its prefix, so new URL("http://localhost:").origin resolves to http://localhost and never equals http://localhost:6274.

Result on the sandbox: every MCP Inspector / loopback DCR registration fails with

400 invalid_request — redirect_uri is not allowed by this server: http://localhost:6274/oauth/callback

Fix

Port FastMCP's component-wise matcher (fastmcp/server/auth/redirect_validation.py):

  • scheme compared exactly
  • host with *.example.com subdomain wildcards (apex excluded)
  • port with a * wildcard, plus RFC 8252 loopback any-port semantics (http://localhost:* / http://127.0.0.1:* match any port)
  • path as a glob (/auth/*)
  • URIs carrying userinfo are rejected outright, so http://localhost@evil.com can never satisfy a localhost pattern and a host can't be extended past a too-broad entry

Verified

Tested against the exact sandbox allow-list — 20 cases:

  • http://localhost:6274/oauth/callback, /oauth/callback/debug, http://127.0.0.1:*
  • https://claude.ai/*, https://claude.com/*, https://sandbox.askii.ai/* and the other askii subdomains
  • ✅ Denied: http://localhost@evil.com/..., https://claude.ai.evil.com/..., https://sandbox.askii.ai.evil.com/..., scheme swaps, unparseable values

tsc --noEmit clean.

Note

A no-redeploy env stopgap exists for the currently-deployed image (give the loopback entries explicit ports: http://localhost:6274/*,http://127.0.0.1:6274/*). This PR is the real fix — once merged and deployed, the allow-list can return to the FastMCP :* form for proper any-port loopback support, identical to the other MCP servers.

🤖 Generated with Claude Code

MCP_ALLOWED_CLIENT_REDIRECT_URIS is one value shared across the stack,
written in FastMCP's pattern syntax (http://localhost:*,
https://claude.ai/*). The origin-equality matcher merged in #33 can't
satisfy a port wildcard: http://localhost:* has no port in its prefix,
so its origin resolves to http://localhost and never equals
http://localhost:6274 — every MCP Inspector / loopback DCR registration
fails with "redirect_uri is not allowed by this server".

Port FastMCP's component-wise matcher: scheme compared exactly, host
with *.example.com subdomain wildcards (apex excluded), port with a "*"
wildcard plus RFC 8252 loopback any-port semantics, path as a glob.
URIs carrying userinfo are rejected outright, so
http://localhost@evil.com can never satisfy a localhost pattern and a
host can never be extended past a too-broad entry.

Verified against the sandbox allow-list (20 cases): Inspector loopback
callbacks and claude.ai / claude.com callbacks match; evil-host,
userinfo and scheme-swap variants do not.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant