Hermes.Client.Base (hermes_mcp v0.10.0)
A GenServer implementation of an MCP (Model Context Protocol) client.
This module handles the client-side implementation of the MCP protocol, including initialization, request/response handling, and maintaining protocol state.
Notes
For initialization and setup, check our Installation & Setup and the Client Usage guides for reference.
Summary
Types
MCP client capabilities
MCP client metadata info
MCP client initialization options
MCP client transport options
Functions
Adds a root directory to the client's roots list.
Calls a tool on the server.
Cancels all pending requests.
Cancels an in-progress request.
Returns a specification to start this module under a supervisor.
Clears all root directories.
Closes the client connection and terminates the process.
Requests autocompletion suggestions for prompt arguments or resource URIs.
Gets a specific prompt from the server.
Gets the server's capabilities as reported during initialization.
Gets the server's information as reported during initialization.
Lists available prompts from the server.
Lists available resources from the server.
Gets a list of all root directories.
Lists available tools from the server.
Merges additional capabilities into the client's capabilities.
Sends a ping request to the server to check connection health. Returns :pong
if successful.
Reads a specific resource from the server.
Registers a callback function to be called when log messages are received.
Registers a callback function to be called when progress notifications are received for the specified progress token.
Removes a root directory from the client's roots list.
Sends a batch of operations to the server.
Sends a progress notification to the server for a long-running operation.
Sets the minimum log level for the server to send log messages.
Starts a new MCP client process.
Unregisters a previously registered log callback.
Unregisters a previously registered progress callback for the specified token.
Types
@type capabilities() :: %{ optional(:roots | String.t()) => %{ optional(:listChanged | String.t()) => boolean() }, optional(:sampling | String.t()) => %{} }
MCP client capabilities
:roots
- Capabilities related to the roots resource:listChanged
- Whether the client can handle listChanged notifications
:sampling
- Capabilities related to sampling
MCP describes these client capabilities on it specification
@type client_info() :: %{ required(:name | String.t()) => String.t(), optional(:version | String.t()) => String.t() }
MCP client metadata info
:name
- The name of the client (required):version
- The version of the client
@type option() :: {:name, GenServer.name()} | {:transport, transport()} | {:client_info, map()} | {:capabilities, map()} | {:protocol_version, String.t()} | GenServer.option()
MCP client initialization options
:name
- Following theGenServer
patterns described on "Name registration".:transport
- The MCP transport options:client_info
- Information about the client:capabilities
- Client capabilities to advertise to the MCP server:protocol_version
- Protocol version to use (defaults to "2024-11-05")
Any other option support by GenServer
.
@type t() :: GenServer.server()
@type transport() :: [ layer: Hermes.Transport.STDIO | Hermes.Transport.SSE | Hermes.Transport.WebSocket | Hermes.Transport.StreamableHTTP, name: GenServer.server() ]
MCP client transport options
:layer
- The transport layer to use, eitherHermes.Transport.STDIO
,Hermes.Transport.SSE
,Hermes.Transport.WebSocket
, orHermes.Transport.StreamableHTTP
(required):name
- The transport optional custom name
Functions
Adds a root directory to the client's roots list.
Parameters
client
- The client processuri
- The URI of the root directory (must start with "file://")name
- Optional human-readable name for the rootopts
- Additional options:timeout
- Request timeout in milliseconds
Examples
iex> Hermes.Client.add_root(client, "file:///home/user/project", "My Project")
:ok
@spec call_tool(t(), String.t(), map() | nil, keyword()) :: {:ok, Hermes.MCP.Response.t()} | {:error, Hermes.MCP.Error.t()}
Calls a tool on the server.
Options
:timeout
- Request timeout in milliseconds:progress
- Progress tracking options:token
- A unique token to track progress (string or integer):callback
- A function to call when progress updates are received
@spec cancel_all_requests(t(), String.t(), opts :: Keyword.t()) :: {:ok, [Hermes.Client.Request.t()]} | {:error, Hermes.MCP.Error.t()}
Cancels all pending requests.
Parameters
client
- The client processreason
- Optional reason for cancellation (defaults to "client_cancelled")
Returns
{:ok, requests}
- A list of the Request structs that were cancelled{:error, reason}
- If an error occurred
@spec cancel_request(t(), String.t(), String.t(), opts :: Keyword.t()) :: :ok | {:error, Hermes.MCP.Error.t()}
Cancels an in-progress request.
Parameters
client
- The client processrequest_id
- The ID of the request to cancelreason
- Optional reason for cancellation
Returns
:ok
if the cancellation was successful{:error, reason}
if an error occurred{:not_found, request_id}
if the request ID was not found
Returns a specification to start this module under a supervisor.
See Supervisor
.
Clears all root directories.
Parameters
client
- The client processopts
- Additional options:timeout
- Request timeout in milliseconds
Examples
iex> Hermes.Client.clear_roots(client)
:ok
@spec close(t()) :: :ok
Closes the client connection and terminates the process.
@spec complete(t(), map(), map(), keyword()) :: {:ok, Hermes.MCP.Response.t()} | {:error, Hermes.MCP.Error.t()}
Requests autocompletion suggestions for prompt arguments or resource URIs.
Parameters
client
- The client processref
- Reference to what is being completed (required)- For prompts:
%{"type" => "ref/prompt", "name" => prompt_name}
- For resources:
%{"type" => "ref/resource", "uri" => resource_uri}
- For prompts:
argument
- The argument being completed (required)%{"name" => arg_name, "value" => current_value}
opts
- Additional options:timeout
- Request timeout in milliseconds:progress
- Progress tracking options:token
- A unique token to track progress (string or integer):callback
- A function to call when progress updates are received
Returns
Returns {:ok, response}
with completion suggestions if successful, or {:error, reason}
if an error occurs.
The response result contains a "completion" object with:
values
- List of completion suggestions (maximum 100)total
- Optional total number of matching itemshasMore
- Boolean indicating if more results are available
Examples
# Get completion for a prompt argument
ref = %{"type" => "ref/prompt", "name" => "code_review"}
argument = %{"name" => "language", "value" => "py"}
{:ok, response} = Hermes.Client.complete(client, ref, argument)
# Access the completion values
values = get_in(Response.unwrap(response), ["completion", "values"])
@spec get_prompt(t(), String.t(), map() | nil, keyword()) :: {:ok, Hermes.MCP.Response.t()} | {:error, Hermes.MCP.Error.t()}
Gets a specific prompt from the server.
Options
:timeout
- Request timeout in milliseconds:progress
- Progress tracking options:token
- A unique token to track progress (string or integer):callback
- A function to call when progress updates are received
Gets the server's capabilities as reported during initialization.
Returns nil
if the client has not been initialized yet.
Gets the server's information as reported during initialization.
Returns nil
if the client has not been initialized yet.
@spec list_prompts( t(), keyword() ) :: {:ok, Hermes.MCP.Response.t()} | {:error, Hermes.MCP.Error.t()}
Lists available prompts from the server.
Options
:cursor
- Pagination cursor for continuing a previous request:timeout
- Request timeout in milliseconds:progress
- Progress tracking options:token
- A unique token to track progress (string or integer):callback
- A function to call when progress updates are received
@spec list_resources( t(), keyword() ) :: {:ok, Hermes.MCP.Response.t()} | {:error, Hermes.MCP.Error.t()}
Lists available resources from the server.
Options
:cursor
- Pagination cursor for continuing a previous request:timeout
- Request timeout in milliseconds:progress
- Progress tracking options:token
- A unique token to track progress (string or integer):callback
- A function to call when progress updates are received
@spec list_roots(t(), opts :: Keyword.t()) :: [Hermes.Client.State.root()]
Gets a list of all root directories.
Parameters
client
- The client processopts
- Additional options:timeout
- Request timeout in milliseconds
Examples
iex> Hermes.Client.list_roots(client)
[%{uri: "file:///home/user/project", name: "My Project"}]
@spec list_tools( t(), keyword() ) :: {:ok, Hermes.MCP.Response.t()} | {:error, Hermes.MCP.Error.t()}
Lists available tools from the server.
Options
:cursor
- Pagination cursor for continuing a previous request:timeout
- Request timeout in milliseconds:progress
- Progress tracking options:token
- A unique token to track progress (string or integer):callback
- A function to call when progress updates are received
Merges additional capabilities into the client's capabilities.
@spec ping( t(), keyword() ) :: :pong | {:error, Hermes.MCP.Error.t()}
Sends a ping request to the server to check connection health. Returns :pong
if successful.
Options
:timeout
- Request timeout in milliseconds (default: 30s):progress
- Progress tracking options:token
- A unique token to track progress (string or integer):callback
- A function to call when progress updates are received
@spec read_resource(t(), String.t(), keyword()) :: {:ok, Hermes.MCP.Response.t()} | {:error, Hermes.MCP.Error.t()}
Reads a specific resource from the server.
Options
:timeout
- Request timeout in milliseconds:progress
- Progress tracking options:token
- A unique token to track progress (string or integer):callback
- A function to call when progress updates are received
@spec register_log_callback( t(), Hermes.Client.State.log_callback(), opts :: Keyword.t() ) :: :ok
Registers a callback function to be called when log messages are received.
Parameters
client
- The client processcallback
- A function that takes three arguments: level, data, and logger name
The callback function will be called whenever a log message notification is received.
@spec register_progress_callback( t(), String.t() | integer(), Hermes.Client.State.progress_callback(), opts :: Keyword.t() ) :: :ok
Registers a callback function to be called when progress notifications are received for the specified progress token.
Parameters
client
- The client processprogress_token
- The progress token to watch for (string or integer)callback
- A function that takes three arguments: progress_token, progress, and total
The callback function will be called whenever a progress notification with the matching token is received.
Removes a root directory from the client's roots list.
Parameters
client
- The client processuri
- The URI of the root directory to removeopts
- Additional options:timeout
- Request timeout in milliseconds
Examples
iex> Hermes.Client.remove_root(client, "file:///home/user/project")
:ok
@spec send_batch(t(), [Hermes.Client.Operation.t()]) :: {:ok, ok: any(), error: Hermes.MCP.Error.t()} | {:error, Hermes.MCP.Error.t()}
Sends a batch of operations to the server.
Parameters
client
- The client processoperations
- List of Operation structs to send as a batch
Returns
{:ok, results}
- A list of results in the same order as the operations. Each result is either{:ok, response}
or{:error, error}
.{:error, reason}
- If the entire batch fails (e.g., transport error)
Example
operations = [
Operation.new(%{method: "ping", params: %{}}),
Operation.new(%{method: "tools/list", params: %{}})
]
{:ok, results} = Hermes.Client.send_batch(client, operations)
# results is a list: [{:ok, :pong}, {:ok, tools_response}]
@spec send_progress( t(), String.t() | integer(), number(), number() | nil, opts :: Keyword.t() ) :: :ok | {:error, term()}
Sends a progress notification to the server for a long-running operation.
Parameters
client
- The client processprogress_token
- The progress token provided in the original request (string or integer)progress
- The current progress value (number)total
- The optional total value for the operation (number)
Returns :ok
if notification was sent successfully, or {:error, reason}
otherwise.
@spec set_log_level(t(), String.t()) :: {:ok, Hermes.MCP.Response.t()} | {:error, Hermes.MCP.Error.t()}
Sets the minimum log level for the server to send log messages.
Parameters
client
- The client processlevel
- The minimum log level (debug, info, notice, warning, error, critical, alert, emergency)
Returns {:ok, result} if successful, {:error, reason} otherwise.
@spec start_link(Enumerable.t(option())) :: GenServer.on_start()
Starts a new MCP client process.
Unregisters a previously registered log callback.
Parameters
client
- The client processcallback
- The callback function to unregister
Unregisters a previously registered progress callback for the specified token.
Parameters
client
- The client processprogress_token
- The progress token to stop watching (string or integer)