ClaudeCode.MCP.Server (ClaudeCode v0.36.3)
View SourceMacro for generating MCP tool modules from a concise DSL.
Each tool block becomes a nested module that uses Anubis.Server.Component
with schema definitions, execute wrappers, and metadata.
Usage
defmodule MyApp.Tools do
use ClaudeCode.MCP.Server, name: "my-tools"
tool :add do
description "Add two numbers"
field :x, :integer, required: true
field :y, :integer, required: true
def execute(%{x: x, y: y}) do
{:ok, "#{x + y}"}
end
end
tool :get_time do
description "Get current UTC time"
def execute(_params) do
{:ok, DateTime.utc_now() |> to_string()}
end
end
endGenerated Module Structure
Each tool block generates a nested module (e.g., MyApp.Tools.Add) that:
- Uses Anubis.Server.Component with
type: :tool - Has a
schemablock for Peri-validated input parameters - Has
input_schema/0returning JSON Schema (via Anubis Component) - Has
execute/2accepting(params, frame)and delegating to the user's execute function
Execute Function
The user's execute function can be arity 1 or 2:
def execute(params)— receives validated params onlydef execute(params, frame)— receives params andAnubis.Server.Frame.t()(access assigns viaframe.assigns)
Return Values
The user's execute function can return:
{:ok, binary}— returned as text content{:ok, map | list}— returned as JSON content{:ok, other}— converted to string and returned as text content{:error, message}— returned as error content{:ok, value, frame}— text/JSON content with updated frame{:error, message, frame}— error content with updated frame{:noreply, frame}— no content, updated frame{:reply, %Response{}, frame}— native Anubis response (passthrough){:error, %Error{}, frame}— native Anubis error (passthrough)
Summary
Functions
Sets the description for a tool. Must be used inside a tool block.
Checks if the given module was defined using ClaudeCode.MCP.Server.
Converts an error message to an Anubis.Server.Response with isError: true.
Converts a value to an Anubis.Server.Response for a tool result.
Defines a tool within a ClaudeCode.MCP.Server module.
Translates a user's execute return value into a native Anubis response tuple.
Functions
Sets the description for a tool. Must be used inside a tool block.
The description is extracted at compile time from the AST — this macro
exists so that import makes description/1 available in tool blocks.
Example
tool :add do
description "Add two numbers"
field :x, :integer, required: true
def execute(%{x: x, y: y}) do
{:ok, "#{x + y}"}
end
end
Checks if the given module was defined using ClaudeCode.MCP.Server.
Returns true if the module exports __tool_server__/0, false otherwise.
@spec to_error_response(term()) :: Anubis.Server.Response.t()
Converts an error message to an Anubis.Server.Response with isError: true.
Used by generated execute wrappers to translate SDK error return values.
@spec to_response(term()) :: Anubis.Server.Response.t()
Converts a value to an Anubis.Server.Response for a tool result.
Used by generated execute wrappers to translate SDK return values.
Defines a tool within a ClaudeCode.MCP.Server module.
Parameters
name- atom name for the tool (e.g.,:add)block- the tool body containing adescription, optionalfielddeclarations, and adef executefunction
Examples
tool :add do
description "Add two numbers"
field :x, :integer, required: true
field :y, :integer, required: true
def execute(%{x: x, y: y}) do
{:ok, "#{x + y}"}
end
end
@spec wrap_result(term(), Anubis.Server.Frame.t()) :: {:reply, Anubis.Server.Response.t(), Anubis.Server.Frame.t()} | {:noreply, Anubis.Server.Frame.t()} | {:error, Anubis.MCP.Error.t(), Anubis.Server.Frame.t()}
Translates a user's execute return value into a native Anubis response tuple.
This is called by the generated execute/2 wrapper in each tool module.