Summary

Mneme HQ shipped an MCP server so AI assistants could query a project’s architectural decisions at prompt time, rather than guessing at conventions. In the field it broke in four predictable places: scope was set too wide and too narrow, protocol versions skewed between clients, cached context went stale, and tool schemas failed validation. Most of those are fixed. Relevance ranking is not. The lesson is that an MCP server is only as good as the boundary it draws around what the model is allowed to see.

The Model Context Protocol gives an AI assistant a structured way to call out to a server for tools and data. For Mneme HQ that mapped onto an obvious idea. Mneme HQ already stores a team’s architectural decisions as YAML in the repository. An MCP server could expose those decisions to an assistant at the moment it writes code, so the model is reasoning from the team’s actual rules instead of inferring conventions from whatever happens to be in its context window.

That was what we set out to ship: a server with a small set of tools that let an assistant ask which decisions apply to the file or feature in front of it, and receive the relevant rules back as structured context. The premise held up. The execution broke in ways that were obvious only after the fact. This is the honest version of what happened, because the value of a build-in-public postmortem is in the parts that did not go to plan.

A clarification on terms, because they matter here. The server runs locally alongside the developer’s assistant. It does not call out to a hosted service or send a team’s decisions anywhere. The decisions live in the repository, the server reads them from disk, and the assistant talks to the server over the protocol’s standard transport. That design constraint was deliberate, and it shaped most of the failures that followed, because a server that holds no state of its own has nowhere to hide a stale assumption except in a cache it forgot to invalidate.

What We Set Out to Ship

The design was deliberately narrow. Three tools: one to list the decision categories in a repository, one to fetch the decisions matching a query, and one to return the full text of a single decision by identifier. The assistant would call the second tool with a description of the task, the server would return the applicable rules, and the model would generate code that conformed to them.

This is the same problem Mneme HQ exists to solve, approached from a different angle. The reasoning behind the decision store is covered in why I built Mneme HQ; the MCP server is an attempt to deliver that store into the one context where it matters most, the prompt itself. The protocol mechanics are unpacked further in the Mneme HQ MCP protocol breakdown. The premise was sound. What it did not survive was contact with real repositories and real clients.

What Actually Broke

Scope broke first. The first version exposed every decision in the repository through one broad query tool. On a small project this was fine. On a real codebase with a hundred-plus decisions, the tool flooded the model’s context with rules that had nothing to do with the task, and the signal drowned. So we narrowed it. Then the opposite failure appeared: a developer working on an authentication change got nothing back, because the relevant decisions were filed under a category the narrowed query never searched.

An MCP server scoped too broadly buries the model in irrelevant context; an MCP server scoped too narrowly returns nothing the developer actually needed.

Protocol version skew broke next, and it broke quietly. We tested against one MCP client and shipped. A second client implemented a different revision of the protocol, and capability negotiation that the first client honoured, the second ignored. The server assumed a baseline that was not guaranteed. Requests that should have been rejected with a clear error instead returned partial responses, which is the worst kind of failure: silent and plausible.

Protocol version skew between MCP clients causes silent partial failures when a server assumes capabilities the client never agreed to support.

Then context injection went stale. The server read the decision store once at startup and cached it. That was a deliberate choice for latency, and a wrong one. When a developer edited a decision mid-session, the assistant kept returning the old rule. The model was confidently conformant to a decision the team had already overturned. A tool meant to keep code aligned with current decisions was quietly enforcing yesterday’s.

The fourth failure was tool-schema validation. MCP requires each tool to declare an input schema, and clients validate calls against it. Our schema was too permissive in some fields and too strict in others. A client that passed an optional parameter as null where the schema expected the key to be absent had its entire call rejected. The error surfaced to the user as a generic tool failure, with nothing to indicate the cause was a schema mismatch rather than a problem with their request.

A tool schema permissive where strictness is required, and strict where permissiveness is required, fails calls without telling the caller why.

What We Changed

Scope became dynamic rather than fixed. Instead of one broad tool or one narrow one, the query tool now takes the file path and a task description and ranks decisions by category proximity, returning a bounded set rather than everything or nothing. It is not perfect, but it fails less often in both directions.

For protocol skew, the server now negotiates against the client’s declared protocol version rather than assuming a baseline, and fails loudly when a required capability is absent. A clear error at connection time is worth more than a plausible wrong answer at call time. This is the same principle that runs through the rest of the product: a rule that can be silently ignored is not a rule. A decision that can be ignored isn’t a decision. It’s a suggestion.

The stale-context problem was the cheapest to fix and the most embarrassing to have shipped. The cache now keys on the modification time of the decision files and re-reads on change. The latency cost is small and the correctness gain is total. Caching without invalidation is not an optimisation; it is a bug with better marketing.

Schema validation got tightened against the actual shape of the calls clients were making, with the optional-versus-absent distinction made explicit, and the server now returns a structured error that names the offending field. Most of the remaining support questions about the server have been about exactly this, which tells us the error messages still are not clear enough.

What We Still Got Wrong

Relevance ranking is the honest unsolved problem. The server can return the decisions that match a query. It cannot reliably order them by how much they actually matter to the task at hand. A decision can be technically applicable and practically irrelevant, and the model treats both with equal weight. The result is that an assistant sometimes gives a correct-but-trivial rule the same prominence as the one that genuinely constrains the work.

We also underestimated how much the value of the server depends on the quality of the decision store behind it. An MCP server that surfaces vague or contradictory decisions surfaces them faster, not better. The early telemetry, which I covered in the first ninety days of Mneme HQ telemetry, shows the server is queried far more in repositories with well-maintained decision stores. The tool amplifies the store. It does not improve it.

The broader point connects to why building this in the open matters at all. A closed MCP server that sits in the path of how an assistant writes your code is asking for a kind of trust that closed tools have not earned, an argument I have made about open source as validation for developer tools. Shipping the failures publicly is part of the same bet. The honest account of what broke is more useful to someone building their own MCP server than any account of what worked.

If you are building an MCP server, the failures above are the ones to design against from the start. Scope is a boundary problem, not a feature. Version negotiation is a correctness problem, not a nicety. Caching is a correctness problem dressed as performance. And the schema is the contract; treat a vague one as a bug you have not hit yet.

Key Takeaways

FAQ

What does the Mneme HQ MCP server do?
The Mneme HQ MCP server lets an AI assistant query a project’s architectural decisions at prompt time. Instead of the assistant guessing at conventions, it can ask the server which decisions apply to the file or feature being worked on, and receive the relevant rules as structured context before it generates code.
What broke first when shipping the MCP server?
Scope was the first thing to break. The initial server exposed every decision in the repository through a single broad tool, which flooded the model’s context with irrelevant rules. The opposite failure also appeared: a narrowly scoped server returned nothing useful because the decisions a developer needed were filed under a category the tool did not search.
Why did MCP protocol version skew cause problems?
Different MCP clients implemented different revisions of the protocol, so a server tested against one client failed against another. Capability negotiation that one client honoured, another ignored. The fix was to negotiate against the declared protocol version rather than assuming a baseline, and to fail loudly when a required capability was absent.
How do you stop an MCP server returning stale context?
Stale context comes from caching decisions without invalidating on change. The server cached the decision set at startup and never re-read it, so edits to the YAML store were invisible until restart. The fix was to key the cache on file modification time and re-read on change, accepting a small latency cost for correctness.
What is still unsolved in the Mneme HQ MCP server?
Relevance ranking is still unsolved. The server can return the decisions that match a query, but ordering them by genuine relevance to the current task remains crude. A decision can be technically applicable and practically irrelevant, and the server cannot yet tell the difference reliably.