ExMCP
โ Production Ready: ExMCP v0.7.0 is production-ready with 100% MCP compliance and comprehensive testing. The API is stable and ready for production use.
Overview
ExMCP is a comprehensive Elixir implementation of the Model Context Protocol, enabling AI models to securely interact with local and remote resources through a standardized protocol. It provides both client and server implementations with multiple transport options, including native Phoenix integration via Plug compatibility.
โจ Key Features
Protocol & Standards
- ๐ Multiple MCP Versions - Supports protocol versions 2024-11-05, 2025-03-26, 2025-06-18, and 2025-11-25
- โ 100% MCP Compliant - Full implementation of official MCP specification
- ๐ ๏ธ Complete Feature Set - Tools, Resources, Prompts, Roots, Subscriptions, Batch requests
- ๐ OAuth 2.1 Support - Complete Resource Server implementation
Performance & Reliability
- โก Ultra-fast Native BEAM - ~15ฮผs local calls with zero serialization overhead
- ๐ Auto-Reconnection - Built-in reconnection with exponential backoff
- ๐๏ธ OTP Integration - Built on solid OTP principles with supervision trees
- ๐ Progress Notifications - Track long-running operations
Integration & Flexibility
-
๐ Phoenix Plug - Native Phoenix integration with
ExMCP.HttpPlug - ๐ Multiple Transports - HTTP/SSE, stdio, and native BEAM support
- ๐ฏ Session Management - Automatic session tracking for SSE connections
- ๐ Bi-directional Communication - Servers can make requests to clients
Developer Experience
- ๐งช Well Tested - Comprehensive test suite with 2600+ tests
- ๐ Extensive Documentation - Complete guides and real-world examples
- ๐ง Easy Configuration - Sensible defaults with flexible customization
- ๐ก๏ธ Security First - Built-in authentication, TLS/SSL, CORS support
๐ฆ Installation
Add ex_mcp to your list of dependencies in mix.exs:
def deps do
[
{:ex_mcp, "~> 0.7.0"}
]
endThen run:
mix deps.get๐ Quick Start
Phoenix Integration (Recommended)
Add MCP server capabilities to your Phoenix app:
# In your Phoenix router (lib/my_app_web/router.ex)
defmodule MyAppWeb.Router do
use MyAppWeb, :router
pipeline :mcp do
plug :accepts, ["json"]
# Add your authentication/authorization here
end
scope "/api/mcp" do
pipe_through :mcp
# Mount MCP server at /api/mcp
forward "/", ExMCP.HttpPlug,
handler: MyApp.MCPHandler,
server_info: %{name: "my-phoenix-app", version: "1.0.0"},
sse_enabled: true,
cors_enabled: true
end
end
# Create your MCP handler (lib/my_app/mcp_handler.ex)
defmodule MyApp.MCPHandler do
use ExMCP.Server.Handler
@impl true
def init(_args), do: {:ok, %{}}
@impl true
def handle_initialize(_params, state) do
{:ok, %{
name: "my-phoenix-app",
version: "1.0.0",
capabilities: %{tools: %{}, resources: %{}}
}, state}
end
@impl true
def handle_list_tools(state) do
tools = [
%{
name: "get_user_count",
description: "Get total number of users",
input_schema: %{type: "object", properties: %{}}
}
]
{:ok, tools, state}
end
@impl true
def handle_call_tool("get_user_count", _args, state) do
count = MyApp.Accounts.count_users()
{:ok, [%{type: "text", text: "Total users: #{count}"}], state}
end
endConnect from any MCP client:
mcp connect http://localhost:4000/api/mcpDSL Server (Quickest Way)
Define tools, resources, and prompts declaratively:
defmodule MyServer do
use ExMCP.Server
deftool "greet" do
description "Greets a person by name"
args do
field :name, :string, required: true, description: "Person to greet"
end
end
defresource "info://about" do
name "About"
description "Server information"
mime_type "text/plain"
end
@impl true
def handle_tool_call("greet", %{"name" => name}, state) do
{:ok, %{content: [text("Hello, #{name}!")]}, state}
end
@impl true
def handle_resource_read("info://about", _uri, state) do
{:ok, [text("MyServer v1.0")], state}
end
endSee the DSL Guide and examples/ for more patterns.
Standalone MCP Client
# Connect to a stdio-based server
{:ok, client} = ExMCP.Client.start_link(
transport: :stdio,
command: ["node", "my-mcp-server.js"]
)
# List available tools
{:ok, tools} = ExMCP.Client.list_tools(client)
# Call a tool
{:ok, result} = ExMCP.Client.call_tool(client, "search", %{
query: "Elixir programming",
limit: 10
})Ultra-Fast Native BEAM Services
For trusted Elixir clusters, use the native BEAM transport:
# Create a service using the ExMCP.Service macro
defmodule MyToolService do
use ExMCP.Service, name: :my_tools
@impl true
def handle_mcp_request("list_tools", _params, state) do
tools = [
%{
"name" => "ping",
"description" => "Test tool",
"inputSchema" => %{"type" => "object", "properties" => %{}}
}
]
{:ok, %{"tools" => tools}, state}
end
@impl true
def handle_mcp_request("tools/call", %{"name" => "ping"}, state) do
{:ok, %{"content" => [%{"type" => "text", "text" => "Pong!"}]}, state}
end
end
# Start your service (automatically registers with ExMCP.Native)
{:ok, _} = MyToolService.start_link()
# Direct service calls (~15ฮผs latency)
{:ok, tools} = ExMCP.Native.call(:my_tools, "list_tools", %{})๐ Documentation
ExMCP provides comprehensive documentation organized for different needs:
๐ Getting Started
- Quick Start Guide - Get running in 5 minutes
- Quick Reference - One-page operation reference
- Migration Guide - Version upgrade instructions
๐ Comprehensive Guides
- User Guide - Complete feature walkthrough with examples
- Phoenix Integration Guide - Detailed Phoenix/Plug integration
- Configuration Guide - All configuration options and examples
- Transport Guide - Transport selection and optimization
- Security Guide - Authentication, TLS, and security best practices
๐ง Development & API
- Development Guide - Setup, testing, and contributing
- API Documentation - Complete API reference
- Architecture Guide - Internal architecture and design decisions
- Examples - Real-world implementation patterns
๐ Protocol & Specifications
- MCP Specifications - Complete protocol documentation for all versions
- Protocol Support Matrix - Feature comparison across versions
๐ฏ Transport Performance
| Transport | Latency | Best For | Use Case |
|---|---|---|---|
| Native BEAM | ~15ฮผs | Internal services | Elixir cluster communication |
| stdio | ~1-5ms | External tools | Subprocess communication |
| HTTP/SSE | ~5-20ms | Network clients | Web applications, remote APIs |
โจ What's New in v0.7.0
- MCP 2025-11-25 Support: Latest protocol version with full spec compliance
- Streamable HTTP: Spec-compliant client and server (session IDs, SSE path, protocol version headers)
- TypeScript SDK Interop: Verified interoperability with the official TypeScript MCP SDK
- Client State Machine: Refactored client with GenStateMachine for better observability
- Agent Simulation Tests: Integration tests with MockLLM for agent workflows
- Conformance Suites: Automated conformance tests for all 4 protocol versions
See the CHANGELOG for complete details and breaking changes.
๐ค Contributing
We welcome contributions! Please see:
- Development Guide for setup and testing instructions
- CHANGELOG.md for version history
- GitHub Issues for bug reports and feature requests
Before contributing:
- Fork the repository
- Create a feature branch
-
Run
make qualityto ensure code quality - Submit a pull request
๐ License
This project is licensed under the MIT License - see the LICENSE file for details.
๐ Acknowledgments
- The Model Context Protocol specification creators
- The Elixir community for excellent tooling and libraries
- Contributors and early adopters providing feedback