# `Urchin.Server`
[🔗](https://github.com/urth-inc/urchin/blob/v0.4.0/lib/urchin/server.ex#L1)

Behaviour and DSL for authoring MCP servers.

There are two ways to define a server:

## DSL

    defmodule Demo do
      use Urchin.Server, name: "demo", version: "1.0.0"

      tool "echo",
        description: "Echo the message back",
        input_schema: %{
          "type" => "object",
          "properties" => %{"message" => %{"type" => "string"}},
          "required" => ["message"]
        } do
        {:ok, [Urchin.Content.text(args["message"])]}
      end

      resource "config://app", name: "config", mime_type: "application/json" do
        {:ok, [Urchin.Content.text_resource("config://app", ~s({"ok":true}))]}
      end

      prompt "greet", arguments: [%{name: "name", required: true}] do
        {:ok, [Urchin.Prompt.user_message(Urchin.Content.text("Hello " <> args["name"]))]}
      end
    end

Inside a `tool`/`prompt` block the bindings `args` (the decoded arguments map) and
`ctx` (an `Urchin.Context`) are available. Inside a `resource`/`resource_template`
block only `ctx` is available; for templates `ctx.uri` and `ctx.params` are set.

Capabilities are derived automatically from the declared features.

Duplicate literal tool names declared via the DSL are rejected at compile time (non-literal
names cannot be compared statically and are not checked). Urchin enforces no tool-name pattern
(the MCP schema imposes none); servers should still follow the MCP naming recommendations (a
conservative charset, a length bound, no whitespace).

## Behaviour

Implement the callbacks directly for full control or stateful servers. All
callbacks except `c:server_info/0` are optional; a feature is considered supported
only when its callbacks are implemented (or declared via the DSL).

## Handler return values

  * `list_*` callbacks: `{:ok, items}` or `{:ok, items, next_cursor}`
  * `call_tool/3`: `{:ok, content}`, `{:ok, content, opts}` (with `:structured_content`
    / `:is_error`), an `Urchin.Result.CallTool` struct, or `{:error, reason}`
  * `read_resource/2`: `{:ok, contents}` or `{:error, reason}`
  * `get_prompt/3`: `{:ok, messages}` or `{:ok, messages, description}`

For every callback, a returned or raised `Urchin.Error` becomes that JSON-RPC error. A
`call_tool/3` handler's `{:error, binary}` is surfaced as a `CallToolResult` with `isError: true`
so the model can self-correct, as is a tool that raises any other exception. For the other
callbacks an `{:error, binary}` becomes a JSON-RPC internal error and any other raised exception
becomes an internal error.

# `call_result`

```elixir
@type call_result() ::
  {:ok, [map()]}
  | {:ok, [map()], keyword()}
  | {:ok, Urchin.Result.CallTool.t()}
  | {:error, Urchin.Error.t() | String.t()}
```

# `cursor`

```elixir
@type cursor() :: String.t() | nil
```

# `list_result`

```elixir
@type list_result(item) ::
  {:ok, [item]}
  | {:ok, [item], cursor()}
  | {:error, Urchin.Error.t() | String.t()}
```

# `call_tool`
*optional* 

```elixir
@callback call_tool(name :: String.t(), args :: map(), Urchin.Context.t()) ::
  call_result()
```

# `capabilities`
*optional* 

```elixir
@callback capabilities() :: map()
```

# `complete`
*optional* 

```elixir
@callback complete(
  ref :: map(),
  argument :: map(),
  completion_context :: map(),
  Urchin.Context.t()
) :: {:ok, map()} | {:error, Urchin.Error.t() | String.t()}
```

# `get_prompt`
*optional* 

```elixir
@callback get_prompt(name :: String.t(), args :: map(), Urchin.Context.t()) ::
  {:ok, [map()]}
  | {:ok, [map()], String.t() | nil}
  | {:error, Urchin.Error.t() | String.t()}
```

# `init`
*optional* 

```elixir
@callback init(arg :: term()) :: {:ok, term()} | {:error, term()}
```

# `instructions`
*optional* 

```elixir
@callback instructions() :: String.t() | nil
```

# `list_prompts`
*optional* 

```elixir
@callback list_prompts(cursor(), Urchin.Context.t()) :: list_result(Urchin.Prompt.t())
```

# `list_resource_templates`
*optional* 

```elixir
@callback list_resource_templates(cursor(), Urchin.Context.t()) ::
  list_result(Urchin.ResourceTemplate.t())
```

# `list_resources`
*optional* 

```elixir
@callback list_resources(cursor(), Urchin.Context.t()) :: list_result(Urchin.Resource.t())
```

# `list_tools`
*optional* 

```elixir
@callback list_tools(cursor(), Urchin.Context.t()) :: list_result(Urchin.Tool.t())
```

# `read_resource`
*optional* 

```elixir
@callback read_resource(uri :: String.t(), Urchin.Context.t()) ::
  {:ok, [map()]} | {:error, Urchin.Error.t() | String.t()}
```

# `server_info`

```elixir
@callback server_info() :: map()
```

# `set_log_level`
*optional* 

```elixir
@callback set_log_level(level :: String.t(), Urchin.Context.t()) :: :ok | {:error, term()}
```

# `subscribe_resource`
*optional* 

```elixir
@callback subscribe_resource(uri :: String.t(), Urchin.Context.t()) ::
  :ok | {:error, term()}
```

# `unsubscribe_resource`
*optional* 

```elixir
@callback unsubscribe_resource(uri :: String.t(), Urchin.Context.t()) ::
  :ok | {:error, term()}
```

# `prompt`
*macro* 

Declares a prompt. The `do` block receives `args` and `ctx` bindings and must return
a `get_prompt/3` result.

# `resource`
*macro* 

Declares a static resource. The `do` block receives `ctx` (with `ctx.uri` set) and
must return a `read_resource/2` result. Defaults `:name` to the URI.

# `resource_template`
*macro* 

Declares a resource template (RFC 6570). The `do` block receives `ctx` with
`ctx.uri` and `ctx.params` (extracted template variables). Defaults `:name` to the
template.

# `tool`
*macro* 

Declares a tool. The `do` block receives `args` and `ctx` bindings and must return
a `call_tool/3` result.

Options beyond the `Urchin.Tool` fields:

  * `:scopes` - OAuth scopes the caller must hold (checked against `ctx.auth`) before
    the handler runs. The call fails with an error when the scopes are missing, including
    when the request carries no authorization.

---

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