Skip to content

[RFC] Standardize timeouts between servers and clients - #1492

Closed
myaroshefsky wants to merge 6 commits into
modelcontextprotocol:mainfrom
myaroshefsky:docs/standard-timeout
Closed

myaroshefsky wants to merge 6 commits into
modelcontextprotocol:mainfrom
myaroshefsky:docs/standard-timeout

Conversation

@myaroshefsky

@myaroshefsky myaroshefsky commented Sep 18, 2025 •

Copy link
Copy Markdown

This RFC proposes adding standardized bi-directional timeout handling to the Model Context Protocol to address widespread interoperability issues where mismatched timeout configurations between clients and servers break the protocol's core promise of universal compatibility.

Treating timing as a capability to be negotiated

Following MCP's spirit of capability declaration and negotiation to improve universal interoperability, this proposal uses responder-recommended timeouts declared during initialization. It specifically retains full and complete timing control by the requesters, which may use these recommendations to negotiate among the requesters' ideal timeouts, requesters' maximum safe timeouts, and the responders' recommended timeouts.

Leveraging existing lifecycle events (initialization, cancellation)

The implementation includes per-method timeout declarations in capabilities, protocol-wide default timeouts for each method, and support for timeout-triggered cancellations with a dedicated timeout field in cancellation notifications to enable better monitoring and debugging of timeout-related issues.

Incremental improvement

While the community continues exploring comprehensive solutions for long-running tools and async operations (see referenced issues below), this targeted timeout standardization addresses immediate interoperability issues and can be implemented without waiting for those broader architectural decisions. Standardizing timeout handling now will improve protocol reliability and enable more production deployments, which benefits the protocol and community.

Motivation and Context

Without standardized timeout coordination directed at improving reliability, the current MCP specification creates interoperability challenges that affect deployment reliability and limit production adoption.

Observed issues

  1. Vendor-specific behavior: Anthropic's MCP implementation currently has a 5-second timeout for tools/list but a 60-second timeout for other /list operations, which has led to flakiness. After my team raised a bug report, the Anthropic team has asked us to help define what timeout duration would work best for a product like ours (an enterprise MCP gateway that fans out to various MCPs), suggesting that a universal protocol-default timeout may not be appropriate and should be explicitly negotiated between clients and servers.
  2. Silent failures: Users are experiencing timeout errors with no configuration options (TS SDK #245, Inspector #142)
  3. Implementation fragmentation: Python and JavaScript SDKs have different default behaviors

Online evidence in support of improving timeout behavior

Here's a fuller list of community problems caused by the lack of explicit timeout handling in the protocol

TypeScript SDK #245: 13+ reactions asking for longer timeouts

Inspector #142: 21+ reactions requesting configurable timeouts

Continue #5325: "Please add longer mcp_timeout"

Continue #7509 "We have advanced MCP tools that want to use via continue, but we are facing a timeout problem"

LM Studio #727 "The Model Context Protocol (MCP) client in the chat interface has a fixed, non-configurable request timeout. This prevents the use of MCP tools that require more than the default time to complete."

Claude Code #424 "Would greatly appreciate a config option / env var for MCP tool call timeout"

Cline #1306 SDK hard-coded timeout prevents Cline users from extending timeouts

Cline #2296 SDK fails to respect timeout. This was rolled into Cline #4391 Fix MCP System Issues and Compatibility Problems

Codex #2346 Make MCP Request timeout configurable

Gemini CLI #3130 MCP Server times out on windows

N8N Community Requesting configurable MCP timeouts (up to 15 minutes or more)

N8N PR #15886 feat(MCP Client Tool Node): Add Timeout config for the MCP Client tool

Blender #50 Error : MCP error -32001: Request Timed out

Desktop Commander MCP #19 Error: MCP error -32001: Request timed out

Smithery CLI #137 32001 Request timed out error during the initialize phase

Dify #23546 feat: improved MCP timeout

Other protocols

Other successful protocols have tackled the timeout question in various ways, with various levels of acceptance:

  1. HTTP: RFC draft-thomson-hybi-http-timeout-00 defines Request-Timeout headers for client-server timeout negotiation. While this did not move forward, it demonstrates interest.
  2. gRPC: Includes deadline/timeout in protocol headers with automatic clock-skew compensation. This remains requester-defined.
  3. TCP: RFC 5482 defines TCP User Timeout Option for connection-level timeout coordination
  4. WebSocket: Implementations commonly use configurable timeouts with keep-alive mechanisms

Unlike HTTP/gRPC, MCP already has a rich initialization phase where servers declare their capabilities. Adding timeout expectations fits naturally into this existing pattern. Servers already say "I support tools X, Y, Z with these schemas" so adding "and I typically need N seconds" is consistent.

Why not requester-defined timeouts?

Having the requester define a timeout is not likely to reduce the rate of failures. It would just make them more explicit.

MCP's initialization phase gives it a unique advantage over other protocols. While most protocols must rely on requester-defined timeouts, MCP can treat response times as negotiable capabilities during its existing capability exchange. This allows servers to communicate realistic expectations upfront, improving the interoperability that the initialization step was designed to provide.

Clients retain their existing ultimate control and can impose stricter limits when needed, ensuring that server timeout declarations serve as guidance rather than binding requirements.

Goals

The main goals of this change include:

  • Backwards compatibility: This proposal leverages existing lifecycle events (such as initialization and cancellation) with optional properties in order to reduce the chances of breaking changes with existing implementations and permit gradual adoption.
  • Flexibility: In anticipation of this protocol expanding to a wide variety of use cases and supporting special long-running, async, or resumable methods, this proposal aims to deliver narrow explicitness that could be extended with additional capabilities (e.g. this doesn't preclude concepts such as defining extendable timeouts or declaring specific tool calls as having timeout overrides).
  • Reliability: Flakey failures due to lack of timeout coordination currently harms MCPs reputation for use in production use cases. Moving from early adopters to mass adoption requires taking steps to reduce avoidable failures caused by ambiguities or gaps in the specification.
  • Explicitness: In an effort to enable better health and performance monitoring, cancellations caused by timeouts carry an optional property to help differentiate from other forms of cancellations (e.g. a user cancellation). This is important as production use-cases increasingly expect observability about the health of MCP connections.
  • Reasonable defaults: To simplify the path to supporting timeouts without requiring full support, providing protocol default timeouts improves predictability vs. the uncertainty of implementations selecting their own defaults. This would allow SDKs and vendors to provide reasonable coordinated defaults, which is better than undocumented timeout behavior that could lead to flakey failures.

Philosophy of Change

Unlike requester-declared timeouts (as is typical with other protocols, like gRPC), this change aims to improve the rate of successes by providing useful information to the requester that it can use to decide on an appropriate timeout.

Having the requester demand a specific timeout typically will not make the response come faster; it will just ensure a failure. On the other hand, this approach continues to give requesters ultimate control over what timeout they can set, but it gives them information that may influence how they select that timeout.

MCP Timeout - Extension (1)

While 60 seconds is a very reasonable default, this gives the requester the option to decide whether 60 seconds is the true "maximum" timeout or whether they would actually be willing to wait a bit longer.

A UI may wish to enforce a stricter timeout. Meanwhile, autonomous agents may prefer to adopt more flexible timing to decrease the rate of timing failures from over-strict timeouts.

This proposal seeks to yield a net benefit in success rates by enabling discovery of the true upper timing bound on a request rather than requesters making unnecessarily conservative guesses about timing.

This addresses the current information asymmetry where clients must set timeouts without knowledge of server requirements. This need for server timing information is already evident, for instance, when platform providers contact server authors directly to determine appropriate timeout values (see Anthropic example above), indicating that timeout negotiation is happening out-of-band. This proposal formalizes that essential information exchange within the protocol specification, enabling informed timeout decisions based on actual server capabilities rather than external coordination or speculation.

How Has This Been Tested?

These changes have not yet been tested. However, they seem reasonably trivial to implement and test, assuming there is community support for this kind of a change to be explored.

Breaking Changes

This change aims to provide backwards compatibility such that:

  • Existing implementations continue working
  • Clients can gradually adopt timeout coordination
  • Servers without timeout capabilities use current behavior

The main risk of breaking changes would be for implementations that reject the additional properties in certain existing messages, such as:

  • Client and server capability objects now include optional timeouts sub-objects with per-method timeout declarations
  • Added optional timeout?: number field to CancelledNotification params

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Additional context

Other considerations & open discussion

Finer-grained timeouts

It was considered whether to provide finer-grained timeout expectations, such as on a per-tool basis as part of the tool metadata. For example, perhaps one specific tool requires 240 seconds to complete while the rest generally would complete in under 10 seconds.

For now, it was decided that this complexity likely isn't warranted. Instead, the proposal is just to have the responder define the timeout for each method as the longest time it expects to require for any single invocation. According to the specification, either party may still cancel a request for any reason at any time, leaving flexibility for enforcing different timeouts in practice.

Per-request vs. per-method

While it originally seemed logical to consider HTTP-style per-request timeouts made by the requester, the implementer of the operation knows how long it typically takes, and may be in a better position to declare the timeouts.

However, the downside of this approach is that requesters can't adjust for urgent vs. non-urgent requests nor specify tighter timeouts smartly based on specifics (see the comment above about finer-grained timeouts on a per-tool basis).

This proposal currently adopts the "responder declares" approach because it treats timeouts as a property of the operation and prevents an "impedance mismatch" between what the requester expects and what's realistic. It also aligns with the protocol's philosophy of capability declaration during initialization.

Negotiation of timeouts

It was considered whether timeouts should be declared unilaterally by the responder or negotiated somehow between both parties. For example, perhaps responder requests a 60-second timeout but a requester would like there to be a 30-second timeout. This results in unusual conflicts, as the responder may not be able to honor that shorter timeout, resulting in failures.

It was decided for now that the best path may be to let the responders provide information they have about the timeouts they need, allowing the requester to either honor that (if they can be flexible) or use a different behavior (acknowledging the risks). Nothing in the changes requires a requester to respect the responder's declared timeout, as they may still cancel at any time for any reason. However, at least this implementation avoids ambiguity about how long the responder expects to need, leaving timing entirely to protocol defaults or implementer-specific decisions.

In the case of the enterprise gateway that composes various MCP servers into one logical composite server, a gateway may be able to provide an estimate of the duration it requires to perform the fan-out for a tools/list operation based on the number (or type) of servers it expects to need responses from during that call.

Cancellation vs. Error

It was considered whether timeouts should be considered errors or whether to use the cancellation framework. Since timeouts represent the requester deciding "I'm done waiting," cancellation seems to capture this semantic better.

In addition, the timeout field in cancellations makes it trivial to distinguish timeout-triggered cancellations from user-initiated ones, enabling better observability without overloading error semantics.

Timeout extension

It was considered whether the protocol should define more explicit behavior around progress notifications extending the timeout. This leads to potentially ambiguous behaviors that need further explicitness (e.g. whether a declared timeout is for the entire duration or just the expected duration between progress updates).

It was decided for now to avoid that complexity and stay closer to the existing behavior, which specified that the requester may choose to extend the timeout upon progress. Nonetheless, clarity is provided that the declared timeouts should be the timeout expected for the entire method to complete.

Open questions

References for work related to lengthy operations

[#982] [notes] Long running tools/ async tools/ resumability
[#1391 SEP-1391: Asynchronous Tool Execution
[#418] [Specification] Client should send cancellation notification when request timeout

The steering committee is already looking at how to handle long-running tools, async tools, and resumability. While it is worthwhile to consider those conversations in the context of this change, it may be expedient to develop a baseline timeout behavior as an important nearer-term goal in order to improve overall protocol reliability and encourage greater production adoption. Waiting to resolve this together with these other proposals may delay the much-needed clarity around basic timeouts that are currently interfering with even simple cases of enterprise production adoption.

@myaroshefsky myaroshefsky changed the title Docs/standard timeout [RFC] Standardize timeouts between servers and clients Sep 18, 2025
@myaroshefsky
myaroshefsky marked this pull request as ready for review September 18, 2025 18:03
@myaroshefsky
myaroshefsky requested a review from a team September 18, 2025 18:03
@jonathanhefner

Copy link
Copy Markdown
Member

In order to be accepted, this proposal would need an SEP.

(I have not dug into the specifics of this proposal; I am merely pointing out a formality. 😄)

@myaroshefsky

myaroshefsky commented Sep 19, 2025 •

Copy link
Copy Markdown
Author

In order to be accepted, this proposal would need an SEP.

(I have not dug into the specifics of this proposal; I am merely pointing out a formality. 😄)

Thank you! Working on that now in Discord.

@simonrussell

Copy link
Copy Markdown
Contributor

A few thoughts:

  • timeouts are more important to the requester than the responder; the requester is the one with the constraint on what is "too long". You mention grpc, there the requester specifies the deadline. This would work well with your gateway scenario.
  • It feels like a per request deadline could cover most situations? (If the server knows the deadline is too soon, it can just refuse the request)
  • negotiating it at the start might conflict with the other WIP transport SEP trying to make things more stateless (it's not yet guaranteed to become part of the standard but it's probably worth having a look at it)

@myaroshefsky

Copy link
Copy Markdown
Author

Thanks @simonrussell ! I appreciate the ideas.

  • timeouts are more important to the requester than the responder; the requester is the one with the constraint on what is "too long". You mention grpc, there the requester specifies the deadline. This would work well with your gateway scenario.

I originally started thinking that way way, but I realized that a requester setting a specific deadline isn't going to make a responder go faster. It'll just guarantee a failure.

Keeping in the spirit of declaring capabilities that MCP already embraces, I propose that "time required" is also a capability to be declared. Treating it as such is likely to result in increased reliability and interoperability of the spec.

  • It feels like a per request deadline could cover most situations? (If the server knows the deadline is too soon, it can just refuse the request)

Keep in mind that this proposal continues to allow the requester to cancel the request at any time for any reason. There's no obligation of servers to wait the specified amount of time. So I don't believe there's obvious benefit from adding an explicit timeout to the request itself (unless others have cases where the responder would actually do something differently based on that?).

On the other hand, there's obvious benefit from having the requester be aware of approximately how long the responder would consider "reasonable." I haven't yet found a downside to letting the responder declare that information, which the requester can then use:

  • If no timeout declared, use a reasonable default (e.g. 30 seconds)
  • If a timeout is declared, use min(requester_max_timeout, responder_requested_timeout) which would be meaningfully useful if requester_max_timeout is set to 120 seconds and responder_requested_timeout is set to 90 seconds.
  • negotiating it at the start might conflict with the other WIP transport SEP trying to make things more stateless (it's not yet guaranteed to become part of the standard but it's probably worth having a look at it)

I definitely need to read more about that, but is that going to move away from the initialization and capability negotiation paradigm that this uses?

@simonrussell

Copy link
Copy Markdown
Contributor

Thanks @simonrussell ! I appreciate the ideas.

I can definitely see where you're coming from, and perhaps the request deadline might not solve the particular problem you have. It just maybe feels like a lot of extra stuff to add for something that's probably going to be boilerplate for 99% of servers.

And I still don't really know whether a client will wait for longer for something like tools/list -- it kind of changes the way you build it if randomly you might need to wait three minutes for the response, or get progress updates. It feels like those sort of things should always be fast.

Long running tool calls are another question, but then the progress notification already exists as a "keepalive". I think some of the wording you've got here around how that should work is good.

Could your main problem just be fixed by the spec saying "timeouts for X should be Y", and removing the negotiation?

I definitely need to read more about [stateless SEP], but is that going to move away from the initialization and capability negotiation paradigm that this uses?

It removes initialize but adds a server discovery call, and then each request contains the client capabilities. It may not actually be a problem, now that I think about it more. I think conceptually you are adding a bit more to the state that both sides need to maintain though.

@myaroshefsky

myaroshefsky commented Sep 19, 2025 •

Copy link
Copy Markdown
Author

And I still don't really know whether a client will wait for longer for something like tools/list

I have an email thread open with Anthropic's support team now, with them asking my team how long we would need. This kind of responder-recommended timeout negotiation is already happening out-of-band (via email). That seems like a reasonable argument to suggest that those using the protocol would benefit from in-band coordination.

Screenshot 2025-09-18 at 2 11 31 PM

Could your main problem just be fixed by the spec saying "timeouts for X should be Y", and removing the negotiation?

That may result in unnecessarily tight timeframes that don't match real world needs. Imagine an example where (A) the requester is some async job that has no real external time pressure and (B) the responder is some internal service that either lazily needs to spin up upon request or otherwise takes a while. Setting some kind of protocol-default without a way to negotiate it seems like it will limit protocol adoption or encourage non-compliant implementations.

I think conceptually you are adding a bit more to the state that both sides need to maintain though.

That does seem like the main tradeoff. Are we willing to add some timeout numbers to that state in order to improve real-world reliability? As a protocol implementer (both as a client and server, given that our MCP gateway connects on both sides), it is an easy decision from us: uptime and reliability is everything to our customers. I wouldn't think twice about storing a few integers in the state in order to avoid preventable failures.

@domdomegg
domdomegg requested a review from a team as a code owner November 25, 2025 19:37
@localden

Copy link
Copy Markdown
Contributor

Closing this SEP as dormant - it has not received sponsorship and hasn't seen recent updates. We can re-open in the future if there is a desire to resume work on it.

@localden localden closed this Mar 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants