Skip to main content

write_mcp_json_respecting_user_servers

Function write_mcp_json_respecting_user_servers 

Source
pub fn write_mcp_json_respecting_user_servers(
    base_path: &Path,
    generated_content: &str,
) -> Result<()>
Expand description

Write .mcp.json into base_path without destroying a user’s own MCP server entries (issue #3680). Shared by agent.open and the WriteAgentConfig “click Launch” path — the two config-materializing call sites this module keeps in sync.

An agent’s working_directory may be the user’s own project, where a .mcp.json often already exists (and is often committed). A plain fs::write replaced it, dropping every server entry the agent definition didn’t duplicate. Instead:

  • Merge. Every existing mcpServers entry is kept, except the ones a previous materialization wrote (per MANAGED_MCP_SERVERS_MANIFEST), which are replaced by this launch’s set — so a server unbound in Connectors still disappears. Other top-level keys in the existing file are kept too. On a name clash this launch’s entry wins (the agentmux entry must always be ours).
  • No manifest yet (first launch after this change, or a user’s file): a file that already has an agentmux entry was written by AgentMux, so all its entries are treated as managed — the old regenerate-every-launch behavior, once. A file without one is the user’s; all of it is kept.
  • Unreadable or not a JSON object → left untouched and logged, never overwritten — the same “never overwrite a stranger’s file” rule write_claude_md_respecting_ownership follows. Claude Code couldn’t parse such a file either.
  • Owner-only. The file carries the agent’s jekt signing material (inject_jekt_signing_keys_into_mcp_json), so it is written 0600 on Unix, via a temp file renamed into place so it is never briefly visible with the default mode.
  • One launch at a time per directory. .mcp.json and its manifest must describe the same launch, or a server AgentMux wrote gets mistaken for the user’s and is never removed. Neither call site serializes by directory (agent_open’s lock is per agent; WriteAgentConfig has none), so the whole read-merge-write holds an exclusive lock on MCP_JSON_WRITE_LOCK. A file lock rather than an in-process mutex, so two AgentMux instances pointed at one project are serialized too; it is released when the handle drops, including on error or panic.

Not addressed here: the signing material being in this file at all (the identity plan’s M4d/M5 move it out — see SPEC_AGENT_IDENTITY_CARRIED_NOT_DERIVED_2026_09_23.md §6.5), and a user’s project not git-ignoring .mcp.json.