A Streamable HTTP MCP tool call whose server stays quiet for longer than about five minutes never completes. The call eventually fails with
MCP error -32001: Request timed out
even though requestTimeoutMs is set to ten minutes and the server did answer in time. It looks intermittent, because whether it bites depends on what else has configured streaming timeouts in the process first. This is openclaw/openclaw#172488, fixed in PR #172510.
Why it happens
Two different clocks are involved and only one of them is the deadline you set. Your request timeout covers the RPC. Undici separately enforces inactivity limits on the stream carrying the response, and its headersTimeout and bodyTimeout both default to 300 s. A response that stays silent past that has its stream closed, so the RPC dies against a stream that is already gone and the error names your request timeout instead of the real cause.
Anything built on undici inherits this. A fetch with no explicit timeout is not unlimited, it is capped at five minutes of silence.
The fix
Give the dispatcher its own stream budget instead of inheriting the defaults:
import { Agent, setGlobalDispatcher } from 'undici'
setGlobalDispatcher(new Agent({
headersTimeout: 600_000,
bodyTimeout: 600_000,
}))
Raise both. Raising only the request deadline keeps the symptom exactly as it is. For the bundled MCP client the fix was to pass an independent stream inactivity budget through the guarded fetch dispatcher, so quiet calls now wait at least as long as the configured request timeout and no configuration change is needed.
If a five minute silence is legitimate for your server, audit every layer that fetches before you trust the timeout you set. The number in your config is one of at least two that decide when the stream dies.