fix(deps): cap mcp below 2.0.0 (ENG-4250) - #207
Conversation
mcp 2.0.0, published today, removed the mcp.server.fastmcp module that
core/mcp/server.py subclasses. The dependency was declared `mcp>=1.9.4` with no
upper bound, and CI's first step runs `uv pip install -e .`, which resolves
fresh and ignores uv.lock. Every fresh install therefore fails at import:
ModuleNotFoundError: No module named 'mcp.server.fastmcp'
That kills `Test package installation (base)` before any test runs, so Unit
Tests fail on all of 3.10-3.14, on every open PR and on main.
Cap the range. A major bump is entitled to break; the unbounded `>=` was the
defect. Matches the existing `websockets<16.0.0` precedent in the same list.
uv.lock is unchanged, as it already resolved inside 1.x.
Migrating off the removed FastMCP surface is deliberately not bundled here: it
needs an owner decision about the MCP server surface and should not ride along
with an outage stop-gap.
🧪 Testing GuideWhat this PR addresses
Steps to reproduce the original issue
What to verify (expected behavior)
Note Posted by PR Testing Guide · Tag @mendral-app with feedback. |
There was a problem hiding this comment.
LGTM
Straightforward, correct upper-bound cap matching the existing websockets<16.0.0 pattern. The version specifier >=1.9.4,<2.0.0 is valid PEP 440 and precisely excludes the breaking major release. No correctness, security, or operational concerns.
Tag @mendral-app with feedback or questions. View session
🔒 Dependency Cap — Interaction FlowThis PR is a minimal dependency constraint change (1 file, 1 logical line), so a full sequence diagram would be overkill. Here's a concise view of why this cap matters in the install/import flow: sequenceDiagram
participant CI as CI Workflow
participant UV as uv pip install
participant PyPI as PyPI Registry
participant Proj as pyproject.toml
participant Srv as core/mcp/server.py
CI->>UV: uv pip install -e .
UV->>Proj: Read dependencies
Proj-->>UV: mcp>=1.9.4,<2.0.0
UV->>PyPI: Resolve mcp version
PyPI-->>UV: mcp 1.x.y (capped below 2.0.0)
UV-->>CI: Install success
CI->>Srv: import blaxel.core.mcp.server
Srv->>Srv: from mcp.server.fastmcp import FastMCP
Note right of Srv: ✅ Module exists in mcp <2.0.0
Summary: The upper bound Note Posted by PR Sequence Diagram · Tag @mendral-app with feedback. |
|
✅ Linked to Linear issue ENG-4250 — status already In Progress Note Posted by Linear Issue Enforcer · Tag @mendral-app with feedback. |
What broke
mcp 2.0.0was published today at 13:45 UTC and removed themcp.server.fastmcpmodule.src/blaxel/core/mcp/server.pysubclasses it:pyproject.tomldeclaredmcp>=1.9.4with no upper bound, and the workflow's first step runsuv pip install -e ., which resolves fresh and ignoresuv.lock. Every fresh install now fails at import:This kills
Test package installation (base)before any test executes, soUnit Testsfails across 3.10-3.14. It is repo-wide, not branch-specific: every open PR and the next push tomain. Last greenmainrun was 2026-07-24, before the release.Published wheel contents:
mcp/server/fastmcp1.20.02.0.0Upstream split FastMCP out into the standalone
fastmcppackage (currently 3.4.5).Blast radius is one import
Every
mcpimport in our source was audited. Only FastMCP is gone:mcp.ClientSessionmcp.client.streamable_httpmcp.shared.message.SessionMessagemcp.typesmcp.server.fastmcp.FastMCPTotal dependency: one import and one subclass overriding
run(), in a 148-line file.Fix
A major bump is entitled to break; the unbounded
>=was the actual defect. This matches the existingwebsockets<16.0.0precedent in the same dependency list.uv lockproduces no change, since the lockfile already resolved inside 1.x, so the diff is one file.Verification
main@2c405e2using the workflow's own commands (uv venv,uv pip install -e .,import blaxel.core):ModuleNotFoundError.mcp 1.29.0and emit the workflow's own success lines for bothTest package installation (base)and(with extras).main(stale local device-mode credentials hittingapi.blaxel.ai/v0/oauth/token).uv lock: no change.Deliberately not in this PR
Migrating off the removed FastMCP surface. It is small, but it needs an owner decision about the MCP server surface, and an outage stop-gap is the wrong place for it.
Also observed while auditing: 9 of 11 core dependencies are unbounded (
pydantic,pyjwt,python-dateutil,pyyaml,requests,tomli,attrs,httpx,dockerfile-parse). The same failure mode is available to any of them, but a reflexive mass-cap is a policy decision rather than a fix for this outage.Unblocks
ENG-4244 / #206, whose only red checks are this failure.
Linear: ENG-4250
Note
Caps the
mcpdependency at<2.0.0to prevent CI failures caused bymcp 2.0.0removing themcp.server.fastmcpmodule that this SDK subclasses.Written by Mendral for commit 899177d.