Skip to content

Validate MCP-Protocol-Version header in Streamable HTTP handler#1277

Open
Copilot wants to merge 9 commits intomainfrom
copilot/validate-mcp-protocol-header
Open

Validate MCP-Protocol-Version header in Streamable HTTP handler#1277
Copilot wants to merge 9 commits intomainfrom
copilot/validate-mcp-protocol-header

Conversation

Copy link
Contributor

Copilot AI commented Feb 15, 2026

  • Add MCP-Protocol-Version header validation in StreamableHttpHandler.cs for POST, GET, and DELETE handlers
  • Add tests in StreamableHttpServerConformanceTests.cs
  • Add SupportedProtocolVersions as an abstract instance property on McpServer (not McpSession — only relevant to servers)
  • Implement in McpServerImpl (delegates to McpSessionHandler.SupportedProtocolVersions) and DestinationBoundMcpServer
  • Move validation after session resolution in handler, querying the server instance
  • Fix DELETE handler to validate before removing session
  • Change SupportedProtocolVersions from ICollection<string> to IReadOnlyList<string>
Original prompt

This section details on the original issue you should resolve

<issue_title>The server should validate the MCP-Protocol-Version header value</issue_title>
<issue_description>Describe the bug

The 2025-06-18 version of the MCP spec added this requirement on clients:

If using HTTP, the client MUST include the MCP-Protocol-Version: HTTP header on all subsequent requests to the MCP server

The MCP Server framework in the C# SDK does not verify that the client has provided the MCP-Protocol-Version header, and if it was specified, does not verify that it matches the negotiated protocol version for the session or even if it is a valid protocol version.

To Reproduce

Start a session with the new protocol version 2025-06-18. Then send a "tools/list" request that omits the MCP-Protocol-Version header, or with an MCP-Protocol-Version header with a bogus value.

Expected behavior

If the Streaming HTTP session is using protocol version 2025-06-18, a request without an MCP-Protocol-Version header should be rejected, or at the very least generate a warning log message.

If an MCP-Protocol-Version header is provided, the server should verify that a) the value is a valid / known protocol version, and b) it matches the protocol version negotiated for the session, and fail the request if either of these conditions are not satisfied.

Additional context

The ProtocolVersion project in the v0.3.0 branch of this repo, with a few small modifications, can be used to reproduce this problem.

</issue_description>

<agent_instructions>Please ensure this part is appropriately handled in the implementation and tests:

"If the server receives a request with an invalid or unsupported MCP-Protocol-Version, it MUST respond with 400 Bad Request.

So it's an error to have an invalid header but not an error to not have the header at all." </agent_instructions>

Comments on the Issue (you are @copilot in this section)

@stephentoub > If the Streaming HTTP session is using protocol version 2025-06-18, a request without an MCP-Protocol-Version header should be rejected

The spec states:

For backwards compatibility, if the server does not receive an MCP-Protocol-Version header, and has no other way to identify the version - for example, by relying on the protocol version negotiated during initialization - the server SHOULD assume protocol version 2025-06-18.

If the server receives a request with an invalid or unsupported MCP-Protocol-Version, it MUST respond with 400 Bad Request.

So it's an error to have an invalid header but not an error to not have the header at all.</comment_new>
<comment_new>@mikekistler
If the protocol version was negotiated during initialization to be 2025-06-18, wouldn't it be the case that the server has a way to identify the version for the session?</comment_new>
<comment_new>@stephentoub

If the protocol version was negotiated during initialization to be 2025-06-18, wouldn't it be the case that the server has a way to identify the version for the session?

Yes</comment_new>


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

If the server receives a request with an invalid or unsupported
MCP-Protocol-Version header, respond with 400 Bad Request per the
MCP spec. A missing header is allowed for backwards compatibility.

Exposes McpSession.SupportedProtocolVersions as a public static
property so the AspNetCore handler can validate against it.

Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com>
Copilot AI changed the title [WIP] Add validation for MCP-Protocol-Version header Validate MCP-Protocol-Version header in Streamable HTTP handler Feb 15, 2026
Copilot AI requested a review from stephentoub February 15, 2026 12:48
@stephentoub stephentoub marked this pull request as ready for review February 15, 2026 12:53
@stephentoub stephentoub requested a review from halter73 February 15, 2026 12:53
…ns class, use nullable out param

- Move SupportedProtocolVersions from McpSession to new ProtocolVersions
  static class in Protocol namespace (following RequestMethods/NotificationMethods pattern)
- Revert McpSession.cs to original state
- Change out string to out string? with null on success
- Add ProtocolVersionsTests for the new public property

Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com>
The SupportedProtocolVersions doesn't need to be exposed publicly.
Instead, use InternalsVisibleTo to let ModelContextProtocol.AspNetCore
access the internal McpSessionHandler.SupportedProtocolVersions directly.

- Delete ProtocolVersions.cs public static class
- Delete ProtocolVersionsTests.cs
- Add InternalsVisibleTo in Core csproj for AspNetCore
- Reference McpSessionHandler.SupportedProtocolVersions directly

Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com>
…idation

Define supported protocol versions as a private HashSet directly in
StreamableHttpHandler instead of referencing McpSessionHandler internals
or adding any cross-assembly visibility. No new public API surface needed.

Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com>
Copilot AI and others added 2 commits February 15, 2026 15:05
Add abstract SupportedProtocolVersions property to McpServer, implemented
by McpServerImpl (delegating to McpSessionHandler.SupportedProtocolVersions)
and DestinationBoundMcpServer. Protocol version validation in
StreamableHttpHandler now occurs after session resolution, querying the
server instance directly. Remove private HashSet from handler.

Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com>
Use TryGetValue to check version first, then TryRemove to actually
delete. This prevents losing the session if validation fails.

Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com>
…yList<string>

Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.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.

The server should validate the MCP-Protocol-Version header value

2 participants