Skip to content

MCP server lacks shutdown hook, backpressure, and cancellation propagation #1567

Description

@Widthdom

Summary

McpServer.RunAsync is a simple read/dispatch/write loop with no shutdown notification handler, no concurrent-request bound, and no CancellationToken propagation through DbReader. A long-lived MCP server cannot shut down gracefully, an unbounded burst of tool calls can exhaust memory and DB locks, and a client disconnect mid-query leaves orphan operations running until they finish naturally.

Evidence

  • src/CodeIndex/Mcp/McpServer.cs:49-74 — RunAsync loop; no shutdown notification handling, no semaphore bounding concurrent requests.
  • DbReader query methods do not accept a CancellationToken plumbed from the request.

Impact

  • No graceful shutdown for long-lived deployments.
  • Memory / lock pressure under concurrent bursts is unbounded.
  • Client disconnect wastes work on results no one will read.

Proposed direction

  • Handle MCP notifications/shutdown (per the spec) — drain in-flight, close transport, exit cleanly.
  • Add a SemaphoreSlim bounding concurrent in-flight tool calls (configurable, default e.g. 8).
  • Plumb a per-request CancellationToken into DbReader so SQLite commands are cancelled when the client goes away.

Repro env

  • Branch: main @ 2ee912d (release v1.21.0)

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions