Skip to content

ACP mode: host-supplied mcpServers in session/new replace (rather than merge with) settings.json/.mcp.json servers #171

Description

@julianmesa-gitkraken

Summary

When auggie --acp is driven by a host that supplies a non-empty mcpServers array in the session/new (or session/load/fork) request, Auggie completely replaces the MCP servers configured in ~/.augment/settings.json / project .mcp.json with only the servers the host sent, instead of merging the two lists. Any MCP server the user has configured locally (and that the host doesn't know about) silently disappears for the ACP session, with no warning to the user.

Environment

  • auggie installed via npm (@augmentcode/auggie), latest version at time of writing
  • Host: a custom ACP client/editor integration that spawns auggie --acp and always sends at least one MCP server (its own workspace-context server) in session/new
  • OS: macOS

Steps to reproduce

  1. Configure an MCP server in ~/.augment/settings.json (or a project .mcp.json), e.g. a Playwright-Electron server named playwright-electron.
  2. Run auggie interactively and check /mcp — the server is listed and available, confirming the config itself is valid.
  3. Run auggie --acp under a host that sends a non-empty mcpServers array in session/new (e.g. a single workspace-context server).
  4. Inspect the tools available in the resulting session, or the child processes of the auggie --acp process.

Expected behavior

The MCP servers the host supplies via session/new.mcpServers are added to the servers defined in the user's ~/.augment/settings.json / .mcp.json, the same way auggie's own CLI merges --mcp-config with settings-defined servers. A user-configured server should still be available in an ACP session unless it conflicts (e.g. same name) with a host-supplied one.

Actual behavior

  • The auggie --acp process never spawns the locally-configured MCP server (confirmed via process tree: no child process for the server's launch command exists under the auggie --acp PID, only the host-supplied server(s)).
  • Only the tools from the host-supplied mcpServers array are exposed to the session.

Root cause (from reading the installed augment.mjs bundle)

Two functions are involved:

  1. createSession(e, n, r, i) — the ACP session/new handler. e.mcpServers is what the host sent. If it is non-empty, it is turned into tools.mcpConfig for the session config; only when the host sends an empty array does it fall back to this.rootConfig.tools.mcpConfig (the config resolved from the CLI's own --mcp-config/settings at process startup):

    async createSession(e,n,r,i){
      let o=e.mcpServers||[];
      ...
      tools:{...this.rootConfig.tools,
        mcpConfig: s.length>0 ? s.map(l=>JSON.stringify(l)) : this.rootConfig.tools.mcpConfig}
  2. v3e(t, e, n, r, i, o) — builds the final list of MCP servers for the session. t is settings.json's mcpServers; e is the mcpConfig computed above (i.e. whatever the host sent, once non-empty). When e is non-empty, t (settings.json) is ignored entirely — there is no merge step:

    function v3e(t,e,n,r,i,o){
      ...
      if(!e || e.length===0){
        // e empty -> read from settings.json (t)
        ...
      }
      // e non-empty -> t is never consulted; only e is used
      c = await Uzn(e);
      ...
    }

    It is called at session-creation time as:

    let{mcpServers:xe,warns:Ce} = await v3e(i.mcpServers, this.config.tools.mcpConfig, ...)

    i.mcpServers is the settings.json value; this.config.tools.mcpConfig is exactly the array createSession just populated from the host's session/new.mcpServers. Because it's an "or" (host servers replace settings) rather than a merge, any host that sends even one MCP server (which is the common case for an ACP host that provides its own workspace-context tools) causes every user-configured server to be dropped for that session.

Suggested fix

Merge the two lists in v3e (keyed by server name, host-supplied entries winning on conflict) instead of treating a non-empty host list as fully authoritative. This would match the behavior of Claude Code and Codex CLI, which both continue to load a project's .mcp.json in ACP mode in addition to whatever the host supplies via session/new.

Happy to provide more logs/evidence if useful.

Activity

  1. julianmesa-gitkraken commented on Sep 17, 2026

    @julianmesa-gitkraken
    Author

    Follow-up from integrating Auggie 0.36.0 in GitKraken Kepler.

    The issue correctly identifies the ACP replacement bug, but one security boundary needs to be called out explicitly: automatically merging checkout-controlled MCP settings is not safe when those settings can launch stdio processes.

    Observed with the 0.36.0 bundle (SHA-256 6229e1685a5c4f9305ad333d76cd1a05c4315e6a9c8af3bbc75170b524005306):

    • A non-empty host mcpServers list caused configured user MCPs such as Sentry to disappear.
    • The settings map available at the ACP call site was already provenance-blind and could include local/project declarations from the checkout.
    • A local/project stdio declaration can execute arbitrary checkout-controlled commands with the user filesystem and network permissions; the reduced child environment is not a trust boundary.

    The safe merge semantics we need are:

    1. Include host-supplied MCP servers, with host entries winning name conflicts.
    2. Read the user and managed settings levels separately, with managed taking precedence over user.
    3. Do not automatically read local or project settings into an ACP session. Loading those levels needs an explicit trust decision for the checkout.
    4. Preserve provenance through the merge; merging an already-combined settings map is not sufficient because it cannot distinguish trusted global configuration from repository-controlled configuration.

    Kepler has a compatibility patch implementing these semantics while this is unresolved. The follow-up is tracked in https://github.com/gitkraken/kepler/pull/2772. Its regression test confirms that trusted user/managed MCPs are available, while local/project commands are excluded, and that the Kepler-owned Playwright server is supplied separately through a validated absolute launcher path.

    This means the original suggested fix should be narrowed from “merge settings.json and project .mcp.json” to “merge host plus trusted user/managed settings, and require explicit trust before loading checkout-controlled settings.”

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions