Skip to content

feat(coding-agent): support ACP MCP programs - #1378

Merged
sethkarten merged 10 commits into
mainfrom
codex/acp-mcp-programs
Aug 20, 2026
Merged

feat(coding-agent): support ACP MCP programs#1378
sethkarten merged 10 commits into
mainfrom
codex/acp-mcp-programs

Conversation

@hallerite

@hallerite hallerite commented Aug 13, 2026

Copy link
Copy Markdown
Member

Summary

  • accept HTTP and stdio MCP servers supplied through ACP session/new
  • expose them through the existing pre-imported mcp.list_tools and mcp.call_tool Python program API
  • keep ACP transport configuration and credentials scoped to the live ACP session
  • replace and clear ACP MCP configuration across in-process and daemon-backed sessions
  • capability-gate the new daemon command and preserve startup with older daemons

Related Linear task: RES-1159

Architecture

This branch is reconciled with current main and now builds on the kernel-owned generic MCP runtime merged in #1495 and hardened in #1585. It no longer generates one temporary Python package per tool or duplicates MCP transports in mcp_base.py.

ACP server names are added to the session prompt, and the model discovers and calls their tools through:

tools = await mcp.list_tools("task-tools")
result = await mcp.call_tool("task-tools", "lookup", {"query": "example"})

OAuth and credential boundary

ACP HTTP credentials are treated as client-supplied session authority:

  • HTTP uses only the ACP URL and headers.
  • ACP HTTP config never reads auth.json, resolves host bearer-token environment variables, or starts or refreshes Prime Agent OAuth.
  • A same-named persistent MCP server is shadowed without allowing its endpoint-bound stored token to follow the ACP HTTP endpoint.
  • Configuration is cleared on session/close, replacement, failed admission, and disconnect.

ACP stdio is trusted same-user code, not a credential sandbox. It uses the real agent cwd, a scrubbed base environment, and the literal environment values supplied by the ACP client, but the launched process can still read any files available to the Prime Agent user. Only trusted ACP clients should supply stdio servers, or Prime Agent must run inside an external sandbox.

Discussion #1574 tracks a separate path-scoped OAuth discovery bug for user-configured MCP servers. ACP-provided servers do not run that OAuth flow, so this PR keeps that issue out of scope rather than mixing the two credential models.

Daemon compatibility

  • daemon schema revision 22
  • optional acp_mcp_servers capability
  • owner-scoped replacement and cleanup so attached clients cannot overwrite one another
  • replace_acp_mcp_servers is sent only after capability negotiation
  • empty ACP MCP setup remains a no-op, so an older daemon can still create ordinary ACP sessions

Validation

  • npm run check
  • npx tsx ../../node_modules/vitest/dist/cli.js --run test/acp-mcp.test.ts test/mcp-manager.test.ts test/daemon-protocol.test.ts test/agent-connection-daemon.test.ts test/system-prompt.test.ts test/agent-session-services.test.ts — 150 passed
  • uv run python -m unittest discover -s test in prime-agent-runtime — 98 passed
  • git diff --check

Note

Cursor Bugbot is generating a summary for commit b2a213a. Configure here.

Note

Summary

  • accept HTTP and stdio MCP servers supplied through ACP session/new
  • expose them through the existing pre-imported mcp.list_tools and mcp.call_tool Python program API
  • keep ACP transport configuration and credentials scoped to the live ACP session
  • replace and clear ACP MCP configuration across in-process and daemon-backed sessions
  • capability-gate the new daemon command and preserve startup with older daemons

Related Linear task: RES-1159

Architecture

This branch is reconciled with current main and now builds on the kernel-owned generic MCP runtime merged in #1495 and hardened in #1585. It no longer generates one temporary Python package per tool or duplicates MCP transports in mcp_base.py.

ACP server names are added to the session prompt, and the model discovers and calls their tools through:

tools = await mcp.list_tools("task-tools")
result = await mcp.call_tool("task-tools", "lookup", {"query": "example"})

OAuth and credential boundary

ACP HTTP credentials are treated as client-supplied session authority:

  • HTTP uses only the ACP URL and headers.
  • ACP HTTP config never reads auth.json, resolves host bearer-token environment variables, or starts or refreshes Prime Agent OAuth.
  • A same-named persistent MCP server is shadowed without allowing its endpoint-bound stored token to follow the ACP HTTP endpoint.
  • Configuration is cleared on session/close, replacement, failed admission, and disconnect.

ACP stdio is trusted same-user code, not a credential sandbox. It uses the real agent cwd, a scrubbed base environment, and the literal environment values supplied by the ACP client, but the launched process can still read any files available to the Prime Agent user. Only trusted ACP clients should supply stdio servers, or Prime Agent must run inside an external sandbox.

Discussion #1574 tracks a separate path-scoped OAuth discovery bug for user-configured MCP servers. ACP-provided servers do not run that OAuth flow, so this PR keeps that issue out of scope rather than mixing the two credential models.

Daemon compatibility

  • daemon schema revision 22
  • optional acp_mcp_servers capability
  • owner-scoped replacement and cleanup so attached clients cannot overwrite one another
  • replace_acp_mcp_servers is sent only after capability negotiation
  • empty ACP MCP setup remains a no-op, so an older daemon can still create ordinary ACP sessions

Validation

  • npm run check
  • npx tsx ../../node_modules/vitest/dist/cli.js --run test/acp-mcp.test.ts test/mcp-manager.test.ts test/daemon-protocol.test.ts test/agent-connection-daemon.test.ts test/system-prompt.test.ts test/agent-session-services.test.ts — 150 passed
  • uv run python -m unittest discover -s test in prime-agent-runtime — 98 passed
  • git diff --check

[!NOTE]
Cursor Bugbot is generating a summary for commit b2a213a. Configure here.

Changes since #1378 opened

  • Reworked AgentDaemon.handleCommand for replace_acp_mcp_servers case to track acpMcpOwners entries with server names and optional in-flight release promises, acquire session input pause when replacing with non-empty servers, roll back failures by calling session.releaseAcpMcpServers with the union of claimed names, clear ownership by calling session.releaseAcpMcpServers with stored names when replacing with empty servers, store release promises to prevent duplicate concurrent releases, and fence ownership changes until prior releases complete [b2a213a]
  • Implemented AgentSession.releaseAcpMcpServers method to asynchronously accept ownerId and serverNames, check manager.canReleaseAcpServers(ownerId) before proceeding, call replaceAcpServers([], ownerId) to revoke credentials, immediately update base and system prompts without rebuilding the kernel, deduplicate provided server names and if any are present acquire a session input pause, wait for agent idle and event queue drain, execute Python in-kernel to import rlm.mcp and await reload(name) for each server, validate kernel execute result status equals 'ok' and throw on failure, and always release the input pause in finally [b2a213a]
  • Modified mcp._Registry._get_locked method in the Python runtime to reorder and guard configuration fetch by attempting to obtain config within a try/except block, close and remove current generation from registry on exception before re-raising, while preserving existing behavior of returning current generation when config is unchanged or closing and replacing generation when config changes [b2a213a]
  • Extended AgentConnection interface with optional releaseAcpMcpServers method accepting ownerId and serverNames and returning a promise, implemented DaemonAgentConnection.releaseAcpMcpServers to proxy to replaceAcpMcpServers([], ownerId) while ignoring provided names at the transport layer, and implemented InProcessAgentConnection.releaseAcpMcpServers to forward calls to runtimeHost.session.releaseAcpMcpServers [b2a213a]
  • Updated runAcpModeWithConnection function to require connection.releaseAcpMcpServers capability in the capability gate, replace hasAcpMcpServers boolean with acpMcpServerNames string array tracking last admitted names, modify clearAcpMcpServers to call connection.releaseAcpMcpServers(ownerId, serverNames) and clear tracked names, and modify replaceAcpMcpServers to resolve input to configs, capture names, and attempt owner-scoped cleanup for those names using releaseAcpMcpServers on admission error [b2a213a]
  • Updated test files to validate name-scoped release semantics by expecting calls to releaseAcpMcpServers(ownerId, [names]) instead of replaceAcpMcpServers([], ownerId), added spies and mocks for name-scoped release assertions, verified daemon release expectations on rollback and detach with specific server names, extended capability tests to use releaseAcpMcpServers, mocked running IPython kernel manager to assert Python snippet execution invoking await _prime_mcp.reload(name) without runtime rebuild, augmented stdio fixture to optionally write PID to file via FIXTURE_PID_FILE env for process reaping assertions, and added tests for closing cached generations on missing config and reaping real ACP stdio processes on reload [b2a213a]
  • Modified mcp._Registry._get_locked to preserve cached MCP server generations when configuration retrieval fails [8e525ed]
  • Updated ACP session lifecycle to retry failed MCP server releases and prevent slot retention on transport reaping failures [8e525ed]
  • Added guard to prevent MCP server replacement while agent is actively streaming [8e525ed]
  • Added test coverage for MCP server release retry behavior and session slot management [8e525ed]
  • Added test coverage for streaming guard that blocks MCP server replacement [8e525ed]
  • Updated test expectations for MCP registry configuration failure behavior [8e525ed]
  • Modified replaceAcpMcpServers helper within runAcpModeWithConnection to always clear existing MCP servers when acpMcpServerNames is non-empty, regardless of whether replacement servers are provided [80136a7]
  • Updated test to verify MCP server clearing behavior with empty replacement server list [80136a7]

