Skip to content

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

Open
hallerite wants to merge 1 commit into
mainfrom
codex/acp-mcp-programs
Open

feat(coding-agent): support ACP MCP programs#1378
hallerite wants to merge 1 commit into
mainfrom
codex/acp-mcp-programs

Conversation

@hallerite

@hallerite hallerite commented Aug 13, 2026

Copy link
Copy Markdown
Member

Summary

  • discover HTTP and stdio MCP servers supplied through ACP session/new
  • translate each MCP tool into a session-scoped, schema-typed Python program
  • install and replace those generated programs across in-process and daemon-backed sessions
  • advertise HTTP MCP capability only when the active connection supports temporary skills
  • validate names and collisions, isolate ACP MCP configuration from persisted user MCP settings, and clean up generated skills with the session
  • document the ACP behavior and add TypeScript and Python coverage

Why

Verifiers passes environment tools to ACP agents as MCP servers, but Prime Agent previously ignored mcpServers. That made tool-bearing Prime Agent rollouts impossible and required downstream integrations to report MCP as unsupported.

The agent should own the translation from external MCP tools to its native model-facing interface. This change keeps IPython as the model-facing tool and exposes each ACP MCP tool as a pre-imported Python program, matching Prime Agent's RLM architecture.

Validation

  • npm run check
  • npx vitest --run packages/coding-agent/test/acp-mcp.test.ts packages/coding-agent/test/agent-connection-daemon.test.ts packages/coding-agent/test/daemon-protocol.test.ts — 86 passed
  • uv run --project . --with pytest --with 'mcp>=1.28,<2' --with 'httpx>=0.27,<1' pytest test/test_mcp_base.py — 21 passed
  • Verifiers end-to-end smoke test in Docker — reward 1.0
  • Verifiers end-to-end smoke test in a real Prime VM using Prime Inference — reward 1.0, generated MCP program executed successfully, clean sandbox teardown

A separate, small Verifiers PR will add the Prime Agent ACP harness after this behavior is available in a release.


Note

Medium Risk
Introduces session-bound external MCP connectivity and a new daemon capability, but keeps it isolated from persisted MCP settings and validates tool/skill naming collisions before install.

Overview
ACP mode now honors HTTP and stdio MCP servers passed in session/new.mcpServers, which were previously ignored. On session creation the agent discovers each server's tools and materializes one temporary Python skill per tool in the RLM kernel (e.g. task-tools / lookuptask_tools_lookup), using JSON Schema–derived signatures and the client's transport/credentials only—not persisted user MCP settings.

replaceTemporarySkills replaces all skills for a given source (acp:mcp) across in-process sessions, the resource loader, and daemon clients (schema revision 17, capability temporary_skills). Reconfiguring or disposing an ACP session swaps or removes generated skill packages and rejects name collisions with existing skills.

The runtime adds AcpMcpIntegration and make_acp_mcp_skill for stdio/HTTP calls from generated modules. ACP initialize advertises HTTP MCP support only when the active connection can install temporary skills. Docs and TypeScript/Python tests cover discovery, wiring, and daemon capability gating.

Reviewed by Cursor Bugbot for commit 30b44fa. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add MCP server support to ACP mode, exposing tools as session-scoped Python programs

  • ACP sessions can now declare HTTP or stdio MCP servers in session/new; the coding agent discovers their tools and generates one temporary Python skill package per tool in the RLM kernel.
  • acp-mcp.ts handles server resolution, tool discovery via @modelcontextprotocol/sdk, and Python skill generation using rlm.make_acp_mcp_skill.
  • mcp_base.py adds AcpMcpIntegration and make_acp_mcp_skill, which generate async Python functions with signatures derived from JSON Schema and bind them to the specified MCP tool.
  • A new replaceTemporarySkills method is added to AgentSession, AgentConnection, and the daemon protocol (schema revision 17, capability temporary_skills), allowing skills to be atomically replaced between runs.
  • Skills from the previous session are cleaned up on reconfiguration or dispose.

Macroscope summarized 30b44fa.

