-
Notifications
You must be signed in to change notification settings - Fork 233
MCP model silently drops harness-specific keys (e.g. Claude Code oauth) — no passthrough for remote-MCP OAuth client config #1670
Copy link
Copy link
Open
Labels
area/docs-sitedocs/src/content (Starlight), README, doc generation.docs/src/content (Starlight), README, doc generation.area/mcp-configMCP server configuration depth, transports, variable resolution.MCP server configuration depth, transports, variable resolution.priority/highShips in current or next milestoneShips in current or next milestonestatus/acceptedDirection approved, safe to start work.Direction approved, safe to start work.status/shepherdingActively being driven by an APM shepherd runActively being driven by an APM shepherd runstatus/triagedInitial agentic triage complete; pending maintainer ratification (silence = approval).Initial agentic triage complete; pending maintainer ratification (silence = approval).theme/securitySecure by default. Content scanning, lockfile integrity, MCP trust boundaries.Secure by default. Content scanning, lockfile integrity, MCP trust boundaries.type/featureNew capability, new flag, new primitive.New capability, new flag, new primitive.
Metadata
Metadata
Assignees
Labels
area/docs-sitedocs/src/content (Starlight), README, doc generation.docs/src/content (Starlight), README, doc generation.area/mcp-configMCP server configuration depth, transports, variable resolution.MCP server configuration depth, transports, variable resolution.priority/highShips in current or next milestoneShips in current or next milestonestatus/acceptedDirection approved, safe to start work.Direction approved, safe to start work.status/shepherdingActively being driven by an APM shepherd runActively being driven by an APM shepherd runstatus/triagedInitial agentic triage complete; pending maintainer ratification (silence = approval).Initial agentic triage complete; pending maintainer ratification (silence = approval).theme/securitySecure by default. Content scanning, lockfile integrity, MCP trust boundaries.Secure by default. Content scanning, lockfile integrity, MCP trust boundaries.type/featureNew capability, new flag, new primitive.New capability, new flag, new primitive.
Type
Fields
Give feedbackNo fields configured for issues without a type.
Projects
StatusShow more project fields
Todo
Summary
apm's MCP dependency model carries only a fixed field set and silently discards any other keys on render. There is no way to express harness-specific MCP config that apm doesn't model, notably Claude Code's remote-MCP
oauthblock (clientId/callbackPort). For a remote MCP server that requires a pre-registered OAuth client because it does not support Dynamic Client Registration (RFC 7591), this makes the server unusable when configured through apm.Environment
.mcp.json).What happens
MCPDependency(src/apm_cli/models/dependency/mcp.py) models only:name, transport, env, args, version, registry, package, headers, tools, url, command.from_dict: "Unknown keys are silently ignored for forward compatibility."to_dict: serializes only that whitelist.So this
apm.yml:produces a generated
.mcp.jsonslack entry with nooauthkey. No warning is emitted;apm installreports success.Why it matters (concrete failure)
Claude Code's
.mcp.jsonsupports anoauthblock to pin a pre-registered OAuth client. Slack's remote MCP (https://mcp.slack.com/mcp) does not support Dynamic Client Registration, so without a pre-registeredclientIdClaude Code's OAuth fails with:Because apm cannot carry the
oauthblock, a Slack MCP configured via apm cannot authenticate. The same applies to any remote MCP needing harness-specific auth config apm doesn't model.Two distinct problems
claude:/extra:map) to round-trip fields verbatim into the target manifest.Note:
apm packalready strips credential-shaped keys from the Claude.mcp.jsonmanifest, which suggests apm knows.mcp.jsoncarries richer config than the model represents. It currently treats the surplus as something to drop, never to preserve.Proposed fixes
oauthfield, or a genericextra/claudeblock).from_dictdiscards unknown keys instead of dropping them silently.Workaround
Re-inject the field into the generated
.mcp.jsonafterapm installvia a post-install hook, since apm regenerates the file fromapm.ymlon every run.