Long-running tools have timeouts
Why it matters
A tool that calls fetch() with no timeout will hang indefinitely if the remote service is unresponsive — the MCP client freezes waiting for a result that never arrives. A tool that executes shell commands with no timeout can be kept running permanently by a hung subprocess, blocking the server for all clients. CWE-400 (uncontrolled resource consumption) is the mechanism; ISO 25010 performance-efficiency is the quality attribute violated. In agentic workflows where the AI chains multiple tool calls, a single hung tool halts the entire session.
Severity rationale
Medium because missing timeouts cause hangs under degraded network or process conditions rather than immediate failures, but the impact is a frozen session with no recovery path short of restarting the server.
Remediation
Add an AbortController timeout to every fetch() call and a timeout option to every shell command in tool handlers.
// src/tools/fetch.ts — 30-second timeout
server.tool('fetch_url', ..., async ({ url }) => {
const controller = new AbortController()
const timer = setTimeout(() => controller.abort(), 30_000)
try {
const res = await fetch(url, { signal: controller.signal })
clearTimeout(timer)
return { content: [{ type: 'text', text: await res.text() }] }
} catch (error) {
clearTimeout(timer)
const msg = (error as Error).name === 'AbortError'
? `Request timed out after 30s: ${url}`
: `Fetch failed: ${(error as Error).message}`
return { content: [{ type: 'text', text: msg }], isError: true }
}
})
Detection
-
ID:
timeout-handling -
Severity:
medium -
What to look for: Count all long-running operations in tool handlers. Enumerate which have timeout limits vs. which could run indefinitely. Identify tools that perform potentially long-running operations: HTTP requests, database queries, file system operations on large datasets, shell command execution, API calls to external services. Check whether these operations have timeouts configured. Check for
AbortController/AbortSignalusage,setTimeoutwrappers, or timeout options on HTTP clients (fetch timeout, axios timeout). Check that timeout errors are caught and returned asisError: truewith a descriptive message. -
Pass criteria: Tools that make network requests, run queries, or execute commands have explicit timeouts. Timeout errors produce readable error messages (not raw timeout exceptions). At least 90% of tool handlers with external calls must have timeout limits of no more than 30 seconds.
-
Fail criteria: Network-calling tools have no timeout (will hang indefinitely if the remote service is unresponsive), or timeout errors are not caught (crash the server).
-
Skip (N/A) when: All tools are purely computational with no I/O operations. All checks skip when no MCP server is detected.
-
Cross-reference: For graceful shutdown, see
graceful-shutdown. -
Detail on fail:
"Tool 'fetch_url' uses fetch() with no timeout — will hang indefinitely if the target server is unresponsive. The MCP client will appear frozen"or"Tool 'run_command' executes shell commands with no timeout — a hanging process will block the server permanently" -
Remediation: Add timeouts to all I/O operations:
// src/tools/fetch.ts — timeout on external calls const controller = new AbortController() const timeout = setTimeout(() => controller.abort(), 30000) const response = await fetch(url, { signal: controller.signal })server.tool('fetch_url', ..., async ({ url }) => { try { const controller = new AbortController() const timeout = setTimeout(() => controller.abort(), 30_000) // 30s timeout const response = await fetch(url, { signal: controller.signal }) clearTimeout(timeout) const text = await response.text() return { content: [{ type: 'text', text }] } } catch (error) { if (error.name === 'AbortError') { return { content: [{ type: 'text', text: `Request timed out after 30 seconds: ${url}` }], isError: true } } return { content: [{ type: 'text', text: `Fetch failed: ${error.message}` }], isError: true } } })
External references
- cwe · CWE-400 — Uncontrolled Resource Consumption
- iso-25010:2011 · performance-efficiency
Taxons
History
- 2026-04-18·v1.0.0·Initial import from mcp-server·automated