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!

@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
The XML documentation for `McpErrorCode.RequestCancelled` has been
updated to clearly indicate that this error code is reserved for
user-initiated cancellation (e.g., a client sending a JSON-RPC
`$/cancelRequest`).

The C# server implementation does not emit this code for server-side
timeouts. Timeouts are surfaced as regular CallToolResult errors with
timeout metadata (`Meta["IsTimeout"]`, `Meta["TimeoutMs"]`).

This aligns with reviewer feedback and ensures a clean separation
between client cancellation semantics and server timeout behavior.
@halter73
Copy link
Contributor

halter73 commented Nov 15, 2025

Thanks for your contribution, but I'm going close this. For one, this PR still has logic handling $/cancelRequest which appears to be an LSPism rather than "JSON-RPC native cancellation". MCP already specifies notifications/cancelled for this purpose.

As for the part that addresses #922, I think it's better to use MCP Server Handler Filters. The logic in the McpServerImpl.RunWithTimeoutAsync method added by this PR can be duplicated by a CallToolFilter without much effort. You can add timeouts to a bunch of other handlers like resource handlers using filters as well.

A tool call timeout filter might be a good sample to add to the documentation, but I don't think it needs to be a first-class feature. If someone were to submit a PR adding this to filters.md, I think we'd accept it. Long term, it might be interesting to ship built-in handler timeout filters similar to ASP.NET Core's Request Timeout Middleware, but it's not currently priority.

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

4 participants