The Model Context Protocol is a standard way to hand an AI agent a set of tools. You describe what your product can do, the agent's client connects, and from then on the agent can call those tools during a conversation the same way it reads a file or runs a command.
The specification is small and the implementation is not the hard part. A working server is an afternoon. Getting an agent to use it correctly — without guessing at identifiers, without fetching the wrong thing, without confidently concluding that empty output means empty data — is the part that took real design work.
These are the decisions that mattered when we shipped BugDump's MCP server, and they generalise to any developer tool considering one.
First, what MCP actually changes
Without MCP, connecting an agent to your product means the user is the integration. They open your dashboard, find the relevant data, copy it, and paste it into the conversation. Every piece of context is manually ferried across, which caps how much context there is at how much the person is willing to copy.
With MCP, the agent fetches for itself. Concretely, the difference at BugDump is between:
Here is a bug report. [pastes 200 lines of console output]
and:
Look at task #42 in BugDump and fix it.
In the second version the agent pulls the task, lists its reports, reads the console and network telemetry, correlates the stack trace against the actual source files in the repository, and proposes a change. Nobody opened the dashboard. The agent had access to the entire report rather than the portion a human judged worth copying — and the portion a human judges worth copying is exactly the judgement that debugging is supposed to produce, not consume.
That is the shape of the win, and it is why the design goal is not "expose the API." It is "expose an API an agent can navigate without a map."
1. Bind the key to a scope, permanently
Our first design had a project parameter on every tool. It was the obvious translation of the REST API, and it was wrong twice over.
It was wrong for safety. An MCP key lives in a config file and gets used by an autonomous process. The blast radius of that key should be as small as the job allows.
It was wrong for usability. Given a projectId parameter and no project ID, an agent will try to fill it. It will guess proj_1. It will pass the project name. It will invent something plausible, get an error, and try a different invention. A parameter that can be guessed will be guessed.
So a BugDump MCP key is bound to exactly one project, permanently, and no tool takes a project argument. There is nothing to guess. If a user asks about a different project, the server can only say which project this key is scoped to — via a get_current_project tool that exists purely so the agent can orient itself instead of speculating.
The general rule: every parameter an agent cannot derive from prior output is a parameter it will hallucinate. Remove it, or make it discoverable.
2. Design the drill-down chain explicitly
Our tools form a deliberate sequence:
list_tasks → find a task, get its taskId
get_task → read one task
list_reports_for_task → list a task's reports, get each reportId
get_report → read one report
get_report_telemetry → page through everything in that report
Every ID passed to a tool must have come out of a previous response. This is stated in the server instructions in those words, along with an explicit prohibition on constructing IDs.
The failure mode this prevents is subtle and expensive. Agents parallelise aggressively — and correctly, most of the time. But an agent that decides to fan out get_report calls before it has any report IDs will manufacture them, receive seven errors, and burn a large amount of context recovering. The instruction that fixes it is the one that says parallel calls are only safe across IDs you already hold.
3. Accept the identifiers humans actually use
Our tasks have both a UUID and a public ID displayed as #42. Users say "task 42." Nobody has ever said "task 9f8c1a4e-...."
get_task accepts either. This is a small accommodation with a disproportionate effect, because it removes an entire class of failed first attempt. The agent tries the thing the human said, and it works.
Look for the identifier your users type in Slack. Accept that one.
4. Default to summaries, but say what you cut
A single bug report can carry thousands of console entries, hundreds of network requests with bodies, screenshots, and a session replay. Returning all of it by default would flood the agent's context on the first call and leave no room for the actual work.
So get_report defaults to a compact summary: recent console entries, network metadata with bodies stripped.
The critical part is the next sentence in the response. The summary states what was trimmed. Not silently — explicitly, in the payload.
Silent truncation is the worst failure available to a tool designer, because it does not produce an error. It produces a confident wrong answer. An agent that receives a truncated network log with no indication it was truncated will tell the user there were no failing requests. Nobody finds out that was wrong until much later.
This is the same discipline as --max-count in a search tool: report the cap you hit. If your tool caps anything, the cap belongs in the output.
5. Give the agent a way to get the rest
A summary is only acceptable if a full read is available. get_report_telemetry exists for that: it pages through console, network with bodies, or user actions in chronological chunks, with offset and nextOffset, and a hasMore flag that goes false when the stream is exhausted.
Two properties make this workable for an agent rather than just for a program.
Chronological chunks, not arbitrary ones. Ordering by time means a partial read is still meaningful. An agent that fetches the first two pages has the first part of the story, not a random sample of it.
An explicit termination condition. hasMore: false is a fact the agent can act on. "The array came back shorter than the limit" is an inference, and inferences at the end of long tool loops are where agents get creative.
6. Write the instructions for the agent, not the user
MCP servers ship a block of instructions that goes into the agent's context. It is tempting to write marketing copy there. It is a much better use of the space to write the things that are not derivable from the tool schemas:
The order tools must be called in
The prohibition on inventing IDs
Which calls are safe to parallelise, and which are not
What "the summary showed nothing" does and does not mean
That last one earns its place. Our instructions say, in effect: the summary response tells you what was trimmed, so do not assume "summary shows nothing" means "there is nothing." That single sentence prevents a specific wrong conclusion we watched agents reach.
Treat the instruction block as a note to a competent colleague joining mid-task. They can read the type signatures. What they need is the part that would only be learned by getting it wrong.
7. Read-only is a feature
BugDump's MCP server exposes seven tools, and all seven read. None create a task, close a task, or post a comment.
That was a considered choice, not an unfinished one. The workflow the server enables is investigation: pull the evidence, correlate it with the code, propose a fix. The write half of the workflow — deciding a bug is real, deciding it is a duplicate, deciding it is done — is where human judgement is doing the actual work.
There is also a simpler argument. A read-only key that leaks is a disclosure problem. A read-write key that leaks, held by an autonomous process, is a data-integrity problem. Given the choice between the two, and given that write access was not needed for the workflow we were targeting, the decision made itself.
Start read-only. Add writes when a workflow demands them, and scope those keys separately.
The uncomfortable prerequisite
There is a precondition underneath all of this that has nothing to do with protocol design.
An agent cannot ask a follow-up question. It cannot message the reporter to ask which browser they were on. It gets exactly one shot at whatever evidence exists, and if the evidence is thin, it will produce a fluent, well-structured, entirely speculative answer.
Which means the value of an MCP server is capped by the quality of the data behind it. Ours works because a BugDump report already contains the console, the network log, the session replay, the user's actions, and the full environment — captured automatically at the moment the bug happened. The protocol just moves it.
If you are considering an MCP server for your own tool, that is the question worth answering first: is the data behind it complete enough to be acted on without a follow-up question? If yes, MCP is a thin and worthwhile layer. If no, the protocol will only make the gaps easier to reach.