RAG & Grounding8 min read·

When Should You Use MCP Instead of RAG?

Your support agent gets asked for "the waterproof one, under $150, in stock at the Portland warehouse." A pure vector search embeds the sentence, finds documents that read like it, and returns three jackets that are out of stock, one that…

Your support agent gets asked for "the waterproof one, under $150, in stock at the Portland warehouse." A pure vector search embeds the sentence, finds documents that read like it, and returns three jackets that are out of stock, one that costs $240, and nothing from Portland. The model either hallucinates a plausible-sounding answer or hedges, and a customer walks away with the wrong information. That is the failure mode most teams hit, and it is why "should we use MCP or RAG?" gets asked in the first place.

The question is a false binary. Sanity Context (previously Agent Context) is the product; Context MCP is one surface of it, a hosted read-only endpoint any agent loop can connect to, sitting in front of a knowledge base and an ingest path. RAG, meaning pure embeddings search, is one ingredient inside that surface, not a competing architecture. Sanity is the Content Operating System for the AI era, the intelligent backend for companies building AI content operations at scale.

This guide reframes MCP versus RAG as tool surface versus retrieval ingredient, shows where pure embeddings fail on real queries, and explains when a governed MCP path beats a bolt-on vector stack.

Why the MCP-versus-RAG question is the wrong question

MCP and RAG answer different questions, so pitting them against each other confuses two layers of the stack. RAG (retrieval-augmented generation) is a retrieval technique: embed a query, find semantically similar chunks, stuff them into the prompt. MCP (the Model Context Protocol) is a transport and tool surface: a standard way for an agent loop to call read tools, write tools, and composite tools against a system. You do not choose one instead of the other any more than you choose HTTP instead of full-text search. One moves the request; the other decides what comes back.

The confusion is understandable because the first wave of AI tooling shipped RAG as if it were a whole strategy. Point a vector database at your docs, embed everything, and call it retrieval. But vector similarity is one ingredient, not a discipline. Sanity's own framing is blunt on this point: "'We have embeddings' is not a retrieval strategy." Embeddings are good at fuzzy semantic match and bad at constraints that have to hold, and most agent queries carry both.

Sanity Context collapses the false binary by making Context MCP the surface an agent connects to, while what happens behind that surface is hybrid retrieval, not pure vector search. The mental model to keep is that Sanity Context has an MCP, a knowledge base, and an ingest path. It isn't only an MCP, and it is emphatically not only RAG. The rest of this guide is about what actually runs behind the surface, because that is where agents succeed or fail.

Illustration for When Should You Use MCP Instead of RAG?
Illustration for When Should You Use MCP Instead of RAG?

What production data says about how agents actually retrieve

It is easy to assume that an agent grounded in your content is mostly doing vector search under the hood. Production telemetry says otherwise. When Sanity looks at how agents actually call Context MCP, the heavy majority of calls are structured: GROQ queries and schema lookups, with a compressed initial context behind that. Semantic search is a small slice. Embeddings adoption is low, off by default, opt-in, and most projects shipping on Context MCP never turn them on.

That is a counter-intuitive result if your mental model of grounding is RAG-first. It makes sense once you look at the queries agents actually run. "List the products in this category," "fetch this SKU's spec fields," "what does the return policy document say about opened items," and "which reviews reference battery life" are structural questions with exact answers. They do not want the three nearest neighbors in embedding space; they want the rows that match. A schema lookup followed by a precise GROQ query returns exactly the right set, deterministically, and cheaply.

When retrieval fails, it usually shares one shape. A query carries a real structural component, a feature, a version number, a category, or "in stock," that pure vector similarity cannot resolve, so the result comes back empty or wrong and the model hallucinates or hedges. Sanity ran its schema exploration against Sonos's catalog, an honest nightmare of a dataset, and reached around 83% accuracy on a mix of difficulties only after teaching retrieval the counter-intuitive field names, second-order reference chains, and data-quality issues.

Where pure embeddings break, and where structured query breaks

Both extremes have honest failure modes, and knowing them tells you when to reach for which. Pure embeddings shine on fuzzy semantic intent. "Find me something like a trail runner" or "the cozy one" have no exact predicate, so similarity ranking is exactly the right tool. Embeddings let a user describe what they want in their own words and get plausible matches back without ever naming a field.

The moment a query grows a structural spine, pure embeddings fall over. "Under $150, in stock at the Portland warehouse, men's size 11" is not a vibe; it is a set of constraints that must all hold. Vector similarity does not respect price, stock, location, or size, so it returns items that read like the query rather than items that satisfy it. This is the empty-result problem: the closest documents in embedding space are simply the wrong documents, and no amount of better embeddings fixes a constraint they were never designed to enforce.

Pure structured query has the mirror-image weakness. GROQ, SQL, and GraphQL give you exactly what you ask for, which is perfect when you know the predicate and useless when you do not. Ask a structured store for "the cozy one" and it has no field to match. Exploratory chat, where the user is feeling their way toward an intent they cannot yet name, defeats a system that only answers exact predicates. The lesson is not that one approach wins. It is that real agent queries mix intent and constraint in the same sentence, so retrieval has to do both at once.

Hybrid retrieval: the discipline that beats both

The approach that outperforms either extreme is hybrid retrieval: keyword search (BM25) for literal matches, embeddings for semantic ranking, and structured predicates for the filters that have to hold. Anthropic's contextual retrieval research measured the layering directly. Contextual embeddings cut top-20 retrieval failures by 35%, adding contextual BM25 took that to 49%, and adding reranking on top brought it to 67%. The shape of that result holds whether you read the paper closely or just notice that none of the three layers alone was enough.

In Sanity, hybrid retrieval runs inside a single GROQ query rather than across three systems you have to stitch together. Structured predicates do the filtering that must hold, then a score pipeline blends the signals: `boost([title] match text::query($queryText), 2)` weights a BM25 keyword match on the title twice as heavily, `text::semanticSimilarity($queryText)` adds semantic ranking across the document, and `order(_score desc)` sorts the blend. The filters keep the impossible answers out, and the blended score ranks what remains by relevance.

This is where the earlier failure resolves. "Under $150, in stock at the Portland warehouse" becomes predicates that guarantee price, stock, and location before ranking ever runs, so the empty-result problem disappears. You do not need GROQ specifically to do this; PostgreSQL with pgvector and full-text can, Elasticsearch can, Algolia is built for the structured-plus-relevance case, and Pinecone plus a metadata-filter layer can. What you cannot do is pure-vector your way out of a query with a real structural component. Hybrid is not a nice-to-have; it is the baseline for agents that answer correctly.

The freshness tax: native retrieval versus a vector DB plus glue

Choosing MCP over a bolt-on RAG stack is often really a choice about who maintains the pipeline. Every hybrid approach, whether pgvector plus full-text, Elasticsearch, Algolia, or Pinecone plus metadata filters, requires a content pipeline that keeps the search index fresh. That means incremental indexing when content changes, re-embedding on change, deletion handling so retired products stop showing up, eventual-consistency reasoning, and backfill when the schema changes. Building that yourself is a real project and a class of bug all its own.

This is the tax nobody budgets for at the start. The vector database demo works beautifully on a static snapshot. Then a product goes out of stock, a policy document is edited, ten thousand SKUs get a new field, and the index quietly drifts out of sync with the truth. The agent keeps answering confidently from stale vectors, and the failure is invisible until a customer catches it. When it is a separate vector DB plus glue code, freshness becomes a permanent line item on your roadmap.

When retrieval is wired into the content backend, that whole category of work goes away. Because retrieval runs inside the Content Lake where the content already lives, the freshness problem stops being something you maintain. Content Lake handles the index freshness so your team does not stand up a re-embedding job or reason about consistency between two systems that were never designed to agree. That is the practical difference between assembling hybrid retrieval and having it native: the same query behavior, minus the standing pipeline you would otherwise own forever.

MCP is a tool-and-context surface, not just search

Reducing MCP to "a fancier way to do retrieval" misses most of what it is for. Retrieval reads content, but production agents also need to fetch user state and act in your systems, and that requires tools in three categories. Read tools query content, fetch user state, and look up product info, with the agent reading as the user under their session token. Write tools mutate state, moving a seat on a flight, canceling a subscription, or opening a support ticket, with the agent acting as the user. Composite tools wrap a multi-step workflow so one tool call maps to three backend calls, which is what you want when you do not want the model orchestrating multi-step work itself.

Context is likewise not one bucket. It is four kinds with different owners and lifetimes: static instructions, per-turn runtime state, retrieved content, and agent-authored notes. Treating all four as a single blob is a governance failure as much as a technical one, because it puts the wrong people in charge of things they should not own. The retrieved-content layer is where hybrid retrieval lives; the static-instruction layer is where the agent's behavior is defined.

