Plugin MCP Server installation support#217
Merged
danielmeppiel merged 8 commits intomainfrom Mar 9, 2026
Merged
Conversation
Co-authored-by: danielmeppiel <[email protected]>
- Add _extract_mcp_servers() to extract MCP configs from plugin manifests (supports string/array/dict mcpServers, .mcp.json and .github/.mcp.json fallback) - Add _mcp_servers_to_apm_deps() to convert MCP configs to MCPDependency format - Wire extraction into synthesize_apm_yml_from_plugin() and _generate_apm_yml() - Modify collect_transitive() to auto-trust self-defined MCPs from direct deps (depth=1) - Add comprehensive tests for extraction, conversion, and trust model - Update e2e trust gating tests to reflect new direct-dep trust behavior Co-authored-by: danielmeppiel <[email protected]>
Co-authored-by: danielmeppiel <[email protected]>
- Remove unused `re` import from plugin_parser.py - Update docs/plugins.md with MCP server definitions section - Update docs/dependencies.md with direct-dep trust model Co-authored-by: danielmeppiel <[email protected]>
Copilot
AI
changed the title
[WIP] Add support for MCP server installation through APM pipeline
Plugin MCP Server installation support
Mar 9, 2026
Contributor
There was a problem hiding this comment.
Pull request overview
This PR adds MCP server installation support for plugins. It enables plugins to ship MCP server definitions (via mcpServers in plugin.json or .mcp.json files), which are extracted, converted to MCPDependency format, and emitted into the synthesized apm.yml for deployment through the existing MCP pipeline. It also refines the trust model so self-defined MCP servers from direct dependencies (depth=1) are auto-trusted without needing --trust-transitive-mcp.
Changes:
plugin_parser.py: Adds_extract_mcp_servers(),_read_mcp_file(),_read_mcp_json(),_substitute_plugin_root(), and_mcp_servers_to_apm_deps()to extract and convert plugin MCP server definitions, and wires them intosynthesize_apm_yml_from_plugin()and_generate_apm_yml().mcp_integrator.py: Updatescollect_transitive()to build adirect_pathsset from lockfile depth=1 entries, auto-trusting self-defined MCPs from direct dependencies while keeping transitive deps gated behindtrust_private=True.- Docs & tests: Updates
docs/plugins.mdanddocs/dependencies.mdwith trust model documentation, and adds 32 new unit/e2e tests.
Reviewed changes
Copilot reviewed 7 out of 8 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
src/apm_cli/deps/plugin_parser.py |
Core extraction logic for MCP servers from plugin manifests and .mcp.json files |
src/apm_cli/integration/mcp_integrator.py |
Trust model: auto-trust self-defined MCPs from direct deps (depth=1) |
docs/plugins.md |
New documentation section for MCP server definitions in plugins |
docs/dependencies.md |
Updated transitive trust rule to reflect direct dep auto-trust |
tests/unit/test_plugin_parser.py |
27 new tests for extraction, conversion, and integration |
tests/unit/test_transitive_mcp.py |
4 new tests for trust model changes |
tests/unit/test_mcp_lifecycle_e2e.py |
Updated and new e2e tests for self-defined MCP trust gating |
uv.lock |
Version bump from 0.7.4 to 0.7.5 |
Self-defined MCP servers (declared inline in plugin.json) had their
args mangled by runtime-specific formatting logic. The npm code path
prepended the server name as a fake package, and copilot's argument
parser couldn't handle the {is_required, value_hint} format.
Add _raw_stdio field to synthetic server info in _build_self_defined_info()
and handle it with an early return in all three adapters (vscode, copilot,
codex) to bypass registry-specific formatting.
On repeated 'apm install', sub-skills from the same package triggered spurious overwrite warnings because their previous deployment still existed at the target path. Use the lockfile's deployed_files to build a skill_name → owner map. Only warn when a different package would overwrite an existing skill.
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.
Description
Plugins shipping MCP servers (via
mcpServersin plugin.json or.mcp.json) now have those servers extracted, converted toMCPDependencyformat, and emitted into the synthesizedapm.ymlfor deployment through the existing MCP pipeline.Trust model: direct dependencies (depth=1) auto-trust self-defined MCPs; transitive deps still require
--trust-transitive-mcp.Extraction (
plugin_parser.py)_extract_mcp_servers()— resolvesmcpServersasdict(inline),str(file ref), orlist(multi-file, last-wins). Falls back to.mcp.json→.github/.mcp.jsonauto-discovery. Skips symlinks, validates path containment, substitutes${CLAUDE_PLUGIN_ROOT}._mcp_servers_to_apm_deps()— infersstdiofromcommand,http/sse/streamable-httpfromurl+type. All entries getregistry: false.synthesize_apm_yml_from_plugin()and_generate_apm_yml()wired to emitdependencies.mcpwhen plugin MCPs are present.Trust model (
mcp_integrator.py)collect_transitive()buildsdirect_pathsset from lockfile depth=1 entries. Self-defined MCPs from direct deps are auto-trusted; transitive deps (depth>1) still gated behindtrust_private.Type of change
Testing
27 new tests for extraction/conversion (
TestExtractMCPServers,TestMCPServersToDeps,TestGenerateApmYmlMCPDeps,TestSynthesizeMCPIntegration), 4 new trust model tests, 1 updated e2e test. Full suite: 1383 passing.💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.