Build with AI

Sanity Context

Sanity Context is a hosted Model Context Protocol (MCP) server that gives AI agents structured, read-only access to a Sanity dataset.

Sanity Context allows you to build agents that can query Sanity datasets and use them as context. It lets you build assistants that answer from your docs, shopping assistants that recommend products from your catalog, editorial helpers that surface related work, and more.

Using code and front-end skills, you can personalize agents based on context and what you know about your users to create better agentic experiences.

Using the skill below you’ll get a working Model Context Protocol (MCP) endpoint, and an example agent connected to it on your existing site.

How it fits together

Sanity Context is one piece of a working agent setup. Additionally, you will need:

  • An MCP-capable AI harness. Your own application built with the Vercel AI SDK, or anything else that speaks MCP.
  • A Sanity project. Sanity Context reads from your dataset; an empty dataset gives the agent nothing to work with.
  • A Sanity Context configuration. A Sanity document defining what the agent sees, plus optional instructions that shape its behavior.
  • Initial Context. A tool call and API endpoint providing an agent with what it needs to know about your project.

Full details in Prerequisites.

Sanity Context provides the scoped, schema-aware window into your content. It doesn't run the agent loop itself, and it can't write back to your dataset. If you need tools for an agent that creates or modifies content, see the Sanity MCP Server. If you want an editorial assistant with its own harness that runs in the Dashboard, on Slack or through an API, see Content Agent.

Do you fully control the system prompt?

Install the Sanity Context skill

We’ve made a skill for coding agents to walk you through how to set up Sanity Context and make a working user-facing agent on your website. It’s hard work, so we recommend a recent release of a model like Opus or Codex to do this work.

Prompt your coding agent to run the setup skill

The create-agent-with-sanity-context skill asks about your goal, inspects your project, and walks you through configuring Studio, building an example agent, and optionally adding a frontend UI.

Follow the guided steps

The skill generates the schema, code, and configuration you need.

When you're done, you'll have:

  • A Sanity Context document published in your Studio.
  • A working MCP endpoint URL.
  • Optionally: A reference agent implementation (Next.js + Vercel AI SDK by default) that can talk to your users about your content.

To set everything up by hand, see Manual setup. To collect and analyze agent chats, set up Sanity Context insights.

Prerequisites

To set up Sanity Context, you'll need:

  • A Sanity project with content.
  • Sanity Studio 5.1.0 or later for server-side schema support.
  • A deployed schema. Run sanity schema deploy or sanity deploy
  • A Sanity API read token. Create a read token at sanity.io/manage; keep the token server-side.
  • A model and API key. Match the model to the reasoning you need. Simple data and questions work with small, fast models like Claude Haiku or Gemini Flash. If you see errors or misunderstandings, switch to a more capable model.
  • Optionally: a frontend application where your agent will live, such as Next.js or Remix.

Core components

Sanity Context is an MCP endpoint that exposes tools to agents for reading your content. You control what it returns through a Sanity Context document in Studio, or through URL parameters.

Loading...

Sanity Context document

A Sanity Context document defines what an agent can see in your dataset and how it should behave. You can manage these documents in Studio using the @sanity/context plugin.

Each document has the following fields:

  • name. A human-readable name. Shown only in Studio.
  • slug. The identifier the MCP endpoint uses. Set this to something short and stable, like support-bot or product-catalog.
  • instructions. Custom instructions for the agent, in plain language. For example: "Respond in Spanish" or "Only answer questions about product documentation; for anything else, suggest contacting support."
  • groqFilter. An optional GROQ filter expression that limits which documents the agent can read. See Filtering content below.

Filtering content

The groqFilter field accepts a GROQ filter expression, the part inside the [ ... ] of a full GROQ query. It restricts the agent to a subset of your dataset.

Supported operators:

OperatorUse
==, !=Equality
>, <, >=, <=Comparison
&&, ||Boolean combination
inMembership
defined()Field existence check

Sub-queries, projections, and ordering are not supported in groqFilter. Use it to scope, not to shape; the agent applies its own queries on top of whatever filter you set.

Examples:

_type == "product"
_type in ["article", "author"]
_type == "product" && public == true

MCP endpoint

Once you publish a Sanity Context document, the MCP server is reachable at:

https://api.sanity.io/:apiVersion/context/mcp/:projectId/:dataset/:slug
SegmentDescription
:apiVersionAPI version in vYYYY-MM-DD format, e.g. v2026-02-27
:projectIdYour project ID
:datasetDataset name
:slugSlug of the Sanity Context document

You can also connect without a document, using only URL parameters to pass configuration. That endpoint omits the slug:

https://api.sanity.io/:apiVersion/context/mcp/:projectId/:dataset