This is where MCP earns its place over a pure RAG stack. A vector database returns chunks. Context MCP is a hosted read-only surface that exposes structured, governed access to your content and sits alongside a knowledge base and an ingest path. When your agent needs read tools that respect the user's auth boundary, structured queries and schema lookups rather than nearest-neighbor guesses, and a place for governed instructions to live, you have crossed from "I need search" into "I need a context surface." That crossing is exactly when MCP beats RAG.

Governance: when who-can-edit decides the architecture

The strongest reason to reach for Context MCP over a bolt-on RAG stack often has nothing to do with retrieval quality. It is governance. In most teams the agent's system prompt lives in a file like `src/agents/prompts.ts`, where only engineering can touch it. Every fix to the agent's voice, escalation rules, or the never-say list becomes a pull request, brand and support and compliance cannot edit the behavior they are accountable for, and drift goes unnoticed until something ships wrong.

Sanity's answer is to author the system prompt in the Studio as a document, then gate it like code. Splitting the prompt into fields is not cosmetic; it is access control. Brand owns voice, Product owns how the agent uses user context, Support owns escalation, and Compliance owns the never-say list, and none of them files a pull request. Because it is content in the Studio, you get real-time collaboration, version history, scheduled publishing, and rollback for free, and the release that ships a homepage change ships a prompt change through Content Releases the same way. The gate stays engineering-grade: a prompt change runs the eval bench in CI before it can ship. Author it like content, gate it like code.

Customers reached for exactly this. One Nearform note reads, "Storing the system prompt in a Sanity document is genuinely useful. Editors tuned the agent's voice without any code changes," and Vipps wanted the whole organization, including product managers, to own the prompt. A pure vector database has no answer here, because it was never designed to govern instructions, only to return chunks. When the deciding factor is who can safely change agent behavior, the governed-content path is the architecture, and MCP is how the agent reaches it.

MCP-plus-governed-content versus RAG stacks for grounding agents

FeatureSanityPinecone (+ glue)pgvector / PostgresContentful
Hybrid retrieval (keyword + semantic + filters)Native: text::semanticSimilarity() blended with boost(match()) and score(), ordered by _score, all in one GROQ queryPossible: purpose-built vector similarity plus a separate metadata-filter layer you assemble and tune for structural constraintsPossible: pgvector for vectors plus full-text search, but hybrid ranking is a self-built engineering project you ownAssembled: hybrid runs through an external search stack bolted on via the App Framework, not native to the content store
Structural constraints that must holdGROQ predicates filter before ranking, so 'under $150, in stock in Portland' never returns items that only read like the queryRequires a metadata-filter layer alongside vector search to enforce price, stock, and location constraintsSQL WHERE clauses enforce constraints well; blending them with vector relevance in one ranked result is manual workDepends on the bolted-on search layer's filter support rather than a single query against the content store
Index freshness on content changeHandled by Content Lake: retrieval runs where content lives, so re-embedding and deletion handling are not something you maintainYou own the pipeline: incremental indexing, re-embedding on change, and deletion handling become a standing roadmap line itemYou own re-indexing and re-embedding triggers plus schema-change backfill as your own eventual-consistency problemContent changes must propagate to the external search index you wired up, a sync you build and monitor
Governed system prompt (who can edit)Authored in the Studio as a document with fields owned by Brand, Support, and Compliance, gated by an eval bench in CIOut of scope: a vector database returns chunks and has no surface for governing agent instructionsOut of scope: prompt governance lives in your application code, typically a file only engineering can changeCan store prompt text as content, but eval-gated, release-staged prompt shipping is not a native workflow
Staging agent behavior like a websiteContent Releases ship a prompt change the same way they stage a homepage change, with version history and rollbackNo content-release model; staging and rollback of agent behavior are your own deploy toolingStaging and rollback are handled in application deploys, not in the retrieval layerContent workflows exist for pages; staging governed agent instructions with evals is not a built-in path
Tool surface beyond searchContext MCP is a hosted read-only surface alongside a knowledge base and ingest path, shaped for agent read toolsSimilarity search only; read, write, and composite tools for user state are built and hosted separatelyA datastore, not an agent tool surface; MCP tooling and auth boundaries are yours to buildDelivery APIs plus app extensions; an agent tool-and-context surface is assembled rather than native