Fix apm install --global skipping MCP server installation#638
Conversation
There was a problem hiding this comment.
Pull request overview
Fixes global-scope MCP installation so apm install --global installs MCP servers for runtimes that have user/global config paths (instead of blanket-skipping MCP at user scope), and threads scope through install/uninstall MCP cleanup.
Changes:
- Add
supports_user_scopeto MCP client adapters and filter MCP install/cleanup targets based onInstallScope. - Remove the user-scope MCP blanket-disable in
apm installand forwardscopeinto MCP install/remove-stale paths. - Add unit tests plus doc/changelog updates describing the new
--globalMCP behavior.
Reviewed changes
Copilot reviewed 12 out of 13 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/unit/test_global_mcp_scope.py | Adds coverage for adapter scope flags, MCPIntegrator filtering, uninstall cleanup behavior, and install command integration. |
| src/apm_cli/integration/mcp_integrator.py | Adds scope to install() / remove_stale() and filters runtimes at user scope using adapter capability. |
| src/apm_cli/commands/install.py | Removes blanket user-scope MCP skip; forwards scope to MCPIntegrator install/remove_stale. |
| src/apm_cli/commands/uninstall/engine.py | Threads scope through stale MCP cleanup to avoid touching workspace configs in user scope. |
| src/apm_cli/commands/uninstall/cli.py | Passes uninstall scope into _cleanup_stale_mcp(...). |
| src/apm_cli/adapters/client/base.py | Introduces supports_user_scope: bool = False default on MCP adapters. |
| src/apm_cli/adapters/client/copilot.py | Marks Copilot adapter as user-scope-capable (supports_user_scope = True). |
| src/apm_cli/adapters/client/codex.py | Marks Codex adapter as user-scope-capable (supports_user_scope = True). |
| src/apm_cli/adapters/client/cursor.py | Explicitly marks Cursor as workspace-only (supports_user_scope = False). |
| src/apm_cli/adapters/client/opencode.py | Explicitly marks OpenCode as workspace-only (supports_user_scope = False). |
| docs/src/content/docs/guides/dependencies.md | Updates docs to reflect partial user-scope MCP support (global-capable runtimes only). |
| CHANGELOG.md | Adds unreleased “Fixed” entries for global-scope MCP install and --trust-transitive-mcp behavior. |
- Wrap ClientFactory.create_client() in try/except ValueError in both install() and remove_stale() scope filtering so unsupported runtimes are silently skipped instead of crashing - Replace brittle source-text assertion in TestInstallCommandMCPScope with a functional test that calls MCPIntegrator.install() with mocked dependencies and verifies scope filtering end-to-end - Consolidate CHANGELOG into single entry referencing PR microsoft#638 Co-authored-by: Copilot <[email protected]>
Co-authored-by: Copilot <[email protected]>
Remove the blanket should_install_mcp=False gate for InstallScope.USER in install.py. Instead, add scope awareness to MCPClientAdapter via a supports_user_scope class attribute that each adapter declares: - CopilotClientAdapter: True (~/.copilot/mcp-config.json) - CodexClientAdapter: True (~/.codex/config.toml) - VSCodeClientAdapter: False (.vscode/mcp.json) - CursorClientAdapter: False (.cursor/mcp.json) - OpenCodeClientAdapter: False (opencode.json) MCPIntegrator.install() and remove_stale() now accept a scope parameter and filter target_runtimes to only global-capable adapters at USER scope. The uninstall path (_cleanup_stale_mcp) also receives scope so global uninstall only cleans global configs. This also unblocks --trust-transitive-mcp at global scope, which was silently ignored when the blanket MCP gate was active. Fixes microsoft#637 Co-authored-by: Copilot <[email protected]>
- Wrap ClientFactory.create_client() in try/except ValueError in both install() and remove_stale() scope filtering so unsupported runtimes are silently skipped instead of crashing - Replace brittle source-text assertion in TestInstallCommandMCPScope with a functional test that calls MCPIntegrator.install() with mocked dependencies and verifies scope filtering end-to-end - Consolidate CHANGELOG into single entry referencing PR microsoft#638 Co-authored-by: Copilot <[email protected]>
2b9390a to
52627c8
Compare
APM Review Panel — PR #638[>] Verdict: APPROVE-WITH-INLINE-FIXES. Land after a small polish pass; one substantive follow-up issue must be filed before the release that ships this PR. @sergio-sisternes-epam — thank you, this is exactly the kind of silent-footgun fix that earns trust. Four specialists (python-architect, cli-logging-expert, devx-ux-expert, supply-chain-security) converged with no hard blockers; concerns are tight and absorbable. What's excellent
Findings
Merge callLand #1, #2, #3 in this PR (mechanical, ~30 min). Open issues for #4, #5, #6 before merge; reference #4 in the CHANGELOG line so users hitting the lockfile path know it's tracked. Then merge — don't re-queue specialists. Sergio has throughput; we honor that by being decisive on what's same-PR vs follow-up. Suggested CHANGELOG augment:
[+] Ship it. Growth angle
Reviewed via the |
danielmeppiel
left a comment
There was a problem hiding this comment.
Blockers per last comment
- Wrap ClientFactory.create_client() in try/except ValueError in both install() and remove_stale() scope filtering so unsupported runtimes are silently skipped instead of crashing - Replace brittle source-text assertion in TestInstallCommandMCPScope with a functional test that calls MCPIntegrator.install() with mocked dependencies and verifies scope filtering end-to-end - Consolidate CHANGELOG into single entry referencing PR microsoft#638 Co-authored-by: Copilot <[email protected]>
52627c8 to
ab95af3
Compare
The 0.9.0 section had 30 bullets where 9 PRs were over-split: #810 (5 bullets), #514 (5), #700 (2), #778 (3), #638 (2), #808 (paragraph listing every drift fix), plus one orphan ### Changed block holding a single sub-point of the #778 BREAKING entry. Per .github/instructions/changelog.instructions.md: 'One line per PR: concise description ending with (#PR_NUMBER). Combine related PRs into a single line when they form one logical change.' Result: 23 entries, one per PR, terse imperative summaries with the user-facing impact up front. Migration / 'Closes' / 'Previously...' prose moved off the changelog (it belongs in the PR body and CHANGELOG-linked docs). Section is now scannable as headlines instead of essays. No code changes; v0.9.0 tag already published on prior commit. Co-authored-by: Copilot <[email protected]>
Description
Add scope awareness to MCP server installation so that
apm install --globalwrites MCP server entries to global/user-scoped runtime config paths (e.g.~/.copilot/mcp-config.jsonfor Copilot CLI) instead of unconditionally skipping all MCP installation at user scope.Fixes #637
Type of change
Testing