Skip to content

Inspector times out when FastMCP tool emits ctx.info/ctx.report_progress (v2.2.0, LEGACY/STDIO) #2028

Closed

Description

@Avi-Jadhav03

Which version line?

v2 — current (@modelcontextprotocol/inspector@latest)

Which client?

Web

Inspector version

2.2.0

Node version

v26.5.0

Operating system (and browser, for the web client)

MacOS 26.5.2

Transport

stdio

MCP server under inspection

Server: FastMCP local Python server (server.py)

Command used:
fastmcp dev inspector server.py

Transport: stdio
Protocol era: legacy
OAuth: no

Note: Same server/code works via Claude Desktop; timeout is observed via Inspector path.

Steps to reproduce

  1. Fresh launch Inspector using fastmcp dev inspector server.py.
  2. Connect to the local server over stdio.
  3. Open the Tools tab.
  4. Run slow_task (example input: steps=5) where the tool calls ctx.report_progress(...) and ctx.info(...) in a loop.
  5. Observe progress/log lines appear during execution.
  6. Final result does not return; Inspector shows Tool Error: Request timed out.

Expected behavior

Tool should complete and return its final result in Inspector UI, while still allowing mid-execution context notifications (ctx.report_progress(...) / ctx.info(...)).

Actual behavior

When ctx.report_progress() or ctx.info() is invoked, Inspector eventually shows Tool Error: Request timed out, even though server-side execution appears to finish successfully.

If Context is injected but unused (or no Context calls are made), the tool returns normally.

Logs, errors, or screenshots

Error shown in Inspector UI:
Tool Error: Request timed out

Environment:

  • Inspector version: 2.2.0
  • Node.js: v26.5.0
  • OS: macOS 26.5.2
  • Transport: stdio
  • Era: legacy

I can provide additional Protocol/Network logs if maintainers want specific traces.

Already prototyped a fix?

No fix prototyped yet.

Before you submit

  • I searched existing issues and this is not a duplicate.
  • This is not a security vulnerability report (those go through the private advisory process).

Activity

  1. carter-smalls commented on Aug 16, 2026

    @carter-smalls

    Looks like tool error request timed out when ctx.report_progress is called.

    Use badgr-mcp-doctor to diagnostic report showing mcp timeout cause and guidance to resolve it.

    That should help confirm frequency of ctx.report_progress messages causing timeout.

  2. Avi-Jadhav03 commented on Aug 16, 2026

    @Avi-Jadhav03
    Author

    Thanks — I installed and checked badgr-mcp-doctor usage.

    Its required mode is --url <sse-url> (SSE endpoint), but my repro is on stdio transport in Inspector (legacy era), not SSE.

    badgr-mcp-doctor --help output indicates URL/SSE-based diagnostics only.
    Could you share the exact command/flags you want for a stdio-based repro, or should I reproduce this against an SSE endpoint and report that result instead?

  3. cliffhall commented on Aug 19, 2026

    @cliffhall
    Member

    Triage: Priority Medium (total 8)

    • Severity 4 — a tool that emits progress or log notifications never returns its result, so the Inspector reports a timeout for a call that completed on the server
    • Urgency 3 — wanted this milestone; FastMCP's ctx.report_progress / ctx.info are widely used
    • Bonuses: +1 bug label

    The Protocol/Network traces offered above would help — please do attach them.

    Board: #28, Status Incoming (awaiting maintainer review — no milestone yet).

  4. Avi-Jadhav03 commented on Aug 20, 2026

    @Avi-Jadhav03
    Author

    Thanks — attaching protocol trace from a failed run.

    Repro context

    • Date/time: 2026-08-20T14:23Z
    • Inspector: 2.2.0
    • Transport: stdio
    • Era: legacy
    • Tool called: slow_task_v4
    • Input: {"steps": 2}
    • Client request id: 8
    • _meta.progressToken: 8

    What the trace shows

    1. Client sends tools/call with id: 8.
    2. Server emits notifications/message (Starting task).
    3. Server sends a success response with id: 7 (not 8) containing result "Got 2".
    4. ~60s later, client sends notifications/cancelled for requestId: 8 with reason SdkError: Request timed out.

    Raw protocol excerpt (redacted)

    [
      {
        "timestamp": "2026-08-20T14:23:23.013Z",
        "direction": "request",
        "origin": "client",
        "message": {
          "method": "tools/call",
          "id": 8,
          "params": {
            "name": "slow_task_v4",
            "arguments": { "steps": 2 },
            "_meta": { "progressToken": 8 }
          }
        }
      },
      {
        "timestamp": "2026-08-20T14:23:23.042Z",
        "direction": "notification",
        "origin": "server",
        "message": {
          "method": "notifications/message",
          "params": { "level": "info", "data": { "msg": "Starting task" } }
        }
      },
      {
        "timestamp": "2026-08-20T14:23:23.044Z",
        "direction": "response",
        "origin": "server",
        "message": {
          "id": 7,
          "result": {
            "content": [{ "type": "text", "text": "Got 2" }],
            "structuredContent": { "result": "Got 2" },
            "isError": false
          }
        }
      },
      {
        "timestamp": "2026-08-20T14:24:23.019Z",
        "direction": "notification",
        "origin": "client",
        "message": {
          "method": "notifications/cancelled",
          "params": { "requestId": 8, "reason": "SdkError: Request timed out" }
        }
      }
    ]
  5. added this to the v2.5.0 milestone on Aug 24, 2026
  6. modified the milestones: v2.5.0, v2.6.0 on Sep 1, 2026
  7. Avi-Jadhav03 commented on Sep 4, 2026

    @Avi-Jadhav03
    Author

    Thanks for the update. Just confirming: is this issue now targeted for v2.6.0?
    Happy to retest any patch/build if needed.

  8. cliffhall commented on Sep 7, 2026

    @cliffhall
    Member

    @Avi-Jadhav03 Have you tried increasing the Request Timeout value in the Server Settings modal for the given server?

  9. cliffhall commented on Sep 7, 2026

    @cliffhall
    Member

    @Avi-Jadhav03 Thanks for the trace — it's more useful than my timeout suggestion above, which I now think is wrong. Disregard it: your own trace argues against it.

    Reading your excerpt:

    t event
    23.013 client → tools/call id 8, _meta.progressToken: 8
    23.042 server → notifications/message ("Starting task")
    23.044 server → response with id: 7, result "Got 2"
    24:23.019 client → notifications/cancelled for requestId 8, "Request timed out"

    The server answered 31 ms after the request, so nothing was actually slow — raising Request Timeout would only make it hang longer before the same error.

    The response carries id: 7 against a request of id: 8. The SDK matches responses to requests by id, so request 8 never resolves and falls through to the default 60 s timeout (your requestTimeout is 0, meaning the SDK's DEFAULT_REQUEST_TIMEOUT_MSEC) — which is exactly the 60.006 s gap in the trace.

    Two details from the Inspector side that fit this and rule out some alternatives:

    • resetTimeoutOnProgress and progress both default to true, and we wire a per-request onprogress. If genuine notifications/progress were arriving in a loop, the deadline would keep sliding and could not fire at a clean 60 s. That it did suggests no progress notification was ever correlated with request 8.
    • The _meta.progressToken: 8 is the SDK stamping the message id, so the request really was id 8 on the wire.

    Before we dig further, could you narrow it in two ways?

    1. Reproduce without fastmcp dev. fastmcp dev inspector server.py puts FastMCP's dev wrapper between the Inspector and your server — an extra hop, and the most plausible place for a request id to be rewritten. Please launch the Inspector on its own and point a stdio server entry directly at python server.py.
    2. Attach the exported Protocol log (the JSON export from the Protocol tab) rather than a retyped excerpt — an off-by-one id is exactly the kind of thing that can slip in during transcription, and it's the whole finding here.

    If id: 7 vs id: 8 survives a direct stdio connection, it's real and we'll chase it. If it disappears, the wrapper is the culprit and this belongs upstream with FastMCP.

    Moving this to v2.7.0 in the meantime, since it's waiting on the repro rather than on us.

  10. modified the milestones: v2.6.0, v2.7.0 on Sep 7, 2026
  11. Avi-Jadhav03 commented on Sep 8, 2026

    @Avi-Jadhav03
    Author

    Thanks — makes sense. I’ll retest with a direct stdio connection (Inspector launched separately, server command set to python server.py, no fastmcp dev wrapper) and attach the raw Protocol JSON export from the Protocol tab.

  12. 1 remaining item

  13. anythingoah commented on Sep 9, 2026

    @anythingoah

    Sounds like this took a few rounds to pin down was v2.2.0 a version bump that broke something that worked before, or first time trying this pattern?

  14. Avi-Jadhav03 commented on Sep 9, 2026

    @Avi-Jadhav03
    Author

    Good question. This was my first time testing this exact pattern (ctx.info / ctx.report_progress during a tool call), so I can’t yet confirm a regression window.

    I reproduced it consistently on Inspector v2.2.0, including direct stdio (no fastmcp dev wrapper), and attached protocol exports above.

    If useful, I can run a quick version matrix (e.g., v2.1.x vs v2.2.0 vs latest) and report back to identify whether this is a regression.

  15. self-assigned this
    on Sep 11, 2026
  16. Avi-Jadhav03 commented on Sep 11, 2026

    @Avi-Jadhav03
    Author

    # Inspector stdio timeout: consolidated retest findings

    Environment

    • MCP Inspector UI: v2.6.0

    • FastMCP: 3.4.7

    • Python: 3.14

    • Transport: stdio (local process)

    • Inspector launch command:

      npx -y @modelcontextprotocol/inspector \
        /Users/avi/Developer/FastMCP/venv/bin/python server.py
    • fastmcp dev inspector wrapper: not used

    Finding: delayed responses and Inspector timeouts in direct stdio

    From an exported protocol trace taken in a fresh direct-stdio session:

    Request Server response duration Inspector result
    resources/list ~39 ms Returned normally
    tools/list ~108,561 ms Cancelled by Inspector after ~60 s
    prompts/list ~108,566 ms Cancelled by Inspector after ~60 s
    resources/templates/list ~108,571 ms Cancelled by Inspector after ~60 s

    The UI reflects this: Resources may appear immediately, while Tools and Prompts initially show Request timed out. Their responses can arrive much later.

    Tool-call reproduction

    Tool under test:

    async def slow_task_v4(steps: int, ctx: Context) -> str:
        await ctx.info("Starting task")
        return f"Got {steps}"

    steps is not used for any work or delay; all values execute the same code.

    Observed protocol timings:

    Call Server response duration Inspector result
    slow_task_v4(steps=3) ~44,013 ms Result displayed
    slow_task_v4(steps=5) ~141,222 ms Cancelled after ~60 s
    slow_task_v4(steps=1) ~104,115 ms Cancelled after ~60 s
    subtract(3, 3) afterward ~273 ms Returned normally

    In at least one direct-stdio retest, the request and response IDs matched, but Inspector still emitted notifications/cancelled at ~60 seconds. This does not appear to be solely an ID-mismatch issue.

    Current conclusion

    In direct stdio, Inspector sometimes delays delivery of list and tool-call responses past its ~60-second timeout, even though the FastMCP server eventually sends valid responses.

    I have attached the raw protocol exports for the maintainers to inspect.

    inspector-protocol-python-2026-09-11T15-21-17.097Z.json

    Separate banner observation

    I also observed connection failures with FastMCP's startup banner enabled and reliable connections with:

    mcp.run(show_banner=False)

    I have not yet completed a clean A/B reproduction for this, so I am reporting it as an observation rather than a confirmed independent issue.

  17. anythingoah commented on Sep 11, 2026

    @anythingoah

    Good question. This was my first time testing this exact pattern (ctx.info / ctx.report_progress during a tool call), so I can’t yet confirm a regression window.

    I reproduced it consistently on Inspector v2.2.0, including direct stdio (no fastmcp dev wrapper), and attached protocol exports above.

    If useful, I can run a quick version matrix (e.g., v2.1.x vs v2.2.0 vs latest) and report back to identify whether this is a regression.

    @Avi-Jadhav03 That'd actually be really useful, if you're up for it. And funny timing: manually running that kind of version matrix by hand is basically the exact problem I've been building ContractWatch around, automatically catching a regression like this across versions instead of someone having to bisect it manually after the fact. If you do run the matrix and confirm it's v2.2.0-specific, happy to set you up with a free monitor on this repo so you can see whether it would've caught it automatically, no strings attached.

  18. cliffhall commented on Sep 14, 2026

    @cliffhall
    Member

    Thanks for the raw Protocol exports — they were decisive, and they turned out to contain two separate problems. One is a real Inspector bug I've now fixed; the other is server-side and outside the Inspector. Splitting them:

    1. Inspector bug — a progress-reporting tool times out at 60s on the web client (fixed in #2363)

    The web client doesn't talk to your server directly. The browser runs the MCP Client, and its requests are relayed through the Inspector's Node backend: browser → POST /api/mcp/send → backend → your stdio server, with responses coming back over an SSE stream. That relay added two request-response waits that the CLI/TUI (which use a direct transport) don't have, and both were hardcoded to 60s and blind to notifications/progress.

    The MCP SDK's own request timeout resets every time a progress notification arrives (resetTimeoutOnProgress, which the Inspector enables) — that's what lets an arbitrarily long tool keep running as long as it reports progress. But the relay's two progress-blind waits fired first and shadowed it. So a tool that calls ctx.report_progress() in a loop was cancelled at a flat 60s on the web client only, while the same tool rides out fine over the CLI/TUI and in Claude Desktop.

    #2363 makes both relay waits reset on a notifications/progress whose token matches the in-flight request, exactly mirroring the SDK. Verified end-to-end against a real FastMCP stdio server over the relay: a 75-second tool that reports progress now completes instead of being cancelled at 60s.

    One deliberate boundary: log messages (ctx.info → notifications/message) do not reset the deadline — the SDK and every other client treat only progress as liveness, so a tool that merely logs and genuinely runs past the request timeout still times out. If you have a long tool that legitimately needs more headroom, either emit ctx.report_progress() (now honored on web) or raise Request Timeout in Server Settings.

    2. Server-side stall — not an Inspector defect

    Your most recent trace shows responses arriving 44s, 104s, 141s, even 173s after the request, with the correct ids. Crucially, the server's notifications/message ("Starting task") arrives within ~80ms — over the same stdout pipe and the same SSE channel that the delayed response travels. If the Inspector's pipe or relay were buffering, the notification would be just as late as the response. It isn't. That places the delay between your server emitting the notification and flushing the response — i.e. server-side, in the ctx.info(...) → return window.

    I could not reproduce that stall on the exact stack you reported (FastMCP 3.4.7, mcp 1.30.0, Python 3.14.7) across three independent paths — a raw stdio reader, the Inspector CLI, and the full web relay with a real SDK client, including a 20-round concurrent-burst stress test (max round 17ms). The slow_task_v4 server returns in single-digit milliseconds every time here. So the 44–173s you see looks specific to your host — most likely asyncio/anyio scheduling of the stdio writer on a Python 3.14 pre-release, which is consistent with your own finding that mcp.run(show_banner=False) improved reliability (a server-side toggle). For a call stalled >60s with no progress, the ~60s cancellation you saw is the SDK's default request timeout behaving correctly; #2363 does not change that (and shouldn't).

    Two things would let us confirm the server side, if you're up for it:

    1. Re-run on a stable Python (3.12 or 3.13) with the same FastMCP, and see whether the 44–173s stalls disappear.
    2. During a stalled call, capture the server's own logs/stderr (e.g. python -X dev server.py) — that's where a blocked writer or a slow logging handler would show.

    Net: #2363 fixes the ctx.report_progress timeout in the title for the web client. The ctx.info-only stalls in your traces are a server-side latency issue on your host that the fix intentionally doesn't paper over. Happy to keep digging on (2) if the stalls persist on a stable Python.

  19. cliffhall commented on Sep 14, 2026

    @cliffhall
    Member

    Fixed by #2363, merged to v2/main: both web-relay request-response waits now reset on notifications/progress, so a long tool that reports progress no longer times out at 60s on the web client (it already worked over the CLI/TUI). Log-only tools that genuinely run past the request timeout still time out, matching the SDK and every other client.

    Closing this out for the Inspector side. The separate 44–173s server-side stalls in your traces are a FastMCP/Python-3.14 latency issue on your host, not reproducible here — if they persist on a stable Python (3.12/3.13), that's worth a fresh report (ideally with the server's own stderr during a stalled call), and I'm happy to dig in.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingv2Issues and PRs for v2

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions