Summary
Surfaced during PR #810 panel review (rubber-duck pass on a proposed README simplification). Two related items, scoped together because the security fix is a precondition for safely changing default selection.
Item 1: Smart per-runtime sourcing for dual-mode entries
When a registry entry advertises both packages (e.g. docker stdio) and remotes (HTTPS), adapter selection is currently non-deterministic across clients:
- Copilot (
src/apm_cli/adapters/client/copilot.py:186-236): prefers remotes first.
- VS Code (
src/apm_cli/adapters/client/vscode.py:227-345): prefers packages first.
- Codex (
src/apm_cli/adapters/client/codex.py:122-131): falls through to packages if both exist; only skips when remotes and not packages.
This forces the README to use transport: http as a deterministic-selection workaround, which in turn introduced the UX confusion that PR #810 patched with inline disambiguators (# MCP transport name, not URL scheme -- connects over HTTPS).
Naive fix ("strip packages when both exist + no overlay"): blocked because (a) Codex would skip with 'remote not supported' on previously-working installs, (b) VS Code would silently flip from stdio to remote.
Proper fix needs per-runtime sourcing rules -- a small policy table per adapter declaring its preference order and whether it supports remote/stdio at all. The smart-default then becomes 'pick the first variant the runtime supports' rather than a global mutation.
Acceptance criteria
Item 2: _is_github_server host validation
src/apm_cli/adapters/client/copilot.py:675-717 returns True (and triggers GitHub token injection at copilot.py:201-212) on either name match OR hostname match. A poisoned/custom registry entry named github-mcp-server pointing at https://evil.example.com/mcp/ would receive a GitHub token at the non-GitHub host.
This is latent today (only known registry entries with that name are GitHub's own) but tightly coupled to Item 1: if the smart-default expands the remote-path footprint, this risk grows.
Acceptance criteria
Why these are bundled
- (1) without (2) is a security regression amplification.
- (2) without (1) is fine to ship standalone if (1) takes longer.
Related
Summary
Surfaced during PR #810 panel review (rubber-duck pass on a proposed README simplification). Two related items, scoped together because the security fix is a precondition for safely changing default selection.
Item 1: Smart per-runtime sourcing for dual-mode entries
When a registry entry advertises both
packages(e.g. docker stdio) andremotes(HTTPS), adapter selection is currently non-deterministic across clients:src/apm_cli/adapters/client/copilot.py:186-236): prefersremotesfirst.src/apm_cli/adapters/client/vscode.py:227-345): preferspackagesfirst.src/apm_cli/adapters/client/codex.py:122-131): falls through topackagesif both exist; only skips whenremotes and not packages.This forces the README to use
transport: httpas a deterministic-selection workaround, which in turn introduced the UX confusion that PR #810 patched with inline disambiguators (# MCP transport name, not URL scheme -- connects over HTTPS).Naive fix ("strip packages when both exist + no overlay"): blocked because (a) Codex would skip with 'remote not supported' on previously-working installs, (b) VS Code would silently flip from stdio to remote.
Proper fix needs per-runtime sourcing rules -- a small policy table per adapter declaring its preference order and whether it supports remote/stdio at all. The smart-default then becomes 'pick the first variant the runtime supports' rather than a global mutation.
Acceptance criteria
transport: httpoverlay -- bareio.github.github/github-mcp-serverworks deterministically across all runtimes (Copilot uses remote, VS Code uses docker, Codex uses docker, etc).### Changed.Item 2:
_is_github_serverhost validationsrc/apm_cli/adapters/client/copilot.py:675-717returns True (and triggers GitHub token injection atcopilot.py:201-212) on either name match OR hostname match. A poisoned/custom registry entry namedgithub-mcp-serverpointing athttps://evil.example.com/mcp/would receive a GitHub token at the non-GitHub host.This is latent today (only known registry entries with that name are GitHub's own) but tightly coupled to Item 1: if the smart-default expands the remote-path footprint, this risk grows.
Acceptance criteria
_is_github_serverrequires BOTH name match ANDis_github_hostname(parsed_url.hostname)returning True before injecting a GitHub token. Name match alone is no longer sufficient.github-mcp-serveratapi.githubcopilot.com) still gets the token.docs/.../mcp-servers.mdSecurity section.Why these are bundled
Related
transport: http+ inline disambiguators).apm mcp search/list/showignoreMCP_REGISTRY_URLenv var #813, security: validate MCP_REGISTRY_URL and reject http:// overrides at SimpleRegistryClient #814 already handled in PR feat(install): add --mcp flag for declaratively adding MCP servers to apm.yml #810.