Skip to content

Serve MCP 2026-07-28: confirmation via multi-round-trip requests, subscriptions/listen, sessions only for initialize clients - #232

Merged
Mike Krüger (mkrueger) merged 14 commits into
mainfrom
copilot/check-current-pr-and-mcp-sdk-upgrade
Oct 2, 2026
Merged

Mike Krüger (mkrueger) merged 14 commits into
mainfrom
copilot/check-current-pr-and-mcp-sdk-upgrade

Conversation

Copilot AI commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Moves the MCP server onto protocol revision 2026-07-28 (MCP C# SDK 2.2.0, merged in #231) while keeping clients that use the initialize handshake working.

1. Destructive-command confirmation via multi-round-trip requests

Destructive commands (delete, rm, rmcon, rmdb) asked for confirmation through McpServer.ElicitAsync. That is a server-to-client request; it needs a session, and 2026-07-28 removes it from Streamable HTTP.

  • Prompt transport (ToolOperations)
    • The prompt is raised as InputRequiredException with one elicitation input request under key confirm. The prompt text is unchanged.
    • 2026-07-28 clients show the prompt and retry tools/call with the answer.
    • For initialize clients, the SDK sends elicitation/create on the session and retries the handler, so they see the same prompt as before.
    • Clients that don't advertise elicitation are still refused before anything runs.
    • On stateless requests the SDK reports ClientCapabilities as null, so the gate falls back to the per-request capabilities in JsonRpcRequest.Context.
  • Binding the answer (new ConfirmationRequestState)
    • requestState holds stateVersion + "\n" + commandLine, signed with HMAC-SHA256 using a random key generated per process.
    • On retry, a state that is missing, forged, or for another command line is refused.
    • If the shell state version changed between rounds, the existing "context changed" error is returned.
    • Decline or cancel returns the existing "not approved" error.
    • A server restart invalidates pending confirmations, because the key changes.
  • Behavior change: for initialize clients, if the elicitation request itself fails, the SDK now returns a JSON-RPC error instead of the shell's "could not be completed" tool error. Nothing executes in either case.

2. subscriptions/listen for cosmos://shell/current-location

The SDK's built-in listen handler never sends notifications/resources/updated, and on stateless requests it grants nothing, so LocationResourceSubscriptions.ListenAsync replaces it.

  • Sends notifications/subscriptions/acknowledged listing only cosmos://shell/current-location. Other URIs and list-changed filters are left out.
  • If nothing is honored, the request completes right after the acknowledgement.
  • Otherwise it streams notifications/resources/updated on the listen response. Every notification carries the listen request ID in _meta["io.modelcontextprotocol/subscriptionId"].
  • The listener is removed when the client cancels or disconnects, or when the host stops. Held-open POSTs are not ended by the transport on shutdown, so the service does that itself.
  • resources/subscribe / resources/unsubscribe remain for initialize clients, with the existing session-lifetime behavior.

3. HttpServerSessionMode.StatefulForInitializeClients

  • 2026-07-28 requests are served without a session. initialize clients still get a session, used for elicitation and resources/subscribe.
  • RunSessionAsync, Subscribe and Unsubscribe treat an empty session ID as no session.

Tests

  • ConfirmationRequestState: round trip, mismatched command, missing or forged state, tampered payload.
  • Retry flow in ExecuteToolAsync: the first round raises the input request without executing; accept executes; decline, cancel, an answer for another command, and a context change between rounds do not execute.
  • McpConfirmationTests: end to end over HTTP for both 2026-07-28 (native multi-round-trip) and 2025-11-25 (bridged to elicitation/create). The client's decline is honored in both.
  • ListeningClient_ReceivesLocationChangeOnListenStream: checks the acknowledgement contents and subscription ID, delivery of a location change, and that cancelling releases the listener.
  • The existing resources/subscribe tests now pin 2025-11-25. The transport test asserts the new session mode.

Docs

docs/mcp.md covers the multi-round-trip confirmation flow, both subscription mechanisms, and which clients get a session.

Copilot AI and others added 4 commits October 1, 2026 07:42
…ions

Co-authored-by: mkrueger <341098+mkrueger@users.noreply.github.com>
…h-newer-mcp

Co-authored-by: mkrueger <341098+mkrueger@users.noreply.github.com>
…race

Co-authored-by: mkrueger <341098+mkrueger@users.noreply.github.com>
Co-authored-by: mkrueger <341098+mkrueger@users.noreply.github.com>
Comment thread CosmosDBShell.Tests/McpLocationSubscriptionTests.cs Fixed
Comment thread CosmosDBShell/Azure.Data.Cosmos.Shell.Mcp/ToolOperations.cs Fixed
Copilot AI and others added 2 commits October 1, 2026 13:32
Co-authored-by: mkrueger <341098+mkrueger@users.noreply.github.com>
…subscriptions/listen

Co-authored-by: mkrueger <341098+mkrueger@users.noreply.github.com>
Comment thread CosmosDBShell.Tests/McpLocationSubscriptionTests.cs Fixed
Co-authored-by: mkrueger <341098+mkrueger@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

Confirmation-state storage and serialized listener writes allow client-driven resource exhaustion and notification starvation.

Review effort: Balanced
Findings: 2 High severity · 1 Low severity

Open (3)
Resolved since last review (3)

Comment thread CosmosDBShell/Azure.Data.Cosmos.Shell.Mcp/ConfirmationRequestState.cs Outdated
Comment thread CosmosDBShell/Azure.Data.Cosmos.Shell.Mcp/LocationResourceSubscriptions.cs Outdated
Copilot AI balanced review requested due to automatic review settings October 1, 2026 14:16

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🔵 Needs a closer look

Listen-stream writes can delay shutdown, and confirmation-state cleanup scales quadratically under bursts.

Review effort: Balanced
Findings: 2 High severity · 1 Low severity

Open (3)
Previously missed (1)

In code that hasn't changed since last review

Medium severity Use linked shutdown token for acknowledgement write

CosmosDBShell/​Azure.Data.Cosmos.Shell.Mcp/​LocationResourceSubscriptions.cs:172

The linked token is intended to combine request cancellation with StopAsync, but the acknowledgement write still receives only the request token. If shutdown begins while this write is pending, cancelling stopping cannot release the held-open POST and can delay host shutdown. Pass the linked token here.

This issue also appears on line 184 of the same file.

…order-independent

The web server stops before LocationResourceSubscriptions and waits for open
requests until the host shutdown timeout, so cancelling held-open listen POSTs
in StopAsync came too late and shutdown took 30 s. Cancel them when the
application starts stopping instead.

CallTool_EchoCommand_ReturnsSuccessResult relied on its history entry being new;
history drops duplicates and another test records the same echo line, so the
new tests' execution order made it fail. Use a unique message.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings October 1, 2026 14:59
@github-code-quality

github-code-quality Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

Code Coverage Overview

Languages: C#

C# / code-coverage/dotnet

The overall line coverage in commit 20afa30 in the copilot/check-curren... branch remains at 65%, unchanged from commit 97d007f in the main branch.

Show a line coverage summary of the most impacted files.
File main 97d007f copilot/check-curren... 20afa30 +/-
D:\a\CosmosDBSh...olOperations.cs 95% 95% 0%
D:\a\CosmosDBSh...cp\McpServer.cs 100% 100% 0%
D:\a\CosmosDBSh...ubscriptions.cs 86% 89% +3%
D:\a\CosmosDBSh...RequestState.cs 0% 93% +93%

Updated October 02, 2026 07:03 UTC

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🔵 Needs a closer look

Nonce cleanup scales quadratically, and a slow listen stream can block notifications for all subscribers.

Review effort: Balanced
Findings: 2 High severity · 1 Low severity

Open (3)

Each subscriptions/listen request now drains its own coalescing queue and sends
with its own request-linked token, so a slow or stalled stream delays only
itself. The acknowledgement also uses the linked token, so shutdown releases it.

Pending confirmation nonces are tracked in creation order and pruned from the
front, capped at 1,024 entries; beyond that the oldest is dropped.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings October 1, 2026 16:29

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

The unsupported-only subscription path needs focused regression coverage.

Review effort: Balanced
Findings: 1 Low severity

Open (1)
Resolved since last review (3)

…diately

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings October 1, 2026 16:40

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🔵 Needs a closer look

Security-sensitive confirmation and long-lived streaming behavior warrant final human review, with one minor documentation correction outstanding.

Review effort: Balanced
Findings: 1 Low severity

Open (1)
Previously missed (1)

In code that hasn't changed since last review

Low severity Correct elicitation flow documentation

docs/​mcp.md:76

This reverses the confirmation flow: the server supplies the elicitation prompt and asks the client for an answer; it does not ask the client to provide a prompt. Reword this so the documentation matches InputRequest.ForElicitation.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings October 1, 2026 18:33
@mkrueger

Copy link
Copy Markdown
Collaborator

Fixed the "Correct elicitation flow documentation" finding in 7dcefc4: docs/mcp.md now says the server sends the client an elicitation prompt describing the exact command line and waits for the user's answer before anything runs.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🔵 Needs a closer look

The security-sensitive confirmation flow and concurrent streaming lifecycle warrant final human validation despite comprehensive tests.

Review effort: Balanced
Findings: None

Resolved since last review (1)

Copilot AI balanced review requested due to automatic review settings October 2, 2026 06:57

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🔵 Needs a closer look

The security-sensitive confirmation flow and concurrent HTTP subscription lifecycle warrant final human validation despite strong test coverage.

Review effort: Balanced
Findings: None

@mkrueger
Mike Krüger (mkrueger) merged commit f4b09a9 into main Oct 2, 2026
10 checks passed
@mkrueger
Mike Krüger (mkrueger) deleted the copilot/check-current-pr-and-mcp-sdk-upgrade branch October 2, 2026 07:39
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.

4 participants