This pattern is useful for quick testing, isolated environments, or cases where you'd rather not maintain a Studio document. See Without a Sanity Context document for the full pattern.

URL parameters

The endpoint accepts the following query parameters. These apply at request time and are not stored on the document:

ParameterDescription
instructionsOverrides the document's instructions for this request
groqFilterOverrides the document's GROQ filter for this request
perspectiveContent perspective to query. Defaults to published; set to drafts to include draft content
embeddingsSet to true to enable semantic search
workspaceWorkspace name; only applies when multiple workspaces share a dataset

If you pass a parameter that also exists on the Sanity Context document, the URL parameter wins for that request.

Initial context

We ask agents to call the initial_context tool first to orient themselves. It returns a compressed schema overview along with instructions on how to query your content from the context document described above.

If you control the system prompt, for example when building custom agents, you should include the initial context in your system prompt to save on a tool call for every conversation. This reduces user-facing latency.

You can fetch this data via the /initial-context HTTP endpoint and inject it into the system prompt.

Append /initial-context to the MCP URL path (before any query params), using the same auth header:

When you do this, the agent no longer needs this tool, so you should exclude it from the array of tools you hand to the agent. For example for AI-sdk it would look like this:

Tools

Connecting an MCP client to the endpoint exposes four tools. Most agents use several over the course of a single conversation:

ToolPurpose
initial_contextCompressed schema overview. Can be replaced by the /initial-context HTTP endpoint (see above)
schema_explorerReturns detailed schema information for a specific type, including fields and references
groq_queryExecutes a GROQ query against the dataset, subject to any groqFilter in effect
array_field_readerReads large array fields and Portable Text content from a single document

You can test the endpoint by listing the tools directly with curl:

A successful response returns a JSON object with a result.tools array listing the four tools above. If you see a 401, your token is missing or invalid; see Troubleshooting.

Searching text

Through Content Lake, Context supports:

  • Fuzzy text search through BM25
  • Semantic search through dataset embeddings
  • Hybrid combination of both with selectable boosting

Semantic search is available when embeddings are enabled on the dataset. With embeddings, the agent can rank results by meaning rather than exact-match alone. That's useful for natural-language queries like "products that work in cold weather" or "articles about retention strategies."

Semantic search becomes available through the text::semanticSimilarity GROQ function. The agent calls it inside a groq_query like any other GROQ feature.

Enable embeddings on the dataset. See Dataset embeddings for the full setup.

Auto detecting embeddings

When to enable embeddings

Enable embeddings when your agent needs to query content and won’t be able to guess accurately the words or phrases to search for. Product catalogs, knowledge bases, help content, and editorial articles are good candidates.

Embeddings have storage and compute costs. See Dataset embeddings for pricing and the configuration choices that affect cost.

Manual setup

If you prefer not to use the skill, you can of course set up Sanity Context manually. Manual setup has two paths depending on whether you want a Studio document to manage configuration:

  • With a Sanity Context document is the recommended pattern for anything beyond quick testing. Configuration lives in Studio, where it's auditable, editable by non-developers, and shared across environments.
  • Without a Sanity Context document is for quick testing, one-off scripts, or environments where you'd rather pass configuration in the request itself. All configuration moves to URL parameters.

With a Sanity Context document

Install the @sanity/context plugin and add it to your studio config:

This adds a new Sanity Context document type to your studio. Optionally, place the Sanity Context document type in a specific spot in your studio structure:

Next, create and publish a Sanity Context document in your Studio. Configure the fields described in The Sanity Context document. The MCP endpoint URL appears at the top of the document form once it's saved.

Use the URL to connect an MCP client:

import {createMCPClient} from '@ai-sdk/mcp'

const mcpClient = await createMCPClient({
  transport: {
    type: 'http',
    url: 'https://api.sanity.io/:apiVersion/context/mcp/:projectId/:dataset/:slug',
    headers: {
      Authorization: `Bearer <SANITY_API_READ_TOKEN>`,
    },
  },
})

Verify the connection by listing the available tools:

const tools = await mcpClient.tools()
console.log(tools)

You should see initial_context, schema_explorer, groq_query, and array_field_reader. If you don't, see Troubleshooting

Without a Sanity Context document

Connect directly to the project-and-dataset endpoint, passing configuration as URL parameters:

import {createMCPClient} from '@ai-sdk/mcp'

const url = new URL('https://api.sanity.io/:apiVersion/context/mcp/:projectId/:dataset')
url.searchParams.set('groqFilter', '_type == "product"')

const mcpClient = await createMCPClient({
  transport: {
    type: 'http',
    url: url.toString(),
    headers: {
      Authorization: `Bearer <SANITY_API_READ_TOKEN>`,
    },
  },
})

Verify the connection the same way:

const tools = await mcpClient.tools()
console.log(tools)

This pattern is convenient for one-off scripts and testing. For anything you deploy, use the document-based path so configuration stays in Studio rather than scattered across deployment environments.

Security and access

Authentication

Sanity Context uses Sanity API tokens. Pass the token as a Bearer header on every request:

Authorization: Bearer <SANITY_API_READ_TOKEN>

Use a read token. Agents don't need write access; the MCP is read-only by design. Keep the token server-side and never embed it in client code.

What agents can read

Sanity Context exposes three things to the agent:

  • Your schema. Document types, field definitions, and references.
  • Your content. Published documents by default; pass perspective=drafts to include drafts.
  • References. Agents can follow references between documents during a query.

What agents see within those is shaped by groqFilter. With no filter set, the agent can read every published document the token has permission to access.

This is a security boundary, not just a UX hint. Use groqFilter to scope agents to the content they should see: public products only, articles in a published state only, knowledge-base entries from a specific category. For example:

_type == "product" && public == true
_type == "article" && status == "published"
_type in ["faq", "guide"] && audience == "customer"

Mutations

Sanity Context cannot write to your dataset. If you need an agent that creates or updates documents, run those mutations server-side in your own code after the agent decides what to do. For an MCP-based write path, see the Sanity MCP Server.

Troubleshooting

401 Unauthorized

Your Sanity API token is missing or invalid:

  • Confirm the token exists in your environment and is being read by your agent code.
  • Confirm the token has read access to the project and dataset you're targeting.
  • Confirm it's sent as Authorization: Bearer <token>, not as a query parameter or a different header.

403 Forbidden

The token authenticated but doesn't have permission to access the dataset or the requested content. Check the token's scope at sanity.io/manage. If you're using dataset-level ACLs, confirm the token's role covers the documents the agent needs to read.

No schema or empty results

Sanity Context reads your schema from the server, not your local machine. If the agent reports an empty or missing schema:

  • Confirm you're on Sanity Studio 5.1.0 or later.
  • Run sanity schema deploy, or open your hosted Studio in a browser if you deploy with sanity deploy.
  • Retry the MCP connection.

If the schema deploys but queries still return nothing, check whether groqFilter is excluding everything the agent tries to read. A filter like _type == "product" && public == true returns no results if no product has public: true.

Tools not appearing

If mcpClient.tools() returns an empty array or fewer than four tools:

  • Re-check the MCP URL. The path is context/mcp/:projectId/:dataset/:slug. Missing the slug while expecting document-managed config is a common cause.
  • Confirm the Sanity Context document is published, not just saved as a draft.
  • Log the response from a manual tools/list request (see Tools the agent can call) to see the raw MCP response.

GROQ filter errors

groqFilter accepts only filter expressions. See Filtering content for what's supported. Common errors:

  • Using projection syntax ({ name, price }) inside the filter. Filters evaluate to true or false; move projections to the agent's queries instead.
  • Using ordering or slicing (order(...), [0...10]) inside the filter. Same reason.
  • Subqueries like *[...]. Filters are a single boolean expression scoped to one document at a time.

If a filter is invalid, the MCP returns a 400 with the parser error in the response body.

Drafts not appearing

By default, agents only see published documents. To include drafts, pass perspective=drafts as a URL parameter or set it on your Sanity Context document. Drafts are only visible to tokens that have read access to drafts; check the token's permissions if you've set perspective=drafts and still see only published content.

Semantic search not returning ranked results

Semantic search requires embeddings to be enabled on the dataset:

  • Confirm embeddings are enabled. See Dataset embeddings.
  • Confirm ?embeddings=true is on the MCP URL or set on the document.
  • Confirm the agent is constructing queries that use text::semanticSimilarity. Some smaller models won't reach for it without explicit instruction; if the agent ignores it, name the function in your instructions field.

Models behaving erratically

If the agent picks the wrong tool, writes malformed GROQ, or invents field names, the model might be the bottleneck. Try a more capable model and rerun. If the behavior improves, model capability is the limiter. You might also have issues with your instructions. Sit down and read them and make sure they would make sense to an uninformed reader that isn’t you.

Next steps

Once your agent is connected and returning tools, you can deepen the integration:

  • Build an AI shopping assistant. A step-by-step walkthrough that uses Sanity Context to power product discovery.
  • AI shopping assistant starter. A full reference implementation on GitHub.
  • Configure insights. Track and analyze agent conversations so you can better understand how users interact with the agent and your content.
  • Shape your agent's behavior with shape-your-agent once you know what the agent should and shouldn't do.
  • Tune your context instructions with dial-your-context once you have a working baseline and want to refine what the agent prioritizes.

Was this page helpful?