Skip to content

MCP overview

Kestrel ships an MCP (Model Context Protocol) server in the same binary that serves the API and web UI. The agent sees a small, focused set of tools designed for one workflow:

list errors → get one → diagnose → mark resolved with a commit SHA

There is no create_issue, assign, add_comment, or set_priority — those concepts don't exist in Kestrel.

Two transports, same tools

bash
# Best for local agents (Claude Code / Cursor / your CLI). The stdio
# transport reads the SQLite file directly, so it must run on the same
# machine that has data/kestrel.db (use --db to point elsewhere).
kestrel mcp
# Or in a JSON config:
{
  "command": "kestrel",
  "args": ["mcp"],
  "env": { "KESTREL_TOKEN": "<project-token>" }
}
http
# Best for any setup where the agent and the server are not on the same
# host — including the common Docker-deployed case.
POST /mcp HTTP/1.1
Authorization: Bearer <project-token>

The HTTP endpoint requires Authorization: Bearer <token> on every call — anonymous clients get a 401 before tools/list or initialize are exposed, so agents can't enumerate the schema without the token.

Auth → project scoping

Each project's ingest token doubles as the MCP credential. The token a request presents determines the project the tool calls scope to — there's no way to read another project's issues with someone else's token.

This is intentionally simpler than RBAC: one token, one project, one mental model.

Wiring it into Claude Code

If your agent is on the same machine as the server (binary install with the SQLite at ./data/kestrel.db):

json
// ~/.claude/mcp.json
{
  "mcpServers": {
    "kestrel": {
      "command": "kestrel",
      "args": ["mcp"],
      "env": { "KESTREL_TOKEN": "your-project-token" }
    }
  }
}

If Kestrel is in Docker or on another host, point Claude Code at the HTTP transport instead:

json
{
  "mcpServers": {
    "kestrel": {
      "url": "http://localhost:8080/mcp",
      "headers": { "Authorization": "Bearer your-project-token" }
    }
  }
}

After Claude Code restarts, the tools below are available without any prompt scaffolding. Try: "List the open errors and pick the one I should look at first."

What's the point?

The whole reason Kestrel exists is to make this loop short:

  1. Bug ships.
  2. SDK posts an envelope.
  3. Agent sees the new error, reads the resolved stack with source context, recent logs, and the responsible commit.
  4. Agent proposes a fix, the human approves and commits.
  5. Agent calls mark_resolved(issue_id, commit_sha).

Step 4 is the only step a human is required for. Everything else is the agent doing what on-call would do — faster, and without paging anyone.

Released under the MIT License.