Packages
claude_code
0.33.1
0.36.5
0.36.4
0.36.3
0.36.2
0.36.1
0.36.0
0.35.0
0.34.0
0.33.1
0.32.2
0.32.0
0.31.0
0.30.0
0.29.0
0.28.0
0.27.0
0.26.0
0.25.0
0.24.0
0.23.0
0.22.0
0.21.0
0.20.0
0.19.0
0.18.0
0.17.0
0.16.0
0.15.0
0.14.0
0.13.3
0.13.2
0.13.1
0.13.0
0.12.0
0.11.0
0.10.0
0.9.0
0.8.1
0.8.0
0.7.0
0.6.0
0.5.0
0.4.0
0.3.0
0.2.0
0.1.0
Claude Agent SDK for Elixir – Build AI agents with Claude Code
Current section
Files
Jump to
Current section
Files
lib/claude_code/mcp/backend/hermes.ex
if Code.ensure_loaded?(Hermes.Server) do
defmodule ClaudeCode.MCP.Backend.Hermes do
@moduledoc false
@behaviour ClaudeCode.MCP.Backend
alias ClaudeCode.MCP.Server, as: MCPServer
alias Hermes.Server.Component
alias Hermes.Server.Component.Schema
alias Hermes.Server.Frame
alias Hermes.Server.Response
@impl true
def list_tools(server_module) do
%{tools: tool_modules} = server_module.__tool_server__()
Enum.map(tool_modules, fn module ->
%{
"name" => module.__tool_name__(),
"description" => module.__description__(),
"inputSchema" => module.input_schema()
}
end)
end
@impl true
def call_tool(server_module, tool_name, params, assigns) do
%{tools: tool_modules} = server_module.__tool_server__()
case Enum.find(tool_modules, &(&1.__tool_name__() == tool_name)) do
nil ->
{:error, "Tool '#{tool_name}' not found"}
module ->
atom_params = ClaudeCode.MapUtils.safe_atomize_keys(params)
case validate_params(module, atom_params) do
{:ok, validated} ->
execute_tool(module, validated, assigns)
{:error, errors} ->
error_msg = Schema.format_errors(errors)
{:validation_error, "Invalid params: #{error_msg}"}
end
end
end
@impl true
def server_info(server_module) do
%{name: name} = server_module.__tool_server__()
%{"name" => name, "version" => "1.0.0"}
end
@impl true
def compatible?(module) when is_atom(module) do
Code.ensure_loaded?(module) and
function_exported?(module, :start_link, 1) and
not MCPServer.sdk_server?(module) and
has_behaviour?(module, Hermes.Server)
end
defp has_behaviour?(module, behaviour) do
:attributes
|> module.module_info()
|> Keyword.get_values(:behaviour)
|> List.flatten()
|> Enum.member?(behaviour)
end
# -- Private helpers --
defp validate_params(module, params) do
raw_schema = module.__mcp_raw_schema__()
peri_schema = Component.__clean_schema_for_peri__(raw_schema)
Peri.validate(peri_schema, params)
end
defp execute_tool(module, params, assigns) do
frame = Frame.new(assigns)
try do
case module.execute(params, frame) do
{:reply, response, _frame} ->
{:ok, Response.to_protocol(response)}
{:error, %{message: error_msg}, _frame} ->
{:ok,
%{
"content" => [%{"type" => "text", "text" => to_string(error_msg)}],
"isError" => true
}}
end
rescue
e ->
{:ok,
%{
"content" => [%{"type" => "text", "text" => "Tool error: #{Exception.message(e)}"}],
"isError" => true
}}
end
end
end
end