@hallerite
hallerite marked this pull request as ready for review August 13, 2026 20:39
@hallerite
hallerite force-pushed the codex/acp-mcp-programs branch from e278ab6 to 30b44fa Compare August 13, 2026 20:41
Comment thread packages/coding-agent/src/core/agent-session.ts Outdated
Comment thread packages/coding-agent/src/modes/acp/acp-mode.ts Outdated
Comment thread packages/coding-agent/src/modes/acp/acp-mcp.ts Outdated
Comment thread prime-agent-runtime/src/rlm/mcp_base.py Outdated
Comment thread prime-agent-runtime/src/rlm/mcp_base.py Outdated

@sethkarten sethkarten left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please stack on
ACP #1236
MCP #1175

Comment thread packages/coding-agent/src/modes/acp/acp-mode.ts Outdated
@sethkarten

Copy link
Copy Markdown
Contributor

Took over this branch and rebuilt it on current main.

The old per-tool temporary-skill implementation is gone. ACP-provided HTTP and stdio servers now use the kernel-owned mcp.list_tools / mcp.call_tool runtime from #1495 and #1585. This removes the stale-resource fallback, generated-name/schema failures, duplicated MCP transports, and the empty-session kernel rebuild reported in the existing threads.

OAuth scope is explicit: ACP HTTP uses only client-supplied URL/headers and cannot read or refresh stored Prime Agent OAuth, including on same-name collisions. ACP stdio remains trusted same-user code, not a credential sandbox, and the docs now say so. Discussion #1574 remains separate because it concerns OAuth discovery for user-configured MCP servers.

Validation: npm run check; 150 focused TypeScript tests; 96 runtime tests; git diff --check. Independent review found no remaining blocker.

Comment thread packages/coding-agent/src/modes/acp/acp-mode.ts Outdated
Comment thread packages/coding-agent/src/core/agent-session.ts
sethkarten
sethkarten previously approved these changes Aug 20, 2026
Comment thread packages/coding-agent/src/core/mcp/mcp-manager.ts
sethkarten
sethkarten previously approved these changes Aug 20, 2026
Comment thread packages/coding-agent/src/modes/daemon/daemon-mode.ts Outdated
Comment thread packages/coding-agent/src/core/agent-session.ts Outdated
sethkarten
sethkarten previously approved these changes Aug 20, 2026
Comment thread packages/coding-agent/src/core/agent-session.ts Outdated
Comment thread packages/coding-agent/src/modes/daemon/daemon-mode.ts Outdated
sethkarten
sethkarten previously approved these changes Aug 20, 2026
@macroscopeapp

macroscopeapp Bot commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Macroscope has since reviewed this pull request. An earlier review was skipped by a cost limit; a review has now completed, so that notice no longer applies.

Comment thread packages/coding-agent/src/core/agent-session.ts Outdated
sethkarten
sethkarten previously approved these changes Aug 20, 2026
Comment thread prime-agent-runtime/src/rlm/mcp.py Outdated
Comment thread packages/coding-agent/src/core/agent-session.ts
Comment thread packages/coding-agent/src/core/agent-session.ts
sethkarten
sethkarten previously approved these changes Aug 20, 2026

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 8e525ed. Configure here.

Comment thread packages/coding-agent/src/modes/acp/acp-mode.ts
Comment thread packages/coding-agent/src/modes/acp/acp-mode.ts
@sethkarten
sethkarten merged commit c75a637 into main Aug 20, 2026
22 checks passed
@sethkarten
sethkarten deleted the codex/acp-mcp-programs branch August 20, 2026 18:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants