Skip to content

ACP mode loads global ~/.factory/mcp.json servers and blocks initialize on them #1228

@amitach

Description

@amitach

Environment: droid CLI run as an ACP agent via droid exec --output-format acp (also --output-format acp-daemon), macOS, embedded by an ACP client/host.

Summary: When Droid runs as an ACP agent, it loads the user's global MCP servers from ~/.factory/mcp.json in addition to the mcpServers the ACP client supplies in session/new, and it blocks ACP initialize/session startup until every global server connects. If a global server is slow or requires interactive authorization, init hangs until the user responds, stalling the client's turn. With N such servers the delay compounds (serial, blocking).

Concrete example (Xcode's MCP server): With Xcode's MCP server added to Droid (droid mcp listxcode stdio enabled [user]; ~/.factory/mcp.json has "xcode": { "command": "xcrun", … }), starting Droid over ACP makes Xcode pop its own dialog — "Allow 'Factory CLI' to access Xcode? The agent wants to use Xcode's tools to perform actions like building, testing, or modifying code." — and Droid's initialize blocks until the user clicks Allow. Slow to allow → the ACP client's readiness probe times out and reports the agent as not connected; allow quickly → the session proceeds. The Xcode server is irrelevant to the client's request, yet it gates startup.

Expected: In an ACP session the client is the authority on MCP servers (via session/new.mcpServers). Droid should (1) not pull global mcp.json servers into a client-driven ACP session, or make it opt-in; and (2) not block initialize on MCP connections — connect lazily/in the background, tolerant of failures.

Repro:

  1. Add Xcode's MCP server to Droid (xcrun-launched stdio; any slow/prompt-on-connect server works).
  2. With Xcode running, droid exec --output-format acp from any ACP client.
  3. Xcode pops "Allow 'Factory CLI' to access Xcode?" and initialize hangs until allowed.

Contrast: @agentclientprotocol/claude-agent-acp and @zed-industries/codex-acp use only client-provided mcpServers and don't block init on global servers — Droid is the outlier (same global config present for all three; only Droid hangs/prompts).

Notes from the binary: --output-format acprunAcpChild (single session); acp-daemonrunAcpDaemon, which forks its own acp children. Settings/MCP merge is additive, so --settings/FACTORY_RUNTIME_SETTINGS_PATH can add but not remove global servers. Config dir is homedir()/.factory with no override, so a host can't isolate config without hijacking HOME (breaks auth).

Requests: don't load global mcp.json into client ACP sessions (or make it opt-in) and never block initialize on MCP connections; a --no-mcp flag for droid exec; a FACTORY_HOME/config-dir override.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions