Skip to content

feat(acp): let ACP agents configure MCP servers#995

Open
simonrosenberg wants to merge 2 commits into
mainfrom
feat-acp-mcp
Open

feat(acp): let ACP agents configure MCP servers#995
simonrosenberg wants to merge 2 commits into
mainfrom
feat-acp-mcp

Conversation

@simonrosenberg
Copy link
Copy Markdown
Member

@simonrosenberg simonrosenberg commented Jun 1, 2026

Closes #993.

What

Lets ACP agents (Claude Code / Codex / Gemini CLI) use MCP servers through the existing MCP page — no new editor needed. Previously the MCP surfaces were gated off for ACP because the SDK rejected mcp_config on ACPAgent init.

Depends on the SDK change that forwards mcp_config to the ACP subprocess at session creation: OpenHands/software-agent-sdk#3458 (+ docs in OpenHands/typescript-client#197).

Changes

  • agent-server-adapter.ts — include mcp_config in the ACP conversation-start payload. It's a shared field (not one of the stripped ACP_SETTINGS_KEYS), handled explicitly like llm/agent_context; empty/serverless configs are dropped so we never send mcp_config: {}.
  • /mcp route — remove the redirectIfAcpActive clientLoader. The existing MCP editor already reads/writes agent_settings.mcp_config (via parseMcpConfig/toSdkMcpConfig and the add/update/delete mutations), so it drives both agent kinds with zero new UI.
  • extensions-navigation.tsx — drop the now-obsolete disabledByAcp mechanism (MCP was its only consumer; no extensions item needs ACP-gating anymore). The MCP nav item is a normal link under ACP.
  • acp-route-guard.ts — docs updated: /settings and /settings/condenser still redirect for ACP; /mcp intentionally does not.

Behavior

The same agent_settings.mcp_config storage and editor now back both agent kinds. Saving the Agent settings page doesn't clobber mcp_config (buildAcpAgentSettingsDiff doesn't touch it). MCP changes take effect on the next ACP session (the servers bind at session creation).

Validation

End-to-end through this PR's code path (real backend, local auth). Ran the actual buildStartConversationRequest adapter (this PR's changes) — it produced a StartConversationRequest with agent_kind:"acp" and mcp_config. POSTed that exact request to a locally-built openhands-agent-server running the branch SDK, via POST /api/conversations (the same endpoint the canvas uses) → it created the ACP conversation, forwarded mcp_config to the claude-agent-acp subprocess, and the agent actually called the MCP tool:

ACPToolCallEvent  title='mcp__everything__echo'  status=completed
  raw_input  = {"message": "CANVAS-E2E-MCP-4F8A"}
  raw_output = [{"type":"text","text":"Echo: CANVAS-E2E-MCP-4F8A"}]

Verified on the tool event's output, not the reply text. Full chain exercised: canvas adapter payload → agent-server → ACPAgentSettingsACPAgent(mcp_config) → ACP subprocess → MCP server (only the browser clicks were skipped — the same HTTP API the browser drives was used).

SDK layer — the underlying forwarding is independently validated against all three harnesses (Claude / Codex / Gemini) over both stdio and HTTP: OpenHands/software-agent-sdk#3458.

Tests

  • agent-server-adapter: forwards mcp_config for ACP; omits it when serverless. Refocused the existing "LLM-only fields don't leak" test.
  • extensions-navigation: MCP item stays clickable under ACP.
  • mcp route: regression guard that the route exports no ACP-redirect clientLoader.

typecheck + eslint + prettier clean; affected suites green.

🤖 Generated with Claude Code


🐳 Docker images for this PR

GHCR package: https://github.com/OpenHands/agent-canvas/pkgs/container/agent-canvas

Component Value
Image ghcr.io/openhands/agent-canvas
Architectures amd64, arm64
Agent Server ghcr.io/openhands/agent-server:1.24.0-python
Automation openhands-automation==1.0.0a5
Commit 0fcae6461694e4dc1bd3cdc7a3a159beba1287f6

Pull (multi-arch manifest)

# Multi-arch manifest — Docker automatically pulls the correct architecture
docker pull ghcr.io/openhands/agent-canvas:sha-0fcae64

Run

docker run -it --rm \
  -p 8000:8000 \
  ghcr.io/openhands/agent-canvas:sha-0fcae64

All tags pushed for this build

ghcr.io/openhands/agent-canvas:sha-0fcae64-amd64
ghcr.io/openhands/agent-canvas:feat-acp-mcp-amd64
ghcr.io/openhands/agent-canvas:pr-995-amd64
ghcr.io/openhands/agent-canvas:sha-0fcae64-arm64
ghcr.io/openhands/agent-canvas:feat-acp-mcp-arm64
ghcr.io/openhands/agent-canvas:pr-995-arm64
ghcr.io/openhands/agent-canvas:sha-0fcae64
ghcr.io/openhands/agent-canvas:feat-acp-mcp
ghcr.io/openhands/agent-canvas:pr-995

About Multi-Architecture Support

  • Each tag (e.g., sha-0fcae64) is a multi-arch manifest supporting both amd64 and arm64
  • Docker automatically pulls the correct architecture for your platform
  • Individual architecture tags (e.g., sha-0fcae64-amd64) are also available if needed

ACP agents now forward `mcp_config` to their subprocess at session creation
(see software-agent-sdk), so the MCP surfaces no longer need to be gated off
for ACP:

- agent-server-adapter: include `mcp_config` in the ACP conversation-start
  payload (a shared field, handled explicitly like `llm`/`agent_context`),
  dropping empty/serverless configs.
- /mcp route: remove the `redirectIfAcpActive` clientLoader so ACP users can
  reach the MCP editor; the existing editor + `agent_settings.mcp_config`
  storage already drive both agent kinds.
- extensions-navigation: drop the now-obsolete `disabledByAcp` mechanism (MCP
  was its only user); the MCP nav item is clickable under ACP.
- acp-route-guard: update docs — `/mcp` is intentionally no longer guarded.

Closes #993.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel Bot commented Jun 1, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
agent-canvas Ready Ready Preview, Comment Jun 1, 2026 6:21pm

Request Review

Copy link
Copy Markdown
Contributor

all-hands-bot commented Jun 1, 2026

Review complete.

This review was performed through OpenHands Cloud Automation. You can log in and view the conversation here.

Copy link
Copy Markdown
Contributor

@all-hands-bot all-hands-bot left a comment

Choose a reason for hiding this comment

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

Code Review — feat(acp): let ACP agents configure MCP servers

🟢 Good taste — Clean, focused removal of a restriction that no longer holds now that the SDK forwards mcp_config to the ACP subprocess. The implementation is sound and well-tested.


What I looked at

File Observation
src/api/agent-server-adapter.ts New mcp_config forwarding block mirrors the identical guard already used for the OpenHands agent path (buildConfiguredOpenHandsAgentSettings, line 623–628). Consistent pattern, correct behaviour.
src/routes/mcp.tsx clientLoader removed cleanly; the explanatory comment is appropriately verbose given the deliberate asymmetry with /settings and /settings/condenser.
src/components/features/skills/extensions-navigation.tsx disabledByAcp, useSettings, ACP_PROVIDERS imports and all conditional rendering dropped. No dead references left behind.
src/utils/acp-route-guard.ts Doc update is precise — explicitly calls out that /mcp is intentionally NOT guarded. Good for future maintainers.
__tests__/api/agent-server-adapter.test.ts Two new tests exercise the real code path (forwarded with servers; omitted when empty). The existing "LLM-only fields don't leak" test was correctly narrowed — mcp_config no longer belongs in that list.
__tests__/routes/mcp.test.tsx expect("clientLoader" in mcpRoute).toBe(false) is an elegant regression guard.
__tests__/components/features/skills/extensions-navigation.test.tsx Mocks for useSettings and StyledTooltip removed because the component no longer needs them. Tests are simpler and still catch regressions.

One gap worth noting

Missing evidence — The PR description mentions tests passing and linting clean, but there is no screenshot or screen-recording confirming the MCP page is actually reachable and usable under an active ACP agent, nor a link to the originating agent conversation. Since this is a visible UX change (an item that was greyed-out is now a live link), a screenshot of the MCP nav item being clickable under ACP would strengthen confidence that nothing in the rendering path regressed.


Risk Assessment

⚠️ Risk: 🟢 LOW

