microsoft / microsoft/apm

[BUG] Claude MCP entry keeps the old url/headers when a server's transport changes from http to stdio

Open
#2,994 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

area/mcp-config status/accepted theme/security triage/recommended type/bug
Dominant language
Python
Stars
3.8k
Forks
362
Avg merge
1d 17h
Merged PRs (30d)
132

Description

Describe the bug

When a self-defined MCP server that apm previously wrote to ~/.claude.json as an HTTP server (url, headers) is declared again under the same name as a stdio server (command, args, env), the install merges the new definition into the existing entry instead of replacing it. The resulting entry describes both transports at once.

Where, in the 0.30.0 source

  • adapters/client/claude.py, _merge_mcp_server_dicts: each server entry is shallow-merged, {**old, **new}, so every key only the old entry had survives. The docstring gives the reason (keep hand-authored keys such as OAuth blocks), but transport-specific keys survive with them.
  • adapters/client/claude.py, _normalize_mcp_entry_for_claude_code: an entry that still has a url is classified as remote and returned as is, so the stdio normalisation never applies to the merged entry.
  • Observed on a user-scope install after such a change: mcpServers.<name> held the keys type (local), url and headers from the old HTTP definition, and command, args and env from the new stdio one.

To Reproduce

The resulting entry was observed; these steps are derived from the source and were not run as a standalone script.

  1. Install, with -g -t claude, a package whose apm.yml declares {name: example, registry: false, transport: http, url: "http://127.0.0.1:4521/mcp", headers: {Authorization: "Bearer ${TOKEN}"}}.
  2. Replace that declaration with {name: example, registry: false, transport: stdio, command: npx, args: ["-y", "example-mcp"]} and install again.
  3. ~/.claude.jsonmcpServers.example carries url and headers alongside command and args.

Expected behavior

When a server's declared transport changes, the keys specific to the previous transport (url, headers for a remote server; command, args, env, cwd for stdio) are dropped, so the entry describes exactly one transport. Keys apm never manages can still be preserved.

Environment

  • OS: macOS, Apple Silicon
  • APM: Homebrew binary, Agent Package Manager (APM) CLI version 0.30.0
  • Scope: user (-g), target claude

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in adapters/client/claude.py by reading _merge_mcp_server_dicts and _normalize_mcp_entry_for_claude_code, then trace how an existing mcpServers entry is updated. Verify the HTTP-to-stdio reproduction and ensure transport-specific keys from the previous declaration are removed while unmanaged keys remain preserved.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
cli
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
76/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.