goose icon indicating copy to clipboard operation
goose copied to clipboard

fix: feat(acp): Honor MCP servers passed from ACP clients

Open github-actions[bot] opened this issue 1 week ago • 2 comments

Closes #6111

Summary

Changes made for #6111 (feat/acp: Honor MCP servers passed from ACP clients)

Implementation

  • Updated crates/goose-cli/src/commands/acp.rs
    • Imports
      • Now import Envs, ExtensionConfig, ExtensionEntry, and set_extension to construct MCP extensions from ACP input:
        • use goose::agents::extension::Envs;
        • use goose::agents::{Agent, ExtensionConfig, SessionConfig};
        • use goose::config::{get_all_extensions, set_extension, Config, ExtensionEntry};
    • new_session implementation
      • Before creating the Goose session, iterate over args.mcp_servers:
        • For each acp::McpServer::Stdio { name, command, args, env }:
          • Convert env (Vec of name/value pairs from ACP) into HashMap<String, String>.
          • Construct an ExtensionEntry with:
            • enabled: true
            • config: ExtensionConfig::Stdio { name, description: String::new(), cmd: command.display().to_string(), args, envs: Envs::new(envs), env_keys: Vec::new(), timeout: None, bundled: None, available_tools: Vec::new(), }
          • Call set_extension(entry) to persist/update the MCP extension configuration.
      • Non-stdio MCP server variants are ignored (no-op), keeping behavior minimal and aligned with the requirement to support stdio MCP servers.
      • Session creation remains the same except for removal of the prior inline comment about maybe_update_name.

Behavior

  • ACP-provided stdio MCP servers from NewSessionRequest.mcp_servers are now merged into Goose's configured extensions:
    • They are stored via set_extension, using ExtensionConfig::key()/name_to_key, so name conflicts are resolved by last-writer-wins.
    • This matches the requested “union with ACP wins on conflict” behavior: an ACP-provided server with the same logical name will override an existing configuration entry.
  • Existing configured extensions remain unchanged and are still loaded in GooseAcpAgent::new via get_all_extensions.
  • MCP capabilities advertised in initialize remain unchanged:
    • http: false, sse: false.
  • Only stdio transport from ACP is honored; other transports are skipped.

Verification

  • source bin/activate-hermit
  • cargo check
    • Succeeded.
  • cargo test -p goose-cli
    • Fails due to missing system dependency libxcb when linking test binaries; this is an environment limitation, not a code issue.
  • cargo fmt
    • Run and completed.
  • ./scripts/clippy-lint.sh
    • Run via redirected log; no code changes required after linting.

Notable considerations / potential issues

  • Environment variables from ACP mcp_servers.env are passed through Envs::new, which filters out disallowed/sensitive keys as defined in Envs; this may silently drop some ACP-provided env vars (by design for security).
  • set_extension mutates the global extensions configuration:
    • ACP-provided MCP servers will persist for subsequent runs that reuse the same configuration store, consistent with other extension configuration flows.
    • If a client repeatedly sends different command/arg/env combinations for the same server name, later sessions will overwrite earlier ones.
  • Non-stdio transports in mcp_servers are ignored rather than rejected:
    • This is intentional to provide graceful degradation while still meeting the “MUST support stdio MCP servers” requirement.

Generated by goose Issue Solver

github-actions[bot] avatar Dec 14 '25 18:12 github-actions[bot]

Ps the sketch i had in the linked issue was based on the current sdk not the old 0.4. I would recommend work after this to avoid drift https://github.com/block/goose/pull/6109

codefromthecrypt avatar Dec 15 '25 02:12 codefromthecrypt

/goose my sketch in #6111 was imprecise as it subtly affects global state. The goal for ACP is to be like --with-extension which scopes an MCP server addition, not persisting it forever. You should verify something like self.agent.add_extension(config).await.map_err is the correct way to accomplish this goal, and change your code accordingly, and in the same style as other code in this file.

codefromthecrypt avatar Dec 16 '25 01:12 codefromthecrypt

This is not a great PR. Going to close it.

tlongwell-block avatar Dec 17 '25 00:12 tlongwell-block