README.md

# EMCP

An minimal Elixir MCP (Model Context Protocol) server.

## Limitations (for now)

- **No resources or prompts.** Only tools are supported.

## Usage

### 1. Define a tool

```elixir
defmodule MyApp.Tools.Echo do
  @behaviour EMCP.Tool

  @impl EMCP.Tool
  def name, do: "echo"

  @impl EMCP.Tool
  def description, do: "Echoes back the provided message"

  @impl EMCP.Tool
  def input_schema do
    %{
      type: :object,
      properties: %{
        message: %{type: :string},
        count: %{type: :integer},
        temperature: %{type: :number},
        verbose: %{type: :boolean},
        tags: %{type: :array, items: %{type: :string}},
        options: %{
          type: :object,
          properties: %{
            format: %{type: :string}
          }
        }
      },
      required: [:message]
    }
  end

  @impl EMCP.Tool
  def call(%{"message" => message}) do
    EMCP.Tool.response([%{"type" => "text", "text" => message}])
  end

  # Return errors with:
  # EMCP.Tool.error("something went wrong")
end
```

### 2. Configure the server

```elixir
# config/config.exs
config :emcp,
  name: "my-app",
  version: "1.0.0",
  tools: [MyApp.Tools.Echo]
```

### 3. Mount the transport

Add the StreamableHTTP transport to your Phoenix router. Mount it outside any pipeline since EMCP handles content negotiation itself:

```elixir
scope "/mcp" do
  forward "/", EMCP.Transport.StreamableHTTP
end
```

Sessions are managed automatically with a configurable TTL (default 60 minutes):

```elixir
config :emcp, session_ttl: to_timeout(minute: 60)
```

## STDIO Transport

For local development or CLI tools, you can use the STDIO transport instead. It reads JSON-RPC messages from stdin and writes responses to stdout.

Add it to your supervision tree:

```elixir
children = [
  EMCP.Transport.STDIO
]
```

Configure it in Claude Code via `.claude/settings.json`:

```json
{
  "mcpServers": {
    "my-app": {
      "command": "mix",
      "args": ["run", "--no-halt"],
      "cwd": "/path/to/your/elixir/project"
    }
  }
}
```

## Acknowledgements

Based on the official [Ruby MCP SDK](https://github.com/modelcontextprotocol/ruby-sdk) reference implementation.

## Development

The e2e tests use the [MCP Inspector](https://github.com/modelcontextprotocol/inspector) CLI. Install it before running tests:

```bash
cd test/inspector && bun install
```

Then run the tests:

```bash
mix test
```