fix(templates): port python-mcp-proxy to mcp 2 and bump fastmcp to v4 - #917
Open
l2ysho wants to merge 1 commit into
Open
fix(templates): port python-mcp-proxy to mcp 2 and bump fastmcp to v4#917l2ysho wants to merge 1 commit into
l2ysho wants to merge 1 commit into
Conversation
fastmcp 4 requires mcp >= 2.0.0, so the two pins have to move together. mcp 2 replaces the low-level Server handler dicts with constructor-based on_* handlers, renames camelCase result fields, and drops streamablehttp_client, so python-mcp-proxy needs a port to go with the bump. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1 task
l2ysho
marked this pull request as ready for review
September 4, 2026 20:16
Contributor
Author
|
@vdusek can you pls take a look? |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Note
TL;DR
fastmcp 4 #911 could not be closed alone. All required stuff updated in this PR.
Why #911 is red
#911 bumps
fastmcpto>=4.0.2but leavesmcp >= 1.25.0, < 2.0.0next to it. Every Python lint and type-check leg dies in ~8s, before linting starts:renovate/artifactson that PR fails for the same reason — Renovate could not regenerateuv.lock.Why Renovate cannot finish it
Widening
mcpto>= 2.0.0, < 3.0.0resolves, butty checkthen reports 34 diagnostics, all intemplates/python-mcp-proxy/my_actor/mcp_gateway.py. mcp 2 is a breaking rewrite of the low-level server API the proxy is built on:app.request_handlers[types.XRequest] = fnServer(..., on_x=fn)— constructor kwargsRequest, returnstypes.ServerResult(result)(ctx, params), returns the result type directlytypes.ServerResult(...)callable wrapperresponse.serverInforesponse.server_infoCallToolResult(isError=True)CallToolResult(is_error=True)req.params.progressTokenparams.progress_tokenAnd one break the type checker never saw, because the import is resolved at runtime:
mcp 2 renamed it to
streamable_http_client, dropped the per-call HTTP kwargs in favour of a pre-built client, and yields two streams instead of three.What this PR does
Pins —
pyproject.toml,templates/python-mcp-empty/requirements.txt,templates/python-mcp-proxy/requirements.txt:fastmcp→>= 4.0.2, < 5.0.0mcp→>= 2.0.0, < 3.0.0Port —
templates/python-mcp-proxy/my_actor/:mcp_gateway.pyrewritten against theon_*constructor API. Handlers are collected per advertised capability and passed toServer(...)in one go. Whitelist filtering, tool-call charging and the unauthorized-tool error path are unchanged.server.py—streamable_http_client, with headers/timeout/auth moved into acreate_mcp_http_client(...)passed ashttp_client=.models.py,server.py—httpx→httpx2. mcp 2 runs on httpx2 and theauthfield is handed straight to it, so the template would otherwise ship two HTTP stacks.httpxstays in the root env;python-beautifulsoupandpython-startstill use it.Behavior changes worth a reviewer's eye
Two handlers are dropped, because mcp 2 emits a runtime
MCPDeprecationWarningatServer(...)construction for each:logging/setLevelforwarding — "The logging capability is deprecated as of 2026-07-28 (SEP-2577)."resources/subscribeandresources/unsubscribeare kept, so the proxy still works in front of a 2025-era remote. Only the client-side calls are deprecated, not the handler slots, so they cost one# ty: ignore[deprecated]each and no runtime warning.Say the word if you would rather keep logging and progress and accept the startup warnings.
Verification
Local, against the real packages (fastmcp 4.0.2, mcp 2.1.1):
uv run poe lint— clean.uv run poe type-check—All checks passed!(was 34 diagnostics).create_gateway→ client. Tool list filtered to the whitelist, allowed call proxied, unauthorized call returnsis_error=Truewith the right message, charging fired once with the configured count('search_papers', 2), prompts proxied, upstream name/version forwarded.ProxyServer(server_type=HTTP)on another. Through the proxy:initializereports the upstream'supstream-http 9.9.9,list_tools→['echo'],call_tool→echo: hello.python-mcp-emptyunder fastmcp 4: server builds,list_tools→['add'],add(2,3)returns the expected structured content,http_app(transport='streamable-http')still constructs.requirements.txtresolve on their own (arxiv-mcp-serverincluded).Follow-ups, not in this PR
SessionTrackingMiddleware/create_starlette_appstill callsession_manager.handle_request, which mcp 2 keeps. No change needed, but the newerasgi_appis the forward path.python-mcp-proxy/README.md:128points atsrc/mcp_gateway.py; the file lives inmy_actor/. Pre-existing.on_subscriptions_listenas the replacement for resource subscriptions. Wiring the proxy through it is a design change, not a port.Close #911 once this is green.
🤖 Generated with Claude Code