Agent Client Protocol (ACP) for Elixir
Elixir implementation of the Agent Client Protocol — a standardized protocol for communication between code editors (clients) and AI coding agents over JSON-RPC 2.0.
This library is a port of the Rust agent-client-protocol and agent-client-protocol-schema crates.
Installation
Add agent_client_protocol to your list of dependencies in mix.exs:
def deps do
[
{:agent_client_protocol, "~> 0.1.0"}
]
endOverview
The library has two layers:
Schema Types
All ACP message types with JSON serialization (to_json/1 and from_json/1):
- Content —
ContentBlock,TextContent,ImageContent,AudioContent,ResourceLink,EmbeddedResource - Tool Calls —
ToolCall,ToolCallUpdate,ToolKind,ToolCallStatus,ToolCallContent - Plans —
Plan,PlanEntry - Agent Types —
InitializeRequest/Response,AuthenticateRequest/Response,NewSessionRequest/Response,LoadSessionRequest/Response,SetSessionModeRequest/Response,PromptRequest/Response,CancelNotification - Client Types —
SessionNotification,SessionUpdate,RequestPermissionRequest/Response,WriteTextFileRequest/Response,ReadTextFileRequest/Response, terminal operations - Capabilities —
AgentCapabilities,ClientCapabilities,SessionCapabilities,PromptCapabilities,McpCapabilities - MCP Servers —
McpServer(tagged union: Stdio, Http, Sse) - Extensions —
ExtRequest,ExtResponse,ExtNotification - Unstable —
SessionModelState,SessionConfigOption,ForkSessionRequest/Response,ResumeSessionRequest/Response,ListSessionsRequest/Response,ConfigOptionUpdate,SessionInfoUpdate,MaybeUndefined
SDK Layer
ACP.Agent— Behaviour for implementing an ACP agent with callbacks forinitialize,authenticate,new_session,prompt,cancel, etc.ACP.Client— Behaviour for implementing an ACP client with callbacks forrequest_permission,session_notification, file/terminal operations, etc.ACP.Connection— GenServer for bidirectional JSON-RPC 2.0 over IO streams with request/response correlationACP.ClientSideConnection/ACP.AgentSideConnection— High-level connection wrappersACP.Side— Behaviour withClientSide/AgentSideimplementations for message routing and decodingACP.StreamBroadcast— PubSub GenServer for observing protocol messages
Usage
Implementing an Agent
defmodule MyAgent do
use ACP.Agent
@impl true
def initialize(request) do
{:ok, ACP.InitializeResponse.new(ACP.ProtocolVersion.v1())}
end
@impl true
def authenticate(_request) do
{:ok, ACP.AuthenticateResponse.new()}
end
@impl true
def new_session(request) do
{:ok, ACP.NewSessionResponse.new("session-#{System.unique_integer()}")}
end
@impl true
def prompt(request) do
# Process the prompt and send session updates...
{:ok, ACP.PromptResponse.new(:end_turn)}
end
@impl true
def cancel(_notification), do: :ok
endImplementing a Client
defmodule MyClient do
use ACP.Client
@impl true
def request_permission(request) do
# Present permission options to the user...
option = hd(request.options)
{:ok, ACP.RequestPermissionResponse.new({:selected, ACP.SelectedPermissionOutcome.new(option.option_id)})}
end
@impl true
def session_notification(notification) do
IO.inspect(notification.update, label: "Session update")
:ok
end
endWorking with Types
# Create and serialize a content block
text = ACP.TextContent.new("Hello, world!")
json = ACP.ContentBlock.to_json({:text, text})
# => %{"type" => "text", "text" => "Hello, world!"}
# Deserialize
{:ok, {:text, decoded}} = ACP.ContentBlock.from_json(json)
# Session updates
update = {:agent_message_chunk, ACP.ContentChunk.new({:text, ACP.TextContent.new("Hi")})}
json = ACP.SessionUpdate.to_json(update)
# JSON-RPC messages
request = %ACP.RPC.Request{id: 1, method: "initialize", params: %{"protocolVersion" => 1}}
encoded = ACP.RPC.JsonRpcMessage.encode!(request)Protocol Compatibility
This library targets ACP schema version 0.10.6. All stable types are fully implemented. Unstable features (session fork/resume/list, model selection, config options) are included but may change with future protocol versions.
License
MIT