gen_mcp is a server library for the Model Context Protocol (MCP). You define
tools, resources and prompts as plain modules, mount one HTTP plug in your
router, and clients can call them.
The transport is stateless: each request is validated and answered on its own, by a fresh server process. This guide walks through installing the library, defining a tool, mounting the server, and sending it a request.
Installation
Add the library to your dependencies and you are good to go.
defp deps do
[
{:gen_mcp, "~> 2.0"},
]
endQuick start
This guide uses the default server implementation, GenMCP.Suite, together with
the Streamable HTTP transport provided by the GenMCP.Transport.StreamableHTTP
plug. The Suite is the component model: you list your tools, resources and
prompts, and it advertises and routes them.
Define a tool
A tool is an operation a client invokes. To have something to call, define one.
This tool adds two numbers. use GenMCP.Suite.Tool generates the metadata and
argument validation from the options you pass, leaving you to implement
GenMCP.Suite.Tool.call/3.
defmodule MyApp.Tools.Addition do
use GenMCP.Suite.Tool,
name: "add",
description: "Adds two numbers and returns the sum.",
input_schema: %{
type: :object,
properties: %{
a: %{type: :number},
b: %{type: :number}
},
required: [:a, :b]
}
alias GenMCP.MCP.V2607, as: MCP
@impl true
def call(request, _channel, _arg) do
%{"a" => a, "b" => b} = request.params.arguments
{:result, MCP.call_tool_result(text: "#{a + b}")}
end
endThe :input_schema is a plain JSON Schema map, so the validated arguments reach
GenMCP.Suite.Tool.call/3 as a map with string keys, which the function body
destructures. Build the answer with the GenMCP.MCP.V2607 helpers rather than
raw structs: GenMCP.MCP.V2607.call_tool_result/1 wraps the text into a proper
result. The function returns {:result, result}.
See GenMCP.Suite.Tool for richer tools, including casting arguments into a
struct with JSV and streaming long-running work.
Mount the server
Add the GenMCP.Transport.StreamableHTTP plug to your router. You name the
server and list its tools right here, in the plug options. The default server is
the Suite, so no :server option is needed. In a Phoenix router, mount it with
forward:
defmodule MyAppWeb.Router do
use MyAppWeb, :router
scope "/mcp" do
forward "/", GenMCP.Transport.StreamableHTTP,
server_name: "My Addition Server",
server_version: "1.0.0",
tools: [MyApp.Tools.Addition]
end
endYour MCP server is now live at /mcp. :server_name and :server_version
identify the server to clients and are required. For the full set of transport
options, including origin checks and passing per-request data to handlers, see
GenMCP.Transport.StreamableHTTP.
Send a request
Any MCP client that speaks the 2026-07-28 protocol can now connect to the
endpoint and list and call your tool.
To check the installation by hand, POST a JSON-RPC message. Clients usually
start with server/discover, the capability snapshot for this protocol, but
tools/list is the simplest smoke test. This call asks the server what it
serves:
curl http://localhost:4000/mcp \
-H "Content-Type: application/json" \
-H "MCP-Protocol-Version: 2026-07-28" \
-H "Mcp-Method: tools/list" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list",
"params": {
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientInfo": {"name": "curl", "version": "1.0.0"},
"io.modelcontextprotocol/clientCapabilities": {}
}
}
}'
The response lists the add tool. To run it, switch to a tools/call message
and pass the arguments:
curl http://localhost:4000/mcp \
-H "Content-Type: application/json" \
-H "MCP-Protocol-Version: 2026-07-28" \
-H "Mcp-Method: tools/call" \
-H "Mcp-Name: add" \
-d '{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "add",
"arguments": {"a": 2, "b": 3},
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientInfo": {"name": "curl", "version": "1.0.0"},
"io.modelcontextprotocol/clientCapabilities": {}
}
}
}'
The result holds the text content "5". In practice an MCP client builds these
messages and headers for you; the raw form above is useful as a smoke test.
Next steps
- Explore
GenMCP.Suite.Toolto build richer tools, including streaming ones. - Check out
GenMCP.Suite.ResourceRepoto expose data as resources. - Use
GenMCP.Suite.PromptRepoto provide reusable prompts. - Learn about
GenMCP.Suite.Extensionto compose functionality from several modules.