fix(mcp): accept integer progressToken in host progress capture - #32402
Conversation
Greptile SummaryThis PR fixes a
Confidence Score: 5/5Safe to merge — the change is a two-line targeted fix with no side effects on other paths. Both changes are minimal and correct: No files require special attention.
|
| Filename | Overview |
|---|---|
| litellm/proxy/_experimental/mcp_server/server.py | Two-line fix: converts token to string before slicing in the debug log, and replaces a truthiness guard with an explicit is None check. Both changes are correct and minimal. |
| tests/test_litellm/proxy/_experimental/mcp_server/test_mcp_tool_search.py | Adds three targeted regression tests (integer token, zero token, value preservation) using mocks only — no real network calls. |
Reviews (1): Last reviewed commit: "fix(mcp): accept integer progressToken i..." | Re-trigger Greptile
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Merging this PR will improve performance by 13.27%
Warning Please fix the performance issues or acknowledge them on CodSpeed. Performance Changes
Tip Investigate this regression by commenting Comparing |
|
bugbot run |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 75755de. Configure here.
v1.92.0's MCP gateway crashes on every tool call with TypeError: 'int' object is not subscriptable, because _capture_host_progress_callback slices progressToken assuming it's always a string. Claude Code sends integer progress tokens (spec-valid per MCP: progressToken: str | int), so every mcp_server_tool_call fails before reaching the backend server. Upstream fix (BerriAI/litellm#32402) landed 2026-07-08 but hasn't been cut into a stable release yet - only available in the v1.93.0-rc.1 prerelease image.
v1.92.0's MCP gateway crashes on every tool call with TypeError: 'int' object is not subscriptable, because _capture_host_progress_callback slices progressToken assuming it's always a string. Claude Code sends integer progress tokens (spec-valid per MCP: progressToken: str | int), so every mcp_server_tool_call fails before reaching the backend server. Upstream fix (BerriAI/litellm#32402) landed 2026-07-08 but hasn't been cut into a stable release yet - only available in the v1.93.0-rc.1 prerelease image.
Relevant issues
Fixes #32181
Linear ticket
Resolves LIT-4256
Pre-Submission checklist
Please complete all items before asking a LiteLLM maintainer to review your PR
@greptileaito re-request a review after pushing changes)Screenshots / Proof of Fix
The MCP spec types
progressTokenas string or integer, and the MCP Python SDK matches (ProgressToken = str | intinmcp/types.py). Clients such as Claude Code send monotonically increasing integer tokens by default._capture_host_progress_callbackslices the raw token in an eagerly evaluated debug f-string (host_token[:8]), so anytools/callcarrying an integer token raisesTypeError: 'int' object is not subscriptablebefore the backend MCP server is ever dispatched; the handler's catch-all converts that into anisErrortool result, so the backend logs stay clean and the failure masquerades as a gateway fault. The same function also drops the spec-valid integer token0through its truthiness guard, silently disabling progress forwarding for itLive proxy setup, identical for the before and after runs: a real public MCP server behind the proxy, streamable HTTP protocol path (which is the path that captures the host progress context), real Postgres
MCP handshake used by both runs (initialize, capture the session id, send the initialized notification):
Before (bug present, captured at
db2402754a, the unmodified litellm_internal_staging tip)A
tools/callwith an integerprogressTokenfails before the backend is dispatchedProxy log at the same moment, showing the failure is the debug f-string in
_capture_host_progress_callbackand that it fires beforecall_mcp_toolControl call on the same unfixed proxy with a string token succeeds, confirming the failure is integer-specific
After (fix applied, captured at
75755de091)The same call now returns the real tool result, and the edge cases hold: integer token 0 (previously silently dropped by the truthiness guard), a string token, and no token at all
All four variants return the tool output
Proxy log confirming integer tokens (including 0) now make it through capture
Type
🐛 Bug Fix
Changes
_capture_host_progress_callbackinlitellm/proxy/_experimental/mcp_server/server.pynow stringifies the token only inside the debug log line (str(host_token)[:8]), keeping the original value forsend_progress_notificationso the host gets back exactly the token it sent, and the guard checkshost_token is Noneinstead of truthiness so the spec-valid integer token0no longer disables progress forwardingThree regression tests added to
TestCaptureHostProgressCallbackintests/test_litellm/proxy/_experimental/mcp_server/test_mcp_tool_search.py: an integer token returns a callable (raised TypeError before the fix), integer token 0 returns a callable (returned None before the fix), and the forwarded token preserves the original integer value and type. All three fail on the unfixed code and pass with the fix