Both are thin layers of newline-delimited JSON that let one program drive another, and both exist so nobody has to write a custom integration for every pair of tools. This page shows what each protocol connects, what actually travels over the wire, and where the two plug into each other inside a coding agent.
Read the original MCP introduction ↗Before any standard existed, connecting an AI application to an external service meant writing bespoke glue for each pair: one integration for your editor talking to one agent, another for that agent talking to GitHub, a third for the database, and so on. With N applications and M tools, the work grows as N × M. Both MCP and ACP attack this multiplication, but at different layers of the stack. [Introduction]
MCP (Model Context Protocol) connects an AI application to external systems: files, databases, APIs, browsers. Its own documentation calls it "a USB-C port for AI applications." ACP (Agent Client Protocol) connects a code editor to an autonomous coding agent: the program that reads your repository, plans edits, runs commands, and reports back. [ACP introduction]
Underneath, both are dialects of JSON-RPC 2.0, a minimal messaging rule: every message is a UTF-8 JSON object that is either a request (carries an id and a method, expects a response echoing that id), a response (carries the same id plus a result or error), or a notification (no id, one-way, never answered). Nothing else is required: no schemas in the envelope, no session tokens, no streaming format. [JSON-RPC]
| Dimension | MCP | ACP |
|---|---|---|
| Connects | AI app ↔ tools and data | Editor ↔ coding agent |
| Core unit | Tool, resource, prompt (stateless calls) | Session: a long, stateful conversation turn |
| Who calls whom | Client sends requests; server answers (recent spec: servers do not initiate requests) | Bidirectional: agent sends streaming notifications and can call the editor back |
| Origin | Anthropic, open-sourced November 2024 | Zed, in collaboration with Google, 2025 |
| Analogy | USB-C for peripherals | LSP (Language Server Protocol), but for agents |
MCP standardizes the tool plane; ACP standardizes the conversation plane. An agent that codes uses both at once, which is why they are easy to confuse.
An MCP deployment has three roles. The host is the AI application (Claude Code, VS Code, ChatGPT). For every configured server the host instantiates one client, and each client holds a dedicated connection to one server — the program that actually knows how to touch the filesystem, query the database, or call an API. [Architecture]
How that connection works is the transport layer, and there are exactly two standard answers. Stdio: the host spawns the server as a child process and writes one JSON-RPC message per line into its stdin; the server replies on stdout, also one message per line, and may write human-oriented logs to stderr, which the host may capture or ignore. There is no network, no port, no handshake beyond the protocol itself. Streamable HTTP: each message is an HTTP POST to a single MCP endpoint, with the reply arriving either as a plain JSON object or as a request-scoped text/event-stream for long-running work; authentication rides on standard HTTP headers. Protocol semantics are identical on both bindings — only framing and delivery change. [Transport spec]
Message direction is deliberately asymmetric: clients send requests and notifications, servers send responses and notifications, and nothing else exists. Cancellation follows the binding — a notifications/cancelled message on stdio, closing the response stream on HTTP. [Transport spec]
The data layer defines what the messages mean. Servers expose three primitives: tools (executable functions with a JSON Schema for arguments — the ones the model decides to call), resources (readable data such as a file's contents or a database schema), and prompts (reusable templates for structuring conversations). Each has discovery methods (tools/list, resources/list), and tools add tools/call for execution. Clients discover what a server supports with server/discover, which returns the supported protocol versions and a capabilities object, for example {"tools": {"listChanged": true}}. Every later request also carries the protocol version and the client's own capabilities in a metadata field, so the design can treat requests as self-contained. [Architecture]
A concrete turn looks like this — first the listing, then one call:
--> {"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}
<- {"jsonrpc":"2.0","id":2,"result":{"tools":[
{"name":"weather_current","description":"Current weather...",
"inputSchema":{"type":"object","properties":
{"location":{"type":"string"}},"required":["location"]}}]}}
--> {"jsonrpc":"2.0","id":3,"method":"tools/call",
"params":{"name":"weather_current","arguments":{"location":"San Francisco"}}}
<- {"jsonrpc":"2.0","id":3,"result":{"content":[
{"type":"text","text":"68°F, partly cloudy..."}]}}
Tool results are arrays of typed content blocks — text, images, embedded resources — not bare strings, so a server can return a screenshot next to a sentence. Servers can also announce change: after a client opens a subscription stream asking for toolsListChanged, the server emits a one-way notifications/tools/list_changed whenever its tool set changes, and the client reacts by listing again. [Architecture]
ACP's setup is simpler to state: the editor boots the agent as a subprocess on demand, and everything flows over stdin/stdout as newline-delimited JSON. Messages must not contain embedded newlines; stdout carries nothing but valid ACP messages; stderr is free for logs. One connection multiplexes several concurrent sessions, so two threads of thought can run side by side. [ACP transports]
Every connection begins with an initialize request. The client names the newest protocol version it knows (a single integer — breaking changes bump it) and its capabilities, such as whether it can serve file reads, file writes, and terminal methods. The agent answers with the version it will speak and its own capabilities: whether it can load old sessions, and what content its prompts accept (text always; images, audio, embedded context optionally). If the two cannot agree on a version, the client closes the connection and tells the user. [Initialization]
--> {"jsonrpc":"2.0","id":0,"method":"initialize","params":{
"protocolVersion":1,
"clientCapabilities":{"fs":{"readTextFile":true,"writeTextFile":true},
"terminal":true}}}
<- {"jsonrpc":"2.0","id":0,"result":{"protocolVersion":1,
"agentCapabilities":{"loadSession":true,
"promptCapabilities":{"image":true}}}}
Then comes the shape that makes ACP different from MCP: a prompt turn. The client sends session/prompt with content blocks; that single request stays open — a pending JSON-RPC request — while the agent streams progress back as session/update notifications, each tagged with a variant field. The variants are the editor's UI vocabulary: agent_message_chunk (streamed answer text), agent_thought_chunk (reasoning), tool_call and tool_call_update (a tool appearing, moving to in_progress, finishing with content), plan (the to-do list the agent is following), usage_update (tokens used and dollars spent), plus mode, slash-command, and session metadata updates. Only when the work ends does the agent answer the original request with a stopReason such as end_turn, max_tokens, refusal, or cancelled. [Prompt turn]
Two design choices carry most of ACP's weight. First, traffic is bidirectional. While the prompt request is pending, the agent can issue its own requests back to the editor: session/request_permission before running a dangerous command, fs/read_text_file and fs/write_text_file to touch the workspace through the editor rather than directly, terminal/create to run shell commands in a managed pane, and elicitation/create to ask the user a structured question. The agent never needs its own filesystem privileges — the editor is the gatekeeper. [ACP overview]
Second, interruption is first-class. The client may send session/cancel at any moment; it then marks unfinished tool calls as cancelled and answers any pending permission requests with a cancelled outcome, while the agent must abort model calls and in-flight tools and — critically — must convert whatever exception its libraries throw into the meaningful cancelled stop reason, because editors display raw errors to users. [Prompt turn]
An ACP agent is typically also an MCP client. When the editor forwards your prompt, it passes along the configuration of the MCP servers you have set up, and the agent connects to them itself — that is how your filesystem, Sentry, or Postgres tools become visible to a Gemini or Claude agent running under ACP. If the editor wants to offer its own tools to such an agent, it does not try to run MCP and ACP on one socket: it starts a small MCP server proxy that tunnels MCP requests back to the editor. [ACP architecture]
ACP was also built to reuse MCP's homework: it is JSON-RPC-based and re-uses MCP's JSON types wherever possible so integrators do not maintain two representations of the same content, and agents advertise their MCP transport support (http, sse) during initialization. [ACP architecture] [Initialization]
| Choose | When | Cost |
|---|---|---|
| MCP | You are exposing a capability (query, read, act) to any AI application | No notion of a conversation; you manage state yourself |
| ACP | You are building an editor UI over a stateful, streaming, permission-asking agent | Heavier session machinery; smaller ecosystem than MCP |
| Both | Every serious coding agent: ACP to the editor, MCP to the tools | Two specs to keep up with |
The pattern is the opposite of each other: MCP began as one company's protocol and spent a year buying neutrality through a foundation; ACP began as one editor's protocol and grew by getting rival editors and agents to adopt it — its ecosystem now lists Zed, JetBrains, VS Code, Emacs and Neovim as clients, and Claude, Codex, Gemini CLI and others as agents. [Zed ACP]
| From | Relation | To |
|---|---|---|
| Pipes and subprocesses | enables | stdio transport in both protocols |
| JSON-RPC 2.0 | formalized-by (from the protocol's view) | MCP and ACP message format |
| LSP precedent | enables | ACP's editor/agent split |
| Primitives | part-of | MCP data layer |
| Capability negotiation | part-of | MCP discovery and ACP initialize |
| Session updates | part-of | ACP prompt turn |
| ACP | requires | MCP (agents consume MCP tool servers) |
| MCP | enables | tool registries and connectors |
| ACP | enables | editor-agnostic agents |
| MCP | contrasts-with | ACP (tool plane vs conversation plane) |
Edges follow the descriptions in the MCP architecture overview and the ACP architecture page. [Architecture] [ACP architecture]
Three limits deserve explicit words. First, the moving target: MCP's revision history is aggressive — recent versions moved to per-request metadata and deprecated server-initiated requests such as model sampling, and ACP's v2 draft would restructure the prompt lifecycle and permission model, so any wire-level detail here should be re-checked against the current spec before you implement it. [Transport spec] [v2 draft] Second, remote ACP is unfinished: stdio dominates both protocols today, and ACP's own documentation marks streamable HTTP for agents as a draft in progress, so cloud-hosted agents are not yet a first-class story. [ACP transports] Third, this page assumes trust it does not examine: ACP is explicitly designed for an editor talking to a model you trust, where the editor hands the agent filesystem and MCP access; the permission requests are the control surface, and how strictly an implementation gates them is a security question this page does not answer. [ACP architecture] Also out of scope: model quality, prompt design, and any performance comparison — the protocols only guarantee delivery of messages, not what the model does with them. [Architecture]