# `ExMCP.ACP.Types`
[🔗](https://github.com/azmaveth/ex_mcp/blob/v1.0.0/lib/ex_mcp/acp/types.ex#L1)

Type specifications and builder functions for the Agent Client Protocol (ACP).

ACP uses JSON-RPC 2.0 as its wire format (same as MCP). All types are plain maps
matching the ex_mcp convention — no structs for protocol types.

## Content Blocks

ACP supports text and image content blocks in prompts and responses:

    text_block("Hello, world!")
    image_block("image/png", "base64data...")

## Session Management

Sessions track agent conversations. Create with `new_session_params/2`,
send prompts with `prompt_params/2`.

# `agent_capabilities`

```elixir
@type agent_capabilities() :: %{
  optional(:auth) =&gt; %{optional(:logout) =&gt; map() | nil},
  optional(:loadSession) =&gt; boolean(),
  optional(:promptCapabilities) =&gt; %{
    optional(:image) =&gt; boolean(),
    optional(:audio) =&gt; boolean(),
    optional(:embeddedContext) =&gt; boolean()
  },
  optional(:mcpCapabilities) =&gt; %{
    optional(:acp) =&gt; boolean(),
    optional(:http) =&gt; boolean(),
    optional(:sse) =&gt; boolean(),
    optional(:_meta) =&gt; map()
  },
  optional(:sessionCapabilities) =&gt; %{
    optional(:list) =&gt; session_list_capabilities() | nil,
    optional(:resume) =&gt; session_resume_capabilities() | nil,
    optional(:close) =&gt; session_close_capabilities() | nil,
    optional(:delete) =&gt; session_delete_capabilities() | nil,
    optional(:fork) =&gt; session_fork_capabilities() | nil,
    optional(:additionalDirectories) =&gt; map() | nil
  }
}
```

# `agent_info`

```elixir
@type agent_info() :: %{
  :name =&gt; String.t(),
  :version =&gt; String.t(),
  optional(:title) =&gt; String.t()
}
```

# `agent_message_chunk_update`

```elixir
@type agent_message_chunk_update() :: %{
  sessionUpdate: :agent_message_chunk,
  content: content_block()
}
```

# `agent_thought_chunk_update`

```elixir
@type agent_thought_chunk_update() :: %{
  sessionUpdate: :agent_thought_chunk,
  content: content_block()
}
```

# `audio_block`

```elixir
@type audio_block() :: %{type: :audio, mimeType: String.t(), data: String.t()}
```

# `auth_method`

```elixir
@type auth_method() :: %{
  :id =&gt; String.t(),
  :name =&gt; String.t(),
  optional(:description) =&gt; String.t(),
  optional(:type) =&gt; String.t()
}
```

# `available_commands_update`

```elixir
@type available_commands_update() :: %{
  sessionUpdate: :available_commands_update,
  availableCommands: [map()]
}
```

# `client_capabilities`

```elixir
@type client_capabilities() :: %{
  optional(:fs) =&gt; %{
    optional(:readTextFile) =&gt; boolean(),
    optional(:writeTextFile) =&gt; boolean()
  },
  optional(:terminal) =&gt; boolean()
}
```

# `client_info`

```elixir
@type client_info() :: %{
  :name =&gt; String.t(),
  :version =&gt; String.t(),
  optional(:title) =&gt; String.t()
}
```

# `close_session_request`

```elixir
@type close_session_request() :: %{sessionId: String.t()}
```

# `config_option`

```elixir
@type config_option() :: %{
  :id =&gt; String.t(),
  :name =&gt; String.t(),
  :type =&gt; String.t(),
  :currentValue =&gt; String.t(),
  :options =&gt; list(),
  optional(:description) =&gt; String.t(),
  optional(:category) =&gt; String.t()
}
```

# `config_option_update`

```elixir
@type config_option_update() :: %{
  sessionUpdate: :config_option_update,
  configOptions: [config_option()]
}
```

# `content_block`

```elixir
@type content_block() ::
  text_block()
  | image_block()
  | audio_block()
  | resource_link_block()
  | resource_block()
```

# `current_mode_update`

```elixir
@type current_mode_update() :: %{
  sessionUpdate: :current_mode_update,
  currentModeId: String.t()
}
```

# `delete_session_request`

```elixir
@type delete_session_request() :: %{sessionId: String.t()}
```

# `embedded_resource`

```elixir
@type embedded_resource() ::
  %{:uri =&gt; String.t(), :text =&gt; String.t(), optional(:mimeType) =&gt; String.t()}
  | %{
      :uri =&gt; String.t(),
      :blob =&gt; String.t(),
      optional(:mimeType) =&gt; String.t()
    }
```

# `env_variable`

```elixir
@type env_variable() :: %{name: String.t(), value: String.t()}
```

# `file_read_request`

```elixir
@type file_read_request() :: %{
  :sessionId =&gt; String.t(),
  :path =&gt; String.t(),
  optional(:line) =&gt; non_neg_integer(),
  optional(:limit) =&gt; non_neg_integer()
}
```

# `file_write_request`

```elixir
@type file_write_request() :: %{
  sessionId: String.t(),
  path: String.t(),
  content: String.t()
}
```

# `fork_session_request`

```elixir
@type fork_session_request() :: %{
  :sessionId =&gt; String.t(),
  :cwd =&gt; String.t(),
  optional(:mcpServers) =&gt; [mcp_server()],
  optional(:additionalDirectories) =&gt; [String.t()]
}
```

# `fork_session_response`

```elixir
@type fork_session_response() :: %{
  :sessionId =&gt; String.t(),
  optional(:modes) =&gt; map() | nil,
  optional(:configOptions) =&gt; [config_option()] | nil
}
```

# `http_header`

```elixir
@type http_header() :: %{name: String.t(), value: String.t()}
```

# `http_mcp_server`

```elixir
@type http_mcp_server() :: %{
  type: :http,
  name: String.t(),
  url: String.t(),
  headers: [http_header()]
}
```

# `image_block`

```elixir
@type image_block() :: %{type: :image, mimeType: String.t(), data: String.t()}
```

# `initialize_request`

```elixir
@type initialize_request() :: %{
  :clientInfo =&gt; client_info(),
  optional(:clientCapabilities) =&gt; client_capabilities(),
  optional(:protocolVersion) =&gt; pos_integer()
}
```

# `initialize_response`

```elixir
@type initialize_response() :: %{
  :agentInfo =&gt; agent_info(),
  optional(:agentCapabilities) =&gt; agent_capabilities(),
  optional(:authMethods) =&gt; [auth_method()],
  optional(:protocolVersion) =&gt; pos_integer()
}
```

# `list_sessions_request`

```elixir
@type list_sessions_request() :: %{
  optional(:cursor) =&gt; String.t(),
  optional(:cwd) =&gt; String.t()
}
```

# `list_sessions_response`

```elixir
@type list_sessions_response() :: %{
  :sessions =&gt; [session_info()],
  optional(:nextCursor) =&gt; String.t()
}
```

# `load_session_request`

```elixir
@type load_session_request() :: %{
  :sessionId =&gt; String.t(),
  :cwd =&gt; String.t(),
  :mcpServers =&gt; [mcp_server()],
  optional(:additionalDirectories) =&gt; [String.t()]
}
```

# `mcp_server`

```elixir
@type mcp_server() :: stdio_mcp_server() | http_mcp_server() | sse_mcp_server()
```

# `mode`

```elixir
@type mode() :: %{
  :id =&gt; String.t(),
  :name =&gt; String.t(),
  optional(:description) =&gt; String.t()
}
```

# `new_session_request`

```elixir
@type new_session_request() :: %{
  :cwd =&gt; String.t(),
  :mcpServers =&gt; [mcp_server()],
  optional(:additionalDirectories) =&gt; [String.t()]
}
```

# `new_session_response`

```elixir
@type new_session_response() :: %{sessionId: String.t()}
```

# `permission_option`

```elixir
@type permission_option() :: %{
  :optionId =&gt; String.t(),
  :name =&gt; String.t(),
  :kind =&gt; String.t(),
  optional(:description) =&gt; String.t()
}
```

# `permission_outcome`

```elixir
@type permission_outcome() :: %{
  :outcome =&gt; String.t(),
  optional(:optionId) =&gt; String.t()
}
```

# `permission_request`

```elixir
@type permission_request() :: %{
  sessionId: String.t(),
  toolCall: tool_call_info(),
  options: [permission_option()]
}
```

# `plan`

```elixir
@type plan() :: %{sessionUpdate: :plan, entries: [plan_entry()]}
```

# `plan_entry`

```elixir
@type plan_entry() :: %{
  content: String.t(),
  priority: :high | :medium | :low,
  status: :pending | :in_progress | :completed
}
```

# `prompt_request`

```elixir
@type prompt_request() :: %{sessionId: String.t(), prompt: [content_block()]}
```

# `prompt_response`

```elixir
@type prompt_response() :: %{stopReason: String.t()}
```

# `resource_block`

```elixir
@type resource_block() :: %{type: :resource, resource: embedded_resource()}
```

# `resource_link_block`

```elixir
@type resource_link_block() :: %{
  :type =&gt; :resource_link,
  :uri =&gt; String.t(),
  :name =&gt; String.t(),
  optional(:mimeType) =&gt; String.t(),
  optional(:title) =&gt; String.t(),
  optional(:description) =&gt; String.t(),
  optional(:size) =&gt; non_neg_integer()
}
```

# `resume_session_request`

```elixir
@type resume_session_request() :: %{
  :sessionId =&gt; String.t(),
  :cwd =&gt; String.t(),
  optional(:mcpServers) =&gt; [mcp_server()],
  optional(:additionalDirectories) =&gt; [String.t()]
}
```

# `session_close_capabilities`

```elixir
@type session_close_capabilities() :: map()
```

# `session_delete_capabilities`

```elixir
@type session_delete_capabilities() :: map()
```

# `session_fork_capabilities`

```elixir
@type session_fork_capabilities() :: map()
```

# `session_info`

```elixir
@type session_info() :: %{
  :sessionId =&gt; String.t(),
  :cwd =&gt; String.t(),
  optional(:title) =&gt; String.t(),
  optional(:updatedAt) =&gt; String.t(),
  optional(:additionalDirectories) =&gt; [String.t()]
}
```

# `session_info_update`

```elixir
@type session_info_update() :: %{
  :sessionUpdate =&gt; :session_info_update,
  optional(:title) =&gt; String.t(),
  optional(:updatedAt) =&gt; String.t()
}
```

# `session_list_capabilities`

```elixir
@type session_list_capabilities() :: map()
```

# `session_resume_capabilities`

```elixir
@type session_resume_capabilities() :: map()
```

# `session_update`

```elixir
@type session_update() ::
  user_message_chunk_update()
  | agent_message_chunk_update()
  | agent_thought_chunk_update()
  | tool_call()
  | tool_call_update()
  | plan()
  | available_commands_update()
  | config_option_update()
  | current_mode_update()
  | session_info_update()
  | usage_update()
```

# `session_update_params`

```elixir
@type session_update_params() :: %{sessionId: String.t(), update: session_update()}
```

# `sse_mcp_server`

```elixir
@type sse_mcp_server() :: %{
  type: :sse,
  name: String.t(),
  url: String.t(),
  headers: [http_header()]
}
```

# `stdio_mcp_server`

```elixir
@type stdio_mcp_server() :: %{
  type: :stdio,
  name: String.t(),
  command: String.t(),
  args: [String.t()],
  env: [env_variable()]
}
```

# `text_block`

```elixir
@type text_block() :: %{type: :text, text: String.t()}
```

# `tool_call`

```elixir
@type tool_call() :: %{
  :sessionUpdate =&gt; :tool_call,
  :toolCallId =&gt; String.t(),
  :title =&gt; String.t(),
  optional(:status) =&gt; String.t(),
  optional(:content) =&gt; [map()]
}
```

# `tool_call_info`

```elixir
@type tool_call_info() :: %{
  :toolName =&gt; String.t(),
  optional(:toolCallId) =&gt; String.t(),
  optional(:arguments) =&gt; map()
}
```

# `tool_call_update`

```elixir
@type tool_call_update() :: %{
  :sessionUpdate =&gt; :tool_call_update,
  :toolCallId =&gt; String.t(),
  optional(:title) =&gt; String.t(),
  optional(:status) =&gt; String.t(),
  optional(:content) =&gt; [map()]
}
```

# `usage_update`

```elixir
@type usage_update() :: %{
  :sessionUpdate =&gt; :usage_update,
  :used =&gt; non_neg_integer(),
  :size =&gt; non_neg_integer(),
  optional(:cost) =&gt; map()
}
```

# `user_message_chunk_update`

```elixir
@type user_message_chunk_update() :: %{
  sessionUpdate: :user_message_chunk,
  content: content_block()
}
```

# `agent_capabilities`

```elixir
@spec agent_capabilities(keyword()) :: map()
```

Creates ACP agent capabilities.

Supported options: `:load_session`, `:acp_mcp`, `:http_mcp`, `:sse_mcp`,
`:beam_mcp`, `:image`, `:audio`, `:embedded_context`,
`:session_list`, `:session_resume`, `:session_close`, `:session_delete`,
`:session_fork`, `:additional_directories`, and `:logout`.

# `audio_block`

```elixir
@spec audio_block(String.t(), String.t(), keyword()) :: map()
```

Creates an audio content block.

# `auth_method`

```elixir
@spec auth_method(String.t(), String.t(), keyword()) :: map()
```

Creates an authentication method advertised by an agent.

# `auth_required_code`

```elixir
@spec auth_required_code() :: integer()
```

Error code indicating authentication is required.

# `available_commands_update`

```elixir
@spec available_commands_update(String.t(), [map()]) :: map()
```

Creates an available_commands_update session update notification.

# `client_info`

```elixir
@spec client_info(String.t(), String.t(), keyword()) :: map()
```

Creates client info for the initialize handshake.

# `config_option_update`

```elixir
@spec config_option_update(String.t(), [map()]) :: map()
```

Creates a config_option_update session update notification.

# `config_option_value`

```elixir
@spec config_option_value(String.t(), String.t(), keyword()) :: map()
```

Creates a config option value for select-style session config.

# `current_mode_update`

```elixir
@spec current_mode_update(String.t(), String.t()) :: map()
```

Creates a current_mode_update session update notification.

# `env_variable`

```elixir
@spec env_variable(String.t(), String.t()) :: map()
```

Creates an environment variable entry for a stdio MCP server.

# `http_header`

```elixir
@spec http_header(String.t(), String.t()) :: map()
```

Creates an HTTP header entry for a Streamable HTTP MCP server.

# `http_mcp_server`

```elixir
@spec http_mcp_server(String.t(), String.t(), keyword()) :: map()
```

Creates an HTTP MCP server config for ACP session setup.

# `image_block`

```elixir
@spec image_block(String.t(), String.t(), keyword()) :: map()
```

Creates an image content block.

# `new_session_params`

```elixir
@spec new_session_params(
  String.t(),
  keyword()
) :: map()
```

Creates params for a new session request.

## Options

- `:mcp_servers` - list of MCP server maps, preferably from
  `stdio_mcp_server/3`, `http_mcp_server/3`, or `sse_mcp_server/3`
- `:additional_directories` - extra absolute workspace root paths

# `plan`

```elixir
@spec plan(String.t(), [map()]) :: map()
```

Creates a stable ACP `plan` session update notification.

# `plan_entry`

```elixir
@spec plan_entry(String.t(), String.t(), String.t()) :: map()
```

Creates a plan entry.

# `plan_update`

```elixir
@spec plan_update(String.t(), [map()]) :: map()
```

Creates a stable ACP `plan` session update notification.

# `prompt_params`

```elixir
@spec prompt_params(String.t(), String.t() | [map()]) :: map()
```

Creates params for a prompt request.

Content can be a string (auto-wrapped as text block) or a list of content block maps.

# `request_cancelled_code`

```elixir
@spec request_cancelled_code() :: integer()
```

Error code indicating a request was cancelled.

# `resource_block`

```elixir
@spec resource_block(
  String.t(),
  keyword()
) :: map()
```

Creates a resource content block.

# `resource_link_block`

```elixir
@spec resource_link_block(
  String.t(),
  keyword()
) :: map()
```

Creates a resource link content block.

# `resource_not_found_code`

```elixir
@spec resource_not_found_code() :: integer()
```

Error code indicating a resource was not found.

# `select_config_option`

```elixir
@spec select_config_option(String.t(), String.t(), String.t(), [map()], keyword()) ::
  map()
```

Creates a select-style session config option.

# `session_capabilities`

```elixir
@spec session_capabilities(keyword()) :: map()
```

Creates session capability metadata.

# `session_info`

```elixir
@spec session_info(String.t(), String.t(), keyword()) :: map()
```

Creates a session info entry returned by session/list.

# `session_info_update`

```elixir
@spec session_info_update(
  String.t(),
  keyword()
) :: map()
```

Creates a session_info_update session update notification.

# `sse_mcp_server`

```elixir
@spec sse_mcp_server(String.t(), String.t(), keyword()) :: map()
```

Creates an SSE MCP server config for ACP session setup.

# `stdio_mcp_server`

```elixir
@spec stdio_mcp_server(String.t(), String.t(), keyword()) :: map()
```

Creates a stdio MCP server config for ACP session setup.

# `text_block`

```elixir
@spec text_block(
  String.t(),
  keyword()
) :: map()
```

Creates a text content block.

# `usage_update`

```elixir
@spec usage_update(String.t(), non_neg_integer(), non_neg_integer(), keyword()) ::
  map()
```

Creates a usage_update session update notification.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
