Fix request-scoped draft client capabilities#1685
Open
PranavSenthilnathan wants to merge 2 commits into
Open
Conversation
Route client capability resolution through request-scoped DestinationBoundMcpServer state for 2026-07-28+ requests, stop persisting per-request capabilities into McpServerImpl global state, and add a concurrency regression test that verifies overlapping requests observe their own declared capabilities. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Gate DestinationBoundMcpServer.ClientInfo on the 2026-07-28+ protocol like ClientCapabilities so request handlers observe this request's declared client info rather than falling back to shared session state, which under a stateful transport could belong to a different concurrent request. Add a regression test verifying a tool observes the per-request client info. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Fixes a concurrency race in draft (2026-07-28 / SEP-2575) sessions by ensuring client capabilities and client info are resolved per request from _meta, rather than being persisted into shared McpServerImpl session state.
Changes:
- Moves draft-protocol
ClientCapabilities/ClientInforesolution intoDestinationBoundMcpServerso concurrent requests don’t observe each other’s_meta. - Stops
McpServerImpl.PrependMetaReadingFilterfrom writing per-request client capabilities into shared server state. - Adds regression tests for concurrent per-request capabilities and request-scoped client info observation.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| tests/ModelContextProtocol.Tests/Client/McpClientMetaTests.cs | Adds concurrency and request-scoped meta tests for draft protocol behavior. |
| src/ModelContextProtocol.Core/Server/McpServerImpl.cs | Removes shared per-request capability state sync; threads request context into the destination-bound server wrapper. |
| src/ModelContextProtocol.Core/Server/DestinationBoundMcpServer.cs | Implements request-scoped ClientCapabilities/ClientInfo resolution for 2026-07-28+ requests. |
Comment on lines
+8
to
+13
| internal sealed class DestinationBoundMcpServer(McpServerImpl server, ITransport? transport, JsonRpcRequest? jsonRpcRequest = null) : McpServer | ||
| #pragma warning restore MCPEXP002 | ||
| { | ||
| private readonly bool _isJuly2026OrLaterRequest = IsJuly2026OrLaterProtocolRequest(jsonRpcRequest, server.NegotiatedProtocolVersion); | ||
| private readonly ClientCapabilities? _requestClientCapabilities = jsonRpcRequest?.Context?.ClientCapabilities; | ||
| private readonly Implementation? _requestClientInfo = jsonRpcRequest?.Context?.ClientInfo; |
|
|
||
| private readonly TaskCompletionSource<JsonNode?> _initializeMeta = new(); | ||
|
|
||
| private const string ClientCapabilitiesMetaKey = "io.modelcontextprotocol/clientCapabilities"; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #1670
Under the 2026-07-28 draft protocol (SEP-2575) there is no
initializehandshake; eachrequest carries the client's capabilities/info per-request in
_meta. The server waspersisting these into shared session state on
McpServerImpl, so concurrent requests on asingle stateful session (stdio/stream/stateful HTTP) raced and observed each other's
capabilities. The spec requires a server MUST NOT infer client capabilities from previous
requests.
This moves resolution into the per-request
DestinationBoundMcpServer:ClientCapabilities: stateless ->null(keeps the "unsupported in stateless mode"sentinel); 2026-07-28+ -> this request's
_metavalue, or empty when absent (neverinferred from another request); legacy -> session state from
initialize.ClientInfo: same shape (request-scoped for 2026-07-28+, session for legacy).McpServerImpl.PrependMetaReadingFilterno longer writes per-request capabilities toshared state (the race source). It still syncs client info for endpoint-name logging,
which handlers no longer read on draft sessions.
Tests: one fires two overlapping tool calls with different
_metacapabilities and assertseach sees its own; another asserts a tool observes the per-request client info.