Hermes.Client (hermes_mcp v0.13.0)
High-level DSL for defining MCP (Model Context Protocol) clients.
This module provides an Ecto-like interface for creating MCP clients with minimal boilerplate. By using this module, you get a fully functional MCP client with automatic supervision, transport management, and all standard MCP operations.
Usage
Define a client module:
defmodule MyApp.AnthropicClient do
use Hermes.Client,
name: "MyApp",
version: "1.0.0",
protocol_version: "2024-11-05",
capabilities: [:roots, {:sampling, list_changed?: true}]
end
Add it to your supervision tree:
children = [
{MyApp.AnthropicClient,
transport: {:stdio, command: "uvx", args: ["mcp-server-anthropic"]}}
]
Use the client:
{:ok, tools} = MyApp.AnthropicClient.list_tools()
{:ok, result} = MyApp.AnthropicClient.call_tool("search", %{query: "elixir"})
Options
The use
macro accepts the following required options:
:name
- The client name to advertise to the server (string):version
- The client version (string):protocol_version
- The MCP protocol version (string):capabilities
- List of client capabilities (see below)
Capabilities
Capabilities can be specified as:
- Atoms:
:roots
,:sampling
- Tuples with options:
{:roots, list_changed?: true}
- Maps for custom capabilities:
%{"custom" => %{"feature" => true}}
Transport Configuration
When starting the client, you must provide transport configuration:
{:stdio, command: "cmd", args: ["arg1", "arg2"]}
{:sse, base_url: "http://localhost:8000"}
{:websocket, url: "ws://localhost:8000/ws"}
{:streamable_http, url: "http://localhost:8000/mcp"}
Process Naming
By default, the client process is registered with the module name.
You can override this with the :name
option in child_spec
or start_link
:
# Custom atom name
{MyApp.AnthropicClient, name: :my_custom_client, transport: ...}
# For distributed systems with registries (e.g., Horde)
{MyApp.AnthropicClient,
name: {:via, Horde.Registry, {MyCluster, "client_1"}},
transport_name: {:via, Horde.Registry, {MyCluster, "transport_1"}},
transport: ...}
When using via tuples or other non-atom names, you must explicitly provide
the :transport_name
option. For atom names, the transport is automatically
named as Module.concat(ClientName, "Transport")
.
Summary
Functions
Generates an MCP client module with all necessary functions.
Guard to check if an atom is a valid client capability.
Guard to check if a capability is supported by checking map keys.
Types
@type capabilities() :: [capability() | {capability(), capability_opts()} | map()]
@type capability() :: :roots | :sampling
@type capability_opts() :: [{:list_changed?, boolean()}]
Functions
Generates an MCP client module with all necessary functions.
This macro is used via the use
directive and accepts the following options:
:name
- Client name (required, string):version
- Client version (required, string):protocol_version
- MCP protocol version (required, string):capabilities
- List of capabilities (optional, defaults to empty list)
The macro generates:
child_spec/1
- For supervision tree integrationstart_link/1
- To start the client- All MCP operation functions (ping, list_tools, call_tool, etc.)
Guard to check if an atom is a valid client capability.
Guard to check if a capability is supported by checking map keys.