# `Anubis.Server.Component`

The DSL behind `use Anubis.Server.Component`.

A component is one addressable piece of an MCP server: a tool, a prompt
or a resource. `use Anubis.Server.Component` injects the callbacks for
whichever type you pass, so you only write the part that is yours (the
`execute/2`, `get_messages/2` or `read/2` implementation) plus the schema.

    defmodule MyApp.Tools.Search do
      use Anubis.Server.Component, type: :tool, name: "search", title: "Search"

      schema do
        field(:query, :string, description: "What to look for")
      end

      @impl true
      def execute(%{"query" => query}, frame) do
        {:reply, Response.text(Response.tool(), MyApp.search(query)), frame}
      end
    end

## Options

`:type` is required and must be `:tool`, `:prompt` or `:resource`. The
options below are accepted by all three types, plus the ones each
behaviour documents.

  * `:name` - the wire name. Defaults to the module basename for
    resources, `nil` otherwise.
  * `:title` - a human-readable label.
  * `:description` - defaults to the module `@moduledoc`.
  * `:annotations` - behaviour-specific hints (`readOnlyHint`,
    `destructiveHint`, ...).
  * `:meta` - arbitrary `_meta` on the tool or resource descriptor.
  * `:icons` - icons rendered by supporting clients.
  * `:scopes` - authorization scopes required to see this component.

Resources additionally take `:uri` or `:uri_template` (mutually
exclusive) and `:mime_type`. Tools additionally take `:task_support`
(`:forbidden`, `:optional` or `:required`).

## Schemas

`schema/1` and `output_schema/1` wrap a Peri schema and compile it at
build time, so the JSON Schema handed to clients is derived from the
same source that validates arguments:

    schema do
      field(:query, :string, description: "What to look for")
      field(:limit, :integer, default: 10)
    end

See `Anubis.Server.Component.Tool`, `.Prompt` and `.Resource` for the
callbacks each type must implement, and the *Building a Server* guide
for end-to-end examples.

# `component?`

Checks if a module is a valid component.

## Parameters
  * `module` - The module atom to check

## Returns
  * `true` if the module uses `Anubis.Server.Component`
  * `false` otherwise

## Examples

    iex> defmodule MyTool do
    ...>   use Anubis.Server.Component, type: :tool
    ...> end
    iex> Anubis.Server.Component.component?(MyTool)
    true

    iex> defmodule NotAComponent do
    ...>   def hello, do: :world
    ...> end
    iex> Anubis.Server.Component.component?(NotAComponent)
    false

# `embeds_many`
*macro* 

Defines a field that embeds many objects (array of objects).

## Examples

    embeds_many :users, description: "List of users" do
      field :id, :string, required: true, description: "User ID"
      field :name, :string, description: "User name"
    end

    embeds_many :tags, required: true do
      field :name, :string, required: true
      field :value, :string
    end

# `embeds_one`
*macro* 

Defines a field that embeds one object.

## Examples

    embeds_one :user, description: "User object" do
      field :id, :string, required: true, description: "User ID"
      field :name, :string, description: "User name"
    end

    embeds_one :address, required: true do
      field :street, :string, required: true
      field :city, :string, required: true
      field :zip, :string
    end

# `field`
*macro* 

Defines a field with metadata for JSON Schema generation.

Supports both simple fields and nested objects with their own fields.

## Examples

    # Simple field
    field :email, {:required, :string}, format: "email", description: "User's email address"
    field :age, :integer, description: "Age in years"
    
    # Nested field
    field :user do
      field :name, {:required, :string}
      field :email, :string, format: "email"
    end

    # Nested field with metadata
    field :profile, description: "User profile information" do
      field :bio, :string, description: "Short biography"
      field :avatar_url, :string, format: "uri"
    end

    # Mirrored into the Mcp-Param-Region header by 2026-07-28 clients
    field :region, :string, required: true, mcp_header: "Region"

`mcp_header:` puts `x-mcp-header` on the parameter; see
`Anubis.Server.McpParam` for the rules it must follow and how the header is
checked.

# `get_description`

Extracts the description from a component module.

## Parameters
  * `module` - The component module atom

## Returns
  * The description from `description/0` callback if defined
  * Falls back to the module's `@moduledoc` if no callback is defined
  * Empty string if neither is defined

## Examples

    iex> defmodule MyTool do
    ...>   @moduledoc "A helpful tool"
    ...>   use Anubis.Server.Component, type: :tool
    ...> end
    iex> Anubis.Server.Component.get_description(MyTool)
    "A helpful tool"

    iex> defmodule MyToolWithCallback do
    ...>   @moduledoc "Default description"
    ...>   use Anubis.Server.Component, type: :tool
    ...>   def description, do: "Custom description from callback"
    ...> end
    iex> Anubis.Server.Component.get_description(MyToolWithCallback)
    "Custom description from callback"

# `get_type`

Gets the component type (:tool, :prompt, or :resource).

## Parameters
  * `module` - The component module atom

## Returns
  * `:tool` - If the module is a tool component
  * `:prompt` - If the module is a prompt component
  * `:resource` - If the module is a resource component

## Examples

    iex> defmodule MyTool do
    ...>   use Anubis.Server.Component, type: :tool
    ...> end
    iex> Anubis.Server.Component.get_type(MyTool)
    :tool

# `output_schema`
*macro* 

Defines the output schema for a tool component.

This schema describes the expected structure of the tool's output in the
structuredContent field. Only available for tool components.

# `schema`
*macro* 

Defines the parameter schema for the component.

The schema uses Peri's validation DSL and is automatically validated
before the component's callback is executed.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
