AI Agent Integration (MCP)
Use earl templates as tools in AI agents via the Model Context Protocol
Earl implements a Model Context Protocol (MCP) server (protocol version 2024-11-05), letting AI agents discover and invoke your API templates as native tools.
earl mcp [stdio|http] [--mode full|discovery] [--listen ADDR] [--yes] [--allow-unauthenticated]Modes
Earl exposes templates to agents in two modes. Choose the one that fits your template library size and agent capabilities.
Full Mode
earl mcp stdio --mode fullEvery template in the catalog becomes a separate MCP tool. The agent sees all tools in its tools/list response and can call any of them directly.
Best when you have a small number of templates (under ~30) and want the agent to see everything at once.
Discovery Mode
earl mcp stdio --mode discoveryInstead of exposing every template, discovery mode registers only two meta-tools:
earl.tool_search — Find matching templates by natural-language query.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
query | string | Yes | — | Natural-language intent to match against metadata |
limit | integer | No | 10 | Maximum matches to return (1–50) |
mode | string | No | — | Filter by read or write |
provider | string | No | — | Filter by provider name (e.g., github) |
category | string | No | — | Filter by category |
Returns a ranked list of matching tools with name, score, summary, mode, categories, and the full tool schema.
earl.tool_call — Execute a discovered template tool.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
name | string | Yes | — | Exact tool name returned by earl.tool_search |
arguments | object | No | {} | Arguments for the selected template tool |
In discovery mode, the server also returns an instructions field during initialization that guides the agent to use the two-step search-then-call workflow.
Full vs Discovery Trade-offs
| Concern | Full | Discovery |
|---|---|---|
| Context window cost | One tool definition per template | Always two tool definitions |
| Latency | Single tool call | Two calls (search + invoke) |
| Scalability | Degrades with hundreds of templates | Constant overhead regardless of catalog size |
| Agent compatibility | Works with any MCP client | Requires agent capable of multi-step tool use |
Discovery mode is recommended when your catalog exceeds ~30 templates. The search scoring considers tool names, titles, summaries, descriptions, categories, and parameter names.
Claude Desktop
Add earl to your claude_desktop_config.json:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"earl": {
"command": "earl",
"args": ["mcp", "stdio", "--mode", "full", "--yes"]
}
}
}{
"mcpServers": {
"earl": {
"command": "earl",
"args": ["mcp", "stdio", "--mode", "discovery", "--yes"]
}
}
}If earl was installed via cargo install, Claude Desktop may not find it on PATH. Use the full binary path instead. Find it with which earl (macOS/Linux) or where earl (Windows):
{
"mcpServers": {
"earl": {
"command": "/absolute/path/to/earl",
"args": ["mcp", "stdio", "--mode", "full", "--yes"]
}
}
}Claude Code
Add earl as an MCP server in your Claude Code settings (.claude/settings.json or ~/.claude/settings.json):
{
"mcpServers": {
"earl": {
"command": "earl",
"args": ["mcp", "stdio", "--mode", "discovery", "--yes"]
}
}
}Discovery mode is recommended for Claude Code since it keeps the tool list small and avoids consuming the agent's context window.
Transports
Stdio
The default transport. Earl reads JSON-RPC requests from stdin and writes responses to stdout.
earl mcp stdio --mode full --yesThe stdio transport supports two framing formats:
- Content-Length framing — HTTP-style headers (
Content-Length: N\r\n\r\n<body>). This is the format earl uses when writing responses. - Line-delimited JSON — One JSON object per line (newline-terminated). Earl accepts this as input for compatibility with simpler clients.
Both formats can be mixed on the input side; earl auto-detects which format each incoming message uses.
HTTP
For non-stdio integrations, earl can serve MCP over HTTP:
earl mcp http --listen 127.0.0.1:8977 --mode full --yes --allow-unauthenticated| Endpoint | Method | Description |
|---|---|---|
/mcp | POST | JSON-RPC endpoint for MCP requests |
/health | GET | Health check — returns 204 No Content |
The --listen flag defaults to 127.0.0.1:8977.
The HTTP transport requires authentication by default. You must either configure JWT authentication (see Authentication below) or explicitly pass --allow-unauthenticated to opt out. The two options are mutually exclusive — earl will refuse to start if both are set.
Authentication
When using the HTTP transport, earl supports JWT-based authentication to control who can access your MCP tools.
JWT Configuration
Add an [auth.jwt] section to your config file (~/.config/earl/config.toml):
[auth.jwt]
audience = "https://api.example.com"
issuer = "https://accounts.example.com"
jwks_uri = "https://accounts.example.com/.well-known/jwks.json"Alternatively, use OIDC discovery to auto-resolve the issuer and JWKS URI:
[auth.jwt]
audience = "https://api.example.com"
oidc_discovery_url = "https://accounts.example.com/.well-known/openid-configuration"| Field | Type | Required | Default | Description |
|---|---|---|---|---|
audience | string | Yes | — | Expected aud claim in the JWT |
oidc_discovery_url | string | If issuer/jwks_uri not set | — | OIDC discovery endpoint to resolve issuer and JWKS URI |
issuer | string | If oidc_discovery_url not set | — | Expected iss claim in the JWT |
jwks_uri | string | If oidc_discovery_url not set | — | URL to fetch the JSON Web Key Set for token verification |
algorithms | string[] | No | ["RS256"] | Allowed signing algorithms (RS256, RS384, RS512, ES256, ES384, PS256, PS384, PS512, EdDSA) |
clock_skew_seconds | integer | No | 30 | Maximum clock skew tolerance in seconds (capped at 300) |
jwks_cache_max_age_seconds | integer | No | 900 | How long to cache JWKS keys before refreshing |
When JWT is configured, clients must include a Bearer token in the Authorization header. The token must contain exp, sub, iss, and aud claims. The sub claim identifies the authenticated subject for policy evaluation.
earl mcp http --listen 127.0.0.1:8977 --mode full --yesUnauthenticated Access
For development or trusted environments, you can skip authentication:
earl mcp http --listen 127.0.0.1:8977 --allow-unauthenticatedUsing --allow-unauthenticated is not recommended for production. Without
authentication, anyone who can reach the server can call your tools.
Policy Engine
When JWT authentication is enabled, you can define access control policies that restrict which subjects can call which tools. Policies are defined as [[policy]] entries in your config file.
[[policy]]
subjects = ["user:alice", "group:admins"]
tools = ["github.*"]
effect = "allow"
[[policy]]
subjects = ["*"]
tools = ["github.delete_repo"]
modes = ["write"]
effect = "deny"| Field | Type | Required | Description |
|---|---|---|---|
subjects | string[] | Yes | JWT sub values to match (supports * glob) |
tools | string[] | Yes | Tool name patterns to match (supports * glob per segment) |
modes | string[] | No | Restrict to read and/or write tools (omit for both) |
effect | string | Yes | allow or deny |
Evaluation Rules
Policies use a deny-overrides model:
- All matching policies (by subject, tool, and mode) are collected.
- If any matching policy has
effect = "deny", the call is denied. - If any matching policy has
effect = "allow"(and none deny), the call is allowed. - If no policies match, the call is denied (default deny).
Glob Patterns
The * wildcard matches any characters within a single segment (separated by .). A lone * matches everything.
| Pattern | Matches | Does Not Match |
|---|---|---|
github.* | github.create_issue | slack.send_message |
*.delete_* | github.delete_repo | github.admin.delete |
* | any tool | — |
Policies only apply to authenticated requests. Unauthenticated requests (when
using --allow-unauthenticated) bypass the policy engine entirely and are
gated only by the --yes flag for write-mode tools.
Write-Mode Safety
Write-mode tools (templates with annotations.mode = "write") are blocked by default. When a write-mode tool is called without opt-in, the server returns an error:
- Error code:
-32001 - Message:
write-mode tools are disabled on this server instance
Pass --yes when starting the server to allow write-mode tool execution:
earl mcp stdio --mode full --yesThis prevents agents from performing destructive actions without explicit operator opt-in.
Troubleshooting
Run earl doctor to validate templates and configuration before starting the MCP server.
Earl logs errors to stderr. To capture logs when running as an MCP server, redirect stderr to a file in your shell before launching, or check your MCP client's server log output.
earl mcp stdio --mode full --yes 2>/tmp/earl-mcp.log