Skip to content

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

Description

@ahegyes

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.json → mcpServers.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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/mcp-configMCP server configuration depth, transports, variable resolution.status/acceptedHuman scope approval; verify the issue's approval record and review contact before work.theme/securitySecure by default. Content scanning, lockfile integrity, MCP trust boundaries.triage/recommendedAutomated advice completed; not human scope approval.type/bugSomething does not work as documented.

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions