PR #33 widens mcp to <3. That pulls 2.x, where mcp.server.fastmcp no longer exists. The typecheck catches it, but the runtime behaviour is the defect worth fixing, and it is §2.1's failure mode in our own error handling.
Reproduced
Fresh venv, mcp>=2,<3 resolving to 2.1.1, with kicad-netspec installed from this working tree:
$ python -c "import mcp.server.fastmcp"
ModuleNotFoundError: No module named 'mcp.server.fastmcp'. This is mcp 2.x, where
FastMCP was renamed to MCPServer (from mcp.server.mcpserver import MCPServer) and
other APIs changed; see the migration guide at
https://py.sdk.modelcontextprotocol.io/v2/migration/#fastmcp-renamed-to-mcpserver
or pin 'mcp<2' to keep running v1 code.
Upstream could hardly be more helpful: it names the rename, the new import path, the guide, and the escape hatch.
Now netspec:
$ netspec-mcp
netspec-mcp needs the mcp extra: pip install 'kicad-netspec[mcp]'
$ echo $?
4
The extra is installed. mcp.py:212 catches ImportError — and ModuleNotFoundError is a subclass — so the precise upstream diagnosis is discarded and replaced with a confident statement of the wrong cause. The user is told to install something they already have.
Exit 4 is arguably the right outcome: netspec could not tell you about your board. The reason is fabricated, which is the thing §2.3 forbids — a plausible substitute for an answer we did not have.
Correcting my own earlier note
I wrote on #33 that netspec "raises a deliberate error naming that migration, and it fired correctly on its first real occasion." That was wrong twice: the handler is not deliberate about the rename, and it does not name it. What actually fires is pyright, in the Check job:
src/kicad_netspec/mcp.py:36:36 - error: "FastMCP" is unknown import symbol
src/kicad_netspec/mcp.py:113:36 - error: "FastMCP" is unknown import symbol
The typecheck is the only thing that reports the truth, and it only runs in CI. A user on mcp 2.x gets the misleading message.
Two separable pieces of work
1. Stop discarding the cause. An ImportError whose module is mcp.* is not evidence that the extra is missing. Distinguish "the package is absent" from "the package is present and the symbol moved", and when it is the latter, print what upstream said rather than a guess. This is worth doing regardless of when the migration happens, and it is small.
2. The migration itself. from mcp.server.fastmcp import FastMCP becomes from mcp.server.mcpserver import MCPServer (mcp.server.MCPServer also resolves on 2.1.1). Whether the rest of the API netspec uses moved as well is unestablished — I checked the import, not the surface — so the guide is the starting point, not this issue.
Keeping mcp<2 is a legitimate answer to (2) and no answer at all to (1).
Done when
Refs #33.
PR #33 widens
mcpto<3. That pulls 2.x, wheremcp.server.fastmcpno longer exists. The typecheck catches it, but the runtime behaviour is the defect worth fixing, and it is §2.1's failure mode in our own error handling.Reproduced
Fresh venv,
mcp>=2,<3resolving to 2.1.1, withkicad-netspecinstalled from this working tree:Upstream could hardly be more helpful: it names the rename, the new import path, the guide, and the escape hatch.
Now netspec:
The extra is installed.
mcp.py:212catchesImportError— andModuleNotFoundErroris a subclass — so the precise upstream diagnosis is discarded and replaced with a confident statement of the wrong cause. The user is told to install something they already have.Exit
4is arguably the right outcome: netspec could not tell you about your board. The reason is fabricated, which is the thing §2.3 forbids — a plausible substitute for an answer we did not have.Correcting my own earlier note
I wrote on #33 that netspec "raises a deliberate error naming that migration, and it fired correctly on its first real occasion." That was wrong twice: the handler is not deliberate about the rename, and it does not name it. What actually fires is pyright, in the
Checkjob:The typecheck is the only thing that reports the truth, and it only runs in CI. A user on mcp 2.x gets the misleading message.
Two separable pieces of work
1. Stop discarding the cause. An
ImportErrorwhose module ismcp.*is not evidence that the extra is missing. Distinguish "the package is absent" from "the package is present and the symbol moved", and when it is the latter, print what upstream said rather than a guess. This is worth doing regardless of when the migration happens, and it is small.2. The migration itself.
from mcp.server.fastmcp import FastMCPbecomesfrom mcp.server.mcpserver import MCPServer(mcp.server.MCPServeralso resolves on 2.1.1). Whether the rest of the API netspec uses moved as well is unestablished — I checked the import, not the surface — so the guide is the starting point, not this issue.Keeping
mcp<2is a legitimate answer to (2) and no answer at all to (1).Done when
mcp2.x installed,netspec-mcpreports the actual cause; a test pins the two cases apart, with the absent-package case still saying to install the extrajust checkis green against whichevermcpthe lock resolvesRefs #33.