Skip to content

SDK Regression: Re-allow browser-based MCP clients via CORS#2359

Merged
SamMorrowDrums merged 1 commit intomainfrom
rosstarrant/allow-browser-mcp-clients
Apr 21, 2026
Merged

SDK Regression: Re-allow browser-based MCP clients via CORS#2359
SamMorrowDrums merged 1 commit intomainfrom
rosstarrant/allow-browser-mcp-clients

Conversation

@RossTarrant
Copy link
Copy Markdown
Contributor

@RossTarrant RossTarrant commented Apr 20, 2026

Summary

Add CORS support and configurable cross-origin protection to allow browser-based MCP clients to connect to the HTTP server.

Why

We recently upgraded the MCP Go SDK from v1.3.1 to v1.5.0, which brought in cross-origin request protection added in v1.4.1. This uses net/http.CrossOriginProtection to reject cross-origin POST requests by default based on the Sec-Fetch-Site header.

The Go SDK maintainers have indicated the feature may be reverted. In the meantime, we bypass it in the HTTP handler and add CORS middleware so browser clients work correctly.

Browser-based clients (e.g. MCP Inspector which was used to test this PR) send Sec-Fetch-Site: cross-site and get a 403. Additionally, the HTTP server had no CORS headers, so browsers blocked requests at the preflight stage before even reaching the CSRF check.

Fixes #2342

What changed

  • Cross-origin protection bypass (pkg/http/handler.go): The SDK's Sec-Fetch-Site rejection is bypassed directly in the handler using AddInsecureBypassPattern("/"). This is hardcoded — not configurable — per maintainer guidance to keep it as invisible plumbing.
  • CORS middleware (pkg/http/middleware/cors.go): New middleware sets Access-Control-* headers on MCP endpoint responses, enabling browser preflight (OPTIONS) and cross-origin fetch() calls. Exposes Mcp-Session-Id and WWW-Authenticate (needed for OAuth resource discovery and scope challenges).
  • Tests: Cross-origin protection tests verify cross-site, same-origin, and native client requests all succeed. CORS tests verify preflight and response headers.

MCP impact

  • No tool or API changes
  • Tool schema or behavior changed
  • New tool added

Prompts tested (tool changes only)

  • N/A

Security / limits

  • No security or limits impact

  • Auth / permissions considered

  • Data exposure, filtering, or token/size limits considered

  • CORS uses Access-Control-Allow-Origin: * which is safe because auth is bearer-token-only (not cookie-based)

  • Cross-origin protection bypass is opt-in via ServerConfig; SDK default (reject) is preserved for library consumers

Tool renaming

  • I am renaming tools as part of this PR (e.g. a part of a consolidation effort)
    • I have added the new tool aliases in deprecated_tool_aliases.go
  • I am not renaming tools as part of this PR

Note: if you're renaming tools, you must add the tool aliases. For more information on how to do so, please refer to the official docs.

Lint & tests

  • Linted locally with ./script/lint
  • Tested locally with ./script/test

Docs

  • Not needed
  • Updated (README / docs / examples)

@RossTarrant RossTarrant marked this pull request as ready for review April 21, 2026 08:11
@RossTarrant RossTarrant requested a review from a team as a code owner April 21, 2026 08:11
Copilot AI review requested due to automatic review settings April 21, 2026 08:11
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds CORS support and makes the MCP Go SDK’s cross-origin request protection configurable so browser-based MCP clients can reach the HTTP MCP endpoints (addressing the new default 403 behavior after the go-sdk upgrade).

Changes:

  • Add ServerConfig.CrossOriginProtection and plumb it through to mcp.StreamableHTTPOptions.
  • Default RunHTTPServer to bypass cross-origin protection when not explicitly configured.
  • Add SetCorsHeaders middleware (including OPTIONS preflight handling) and tests for CORS + cross-origin protection behavior.
Show a summary per file
File Description
pkg/http/server.go Adds CrossOriginProtection config + defaults local server to bypass SDK cross-origin protection; wires CORS middleware into MCP route group.
pkg/http/handler.go Passes CrossOriginProtection into the SDK handler and introduces CORS middleware implementation.
pkg/http/handler_test.go Adds unit tests for CORS headers and for SDK cross-origin protection allow/deny behavior.

Copilot's findings

  • Files reviewed: 3/3 changed files
  • Comments generated: 3

Comment thread pkg/http/server.go Outdated
Comment thread pkg/http/handler_test.go Outdated
Comment thread pkg/http/handler.go Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot's findings

  • Files reviewed: 3/3 changed files
  • Comments generated: 2

