ClaudeCode.MCP.Server (ClaudeCode v0.36.3)

View Source

Macro 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
end

Generated Module Structure

Each tool block generates a nested module (e.g., MyApp.Tools.Add) that:

  • Uses Anubis.Server.Component with type: :tool
  • Has a schema block for Peri-validated input parameters
  • Has input_schema/0 returning JSON Schema (via Anubis Component)
  • Has execute/2 accepting (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 only
  • def execute(params, frame) — receives params and Anubis.Server.Frame.t() (access assigns via frame.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

description(text)

(macro)

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

sdk_server?(module)

@spec sdk_server?(module()) :: boolean()

Checks if the given module was defined using ClaudeCode.MCP.Server.

Returns true if the module exports __tool_server__/0, false otherwise.

to_error_response(msg)

@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.

to_response(v)

@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.

tool(name, list)

(macro)

Defines a tool within a ClaudeCode.MCP.Server module.

Parameters

  • name - atom name for the tool (e.g., :add)
  • block - the tool body containing a description, optional field declarations, and a def execute function

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

wrap_result(result, frame)

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.