Skip to content

Conversation

@bkarakaya01
Copy link

@bkarakaya01 bkarakaya01 commented Nov 7, 2025

This PR introduces server-side tool timeout support and ensures proper JSON-RPC $/cancelRequest handling.

Summary of Changes

  • Added DefaultToolTimeout to McpServerOptions
  • Added IMcpToolWithTimeout interface for per-tool override
  • Enforced tool execution timeout inside the tools/call pipeline via linked CTS
  • Added NotificationMethods.JsonRpcCancelRequest constant
  • Introduced SlowTool fixture for timeout scenarios
  • Added tests covering:
    • per-tool timeout
    • default server timeout
    • client-initiated $/cancelRequest cancellation path
  • Normalized English summaries / comments

Fixes #922

Motivation and Context

Timeout control at the server/tool level is required for predictable behavior when dealing with long-running tool executions.
$/cancelRequest handling complements this by ensuring JSON-RPC cancellation semantics correctly surface to the caller.

How Has This Been Tested?

All new behavior is covered via unit tests under McpServerToolTimeoutTests using TestServerTransport.

Breaking Changes

No breaking changes. Existing server implementations continue to work without modification.

Types of Changes

  • New feature (non-breaking enhancement)
  • Bug fix
  • Breaking change
  • Documentation update

Checklist

  • I have read the MCP documentation
  • My code follows the repository style guidelines
  • All tests pass locally
  • I have added tests to cover the new behavior

Additional Context

Server-side timeout is surfaced as a normal tool error with explicit Meta.IsTimeout metadata - this is not modeled as cancellation and is distinct from $/cancelRequest.
This PR also ensures the server does not respond on user-initiated $/cancelRequest per JSON-RPC expectations.

@stephentoub
Copy link
Contributor

Support JSON-RPC $/cancelRequest cancellation

I'm not understanding the purpose of this. Cancellation is already supported with notifications/cancelled

@stephentoub stephentoub added the NO MERGE PR should not be merged until the label is removed label Nov 7, 2025
@bkarakaya01 bkarakaya01 changed the title Support JSON-RPC $/cancelRequest cancellation in server + tests (#922) Add server tool timeouts (default & per-tool) and honor JSON-RPC $/cancelRequest (#922) Nov 7, 2025
@bkarakaya01
Copy link
Author

Support JSON-RPC $/cancelRequest cancellation

I'm not understanding the purpose of this. Cancellation is already supported with notifications/cancelled

I see how my original wording made this look like a cancellation feature PR. The actual primary goal here is server-side tool timeout support. The $ /cancelRequest part was only added because during implementation/tests we noticed cancellation didn’t properly propagate to the running tool without the CTS linkage, so it was more of a supporting fix, not the main feature.

I’ve updated the PR title/description to reflect the real scope (tool timeout) much clearer. Thanks for pointing it out!

&& message is JsonRpcRequest cancelledReq
&& IsUserInitiatedCancellation(oce, cancellationToken, combinedCts))
{
await SendRequestCancelledErrorAsync(cancelledReq, cancellationToken).ConfigureAwait(false);
Copy link
Member

Choose a reason for hiding this comment

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

If the timeout is configured server side can the server than cancel the client request? This seems odd to me.

If have a client and I get a 'cancelled error from the server' how am I to know this is a time-out?

    /// <remarks>
    /// This error is returned when the CancellationToken passed with the request is cancelled before processing completes.
    /// </remarks>
    RequestCancelled = -32800,
Copy link
Member

Choose a reason for hiding this comment

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

If the timeout happens on the server, then this isn't a client cancellation?

@PederHP
Copy link
Member

PederHP commented Nov 10, 2025

I think this is conflating cancellation and server / client time-outs. A server-side timeout is, as I see it, an implementation detail of the server, and not really a protocol level concern.

I can see how convenience to implement this is nice, but if it is added, I think it needs to be much more clear on this being a purely server side interaction, and the client also needs a better error message. This isn't a cancellation - it is the server deciding that long-running tool calls are an error and aborting the client call.

…lation

This introduces support for parsing and honoring JSON-RPC \$/cancelRequest\
notifications, making cancellation semantics compliant with MCP protocol
expectations. Includes a new \JsonRpcCancelRequest\ constant in
\NotificationMethods\ and integrates proper cancellation token linkage inside
the server message loop.

Additionally:
- Added SlowTool test fixture to simulate long-running tools
- Implemented full timeout vs external cancellation tests
- Normalized English summaries / comments in related areas

Fixes modelcontextprotocol#922
@bkarakaya01 bkarakaya01 force-pushed the feature/cancel-request-support-922 branch from fdb2157 to 48ad945 Compare November 10, 2025 10:05
@bkarakaya01
Copy link
Author

I think this is conflating cancellation and server / client time-outs. A server-side timeout is, as I see it, an implementation detail of the server, and not really a protocol level concern.

I can see how convenience to implement this is nice, but if it is added, I think it needs to be much more clear on this being a purely server side interaction, and the client also needs a better error message. This isn't a cancellation - it is the server deciding that long-running tool calls are an error and aborting the client call.

Thanks, that makes sense. I see now that this behavior blurred the line between user cancellation vs server-side timeouts.

I’ve updated the PR so that:

  • User-initiated $/cancelRequest produces no response (silent path, per JSON-RPC expectation)
  • Server timeouts are handled as regular tool errors, with Meta.IsTimeout + Meta.TimeoutMs
  • We no longer emit “cancelled” errors on server timeouts

This keeps the semantics clearly separated and avoids protocol confusion.

Thanks again for the guidance, waiting for your review.

…emit standard cancel; keep server timeouts in RunWithTimeoutAsync
@bkarakaya01 bkarakaya01 requested a review from PederHP November 10, 2025 10:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

NO MERGE PR should not be merged until the label is removed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

McpServerTool Add timeout

3 participants