Skip to content

MCP server has no per-request timeout / deadline - hung handler blocks all clients #1737

Description

@Widthdom

Summary

McpServer.ProcessLineAsync (lines 80-124) dispatches each JSON-RPC request to a tool handler with no per-request timeout or CancellationToken. A malformed query, a pathological FTS5 expression that triggers a runaway scan, or an index in a degraded state can hang inside a tool handler indefinitely. Because the stdio loop is single-threaded, that one stuck handler also blocks every subsequent request from the same client until the server is killed.

Where

  • src/CodeIndex/Mcp/McpServer.cs:80-124 (ProcessLineAsync dispatch)
  • src/CodeIndex/Mcp/McpToolHandlers.cs (handlers don't accept CancellationToken)

Suggested approach

(1) Plumb a CancellationToken through every handler signature; honor it inside long-running query loops. (2) In ProcessLineAsync, wrap the handler invocation in await Task.WhenAny(handlerTask, Task.Delay(timeout, ct)) (or task.WaitAsync(timeout, ct) on .NET 6+) with a configurable per-request timeout (default 60s, configurable via env or initialize params). (3) Return JSON-RPC -32603 (Internal error) with data: { reason: "timeout", elapsed_ms: ... } on timeout. (4) Coordinate with #1567 (shutdown/cancellation propagation) so the same token also fires on server shutdown. (5) Add a regression test: a handler that sleeps longer than the timeout returns a structured timeout error.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions