How the BugMojo MCP Server Works: Bugs Your AI Agent Can Actually Read
A senior-engineer deep dive into the BugMojo MCP server: the 14 tools it exposes, the polymorphic AGENT assignee that makes an AI a first-class bug owner, and a live JSON-RPC wire transcript of what crosses between Claude and BugMojo.

Plenty of bug trackers now ship an MCP server. That is no longer a differentiator. The interesting questions are narrower: what crosses the wire on a tool call, what the payload actually carries, and whether the AI on the other end is a guest with read access or a team member that can own work. This is an architecture deep dive into the BugMojo MCP server — the 14 tools, the thin-client-over-REST design, the polymorphic AGENT assignee, and a real JSON-RPC transcript. It assumes you already know what MCP is; if you don't, start with our developer's primer on MCP. And if you just want to wire it up, the connect-Claude-Code guide is the install walkthrough — this page is the why, not the how.
What the BugMojo MCP server actually is
The BugMojo MCP server is a local stdio program that exposes 14 model-controlled tools over JSON-RPC. It holds no business logic. Each tool is a thin wrapper that turns a tools/call into one authenticated HTTP request against BugMojo's REST API and returns the response JSON verbatim. The data model, not the protocol, is what makes it different from other bug-tracker MCP servers.
MCP tools are model-controlled: the LLM discovers them and decides when to call them, with no glue code from you. The spec also asks the client to keep a human in the loop — to surface a tool's inputs and request confirmation before the server is hit. BugMojo leans on that exactly. Write tools like create_bug and update_bug surface their JSON arguments in Claude Code before anything commits, so you approve the precise mutation, not a vague intent.
The server itself is deliberately boring. The entry file describes it as "a thin client that translates MCP tool calls into HTTP API calls to the BugMojo backend. All business logic lives on the backend, not here." That sentence is the whole design philosophy, and the rest of this article is the consequences of taking it seriously.
The 14 tools, grouped
Every tool is registered with a Zod input schema, so the model receives a typed inputSchema in tools/list and knows the valid fields and enums before it ever calls. The 14 split cleanly into three families:
| Feature | Tool | Family | Read / Write |
|---|---|---|---|
| list_bugs | list_bugs | Core | Read |
| get_bug | get_bug | Core | Read |
| search_bugs | search_bugs | Core | Read |
| create_bug | create_bug | Core | Write |
| update_bug | update_bug | Core | Write |
| add_comment | add_comment | Core | Write |
| list_regression_suites | list_regression_suites | Regression | Read |
| get_regression_suite | get_regression_suite | Regression | Read |
| create_regression_run | create_regression_run | Regression | Write |
| submit_test_result | submit_test_result | Regression | Write |
| get_run_summary | get_run_summary | Regression | Read |
| get_agent_tasks | get_agent_tasks | Agent | Read |
| claim_agent_task | claim_agent_task | Agent | Write |
| update_agent_task | update_agent_task | Agent | Write |
The split matters for safety. An agent doing read-only triage only needs the read tools; an agent that fixes and verifies needs the write tools. Because the family boundary is explicit, you can scope an API key to exactly the surface a given agent should touch — more on that in the security section.
The differentiator: an AI agent is a first-class assignee
BugMojo records bug ownership as two columns: assignee_type, which is MEMBER or AGENT, and assignee_id. An AI agent is therefore a first-class assignee, not a read-only API consumer. A bug can be assigned to an agent the same way it is assigned to a human, and that agent picks the work up through the same MCP tools, comments on it, and moves its status.
This is the row no other issue-tracker MCP has. When Anthropic open-sourced MCP in November 2024, the reference servers covered Google Drive, Slack, GitHub, Git, Postgres, and Puppeteer. None of them — and none of the early adopters since — model an AI agent as a thing a task can be assigned to. They model the agent as a thing that calls the API. That distinction sounds academic until you watch a workflow run end to end.
In BugMojo, both create_bug and update_bug accept an assignee_type enum alongside the assignee_id. Set it to AGENT and the bug is owned by, say, a QA agent. The agent finds its work with get_agent_tasks, takes it with claim_agent_task (an atomic QUEUED → RUNNING transition so two agents can't grab the same task), and reports back with update_agent_task. The same add_comment a human uses is the channel the agent uses. There is no separate "bot API"; the polymorphism is the whole point.
// From the create_bug input schema (Zod).
// The same two fields appear on update_bug — assignment is uniform.
assignee_id: z.string().optional()
.describe("ID of the member or AI agent to assign this bug to"),
assignee_type: z.enum(["MEMBER", "AGENT"]).optional()
.describe("MEMBER (human) or AGENT (AI). Required if assignee_id is set"),A live JSON-RPC transcript
Every MCP tool call rides one JSON-RPC method, tools/call. On connect the client sends tools/list and the server returns all 14 definitions with their inputSchema. When the model acts, it sends tools/call with a tool name and arguments. The server replies with a result whose content[].text holds the BugMojo REST JSON, and sets isError true on a recoverable failure so the model can self-correct.
Abstractions are easy to nod along to. Here is the actual wire. Three messages, in order: the discovery handshake, the call, and a self-correction round where the model fixes its own bad argument. This is the shape you'll see if you turn on MCP debug logging in Claude Code.
1. Discovery. The client asks what's available. The server answers with typed schemas (truncated here to one tool for space):
// request
{ "jsonrpc": "2.0", "id": 1, "method": "tools/list" }
// response (one of 14 tools shown)
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"tools": [
{
"name": "search_bugs",
"description": "Full-text search across all bugs in the workspace...",
"inputSchema": {
"type": "object",
"properties": {
"query": { "type": "string", "minLength": 1 },
"priority": { "enum": ["CRITICAL","HIGH","MEDIUM","LOW","NONE"] },
"status": { "enum": ["OPEN","IN_PROGRESS","IN_REVIEW","RESOLVED","CLOSED","REOPENED"] },
"limit": { "type": "integer", "default": 20, "maximum": 100 }
},
"required": ["query"]
}
}
]
}
}2. The call. The model decides to search for open high-priority checkout bugs and emits a tools/call. The server forwards it to GET /api/v1/bugs/search and returns the REST JSON inside content[].text — a string, because MCP tool results are content blocks, not raw objects:
// request
{
"jsonrpc": "2.0", "id": 2, "method": "tools/call",
"params": {
"name": "search_bugs",
"arguments": { "query": "checkout 500", "priority": "HIGH", "status": "OPEN" }
}
}
// response — REST payload is serialized into content[].text
{
"jsonrpc": "2.0", "id": 2,
"result": {
"content": [{
"type": "text",
"text": "{\n \"bugs\": [{\n \"id\": \"bug_7Fq2\",\n \"number\": 412,\n \"title\": \"Checkout returns 500 on coupon apply\",\n \"status\": \"OPEN\",\n \"priority\": \"HIGH\",\n \"assignee_type\": \"AGENT\",\n \"assignee_id\": \"agent_qa_01\"\n }],\n \"total\": 1\n}"
}]
}
}3. Self-correction. Suppose the model first guessed a wrong enum (priority: "P1"). The Zod schema rejects it, the server returns a recoverable error with isError: true, the model reads the message, fixes the argument, and retries. The human never has to intervene:
// bad call: priority "P1" is not in the enum
{ "jsonrpc":"2.0", "id":3, "method":"tools/call",
"params": { "name":"search_bugs", "arguments": { "query":"checkout", "priority":"P1" } } }
// recoverable failure — NOT a protocol error; the model sees it and adapts
{ "jsonrpc":"2.0", "id":3,
"result": {
"isError": true,
"content": [{ "type":"text",
"text": "Invalid 'priority': expected one of CRITICAL|HIGH|MEDIUM|LOW|NONE" }]
}
}
// the model retries with a valid enum (id:4) → successThe thin-client-over-REST design, and why
The server holds zero business logic. Each tool builds a path, calls one of get/post/patch on a tiny HTTP client, and serializes the result. The client adds a Bearer header and maps status codes to readable errors — 401 becomes "Authentication failed... check your BUGMOJO_API_KEY," 403 becomes "Permission denied... your API key may lack the required permissions." That is the entire client:
const url = `${this.baseUrl}/api/v1${path}`;
const headers = {
Authorization: `Bearer ${this.apiKey}`, // bm_key_...
"Content-Type": "application/json",
"User-Agent": "@bugmojo/mcp-server",
};
const response = await fetch(url, { method, headers, body });
if (response.status === 401) throw new Error("Authentication failed...");
if (response.status === 403) throw new Error("Permission denied...");Three things fall out of this choice, and they're the reason it's worth defending. One: the protocol and the product evolve independently. Permissions, rate limits, validation, and audit logging live on the backend, where they're tested once and apply to every caller — the web UI, the extension, and the MCP server all hit the same /api/v1. Two: the published npm package stays tiny and auditable. A reviewer can read the entire server in one sitting and confirm it only talks to your configured host. Three: it honors a core BugMojo principle — every entity is reachable through the same tRPC/REST API, so a human in the dashboard and an agent over MCP are operating on identical surfaces, never a forked "agent backend" that drifts out of sync.
Transport and where your key lives
Claude Code supports four MCP transports: stdio for local subprocesses, HTTP streamable-http for remote servers, SSE which is deprecated, and WebSocket. BugMojo ships a local stdio server launched via npx. The API key sits in the local MCP config file and travels only on outbound HTTPS calls to your own BugMojo instance, never to a third-party relay.
The server connects over StdioServerTransport — it is a child process Claude Code spawns and talks to over stdin/stdout. Nothing listens on a port; nothing is exposed to the network beyond the outbound calls the tools make. Your bm_key_ key is read from the environment in the local config and used as a Bearer token against the base URL you set. There is no BugMojo-operated middle tier in the path.
One caveat worth stating plainly, because the Claude Code docs do: MCP servers can be a prompt-injection vector. A tool result is text the model reads, and a hostile bug title could in principle carry an instruction. BugMojo's mitigations are the human-in-the-loop confirmation on writes and API-key scoping on what an agent can reach — but you should still only connect MCP servers, and ingest bug data, from sources you trust.
How it compares — honestly
Competitors already ship MCP servers, and some are more capable than BugMojo on their home turf. Sentry's MCP lets developers query production errors and issues straight from the IDE; Atlassian's Remote MCP Server lets Claude summarize work and create Jira issues inside permissioned boundaries. Both are legitimately good. The point of this table is not to claim BugMojo wins everywhere — it doesn't — but to isolate the one capability the issue-tracker MCP servers shipping today don't have.
| Feature | BugMojo MCP | Sentry MCP | Atlassian/Jira MCP |
|---|---|---|---|
| Ships an MCP server | ✓ | ✓ | ✓ |
| Read issues from the IDE | ✓ | ✓ | ✓ |
| Create / update issues via tools | ✓ | partial | ✓ |
| rrweb session replay in the payload | ✓ | via web UI | — |
| Console + network capture in the payload | ✓ | partial | — |
| AI agent as a first-class ASSIGNEE | ✓ | — | — |
| Mature production error-monitoring | early | ✓ | — |
| Deep admin / workflow / governance | basic | n/a | ✓ |
| Marketplace & ecosystem breadth | growing | ✓ | ✓ |
Read that table both directions. If your problem is production exception monitoring at scale, Sentry is more mature and you should use it. If your problem is enterprise workflow governance, Jira's admin depth is unmatched and BugMojo isn't trying to replace it — it pushes captured bugs into Jira (see BugMojo vs Jira). The single row that flips is the last conceptual one: a bug an agent can own, carrying a replayable repro, is a capability with no equivalent in the issue-tracker MCP servers shipping in mid-2026.
Where MCP itself is, in 2026
Some context for why this is worth building against now and not in two years. MCP turned one year old on 25 November 2025. By that anniversary the official registry held close to 2,000 server entries — a 407% jump from the first batch onboarded in September 2025 — with more than 2,900 contributors on the MCP Discord. The bug-tracker category inside that registry is exactly where BugMojo's 14-tool server competes, and the protocol is now stable enough that the November 2025 spec is the version to target, not the 2024 launch docs.
Key takeaways
BugMojo's extension captures rrweb replay, console, and network in one click — then your AI agent reads, triages, and closes it over MCP. The 10-minute setup is in our connect-Claude-Code guide.
Connect Claude Code to BugMojoFrequently asked questions
Frequently asked questions
Sources
- MCP Server Tools specification (tools/list, tools/call, isError, model-controlled, human-in-the-loop) — Anthropic / Model Context Protocol (2025-11-25)
- One Year of MCP: November 2025 Spec Release (registry ~2,000 entries, 407% growth, 2,900+ Discord contributors) — Model Context Protocol Blog (2025-11-25)
- Introducing the Model Context Protocol (original launch announcement, reference servers) — Anthropic (2024-11-25)
- Connect Claude Code to tools via MCP (transports: stdio, HTTP/streamable-http, SSE deprecated, WebSocket; prompt-injection trust warning) — Anthropic (Claude Code docs) (2026)
- MCP Demo Day: How 10 leading AI companies built MCP servers on Cloudflare (Sentry MCP queries errors from the IDE) — Cloudflare (2025)
- Introducing Atlassian's Remote Model Context Protocol (MCP) Server (permissioned boundaries, create Jira issues) — Atlassian (2025)
Get bug-tracking insights, weekly.
Engineering deep-dives, QA playbooks, and honest tool comparisons. No spam — unsubscribe in one click.

