DEV Community

Cover image for I Set a 500ms Timeout and Got 28 Hours
quintetkit
quintetkit

Posted on

I Set a 500ms Timeout and Got 28 Hours

I had an MCP server that occasionally hung, so I gave it a short leash:

{ "mcpServers": { "flaky": { "type": "http", "url": "...", "timeout": 500 } } }
Enter fullscreen mode Exit fullscreen mode

timeout is in milliseconds, so that reads as half a second.

Values below 1000 are ignored. The call falls through to
MCP_TOOL_TIMEOUT, and if that is unset, to its default — about 28 hours.

I had written the tightest limit I could and produced the loosest one available.

Before v2.1.162 a value under 1000 was floored to one second, which is the
behaviour I had in my head. It changed, and nothing in my configuration
changed with it.

Three related things I only learned by reading the whole section:

  • timeout is a hard wall-clock limit per tool call. Progress notifications from the server do not extend it
  • A timeout of at least 1000 also acts as a floor on the idle timeout — calls are never aborted for idleness sooner than that
  • stdio and WebSocket servers have no per-request timer at all

A url with no type is read as a stdio server

{ "mcpServers": { "example": { "url": "https://mcp.example.com/mcp" } } }
Enter fullscreen mode Exit fullscreen mode

There is no defaulting to http. An entry with no type is a stdio server,
stdio requires command, and so the server is skipped as a configuration error:

MCP server "example" has a "url" but no "type"; add "type": "http" (or "sse" / "ws") to this entry
Enter fullscreen mode Exit fullscreen mode

That message exists from v2.1.202. Before it, the same mistake reported
command: expected string, received undefinedyou wrote a url and were told
about a command
, which is a long way from the cause.

Under --output-format stream-json it also appears in the system/init event's
mcp_server_errors, so a script can detect that a server never loaded. That is
the only machine-readable path I have found for it.

A cloned repository cannot approve its own servers

This one cost me the most time, because it looks like a permissions bug.

Servers from .mcp.json need approval. You can commit
enableAllProjectMcpServers or enabledMcpjsonServers to the project's
.claude/settings.json — and in an untrusted folder they are ignored. The
server sits at ⏸ Pending approval, never connected, never health-checked.

Which is correct, and obvious once stated: a repository that could approve its
own MCP servers would be a way to run code on anyone who clones it.

Three sources of approval still apply in an untrusted folder: your own
~/.claude/settings.json, managed settings, and settings passed with
--settings.

The pattern across all of these

Every one of them is a configuration that loads. No error, no warning you
would notice, and a running system that is doing something other than what the
file says.

timeout: 500 is the sharpest example: the file says half a second, the system
says a day and change, and both are working as designed.

What I want from a configuration checker, having been on the wrong end of these,
is not more rules. It is that the ones it does have never fire on something
correct — because the reason I stopped reading startup output in the first place
was that nothing there had ever mattered, and by the time something did, I had
already trained myself past it.

npx @quintetkit/ccheck
Enter fullscreen mode Exit fullscreen mode
error .mcp.json:3
      Server "example" has a `url` but no `type`. Add `"type": "http"` (or "sse" / "ws").
warn  .mcp.json:9
      Server "flaky": `timeout: 500` is in milliseconds; values below 1000 are ignored.
Enter fullscreen mode Exit fullscreen mode

The full set, including the required field per transport:

https://quintetkit.github.io/en/reference/claude-code-mcp-json.html


I publish the configuration for splitting Claude Code into separate personas —
Architect, Coder, Reviewer, Conflict Resolver — under MIT. Copy it, run
./setup.sh, and it works. It does not depend on your tech stack.

https://github.com/quintetkit/quartet

I built one real tool using nothing but this workflow. Every Issue, PR, review
and merge is still there. The parts that went wrong were not deleted.

https://github.com/quintetkit/mdlinkcheck

The version that adds a UI Designer persona, review criteria, a per-Issue
parallel execution script and a 11-chapter guide is on the
product page.

The full kit — five personas, the scripts and the complete guide — is available here.

https://quintetkit.gumroad.com/l/quintet

Top comments (1)

Collapse
 
raknaos profile image
Raknaos

The floor-to-1000ms detail bit me too. I run a small fleet of agents on a VPS and had a tool call that should have died in half a second hanging for what felt like forever, because I never realized the per-request timer only kicks in above that threshold. Reading the whole config section instead of skimming the examples is the only reason I caught it.

Did you end up separating the hard wall-clock timeout from the idle floor in your config, or just set both to the same number and accept the coarser behavior?