create-agent-with-sanity-context
Build AI agents with structured access to Sanity content via Sanity Context. Use when setting up a Sanity-powered chatbot, connecting an AI assistant to Sanity…
npx skills add https://github.com/sanity-io/context --skill create-agent-with-sanity-contextBuild an Agent with Sanity Context
Give AI agents intelligent access to your Sanity content. Unlike embedding-only approaches, Sanity Context is schema-aware—agents can reason over your content structure, query with real field values, follow references, and combine structural filters with semantic search.
Sanity Context gives agents your schema and teaches them GROQ, but it can't know your domain. You close that gap through the Instructions field (dataset-specific query guidance) and optionally the system prompt (agent behavior and tone).
Three actors in this workflow:
- You — the agent executing this skill, helping the user set things up
- The user — the human you're working with, who knows their domain and data
- The production agent — the agent being built, which will serve end users
What You'll Need
The agent code needs only three values:
| Value | Where to get it |
|---|---|
MCP endpoint URL (SANITY_CONTEXT_MCP_URL) | Shown on the endpoint in the Context app once it's created (Step 1) |
Organization API token (SANITY_ORGANIZATION_TOKEN) | Manage → organization → API → Tokens → Add API token, then under Organization permissions check Context. Choose Viewer for an agent that only reads; choose Editor if it also records Insights (Step 3). Project tokens do not work. |
| LLM API key | From your LLM provider (Anthropic, OpenAI, etc.) — any provider works |
Setup also involves:
| Requirement | When | Where to get it |
|---|---|---|
| Context enabled | Always | An organization admin enables it from the organization's Labs page in Manage. This also enables Knowledge Bases |
| Sanity project and dataset | GROQ mode | Picked when creating the endpoint; also where the schema is deployed from (sanity.config.ts) |
| Organization ID | Insights | Manage → organization settings, or the organization's URL |
The organization token is a server-side secret. It must never reach the browser.
How Sanity Context Works
The Sanity Context MCP server gives AI agents structured, read-only access to Sanity content. The core integration pattern:
- Initial Context: Fetch the initial context (the schema in GROQ mode, the Knowledge Base outline in Knowledge Base mode) via the
/initial-contextHTTP endpoint and inject it into the system prompt - MCP Connection: HTTP transport to the MCP endpoint URL
- Authentication: Bearer token using the organization API token
- Tool Discovery: Get available tools from MCP client, pass to LLM
- System Prompt: Tell the production agent its role, tone, and boundaries
Two retrieval modes. The endpoint's content source decides which one it serves:
- GROQ mode (a dataset source): the agent queries the live dataset with GROQ, guided by the schema. Fits structured, consistent content where the schema tells the agent where to look: catalogs, articles, FAQs. For in-between content (a catalog with useful details in prose fields), enable dataset embeddings and stay in GROQ mode.
- Knowledge Base mode (Knowledge Base sources, beta): the agent reads a pre-built index built ahead of time from datasets, websites, and files. Fits answers spread across prose from several places, where finding the answer is the hard part. See Context retrieval modes.
An endpoint serves one mode. If it has both a dataset source and Knowledge Base sources, the dataset wins and the Knowledge Bases are ignored, with no error. Ask the user which fits; GROQ mode is the default for content that lives in a Sanity dataset.
MCP endpoints are created in the Context app in the Sanity Dashboard. Each endpoint has these fields:
| Field | Purpose |
|---|---|
| Title | Human-readable label. The agent also sees it as the heading of its initial context |
| Name | URL identifier (lowercase, numbers, hyphens). Unique in the organization and immutable after creation |
| Content source | What the endpoint serves: a dataset (GROQ mode) or one or more Knowledge Bases (Knowledge Base mode) |
| Instructions | Domain-specific guidance for the agent, injected into the initial context |
| GROQ filter | A GROQ filter expression scoping which documents the agent can read. GROQ mode only |
MCP URL:
https://api.sanity.io/v1/context/organizations/:organizationId/mcp/:endpointName
The Context app shows the URL once the endpoint is created. Changes to instructions or the filter in the Context app take effect without redeploying the agent. If the agent caches /initial-context (recommended below), instruction changes show up when that cache refreshes.
URL query params apply per request (useful for testing and development):
?instructions=<content>— Overrides the endpoint's instructions (an empty?instructions=gives a blank slate)?groqFilter=<expression>— Narrows the endpoint's filter. The saved filter always still applies; the two are combined with&&?perspective=drafts|raw|<releaseId>— Content perspective. Defaults topublished
Initial context:
Always fetch the initial context via the /initial-context HTTP endpoint and inject it into the system prompt. This gives a significant latency improvement on the first message—the agent already knows the schema and available tools without needing a tool call. It also enables better prompt caching since the schema prefix is stable across conversations.
Append /initial-context to the MCP URL path (before any query params), using the same auth header:
# SANITY_CONTEXT_MCP_URL=https://api.sanity.io/v1/context/organizations/:organizationId/mcp/:endpointName
curl "$SANITY_CONTEXT_MCP_URL/initial-context" \
-H "Authorization: Bearer $SANITY_ORGANIZATION_TOKEN"
In a long-running server, cache the result with a short TTL (the reference implementation uses 5 minutes) and include it in your system prompt. A short TTL keeps schema, Instructions, and Knowledge Base rebuilds flowing through without a redeploy.
Critical: the model must always get the initial context. It's either inlined into the system prompt, or available as the
initial_contexttool. Never neither: without it the agent has no schema or outline and guesses.
- Fetch succeeded and inlined → remove the
initial_contexttool, so the model doesn't fetch it again.- Fetch failed, or you don't control the system prompt (e.g. a third-party MCP client) → keep the
initial_contexttool; the agent calls it on the first message.Never remove the tool unless the payload is actually in the system prompt.
Available MCP Tools
The endpoint's mode decides which tools it serves:
- GROQ mode: tools to read the schema, run GROQ queries (with optional semantic search), and read large array fields. Queries are always subject to the endpoint's GROQ filter.
- Knowledge Base mode: tools to search and read Knowledge Base entries.
Both modes serve initial_context: the schema overview (GROQ mode) or the Knowledge Base outline, plus the endpoint's Instructions. It's the same payload as the /initial-context HTTP endpoint.
Don't hardcode the tool list. The set grows over time, so take it from the MCP client (mcpClient.tools() or tools/list). For what each tool does, see Context MCP tools.
For development and debugging: The general Sanity MCP provides broader access to your Sanity project (schema deployment, document management, etc.). Useful during development but not intended for customer-facing applications.
Before You Start: Understand the User's Situation
A complete integration has four distinct components that may live in different places:
| Component | What it is | Examples |
|---|---|---|
| 1. MCP Endpoint | A deployed schema (GROQ mode) or a built Knowledge Base, plus an endpoint created in the Context app | Studio (v5.1.0+) for the schema deploy, Context app in the Sanity Dashboard for Knowledge Bases and the endpoint |
| 2. Agent Implementation | Code that connects to Sanity Context and handles LLM interactions | Next.js API route, Express server, Python service, or any MCP-compatible client |
| 3. Frontend | UI for users to interact with the agent | Chat widget, search interface, CLI—or none for backend services |
| 4. Functions | Scheduled classification via Sanity Blueprints (only with Insights, Step 3) | sanity.blueprint.ts + functions/ directory — has its own placement constraints (see Insights: Project Structure) |
An MCP endpoint is always required, backed by a deployed schema (GROQ mode, Studio v5.1.0+) or a built Knowledge Base: the agent has nothing to connect to without them. Frontend depends on the use case (many agents run as backend services or integrate into existing UIs).
Before writing any code, inspect the project to understand:
- Project layout: Read the top-level
package.json(check forworkspacesor apnpm-workspace.yaml), locate the lockfile, and map out the distinct apps/packages. This determines wheresanity.blueprint.tsandfunctions/will go — see Insights: Project Structure. - Their stack: What framework/runtime? (Next.js, Remix, Node server, Python, etc.)
- Their AI library: Vercel AI SDK, LangChain, direct API calls, etc.
- Their domain: What will the agent help with? (Shopping, docs, support, search, etc.)
- Which components they need help with: They may only need one or two.
- Components in different repos (most common): You may only have access to one component. Complete what you can, then tell the user what steps remain for the other repos.
- Co-located components: All in the same project—work through them based on what the user wants to tackle first.
- No Studio in the codebase? For GROQ mode, ask the user whether the schema is already deployed from a Studio elsewhere. If it isn't, it has to be deployed before the endpoint will serve. Knowledge Base mode doesn't need a deployed schema.
Workflow
Always present the full workflow. Even if the user's request seems narrow, inform them of all four steps — you don't have to implement everything, but they should know what's available. Step 3 is optional and Step 4 is recommended once the agent works; make sure the user knows both exist, then let them decide. Walk the user through the steps, explaining what each unlocks:
- Create the MCP Endpoint — Deploy the schema or build a Knowledge Base, then create an endpoint in the Context app
- Build the Agent — Get a working chatbot connected to their content
- Conversation Insights (optional) — Track and classify conversations to see where the agent succeeds and struggles
- Tune the Agent — Refine instructions and system prompt using the tuning skills
After completing each step, present the next one. Stop when the user has what they need or explicitly defers.
Step 1: Create the MCP Endpoint
Confirm the retrieval mode with the user first (see Two retrieval modes), then prepare the content source.
GROQ mode: deploy the schema. The MCP server reads the schema from Sanity, not from the local machine, and an endpoint with a dataset source won't serve without a deployed schema from Studio v5.1.0+. Check the Studio's sanity version first. Then, from the Studio directory:
- Any Studio:
npx sanity schema deploy - Sanity-hosted Studio:
npx sanity deployalso works, but the user then has to open the deployed Studio in the browser once to trigger the schema deployment - Externally hosted Studio (Sanity CLI v5.8.0+):
npx sanity deploy --external --schema-requiredregisters the external URL and fails fast if the schema deploy fails
Knowledge Base mode: create and build the Knowledge Base. The user does this in the Context app (organization Administrator or Developer role). At a high level:
- Select New knowledge base and give it a Title and a Purpose: one or two sentences on who it serves and what it helps with. A specific purpose produces a better build
- Add source: a dataset, a website, or files. Start with a focused set of current material
- Select Build entries and wait for Entries up to date, then skim Entries and Issues
For details on sources, issues, and keeping it current, point the user to Create a Knowledge Base.
Create the endpoint in the Context app. The user does this in the Sanity Dashboard; it needs the Administrator or Developer role in the organization. Attaching a dataset also needs the Administrator or Developer role on the dataset's project, with unrestricted read access to that dataset. Tell them what to enter:
- Open the Context app in the Sanity Dashboard and select New MCP endpoint
- Title: something readable, e.g. "Product Assistant"
- Name: short and stable, e.g.
product-assistant. It becomes part of the URL and can't be changed later - Content source:
- GROQ mode: choose the Dataset tab, then pick the project and dataset. Projects where the user lacks that role are disabled
- Knowledge Base mode: choose the Knowledge bases tab and check the Knowledge Bases to serve
- GROQ filter (GROQ mode, optional): a filter expression such as
_type in ["product", "category"]. Start broad; thedial-your-contextskill helps narrow it - Instructions: leave empty for now; Step 4 covers them
- Select Create endpoint, and copy the endpoint URL from its detail page
Get the organization token if the user doesn't have one yet (see What You'll Need). Store it as SANITY_ORGANIZATION_TOKEN next to the agent's other secrets.
Validate the endpoint:
curl -X POST "$SANITY_CONTEXT_MCP_URL" \
-H "Authorization: Bearer $SANITY_ORGANIZATION_TOKEN" \
-H "Accept: application/json, text/event-stream" \
-H "Content-Type: application/json" \
-d '{"jsonrpc": "2.0", "method": "tools/list", "id": 1}'
The response should return a result.tools array that includes initial_context. If it returns an error or an empty list, see Troubleshooting.
Step 2: Build the Agent (Adapt to user's stack)
The user already has an agent or MCP client? They just need to connect it to the MCP endpoint URL with the organization token as a Bearer token. The tools will appear automatically.
Building from scratch? Help the user set up the MCP connection and LLM integration. Whatever the stack, the model must get the initial context: inlined into the system prompt, or as the initial_context tool (see Initial context). The snippets and reference implementations use Vercel AI SDK v7 with Anthropic, but the pattern works with any LLM provider (OpenAI, local models, etc.). Start with the basics and add advanced patterns as needed.
Follow references/connecting-an-agent.md: install, the initial context fetch, a request/response pattern for CLIs and APIs, a streaming route for chat UIs with where it goes in each framework, framework pitfalls, and a map of the full Next.js reference implementation.
Check it end to end: ask the agent "What content do you have access to?" With the initial context inlined, it answers straight away without calling the initial_context tool.
System prompt: keep it short and focused on behavior; the shape-your-agent skill covers what to put in it.
Step 3: Conversation Insights (Optional)
Offer Insights; the user decides. Without tracking, there's no easy way to know whether the agent is helping users or failing silently. Insights shows what users ask, where the agent struggles, and what content is missing. It adds a Context Editor token and a scheduled function, so skip it if the user doesn't want that yet.
If the user wants it, setup is two parts — do both:
- Telemetry — Add one integration to your existing
streamTextcall (stores conversation transcripts in the organization's Context store). Recording conversations needs a Context Editor token; one Editor token can serve both the MCP and Insights - Classification — Deploy a scheduled function that analyzes conversations with the user's own AI SDK model and records verdicts back through the Context API
Telemetry without classification just stores raw conversations. Classification is what extracts success scores, sentiment, and content gaps — the actual insights. Set up both together.
Follow references/conversation-classification.md to set this up. The guide covers both parts end-to-end. Insights appears in the Context app in the Sanity Dashboard once conversations are classified.
Step 4: Tune Your Agent (Recommended)
Once the production agent works:
-
Tune the Instructions field using the
dial-your-contextskill — an interactive session where you explore the user's dataset together, verify findings, and produce concise Instructions that teach the production agent what the schema alone doesn't make obvious: counter-intuitive field names, second-order reference chains, data quality issues, required filters, and query patterns. The skill can also help configure the endpoint's GROQ filter to scope what content the production agent sees. The user pastes the results into the endpoint's Instructions and GROQ filter fields in the Context app.Knowledge Base mode:
dial-your-contexttargets GROQ mode. For a Knowledge Base, answers improve in the Context app by resolving issues and fixing sources; see Resolve Knowledge Base issues. -
Shape the system prompt (optional) using the
shape-your-agentskill — if the user controls the production agent's system prompt, this helps define tone, boundaries, and guardrails. Skip this if the user doesn't control the system prompt.
Best Practices
- Content filters: Use the endpoint's GROQ filter to scope what the production agent sees — start broad, then narrow based on what it actually needs. The filter is a GROQ filter expression, the part inside
*[...], not a full query or projection. Examples:_type in ["product", "article"],_type == "article" && language == "en",_type == "product" && references(*[_type == "category" && slug.current == "electronics"]._id) - Instructions field: Keep it concise — only include what the auto-generated schema doesn't make obvious. Don't duplicate schema information. See the
dial-your-contextskill. - System prompts: Be explicit about forbidden behaviors and formatting rules. Less is more — an over-engineered prompt can interfere with the Instructions content. See the
shape-your-agentskill. - Package versions:
@sanity/contextis only needed for Insights (Step 3); an agent without Insights doesn't install it. When you do use it, use the latest version — runnpm info @sanity/context versionto get it. For other packages, usenpm info <package> versionfor the latest release, but stay on the major versions the referencepackage.jsonuses (the snippets are written for those majors, e.g. AI SDK v7). AI SDK and Sanity packages update frequently, and using outdated versions will cause errors that are hard to debug.
Troubleshooting
"401 Unauthorized" from MCP
- "Missing Sanity session": no token, or no
Bearerheader. - "Not a member of this organization": an invalid token, or a token that isn't in the organization from the URL.
On the MCP route both come back as JSON-RPC -32001 with that message. /initial-context errors also include a code: missingCredential or organizationAccessDenied. Confirm SANITY_ORGANIZATION_TOKEN is set, is read by the agent code, is sent as Authorization: Bearer <token>, and that the organization ID in the URL is right.
"404": MCP endpoint not found
HTTP 404 with JSON-RPC -32001 and the message "MCP endpoint not found: ". The endpoint name or organization ID in the URL is wrong. Copy the URL from the endpoint in the Context app; the name is lowercase and can't be changed. (-32001 is also used for the 401 above, so check the HTTP status.)
"403 Forbidden": JSON-RPC -32007 (contextGrantRequired) or -32006 (knowledgeBaseAccessDenied)
The token is not an organization API token with Context access. -32007 comes from the check on endpoints with a dataset source; -32006 ("No access to knowledge base 'kb…'") comes from the check on each Knowledge Base an endpoint serves. A project token is the most common first-run failure: it is refused however broad its permissions. Create an organization token as described in What You'll Need.
The -32007 message reads "This requires an organization API token with Context access ('sanity.knowledge-base.read')…". On /initial-context the same failure shows the code contextGrantRequired.
-32004: "Only datasets with deployed Studio applications are supported"
The schema isn't deployed for the endpoint's project and dataset. Deploy it from a Studio on v5.1.0+ (see Step 1), then reconnect.
-32005: 'Mode is set to "knowledge_base" but no knowledge bases are configured'
The endpoint has no dataset source and no Knowledge Base it can serve. For GROQ mode, edit the endpoint in the Context app and choose the Dataset tab as its content source. For Knowledge Base mode, check that at least one Knowledge Base is selected on the endpoint.
"No documents found" / Empty results
Check the endpoint's GROQ filter in the Context app:
- Is the GROQ filter correct?
- Are the document types spelled correctly?
- Are there published documents matching the filter? The endpoint reads the
publishedperspective by default
A filter that matches nothing looks like a broken connection, so check it before debugging the connection. If several Studio workspaces point at the same dataset, the endpoint uses the first one unless ?workspace=<name> is set, which can serve the wrong schema.
Tools not appearing
- Check that
mcpClient.tools()returns tools (log it) - Ensure the MCP URL is correct: organization ID and endpoint name
- If the URL has a
toolsparam, it narrows the tool list; drop it to see everything