Comment thread pkg/http/handler.go Outdated
Comment thread pkg/http/handler_test.go Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot's findings

  • Files reviewed: 3/3 changed files
  • Comments generated: 1

Comment thread pkg/http/handler.go Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot's findings

  • Files reviewed: 3/3 changed files
  • Comments generated: 1

Comment thread pkg/http/handler.go Outdated
Comment thread pkg/http/handler.go Outdated
Comment on lines +420 to +432
var corsAllowHeaders = strings.Join([]string{
"Content-Type",
"Mcp-Session-Id",
"Mcp-Protocol-Version",
"Last-Event-ID",
headers.AuthorizationHeader,
headers.MCPReadOnlyHeader,
headers.MCPToolsetsHeader,
headers.MCPToolsHeader,
headers.MCPExcludeToolsHeader,
headers.MCPFeaturesHeader,
headers.MCPLockdownHeader,
headers.MCPInsidersHeader,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I was actually going to say define this inside the SetCorsHeaders (before returning the closure), so it's defined when you create the middleware and then used each time.

Also more importantly, we have a middleware package and this should move there.

Copy link
Copy Markdown
Contributor Author

@RossTarrant RossTarrant Apr 21, 2026

Choose a reason for hiding this comment

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

thanks for the feedback, this logic now sits in cors.go and defines the allowed headers inside SetCorsHeaders like you suggested

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot's findings

  • Files reviewed: 3/3 changed files
  • Comments generated: 1

Comment thread pkg/http/handler.go Outdated
Copy link
Copy Markdown

@marknilsn marknilsn left a comment

Choose a reason for hiding this comment

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

I don’t think “Docs: not needed” is quite right here. This changes the practical exposure model of RunHTTPServer for browser clients, so I’d like a short docs/README note on the default posture and when operators may want stricter CrossOriginProtection behavior before merging.

@RossTarrant
Copy link
Copy Markdown
Contributor Author

I don’t think “Docs: not needed” is quite right here. This changes the practical exposure model of RunHTTPServer for browser clients, so I’d like a short docs/README note on the default posture and when operators may want stricter CrossOriginProtection behavior before merging.

Thanks for the feedback - you're right this should be documented. I've added a section to docs/streamable-http.md that covers the changes being made

@SamMorrowDrums
Copy link
Copy Markdown
Collaborator

SamMorrowDrums commented Apr 21, 2026

@marknilsn docs are not needed because this is not a feature, it's a patch. MCP specifically is meant to support cross origin. Even the most basic tool the MCP Inspector will fail because it's a browser based client.

This was a regression in the Go SDK caused by an erroneous vulnerability report being taken seriously and patched when it should not have been. They aren't intending to revert it until a later breaking change release because of their commitment to stability, but the consequence of this is that we need to patch it on our end until they do.

@SamMorrowDrums
Copy link
Copy Markdown
Collaborator

To put it more precisely, any client can try to connect to an MCP and the CORS headers don't matter.

It's only browser based clients that are improperly being rejected, and I would not recommend any server host apply CORS policy for MCP, and instead use something more secure like internal network IPs only.

@SamMorrowDrums
Copy link
Copy Markdown
Collaborator

@RossTarrant will you please make sure the details are reflected in the PR description to serve as a record.

We can even put the PR link as a code comment for posterity.

Comment thread pkg/http/handler.go Outdated
}

// Bypass cross-origin protection: this server uses bearer tokens (not
// cookies), so Sec-Fetch-Site CSRF checks are unnecessary. See PR #XXXX.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@RossTarrant it didn't put the PR number. Just xxx

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good catch, have updated

@SamMorrowDrums SamMorrowDrums changed the title Allow browser-based MCP clients via CORS and cross-origin bypass SDK Regression: Re-allow browser-based MCP clients via CORS Apr 21, 2026
@RossTarrant RossTarrant force-pushed the rosstarrant/allow-browser-mcp-clients branch from 3edd0d7 to 924d1db Compare April 21, 2026 14:28
Copy link
Copy Markdown
Collaborator

@SamMorrowDrums SamMorrowDrums left a comment

Choose a reason for hiding this comment

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

:shipit:

@SamMorrowDrums SamMorrowDrums merged commit d0320b8 into main Apr 21, 2026
18 checks passed
@SamMorrowDrums SamMorrowDrums deleted the rosstarrant/allow-browser-mcp-clients branch April 21, 2026 14: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.

Is direct browser access to Remote GitHub MCP Server officially supported? Behaviour has changed recently

4 participants