
こんにちは、サーバーサイドエンジニアのnissyiです。スマートバンク 新春エンジニア駅伝 2026の第十三区走者として襷を繋いでいきます。第十二区は、yokomiiさんによる「Navigation 3 の Shared ViewModel の実現方法について考える」でした。ぜひ、こちらもご覧ください。
私ごとですが、最近はClaude Codeをたくさん活用していて、Claude Codeなしじゃ仕事ができない体になってきました。そこである日、「自作のGUIアプリにもClaude Codeを組み込んで活用しよう!」と思い立ったのですが、Claude CodeとGUIアプリの連携を実現するにはどうしたらいいのかわからず、手が止まってしまいました。
私は普段、Zedを使用しているのですが、ZedではネイティブUI上でClaude Codeとの連携が可能です。あの連携はどのように実現しているのでしょう?
ZedとClaude Codeの連携について調べてみると、Agent Client Protocolというものが一役買っていることに辿り着きました。このProtocolはZed以外にもJetBrains系のIDEやNeovim、ObsidianのプラグインといったClientに活用されていたり、Claude Code以外のAgent(Gemini CLIなど)も対応していたりします。
今回は、このプロトコルと、ACPを使ってClaude Codeと対話できるclaude-code-acpについて紹介します。
Agent Client Protocol とは
Agent Client Protocol(以下、ACP)は、エディタと AI エージェントの通信を標準化するオープンプロトコルです。ACPに則ることで、エディタ対AIエージェント間における個別のカスタマイズ実装などの手間を省けるようになります。
なお、AIエージェント関連のプロトコルには他にModel Context Protocol(MCP)、Agent-to-Agent Protocol(A2A)などのプロトコルや、MCP Appsなどの拡張仕様もあります。これらの違いについて簡単に整理すると以下のようになります。
| プロトコル・実装 | 主な用途 | 提唱者 |
|---|---|---|
| ACP | エディタとエージェントの連携 | Anthropic |
| A2A | マルチエージェント間の協調 | |
| MCP | エージェントの能力を拡張 | Anthropic |
| MCP-UI | MCP Apps の先駆けとなった実装 | Ido Salomon, Liad Yosef |
| OpenAI Apps SDK | ChatGPT 内で UI を表示するためのSDK | OpenAI |
| MCP Apps | MCP に UI 機能を追加する公式拡張仕様(2026-01-21時点ではドラフト) | MCP-UI(Ido Salomon, Liad Yosef) + Anthropic + OpenAI |
ACPとしては、「ユーザーは主にエディターを使用しており、特定のタスクを支援するためにエージェントにアクセスして使用したいと考えているもの」と想定されているそうです。
ACP assumes that the user is primarily in their editor, and wants to reach out and use agents to assist them with specific tasks.
また、ローカル環境のエージェントとリモート環境のエージェントへの対応を目指しているそうです。(リモート環境のエージェント対応は開発中とのこと。)
- Local agents run as sub-processes of the code editor, communicating via JSON-RPC over stdio.
- Remote agents can be hosted in the cloud or on separate infrastructure, communicating over HTTP or WebSocket
Note: Full support for remote agents is a work in progress. We are actively collaborating with agentic platforms to ensure the protocol addresses the specific requirements of cloud-hosted and remote deployment scenarios.
ローカルのエージェントを使用する場合は、エディタがエージェントをサブプロセスとして起動し、標準入出力を経由したJSON-RPCで通信します。
通信フロー
通信のフローについて簡単に説明します。ここまでは「エディタ」「エージェント」という語句を使用してきましたが、それぞれ「client」「agent」と呼ぶようにします。
基本的な通信フローは以下のステップです。
1. Initialization Phase
まず、 "initialize" で接続を確立します。(必要な場合は、 “authenticate” で認証します。)
2. Session Setup
"session/new" で新しいセッションを開始するか、もしくは "session/load" で既存のセッションを再開します。
3. Prompt turn
client側は "session/prompt" で新たなメッセージを送信します。agentは "session/update" でNotificationを送信します。
…文章だけで読むより、動作の流れを見れた方が理解に役立ちそうです。次は、claude-code-acpを使ってClaude CodeとACPに則ったやりとりをしてみましょう!
claude-code-acp とは
claude-code-acpは、Claude Code SDKをACP形式に変換するアダプターです。Zed Industries が開発し、Apache License 2.0でオープンソース公開されています。
Claude Codeは公式でACPに対応していないため、claude-code-acpを用いてACPを体験してみます。
体験してみる
1. installと起動
READMEを参考に、npmを用いてinstallします。
npm install -g @zed-industries/claude-code-acp
次に、npxを用いて起動します。起動後は、特に何も表示されていないような状態になりますが、こちらからRPCを送信できる状態になっています。
[~/acp] % npx @zed-industries/claude-code-acp // 何も表示されていないがRPC待ちの状態
2. initialize
早速ですが、Claude CodeとACPでの接続を確立してみましょう。最初は以下のようなJSONを送信します。
{ "jsonrpc": "2.0", "id": 0, "method": "initialize", "params": { "protocolVersion": 1 } }
ですが、このままではJSON-RPCとして使用できないので、単一行にします。*1
{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"protocolVersion":1}}
これをターミナル上でペースト + Enterすると送信され、応答が返ってきます。私の手元では以下の応答が返ってきました。
{"jsonrpc":"2.0","id":0,"result":{"protocolVersion":1,"agentCapabilities":{"promptCapabilities":{"image":true,"embeddedContext":true},"mcpCapabilities":{"http":true,"sse":true},"sessionCapabilities":{"fork":{},"resume":{}}},"agentInfo":{"name":"@zed-industries/claude-code-acp","title":"Claude Code","version":"0.13.1"},"authMethods":[{"description":"Run `claude /login` in the terminal","name":"Log in with Claude Code","id":"claude-login"}]}}
3. session/new
次は新たなセッションを開始するために、以下のJSONを使用します。
{ "jsonrpc": "2.0", "id": 1, "method": "session/new", "params": { "cwd": "/Users/y-onishi/acp", "mcpServers":[] } }
こちらを送信すると、私の手元では以下の二つの応答が返ってきました。Claude Codeが使用可能なmodelやmode、カスタムスラッシュコマンドといった情報が含まれています。
{"jsonrpc":"2.0","id":1,"result":{"sessionId":"12e1fe46-xxxx...","models":{"availableModels":[{"modelId":"default","name":"Default (recommended)","description":"Opus 4.5 · Most capable for complex work"},{"modelId":"sonnet","name":"Sonnet","description":"Sonnet 4.5 · Best for everyday tasks"},{"modelId":"haiku","name":"Haiku","description":"Haiku 4.5 · Fastest for quick answers"}],"currentModelId":"default"},"modes":{"currentModeId":"default","availableModes":[{"id":"default","name":"Default","description":"Standard behavior, prompts for dangerous operations"},{"id":"acceptEdits","name":"Accept Edits","description":"Auto-accept file edit operations"},{"id":"plan","name":"Plan Mode","description":"Planning mode, no actual tool execution"},{"id":"dontAsk","name":"Don't Ask","description":"Don't prompt for permissions, deny if not pre-approved"},{"id":"bypassPermissions","name":"Bypass Permissions","description":"Bypass all permission checks"}]}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"12e1fe46-xxxx...","update":{"sessionUpdate":"available_commands_update","availableCommands":[{"name":"compact","description":"Clear conversation history but keep a summary in context. Optional: /compact [instructions for summarization]","input":{"hint":"<optional custom summarization instructions>"}},{"name":"init","description":"Initialize a new CLAUDE.md file with codebase documentation","input":null},{"name":"pr-comments","description":"Get comments from a GitHub pull request","input":null},{"name":"review","description":"Review a pull request","input":null},{"name":"security-review","description":"Complete a security review of the pending changes on the current branch","input":null}]}}}
1つ目の応答に含まれている ”sessionId” は次でも使用します。
4. session/prompt
次はpromptを送信してみましょう。先ほどの応答で得られた”sessionId”を使用して、次のようなJSONを組み立てます。
{ "jsonrpc": "2.0", "id": 2, "method": "session/prompt", "params": { "sessionId": "12e1fe46-xxxx...", "prompt": [{ "type": "text", "text": "hello,world!" }] } }
こちらを送信すると、Claude Codeから応答が返ってきます。少々読みづらいですが、「こんにちは!何かお手伝いできることはありますか?」と書かれていますね。
{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"12e1fe46-xxxx...","update":{"sessionUpdate":"agent_message_chunk","content":{"type":"text","text":""}}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"12e1fe46-xxxx...","update":{"sessionUpdate":"agent_message_chunk","content":{"type":"text","text":"こ"}}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"12e1fe46-xxxx...","update":{"sessionUpdate":"agent_message_chunk","content":{"type":"text","text":"んにちは!"}}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"12e1fe46-xxxx...","update":{"sessionUpdate":"agent_message_chunk","content":{"type":"text","text":"何"}}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"12e1fe46-xxxx...","update":{"sessionUpdate":"agent_message_chunk","content":{"type":"text","text":"かお手伝いできること"}}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"12e1fe46-xxxx...","update":{"sessionUpdate":"agent_message_chunk","content":{"type":"text","text":"は"}}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"12e1fe46-xxxx...","update":{"sessionUpdate":"agent_message_chunk","content":{"type":"text","text":"ありますか?"}}}} {"jsonrpc":"2.0","id":2,"result":{"stopReason":"end_turn"}}
これでAPCを用いたClaude Codeとの対話ができました!なお、ここまでに使用したJSONスキーマの詳細については以下に書かれています。興味がある方はぜひご覧ください。
まとめ
今回はAgent Client ProtocolとACPを通じたClaude Codeとの対話について紹介しました。このように規格が定まったりエコシステムが発展していくと、開発の手間を減らしつつも活用の幅が広がって嬉しいですね!
私はRubyからACPを活用したいと思い、Rubyのclientの開発に挑戦してみようかなと思っています。この話はまたどこかでできたらと思います。
明日の駅伝第十四区走者はSREのcapytanさんです。皆さんお楽しみに〜!
*1:以降は単一行のサンプルを省略します。