← All posts
Engineering

Serving context over MCP: what we got wrong first

Mahari Kalau10 min readJul 2026
Serving context over MCP: what we got wrong first

Our first MCP server worked beautifully in development and fell over the first week it saw real agent traffic. Three of the mistakes were interesting enough to write down.

Mistake one: treating every call as stateless

The clean design is one tool call, one resolved context package, no memory between calls. It is also wasteful, because agents in a conversation ask about the same entities repeatedly.

An analytics agent working through a churn question might make eleven calls in ninety seconds, and nine of them touch the same three definitions. Resolving the graph from scratch each time meant we were doing the same traversal over and over.

# before: 11 calls, 11 full traversals avg_latency: 42ms total: 462ms of resolution work # after: session-scoped entity cache cold_call: 42ms warm_call: 6ms total: 102ms

The fix was a session-scoped cache keyed on entity set, invalidated on any knowledge update touching those entities. Not complicated — we just did not think we needed it.

Mistake two: returning everything the scope allowed

Early on, a call to get_context returned every item in the caller's scope. If the scope had forty definitions, the agent got forty definitions.

This felt safe — the agent can decide what it needs — and it defeated the entire point of composition. We had rebuilt context stuffing with extra steps.

A permission boundary is not a relevance filter. We were conflating "may see" with "should receive".

The correction was to make intent a required parameter rather than an optional hint. An agent must say what it is trying to do, and it gets the items relevant to that intent within its scope. Agents that pass a vague intent get a disambiguation response rather than a data dump.

Mistake three: no backpressure signal

When a workflow agent looped over 2,000 accounts and issued a context call per account, our server dutifully answered all of them. Latency for every other caller degraded, and we found out from a customer rather than from monitoring.

What we added: per-caller rate limits with a structured retry_after in the MCP error payload, plus a batch endpoint for exactly this pattern. Agents that respect the signal now degrade gracefully instead of hammering.

The shape we settled on

Three tools rather than one, each with a narrow contract:

  1. resolve_context — takes an intent and optional entity hints, returns a composed package with provenance. The workhorse.
  2. list_definitions — returns names and one-line summaries within scope, no bodies. Cheap, cacheable, lets an agent orient before asking for detail.
  3. check_conflict — asks whether a given concept has unresolved conflicts. Agents use it to decide whether to answer or escalate.

Splitting these out meant agents stopped over-fetching to compensate for a coarse interface. Median payload dropped by roughly two-thirds without any change to the underlying composition logic.

What we would tell someone starting out

Mahari Kalau

Mahari Kalau

Founder & CEO, OneClickBrain

Writes about context engineering, agent architecture, and the unglamorous parts of enterprise AI.

Keep reading

⚡
Performance

Cutting prompt size by 87% without losing accuracy

11 min read · Jul 2026
🔒
Governance

Permissions belong in the context layer

7 min read · Aug 2026
📄
Featured

Why RAG alone can't fix enterprise hallucinations

12 min read · Aug 2026