- A timeout is a caller or server deadline, not a complete diagnosis of what happened.
- Cancellation is cooperative and cannot rewind a side effect that already occurred.
- Progress notifications are optional and request-scoped; tasks are useful for durable long-running work but remain experimental.
- Measure slow tails, cancellations, timeouts, retries, and application outcomes as separate signals.
A timeout is a boundary decision, not a diagnosis. It says that a caller stopped waiting under a particular policy. The server may still be running, may have completed successfully, or may have been cancelled. MCP teams need to model those states separately because a single timeout number can hide dependency slowness, queueing, client impatience, or work that should have been moved to a durable task.
Choose a deadline from the workflow
Start with the user or agent workflow, then allocate time across the MCP call and its dependencies. A search tool may need a short deadline. A report-generation tool may need a longer budget but should not hold a connection open while a job runs for minutes. The correct number depends on the operation, client behavior, dependency limits, and the cost of a partial result.
- Set one server-side maximum so a client cannot create unbounded work.
- Propagate a remaining deadline to downstream calls rather than restarting the clock for every dependency.
- Reserve time for validation, cleanup, and a useful error response.
- Measure the slow tail by tool and outcome. Average latency is not a safe timeout policy.
Cancellation is cooperative
MCP supports cancellation notifications. A receiver should stop work when it can, but cancellation does not rewind a side effect that has already happened. A server should check cancellation between expensive stages, pass cancellation to downstream libraries where supported, release resources in a finally path, and make the final state explicit.
async function runReport(input, signal) {
await checkCancelled(signal);
const rows = await fetchRows(input, { signal });
await checkCancelled(signal);
const report = await buildReport(rows, { signal });
return report;
}Progress tells a client that work is alive
A client can include a progress token, and a server can send progress notifications associated with that token. Progress is optional and request-scoped. It does not prove that the host rendered the update, that a user saw it, or that the agent will wait forever. Send meaningful milestones at a bounded rate, and stop sending updates after completion or cancellation.
When a task is a better fit
The tasks extension represents durable state for work that should be polled and retrieved later. The current specification describes statuses such as working, input_required, completed, failed, and cancelled, along with task identifiers, TTLs, and suggested poll intervals. Tasks are currently experimental, so document the client support you require and provide a fallback for clients that do not negotiate it.
A task does not automatically equal a business success. A completed task means the protocol operation reached its completed state. If the operation creates a deployment, sends a message, or exports a report, emit or store the application outcome that proves the useful result.
Avoid the timeout and retry trap
- Do not retry a state-changing operation simply because the waiting client timed out.
- Give long work a status or reconciliation tool so a caller can query the result safely.
- Keep a timeout error distinct from a tool execution error and a cancellation result.
- Record whether the handler stopped before the side effect, after the side effect, or in an unknown state.
Telemetry for slow MCP calls
Capture the tool name, start and end timestamps, outcome class, cancellation or timeout marker, dependency phase when safe, and deployment identifier. Keep payload capture bounded and redacted. A timeline that says a call took 18 seconds is useful; a timeline that also shows it spent 17 seconds waiting on a named dependency is far more actionable, provided the dependency label does not contain sensitive data.
TrackMCP observes the server boundary and can connect observed latency, tool errors, retries, and explicit workflow signals. It cannot see a client's private deadline policy or model reasoning unless that information is deliberately emitted by a component you control.
Does cancelling an MCP request guarantee that the work stopped?
No. Cancellation is cooperative. The server should attempt to stop work, but an external side effect may already have happened and some dependencies may not support immediate cancellation.
Should every long-running MCP tool use tasks?
No. A bounded operation can use an ordinary request with progress or a clear timeout. Tasks are useful when work must outlive the original request and the client supports the experimental extension.
Is a timeout the same as a server error?
No. A timeout says a caller stopped waiting. The server may have failed, completed, been cancelled, or reached an unknown side-effect state.
About the publisher
TrackMCP, also written Track MCP
TrackMCP helps teams understand which clients connect to their MCP servers, which tools agents use, and where workflows fail. Learn more about Track MCP.
See this on your own server
TrackMCP turns your MCP server's calls into adoption, workflows, and outcomes. One line to install.