ExMCP.ACP.Client (ex_mcp v1.0.0-rc.0)

View Source

GenServer client for the Agent Client Protocol (ACP).

Manages connections to ACP-compatible coding agents over stdio, handling the initialize handshake, session lifecycle, and bidirectional communication (streaming updates from agent, permission/file requests from agent).

Usage

{:ok, client} = ExMCP.ACP.Client.start_link(
  command: ["gemini", "--acp"],
  handler: MyApp.ACPHandler
)

{:ok, %{"sessionId" => sid}} = ExMCP.ACP.Client.new_session(client, "/path/to/project")
{:ok, %{"stopReason" => _}} = ExMCP.ACP.Client.prompt(client, sid, "Fix the bug in auth.ex")

Options

  • :command — command list for the agent subprocess (required)
  • :handler — module implementing ExMCP.ACP.Client.Handler (default: DefaultHandler)
  • :handler_opts — options passed to handler.init/1 (default: [])
  • :event_listener — PID to receive {:acp_session_update, session_id, update} messages
  • :client_info%{"name" => ..., "version" => ...} (default: %{"name" => "ex_mcp", "version" => "0.1.0"})
  • :capabilities — client capabilities map
  • :protocol_version — integer (default: 1)
  • :name — GenServer name registration

Summary

Functions

Returns the agent's capabilities from the initialize handshake.

Returns the agent's authentication methods from the initialize handshake.

Cancels the current prompt in a session (fire-and-forget).

Returns a specification to start this module under a supervisor.

Closes an active session and frees agent-side resources.

Deletes a session from the agent's session history.

Disconnects from the agent.

Forks an existing session into a new independent session.

Lists available sessions from the agent. Stabilized in ACP spec March 9, 2026.

Loads an existing session and replays previous messages when the agent supports it.

Logs out of the current authenticated state if the agent supports auth.logout.

Creates a new agent session.

Sends a prompt to the agent and blocks until the response arrives.

Resumes an existing session without replaying previous messages.

Sets a config option for a session.

Sets the agent mode for a session.

Sets the model for a session.

Starts the ACP client and connects to the agent.

Returns the client connection status.

Functions

agent_capabilities(client)

@spec agent_capabilities(GenServer.server()) :: {:ok, map() | nil}

Returns the agent's capabilities from the initialize handshake.

auth_methods(client)

@spec auth_methods(GenServer.server()) :: {:ok, [map()]}

Returns the agent's authentication methods from the initialize handshake.

authenticate(client, method_id_or_params \\ %{}, opts \\ [])

@spec authenticate(GenServer.server(), String.t() | map(), keyword()) ::
  {:ok, map() | nil} | {:error, any()}

Authenticates with the agent.

Pass either a method ID advertised in the initialize response's "authMethods" list or a full params map for adapter compatibility.

cancel(client, session_id)

@spec cancel(GenServer.server(), String.t()) :: :ok

Cancels the current prompt in a session (fire-and-forget).

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

close_session(client, session_id, opts \\ [])

@spec close_session(GenServer.server(), String.t(), keyword()) ::
  {:ok, map() | nil} | {:error, any()}

Closes an active session and frees agent-side resources.

delete_session(client, session_id, opts \\ [])

@spec delete_session(GenServer.server(), String.t(), keyword()) ::
  {:ok, map() | nil} | {:error, any()}

Deletes a session from the agent's session history.

disconnect(client)

@spec disconnect(GenServer.server()) :: :ok

Disconnects from the agent.

end_session(client, session_id)

@spec end_session(GenServer.server(), String.t()) ::
  :ok | {:ok, map() | nil} | {:error, any()}

Ends a session.

Uses session/close when advertised by the agent, otherwise preserves the historical local telemetry-only behavior.

fork_session(client, session_id, cwd, opts \\ [])

@spec fork_session(GenServer.server(), String.t(), String.t(), keyword()) ::
  {:ok, map() | nil} | {:error, any()}

Forks an existing session into a new independent session.

session/fork is currently unstable in ACP and requires the agent to advertise sessionCapabilities.fork.

list_sessions(client, opts \\ [])

@spec list_sessions(
  GenServer.server(),
  keyword()
) :: {:ok, map()} | {:error, any()}

Lists available sessions from the agent. Stabilized in ACP spec March 9, 2026.

load_session(client, session_id, cwd, opts \\ [])

@spec load_session(GenServer.server(), String.t(), String.t(), keyword()) ::
  {:ok, map()} | {:error, any()}

Loads an existing session and replays previous messages when the agent supports it.

cwd is required per ACP spec.

logout(client, opts \\ [])

@spec logout(
  GenServer.server(),
  keyword()
) :: {:ok, map() | nil} | {:error, any()}

Logs out of the current authenticated state if the agent supports auth.logout.

new_session(client, cwd, opts \\ [])

@spec new_session(GenServer.server(), String.t(), keyword()) ::
  {:ok, map()} | {:error, any()}

Creates a new agent session.

cwd is required per ACP spec (https://agentclientprotocol.com/protocol/session-setup).

prompt(client, session_id, content, opts \\ [])

@spec prompt(GenServer.server(), String.t(), String.t() | [map()], keyword()) ::
  {:ok, map()} | {:error, any()}

Sends a prompt to the agent and blocks until the response arrives.

Streaming session/update notifications are delivered to the handler and event listener as they arrive. The caller is unblocked when the agent sends the JSON-RPC result for the prompt request.

resume_session(client, session_id, cwd, opts \\ [])

@spec resume_session(GenServer.server(), String.t(), String.t(), keyword()) ::
  {:ok, map() | nil} | {:error, any()}

Resumes an existing session without replaying previous messages.

cwd is required per ACP spec.

set_config_option(client, session_id, config_id, value)

@spec set_config_option(GenServer.server(), String.t(), String.t(), any()) ::
  {:ok, map()} | {:error, any()}

Sets a config option for a session.

set_mode(client, session_id, mode_id)

@spec set_mode(GenServer.server(), String.t(), String.t()) ::
  {:ok, map()} | {:error, any()}

Sets the agent mode for a session.

set_model(client, session_id, model_id)

@spec set_model(GenServer.server(), String.t(), String.t()) ::
  {:ok, map()} | {:error, any()}

Sets the model for a session.

start_link(opts)

@spec start_link(keyword()) :: GenServer.on_start()

Starts the ACP client and connects to the agent.

status(client)

@spec status(GenServer.server()) :: atom()

Returns the client connection status.