agent-mcp-manager-v0.0.2
Pre-releaseCloses two production bug reports surfaced while installing remote MCP servers (BrowserOS) across coding agents. Both are rooted in the same gap: upstream docker/mcp-gateway writes one stdio entry per client by Go-type, so it never modelled per-agent transport capability. This library had generalised to "write any transport per caller spec" without adding the per-agent gate, which let it produce shapes some agents reject.
What changes by agent
| Agent | What changes |
|---|---|
claude-desktop |
link() with an http/sse spec now throws UnsupportedTransportError at the API boundary instead of writing a {url, headers} block Claude Desktop will silently skip on next launch with "not a valid MCP server configuration." stdio specs unchanged. |
codex |
Same typed enforcement, for parity. Codex was already stdio-only via the TOML emitter; the rejection is now a typed error you can catch in a fan-out loop. |
claude-code system (~/.claude.json) |
Unchanged. Still accepts stdio, sse, and http with no type tag. |
claude-code project (.mcp.json) |
Now stdio-only AND injects type: "stdio", matching upstream Docker's set: .mcpServers[$NAME] = $JSON+{"type":"stdio"}. Newer Claude Code releases require this tag; the library was silently producing entries those releases would skip. |
vscode |
Was hardcoding type: "stdio" on every entry (wrong for http/sse). Now writes type: matching spec.transport. Stdio callers see no change. |
cursor, gemini, zed |
Unchanged. |
What changes library-wide
UnsupportedTransportError(new typed error). Includesagent,transport,details.supported, and anmcp-remoteshim hint. Exported from the package root.McpTransport(new public type, just'stdio' | 'sse' | 'http').link({ allowOverwrite: true })(new opt-in). Bypasses the foreign-entry guard, takes ownership of an existing on-disk entry, and records it in the manifest. Defaultfalse. Does NOT bypass the transport-capability check.getCatalogEntryandresolveAgentSurfacenewly exported. UseresolveAgentSurface(id, scope).supportedTransportsto pre-filter agents by transport capability before linking; it honours scope-specific overrides (Claude Code project scope is stdio-only, system is not).
Recovering from ForeignEntryError
If link() throws Cannot replace a user-edited entry. Please remove <name> from this agent's config manually and try again, it means the on-disk config already has an entry under that name the workspace manifest did not write. Two options:
// Take ownership and rewrite with your spec:
await mgr.link({
serverName: 'BrowserOS',
agent: 'claude-code',
allowOverwrite: true,
})
// Or remove manually and retry without the flag.Registering a remote MCP server in a stdio-only agent
claude-desktop, codex, and claude-code project scope only accept stdio entries. Wrap the URL with mcp-remote:
await mgr.add({
name: 'browseros',
spec: {
transport: 'stdio',
command: 'npx',
args: [
'-y',
'mcp-remote',
'https://browseros.example.com/mcp',
'--header',
`Authorization: Bearer ${process.env.BROWSEROS_TOKEN}`,
],
},
})
for (const a of (await detectInstalledAgents()).filter((a) => a.installed)) {
await mgr.link({ serverName: 'browseros', agent: a.id })
}The library does not auto-shim through mcp-remote in this release. Auto-shim is on the v0.2 roadmap so the manifest stays a faithful record of intent.
Pre-filter pattern (scope-aware)
import { resolveAgentSurface, type AgentScope, type McpTransport } from 'agent-mcp-manager'
const scope: AgentScope = 'system'
const supports = (id, t: McpTransport) =>
resolveAgentSurface(id, scope).supportedTransports.includes(t)
for (const a of (await detectInstalledAgents()).filter((a) => a.installed)) {
if (!supports(a.id, 'http')) continue
await mgr.link({ serverName: 'github', agent: a.id })
}Upstream Docker conformance
Now matches the per-agent on-disk shape upstream docker/mcp-gateway writes for every agent in our catalog. Three known deltas remain by design or are deferred:
- VS Code: we write three transports; upstream writes one. Intentional (VS Code accepts all three when tagged correctly).
- Zed spread order (defaults vs caller-supplied): deferred to v0.2.
- Missing agents (Cline, Continue.dev, Goose, LM Studio, OpenCode, Sema4, Crush, Kiro): planned for v0.2.
Out of scope for 0.0.2 (planned)
- Auto-shim http/sse via
mcp-remotefor stdio-only agents. - Case-insensitive name matching (manifest schema change).
adopt()primitive that preserves the on-disk shape verbatim instead of rewriting.