[BUG] Claude MCP entry keeps the old url/headers when a server's transport changes from http to stdio
Nobody has claimed this yet.
- 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 aurlis 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 keystype(local),urlandheadersfrom the old HTTP definition, andcommand,argsandenvfrom 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.
- Install, with
-g -t claude, a package whoseapm.ymldeclares{name: example, registry: false, transport: http, url: "http://127.0.0.1:4521/mcp", headers: {Authorization: "Bearer ${TOKEN}"}}. - Replace that declaration with
{name: example, registry: false, transport: stdio, command: npx, args: ["-y", "example-mcp"]}and install again. ~/.claude.json→mcpServers.examplecarriesurlandheadersalongsidecommandandargs.
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), targetclaude
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- 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