Skip to content

Conversation

@nikomatsakis
Copy link

  • Proposes extending ACP with proxy chain capabilities for composable agent architectures
  • Defines conductor/proxy roles and initialization protocols
  • Includes MCP-over-ACP transport for seamless tool integration
  • Provides complete protocol specification with examples and FAQ
  • Enables universal extension mechanism that subsumes existing approaches

- Proposes extending ACP with proxy chain capabilities for composable agent architectures
- Defines conductor/proxy roles and initialization protocols
- Includes MCP-over-ACP transport for seamless tool integration
- Provides complete protocol specification with examples and FAQ
- Enables universal extension mechanism that subsumes existing approaches
@nikomatsakis nikomatsakis requested a review from a team as a code owner November 15, 2025 18:19
@nikomatsakis
Copy link
Author

One thing I am noticing as I work with this system:

It would be really nice if the MCP-over-ACP protocol gave you the ability to correlate an MCP request with an ACP session-id that it originates from. I'm working on some research agent proxies that would benefit from this because they want to remember some details from the originating session to know how to react.

Copy link
Member

@benbrandt benbrandt left a comment

Choose a reason for hiding this comment

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

Alright a few questions, but overall I'm quite excited about what this unlocks!


### Capability Reference

**Proxy Capability** (`"proxy": true`)
Copy link
Member

Choose a reason for hiding this comment

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

Just to be clear:

  • a Client offers this as a capability to indicate to the agent it should run in proxy mode
  • an Agent offers this as a capability if it can work as a proxy and agrees to do so?

You cover this later, and if I understand correctly, the only ones who use this capability are components of the conductor<->proxy connection, it shouldn't be used elsewhere? Like basically a registration with a conductor at some level in the chain?

I guess I am trying to better understand which components would set this to "true" in the chain and which would not need to or should not?

Copy link
Author

Choose a reason for hiding this comment

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

Yeah, it's a bit tricky. The way I did it is like this: the conductor (and only the conductor) offers this capability to the "proxy" components (those that have a successor). It indicates to them that they can send messages to their successor. Then they respond with this capability to indicate that they are capable of being used in proxy mode.

This way, if a "terminal agent" like claude-code-acp is used in proxy position, the conductor will return an error, since that makes no sense.

On the other hand, if an agent is designed to be used as a proxy, it can error if it does NOT receive the proxy capability.

Some agents can operate either as a terminal agent OR a proxy (including the conductor itself), so they check for whether they've been offered the proxy capability to decide how they are operating.


- **Conductor ↔ proxy initialization**: `InitializeRequest` contains `"proxy": true`. The server MUST respond with `"proxy": true` in the `InitializeResponse` to acknowledge it will act as a proxy. The conductor MUST error and terminate if the server responds without `"proxy": true`.

- **Proxy ↔ successor agent**: When a proxy receives an `InitializeRequest`, it MUST remove the `"proxy"` capability before forwarding via `proxy/successor/request`.
Copy link
Member

Choose a reason for hiding this comment

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

Note for later down the line: it would be great at the SDK level to have helpers for this at some level to make it easier not to forget this.

Copy link
Author

Choose a reason for hiding this comment

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

Yeah, I think I baked this into the SDK actually so that agents don't have to do anything in particular.

- It is only legal to include in a server's initialization response if it was offered by the client. In that case, it indicates that the server agrees to act as a proxy, not as an agent.
- When a component responds with proxy capability, it SHOULD forward requests it does not understand and it SHOULD preserve metadata fields when forwarding messages.

**MCP-over-ACP Transport** (`"mcp_acp_transport": true`)
Copy link
Member

Choose a reason for hiding this comment

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

Minor thing, but i wonder if there is a way to merge this with the existing MCP capabilities? https://agentclientprotocol.com/protocol/initialization#mcp-capabilities

We currently only have it on the server side. I could see that if a client supplies an mcp server of type "acp" transport it is an implicit indication that it would support it? And then the client should only send one of the agent responds withe an acp capability here?

It might be too implicit, but could work.

Copy link
Author

Choose a reason for hiding this comment

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

Could work, yes. It'd be nice not to have to separate out these things to be honest. I used to have just one (proxy + acp-over-mcp), but I separate them to allow for agents that can natively use mcp-over-acp.


### Why do proxies remove the proxy/MCP capabilities when forwarding to their successor?

The conductor would always re-add these capabilities anyway, which shows that they are really specific to conductor↔proxy communication and so we decided to simply omit them. This makes it clear that these capabilities are part of the conductor's orchestration protocol rather than something proxies need to understand or manage.
Copy link
Member

Choose a reason for hiding this comment

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

One thought I had: is the relationship between conductor and proxy distinct enough to require it's own initialize method?

That being said, it is possible these things want to modify the initialize call to the eventual agent, so we should probably leave as is.

The next question is: should this be a capability? Or a top-level param?
Kind of thinking out loud, I guess there's just something about this that isn't just "I can act as a proxy" and more of a flag of "we must have a proxy relationship" that is hanging me up currently.

I actually think what you have proposed is ultimately fine, but there's just something here that makes me want to reflect this differently than a capability... but I am not sure if that instinct is correct or if I am overthinking it.

Copy link
Author

Choose a reason for hiding this comment

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

Good point. I agree it doesn't quite feel right to me. Maybe a method like initialize/proxy makes sense instead? It's not really a capability, as you say, and it winds up requiring some "finnicky" stuff to act like one.


### Language-Specific Proxy Ecosystems

The monolithic nature of agent development has meant that most of the "action" happens within agents. We wish to invert this, with agents trending towards simple agentic loops, and the creativity being pushed outwards into the broader ecosystem.
Copy link
Member

Choose a reason for hiding this comment

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

I think this actually helps me figure out a better home for some unexplored design space of how best to handle IDE->agent functionality.

Like if we wanted to have a "standardized" way to offer IDE capabilities to an agent, like surfacing diagnostics, or even the current file system + terminal APIs, these could potentially move to "proxy" space potentially (would need to sort out how the specific proxy would talk back to what is essentially the "client")

But it would allow for a lot of experimentation on the best way to expose this without muddying the main protocol (especially since there is more demand for non-IDE clients) while still providing a lot more control and power than just offering an MCP server from the client

@josevalim
Copy link
Contributor

I wonder if, instead of baking proxies into the protocol, we should instead augment the protocol to make proxies possible (in case it isn't already). For example, HTTP does not have proxy specific messages, instead the proxy is a natural extension of the protocol.

FWIW, we have already implemented a websockets-to-io ACP proxy, and besides MCP-over-ACP (which we also had to emulate), the proxy works just fine. So I wonder if the benefits here could be implemented by cascading ACP commands: my-proxy foo-bar-proxy claude-code-acp.

The reason I bring this up is because extensions to ACP will push complexity to either client or agents (or both), and given ACP is a M:N protocol, any extension we push needs to be implemented either M, N, or M+N times. Unless I am misunderstanding the proposal. :)

It would be really nice if the MCP-over-ACP protocol gave you the ability to correlate an MCP request with an ACP session-id that it originates from. I'm working on some research agent proxies that would benefit from this because they want to remember some details from the originating session to know how to react.

Yes, this is a must have, as you can have multiple ACP sessions over the same channel.

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.

3 participants