@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
}));
if (this._resourceLoader.replaceSkillResources) {
this._resourceLoader.replaceSkillResources(resources, source);
} else if (resources.length > 0) {

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.

🟡 Medium core/agent-session.ts:1401

The fallback extendResources call preserves previously registered skill paths, so repeated ACP MCP updates leave removed tools loaded and an empty update cannot clear them; renamed tools can also collide with stale generated skills. Use a true replacement path for ResourceLoader implementations that lack replaceSkillResources (or update the interface so replacement is always available).

🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @packages/coding-agent/src/core/agent-session.ts around line 1401:

The fallback `extendResources` call preserves previously registered skill paths, so repeated ACP MCP updates leave removed tools loaded and an empty update cannot clear them; renamed tools can also collide with stale generated skills. Use a true replacement path for `ResourceLoader` implementations that lack `replaceSkillResources` (or update the interface so replacement is always available).

Evidence trail:
packages/coding-agent/src/core/agent-session.ts:1386-1409 @ e278ab6f8e045e12bcdf248276ebad6343789619
packages/coding-agent/src/core/resource-loader.ts:29-40, 297-352 @ e278ab6f8e045e12bcdf248276ebad6343789619
packages/coding-agent/src/core/sdk.ts:60-61, 155-184 @ e278ab6f8e045e12bcdf248276ebad6343789619
packages/coding-agent/src/modes/acp/acp-mcp.ts:212-247 @ e278ab6f8e045e12bcdf248276ebad6343789619

@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 4 potential issues.

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 30b44fa. Configure here.

throw acp.RequestError.invalidParams({ reason: "MCP servers are unavailable in this ACP host" });
}
try {
await configureMcpServers?.(params.mcpServers, actualCwd ?? requestedCwd);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Empty MCP setup still replaces skills

High Severity

session/new always runs MCP configure, and configure always calls replaceTemporarySkills, even when mcpServers is empty. Daemon connections expose that method regardless of the temporary_skills capability, so an older daemon rejects every new ACP session. The same path also rebuilds the IPython kernel on sessions that never used MCP, and initialize still advertises HTTP MCP support.

Additional Locations (2)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 30b44fa. Configure here.

function skillImportName(server: string, tool: string): string {
const normalized = `${server}_${tool}`.replace(/\W/g, "_");
return /^\d/.test(normalized) ? `_${normalized}` : normalized;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

MCP names keep uppercase letters

Medium Severity

skillImportName only rewrites non-word characters and never lowercases. MCP server and tool names may include uppercase letters, so the later lowercase-only skill-name check rejects those tools and fails the whole session/new instead of installing a valid Python skill.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 30b44fa. Configure here.

parameters.sort(
key=lambda parameter: parameter.default is not inspect.Parameter.empty
)
return inspect.Signature(parameters)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Schema keywords break generated skills

Medium Severity

_mcp_tool_signature keeps JSON Schema properties that pass str.isidentifier() but are Python keywords such as from or class. inspect.Parameter then raises ValueError while the generated module is imported, so the skill is installed as unavailable and the MCP tool cannot be called.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 30b44fa. Configure here.

)
streams = stdio_client(
StdioServerParameters(command=command, args=args, env=env)
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Stdio MCP calls drop session cwd

Medium Severity

Tool discovery starts stdio MCP servers with the ACP session cwd, but the generated Python skill serializes only command, args, and env. Runtime StdioServerParameters therefore omit cwd, so later tool calls can spawn in a different working directory than discovery used.

Additional Locations (2)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 30b44fa. Configure here.

@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

if (options.ownStdout !== false && !options.stream) {
takeOverStdout();
}
const mcp = connection.replaceTemporarySkills

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.

🟠 High acp/acp-mode.ts:248

Daemon-backed ACP sessions fail during session/new because mcp is created whenever replaceTemporarySkills exists, even when the daemon lacks the temporary_skills capability; the unconditional configureMcpServers call then invokes that unsupported method (including for an empty mcpServers list). Check the advertised capability before constructing/using AcpMcpSkillInstaller, or skip configuration when no MCP servers were supplied.

🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @packages/coding-agent/src/modes/acp/acp-mode.ts around line 248:

Daemon-backed ACP sessions fail during `session/new` because `mcp` is created whenever `replaceTemporarySkills` exists, even when the daemon lacks the `temporary_skills` capability; the unconditional `configureMcpServers` call then invokes that unsupported method (including for an empty `mcpServers` list). Check the advertised capability before constructing/using `AcpMcpSkillInstaller`, or skip configuration when no MCP servers were supplied.

Evidence trail:
packages/coding-agent/src/modes/acp/acp-mode.ts:248-255,303-312 @ 30b44fae; packages/coding-agent/src/modes/agent-connection/daemon-agent-connection.ts:459-468 @ 30b44fae; packages/coding-agent/src/modes/acp/acp-mcp.ts:212-246 @ 30b44fae; git diff MERGE_BASE REVIEWED_COMMIT -- packages/coding-agent/src/modes/acp/acp-mode.ts

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