Skip to content

Conversation

@pja-ant
Copy link
Contributor

@pja-ant pja-ant commented Sep 8, 2025

Add explicit guidance that servers MUST respond with HTTP 403 Forbidden when the Origin header is present but invalid. This addresses part of issue #1398 regarding inconsistent error responses across SDKs. Currently TypeScript returns 403, but Python return 400. 403 seems like the most appropriate response here, so going with that (and will update Python if this is accepted).

Motivation and Context

Spec does not specify the response, so implementations have diverged.

#1398

How Has This Been Tested?

npm serve:docs

Breaking Changes

Technically this could be a breaking change if there are some clients somewhere are relying on specific implementation of this from specific SDKs, but since e.g. TypeScript SDK already returns 403, it's already behavior that clients have to deal with depending on the server.

Marking as "breaking change" as a precaution, but I think this should be a safe change.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

@pja-ant
Copy link
Contributor Author

pja-ant commented Sep 8, 2025

modelcontextprotocol/python-sdk#1353 for python SDK if this is accepted

@dend
Copy link
Contributor

dend commented Sep 9, 2025

@pja-ant is there a RFC reference we can include that rationalizes the response code?

@pja-ant
Copy link
Contributor Author

pja-ant commented Sep 9, 2025

@pja-ant is there a RFC reference we can include that rationalizes the response code?

Hey @dend. You mean a SEP? Thought that might be overkill, but happy to put one together if you feel it's needed here. The SEP guidelines state (emphasis mine):

The goal is to reserve the SEP process for changes that are substantial enough to require broad community discussion, a formal design document, and a historical record of the decision-making process. A regular GitHub issue or pull request is often more appropriate for smaller, more direct changes.

My sense is that this isn't super substantial, but at the end of the day I'm the noob here so I'll do whatever people like!

In terms of the rationalization: between 400 and 403 (the only two contenders in my opinion), I feel 403 is most appropriate since 400 generally means some sort of "client error" where the server couldn't process even if it wanted whereas 403 "indicates that the server understood the request but refuses to fulfill it", which is exactly what's happening here.

@dsp-ant
Copy link
Member

dsp-ant commented Sep 19, 2025

I think this is fine without a SEP. @localden @pcarleton, any objections to defining 403's?

@pja-ant can you add a minor changelog entry?

pja-ant and others added 2 commits September 19, 2025 15:23
Add explicit guidance that servers MUST respond with HTTP 403 Forbidden
when the Origin header is present but invalid. This addresses part of
issue modelcontextprotocol#1398 regarding inconsistent error responses across SDKs.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
@pcarleton
Copy link
Member

👍 looks reasonable to me, and agree it doesn't need a SEP.

I think Den was asking if there are HTTP RFC's to reference to back up the decision on 403 vs. 400, and I agree with @pja-ant 's read of RFC 9110 that 403 is better here.

cc @ochafik as a bookmark for a good conformance test

@pja-ant pja-ant force-pushed the clarify-403-invalid-origin branch from 7dfb0b8 to e51a039 Compare September 19, 2025 14:26
@dsp-ant dsp-ant merged commit 16eeb7d into modelcontextprotocol:main Sep 19, 2025
2 checks passed
@jacopoc
Copy link

jacopoc commented Nov 22, 2025

Thanks for the improvement introduced in this PR, the added clarification definitely helps.
However, I believe the original top-level requirement:

“Servers MUST validate the Origin header on all incoming connections to prevent DNS rebinding attacks”

still needs refinement to accurately reflect when DNS rebinding protection is relevant and to avoid creating unintended non-compliance in existing SDKs.

As written, the statement implies that all MCP servers, in all environments, must enforce Origin validation. This has two issues:

  1. It conflicts with the current Typescript SDK behavior.
    The SDK defaults enableDnsRebindingProtection to false. If the specification literally requires unconditional validation of the Origin header for DNS rebinding protection, the SDK would not comply with the standard, as it implies that enableDnsRebindingProtection should always be true. Moreover, enabling the protection (true) currently blocks requests from non-browser clients, since they typically do not send an Origin header and validateRequestHeaders rejects them.
  2. DNS rebinding mitigation only makes sense for local deployments.
    The threat model is specific to browser-initiated requests targeting local MCP servers. Public servers are not affected by DNS rebinding, so enforcing Origin validation on all connections "to prevent DNS rebinding attacks" is unnecessary and misleading.

For these reasons, I suggest at least rephrasing the requirement to scope it appropriately:

When running locally, Servers MUST validate the Origin header on all incoming connections to prevent DNS rebinding attacks.”

Even better, since Host validation is the actual mechanism required to prevent DNS rebinding:

When running locally, Servers MUST validate the Host header and the Origin header on all incoming connections to prevent DNS rebinding attacks.”

However, enforcing Origin validation after Host validation should be optional and not mandatory (when running locally).

Please let me know if you would prefer that I file a separate issue for these remarks.

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.

5 participants