Skip to content

fix(private-server): accept the deployment Host on the MCP endpoint#273

Merged
passcod merged 1 commit into
mainfrom
mcp-allowed-hosts
Jun 25, 2026
Merged

fix(private-server): accept the deployment Host on the MCP endpoint#273
passcod merged 1 commit into
mainfrom
mcp-allowed-hosts

Conversation

@passcod

@passcod passcod commented Jun 25, 2026

Copy link
Copy Markdown
Member

🤖 The MCP endpoint (/api/mcp) returns Forbidden: Host header is not allowed for any non-loopback host, so connecting from the production tailnet URL fails — clients (Claude Code) surface this as "needs authentication".

Cause

rmcp's Streamable HTTP transport ships a DNS-rebinding guard whose allowed_hosts defaults to loopback only (localhost, 127.0.0.1, ::1). That defense is aimed at browser-facing localhost MCP servers; it doesn't fit this deployment, where the endpoint is reachable only through the Tailscale ingress (which injects the caller's identity), behind the tagged-device guard and the tailnet-user gate, and serves no CORS headers (so a browser can't make a cross-origin POST to it).

Fix

Disable the Host allowlist by default. An operator who still wants to pin it can set CANOPY_MCP_ALLOWED_HOSTS to a comma-separated list (e.g. canopy.example.ts.net); loopback stays allowed for local dev.

Adds a regression test asserting a non-loopback Host is accepted.

rmcp's Streamable HTTP DNS-rebinding guard defaults allowed_hosts to
loopback only, so the production tailnet host got 'Forbidden: Host header
is not allowed' (which clients surface as 'needs authentication'). The
endpoint is already gated by the Tailscale ingress, the tagged-device
guard, and the tailnet-user check, and serves no CORS headers, so the
browser-oriented host check is redundant here. Disable it by default;
an operator can still pin hosts via CANOPY_MCP_ALLOWED_HOSTS.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@passcod passcod enabled auto-merge June 25, 2026 03:24
@passcod passcod added this pull request to the merge queue Jun 25, 2026
Merged via the queue into main with commit 041d7aa Jun 25, 2026
7 checks passed
@passcod passcod deleted the mcp-allowed-hosts branch June 25, 2026 03:31
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