fix(mcp): report the real import failure, not a missing extra - #36
Merged
Conversation
`netspec-mcp` caught `ImportError` and printed "needs the mcp extra" whatever the cause. `ModuleNotFoundError` is a subclass, so under mcp 2.x -- where `mcp/server/fastmcp.py` is a stub that raises, naming the rename to `MCPServer`, the new import path, the migration guide and the `mcp<2` escape hatch -- all of that was discarded and the user was told to install what they already had. Blame the extra only when the `mcp` package is genuinely absent; when it is present, pass the import's own words through. Exit stays 4 either way: netspec could not run, which says nothing about a design (D10). It was the reason that was fabricated, not the outcome. Closes #35.
Connectivity unchanged
|
The message added for #35 said "this is not a missing dependency: the mcp package is installed". Only the second half was established. On an incomplete install -- mcp present, a transitive dependency of it gone -- the message denied a missing dependency and then printed one: ...this is not a missing dependency: the mcp package is installed. The import said: ModuleNotFoundError: No module named 'pydantic_settings' That is the substitution the change exists to remove, and it also steers the user away from the fix, since reinstalling the extra re-resolves the missing dependency and repairs the install. Narrow the sentence to the lookup that was actually done. Pin the case in a test, and move the helper's tests to a module that is not gated on the extra, so the three that need no `mcp` run without it.
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.
netspec-mcpcaughtImportErrorand printednetspec-mcp needs the mcp extra: pip install 'kicad-netspec[mcp]'whatever the cause.ModuleNotFoundErroris a subclass ofImportError, so undermcp2.x the message was wrong in the one way that matters: the extra is installed, and the user was told to install it.This is piece 1 of the two in #35. Piece 2 — the
FastMCP→MCPServermigration, and whether the rest of the API netspec uses moved with it — is untouched here, and so is themcp>=1.27,<2pin. #33 widens that pin to<3; this change does not depend on that decision and does not pre-empt it. It does change what #33 would look like if merged: instead of an entry point that blames a missing extra, a user on 2.x gets upstream's migration message, so the pin question is visible rather than disguised.The three cases
Measured in three fresh venvs,
kicad-netspecinstalled from this branch.mcp2.1.1 installed. Before:After:
mcpabsent — unchanged, before and after:Incomplete install —
mcp1.30.0 withpydantic-settingsuninstalled. After:The message says only what the lookup established. An earlier revision of this branch said "this is not a missing dependency: the mcp package is installed", which denied a missing dependency in the same breath as printing one — a categorical claim about the whole dependency tree from resolving one name in it. It was also the wrong steer:
pip install 'kicad-netspec[mcp]'re-resolves the missing transitive dependency and repairs that install (measured), so the denial argued against the one thing that works.The change
_diagnose_import_failure(exc, *, mcp_installed)decides between the two messages.main()supplies the observation asimportlib.util.find_spec("mcp") is not None.find_specis a design preference, not a necessity: the exception's ownnameattribute would also separate the reachable cases, and both discriminators agree on all three. Measured:exc.namefind_spec("mcp") is Nonemcp2.1.1 installed'mcp.server.fastmcp'Falsemcpabsent'mcp'Truemcp1.30.0,pydantic-settingsremoved'pydantic_settings'Falsefind_specis preferred because "is the package there" is the question being asked, and asking it directly does not depend on an error attribute keeping its shape across upstream versions. It is a better way to learn the same thing, not the only way.Exit stays
4in every case. Exit4was already the right outcome — netspec could not run, which says nothing about a design (D10). The reason was the fabricated part.Tests
tests/test_mcp_import_failure.py, deliberately not gated on themcpextra — three of its four tests construct their own exceptions and need nomcp, and a module-level gate would take them with it on a contributor machine without the extra:main(), against the realfind_spec: exit4, upstream's text on stderr, nokicad-netspec[mcp]in it — the one test that reads the environment, and the only one that skips without the extratests/test_mcp.pyis unchanged; its gate is still right for the MCP surface it covers, and still fails loudly in CI.No decision in
docs/DECISIONS.mdmoves. D7's pin, D10's exit4, and D18's tool surface are all as they were.Closes #35.