The change removes a client-side redirect and a disabled-state UI. It cannot break existing OpenHands-agent behaviour (code paths are separate). The worst realistic regression is the MCP page loading correctly but the ACP subprocess not picking up the config — that would be caught by the SDK-level change this PR depends on (OpenHands/software-agent-sdk#3458). No API contract changes, no new dependencies.


VERDICT:Worth merging — the core logic is correct, the test coverage matches the stated behaviours, and the net diff is a satisfying −114 lines.

Improve this review? If any feedback above seems incorrect or irrelevant to this repository, you can teach the reviewer to do better by adding a .agents/skills/custom-codereview-guide.md file to your branch with the /codereview trigger and the context the reviewer is missing.

Was this review helpful? React with 👍 or 👎 to give feedback.


This review was generated by an AI agent (OpenHands) on behalf of the user through OpenHands Automation. View conversation

@simonrosenberg
Copy link
Copy Markdown
Member Author

Live end-to-end validation (addresses the review's "missing evidence" note)

Validated the full path with a real Claude Code ACP agent using local auth (~/.claude.json, no API key) and a real stdio MCP server (@modelcontextprotocol/server-everything). This exercises the exact flow this PR enables: agent_settings.mcp_configbuildConfiguredAcpAgentSettingsStartConversationRequest → SDK ACPAgent(mcp_config=…) → forwarded to session/new.

The agent actually called the MCP tool (not just echoed text):

[tool-call] title='mcp__everything__echo'  status=pending → completed
   Input:  {'message': 'OPENHANDS-MCP-FORWARD-7F3A9'}
   Output: [{'type': 'text', 'text': 'Echo: OPENHANDS-MCP-FORWARD-7F3A9'}]

The mcp__everything__echo tool name (MCP prefix) plus the server's Echo: … round-trip output confirm the ACP subprocess connected to the configured MCP server and used it — i.e. MCP forwarding works end-to-end under an active ACP agent. (Covers fresh-session + stdio; http/sse capability-gating and resume re-pass are covered by unit tests in the SDK PR.)

Depends on OpenHands/software-agent-sdk#3458.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 1, 2026

📸 Snapshot Test Report

✅ All snapshots match the main branch baselines.

Category Count
🔴 Changed 0
🆕 New 0
✅ Unchanged 73
Total 73
✅ Unchanged snapshots (73)

archived-conversation

  • conversation-panel-with-archived-badges
  • conversation-view-archived
  • conversation-view-sandbox-error

automations

  • automations-delete-modal
  • automations-list-active-inactive
  • automations-no-automations
  • automations-search-no-results

backends-extended

  • backend-add-blank-disabled
  • backend-add-cloud-advanced-open
  • backend-add-cloud-no-key-disabled
  • backend-add-cloud-with-key-enabled
  • backend-add-form-partially-filled
  • backend-add-invalid-url-disabled
  • backend-add-local-ready
  • backend-add-name-only-disabled
  • backend-add-two-column-layout
  • backend-add-whitespace-host-disabled
  • backend-after-switch
  • backend-cancel-nothing-saved
  • backend-dropdown-two-backends
  • backend-edit-prefilled
  • backend-manage-after-removal
  • backend-manage-two-listed
  • backend-remove-cancelled
  • backend-remove-confirmation
  • backend-switch-overlay

backends

  • backend-add-modal
  • backend-manage-modal
  • backend-selector-open

changes-tab

  • changes-deleted-file
  • changes-diff-viewer
  • changes-empty

collapsible-thinking

  • reasoning-content-collapsed
  • reasoning-content-expanded
  • think-action-collapsed
  • think-action-expanded

mcp-page

  • mcp-custom-server-1-editor-open
  • mcp-custom-server-2-url-filled
  • mcp-custom-server-3-all-filled
  • mcp-custom-server-4-installed
  • mcp-custom-server-editor
  • mcp-empty-installed
  • mcp-search-filtered
  • mcp-slack-install-1-marketplace
  • mcp-slack-install-2-modal
  • mcp-slack-install-3-filled
  • mcp-slack-install-4-installed

onboarding

  • onboarding-step-0-choose-agent
  • onboarding-step-1-check-backend
  • onboarding-step-2-setup-llm
  • onboarding-step-3-say-hello

projects-workspace-browser

  • projects-workspace-browser

settings-page

  • add-backend-modal
  • analytics-consent-modal
  • home-screen
  • settings-app-page
  • settings-page

settings-secrets

  • secrets-add-form-filled
  • secrets-add-form
  • secrets-after-save
  • secrets-delete-confirm
  • secrets-list

settings-verification

  • condenser-settings
  • verification-settings-off
  • verification-settings-on

sidebar

  • sidebar-collapsed
  • sidebar-conversation-panel
  • sidebar-filter-menu

skills-page

  • skills-empty
  • skills-loaded
  • skills-no-match
  • skills-search-filtered
  • skills-type-filter

Generated by the Snapshot Tests workflow. This comment was created by an AI agent (OpenHands) on behalf of the repo maintainers.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

acp ACP Agents

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Enable MCP servers for ACP agents

2 participants