Building MCP Servers: Lessons from Designing Memplex

7 minMemplex

MCP servers are easy to ship and hard to ship well. Five design patterns we landed on while building Memplex's, with reasoning for each.

Building MCP Servers: Lessons from Designing Memplex

The Model Context Protocol is young. The reference implementations are simple by design — get the protocol working, ship examples, let the ecosystem figure out the patterns. As servers move from demo to production, certain design choices keep recurring as either obviously-right or obviously-wrong.

Here are five we landed on while building Memplex's MCP server. Reasoning for each, in case you're building one yourself.

1. Don't expose a flat resource list

The most common MCP server shape is "list all the resources the client could possibly want, let the client pick." This works for tiny use cases. It fails for anything serious.

The problem: the MCP client is a language model. Models are not great at choosing among 47 resources based on filename and a one-line description. They guess, retrieve the wrong thing, burn context window.

What works better: expose a small number of opinionated tools that take task-shaped parameters. The server internally figures out which resources to read. The model expresses its intent ("I need project context"), the server expresses the policy ("here's what that means in our world").

Memplex's three tools — search_context, get_project_context, explain_inclusion — collapse a much larger resource surface into intent-shaped entry points.

2. Return provenance with every response

Almost no MCP server we've inspected returns source provenance with retrieval responses. They return text; the model uses the text; the trail ends there.

This is fine for low-stakes use cases. It's a problem the moment the user wants to verify what the AI said, or the moment a compliance team needs an audit trail, or the moment something goes wrong and you have to debug why a specific memory was used.

Memplex returns, for every memory in a response:

  • A source link (paragraph-level where the format supports it)
  • A confidence score
  • A lifecycle state
  • The retrieval channel that surfaced it

The model can include this provenance in its answer. The user can click through. The compliance team can audit. The developer can debug. The cost of returning this is minimal; the value is enormous.

3. Make scope and task explicit in the request

The temptation: infer scope and task from the auth context. The user authenticated as themselves; the server figures out the rest.

The problem: same user, different tasks, different scopes. A user debugging a personal project shouldn't get back work context, even though it's the same authenticated identity.

The fix: scope and task are first-class request parameters. The client specifies them. The server uses them in retrieval.

Memplex's search_context request includes scope, task_hint, and destination as required parameters. The retrieval pipeline can't ignore them. Personal context stays out of work tools because the request explicitly says "this is a work-scoped task," and the router filters accordingly.

This costs a bit of client-side complexity (clients have to know how to set scope correctly). It's worth it. The alternative is permissive retrieval that occasionally leaks badly.

4. Token budget is a first-class parameter

Different MCP clients have different context windows. Different destinations have different sensitivities to context size. A response sized for a 200K-token Claude session is wrong for a 32K-token client.

Most MCP servers don't handle this. They return whatever they think is relevant; the client truncates as needed. The truncation is naive — usually "take the first N tokens" — and discards important context.

The fix: the request includes a token_budget. The server reshapes the response to fit, prioritizing the most important memories. If 50K tokens are available, the response uses ~50K. If 10K, the response is denser and focuses on the highest-priority items.

This means the server has to do the prioritization, which is more work than just dumping everything. It's worth it. The model gets a response that fits, not a truncated mess.

5. Ship a trace tool from day one

The explain_inclusion tool lets the client (or the user) ask "why was this memory included in a previous retrieval response?" The trace covers the routing reason, the scope check, the confidence threshold, the channel weights, and the source lineage.

This tool serves three audiences:

  • Users debugging weird AI behavior ("why did it surface that?")
  • Compliance teams auditing what context flowed where
  • Developers building agents on top, who need to understand the retrieval semantics

We shipped explain_inclusion in v0. It cost a small amount of additional design work and pays back every time something needs to be debugged. Most MCP servers will eventually need this; few build it from the start. Build it from the start.

Bonus: keep state local where you can

MCP doesn't dictate where the server runs. You can host it remotely, run it as a sidecar, embed it in the client. Memplex's MCP endpoint runs locally by default.

Why: latency, privacy, resilience. Local servers respond fast, don't leak the request to a remote service, and keep working when the network doesn't.

Remote MCP servers make sense for shared resources (team knowledge bases, multi-user systems). They don't make sense for individual context. The default should be local.

What's still unsettled

The MCP ecosystem is young enough that there are real open questions:

  • How should servers handle long-running operations (background extraction, async retrieval)?
  • What's the right pattern for multi-tenant servers (e.g., team graphs)?
  • How should clients negotiate capabilities with servers?
  • What's the standard error model for governance failures (access denied, scope violation)?

We have opinions on each of these and a partial implementation reflecting them, but the ecosystem hasn't converged. If you're building an MCP server, you have real design surface to claim. The patterns aren't fixed yet. Now is the time to push for the ones you think are right.


Notes on using these posts

Splitting into individual files. Each post starts with --- frontmatter and a # Title. Lovable can either ingest this single file and split it (ask it to "split by ---\n---\ntitle:" if the splitter is finicky), or you can split locally and drop them into /content/blog/ named by slug.

Image placeholders. None of the posts include images. Add a hero image per post in Lovable — generated diagrams or photos work, but don't ship empty <img> tags.

Internal links. None of the posts link to other internal pages yet. After you have the routes set up, consider adding cross-links between related posts (e.g., the graph-RAG post should link to the vector-RAG-stopgap post, and vice versa). This helps SEO and keeps readers on the site.

CTA blocks. Consider a uniform footer CTA on every post — "Memplex is in private alpha. [Join the waitlist]." Don't put it inside the markdown; have Lovable render it as a component at the end of each post template so it's easy to update everywhere at once.

Publishing cadence. If these posts will publish over time rather than all at once, the dates above are already staggered (March 4 → May 6, 2026, roughly twice a week). Adjust the dates to match your actual rollout schedule.

Newsletter republication. Each post is a credible standalone newsletter issue. Cross-post to Substack, Beehiiv, or Medium with rel="canonical" pointing back to memplex.ai/blog/[slug] for SEO.

MCPProtocol DesignDeveloper Tools

● More from Memplex