-
Notifications
You must be signed in to change notification settings - Fork 385
[BUG] Claude MCP entry keeps the old url/headers when a server's transport changes from http to stdio #2994
Copy link
Copy link
Closed
Labels
area/mcp-configMCP server configuration depth, transports, variable resolution.MCP server configuration depth, transports, variable resolution.status/acceptedHuman scope approval; verify the issue's approval record and review contact before work.Human scope approval; verify the issue's approval record and review contact before work.theme/securitySecure by default. Content scanning, lockfile integrity, MCP trust boundaries.Secure by default. Content scanning, lockfile integrity, MCP trust boundaries.triage/recommendedAutomated advice completed; not human scope approval.Automated advice completed; not human scope approval.type/bugSomething does not work as documented.Something does not work as documented.
Description
Activity
Metadata
Metadata
Assignees
Labels
area/mcp-configMCP server configuration depth, transports, variable resolution.MCP server configuration depth, transports, variable resolution.status/acceptedHuman scope approval; verify the issue's approval record and review contact before work.Human scope approval; verify the issue's approval record and review contact before work.theme/securitySecure by default. Content scanning, lockfile integrity, MCP trust boundaries.Secure by default. Content scanning, lockfile integrity, MCP trust boundaries.triage/recommendedAutomated advice completed; not human scope approval.Automated advice completed; not human scope approval.type/bugSomething does not work as documented.Something does not work as documented.
Type
Projects
- StatusShow more project fieldsNo status
Describe the bug
When a self-defined MCP server that apm previously wrote to
~/.claude.jsonas 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.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.
-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}"}}.{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,headersfor a remote server;command,args,env,cwdfor stdio) are dropped, so the entry describes exactly one transport. Keys apm never manages can still be preserved.Environment
Agent Package Manager (APM) CLI version 0.30.0-g), targetclaude