Connect Sanity Context with Vercel AI SDK
Connect Sanity Context to a TypeScript agent using the Vercel AI SDK and Anthropic.
The Vercel AI SDK is a TypeScript toolkit for building AI applications and agents. This guide shows you how to connect an AI SDK agent to Sanity Context. You'll build a script that loads your schema or Knowledge Base outline into the agent's instructions, connects to your Context MCP endpoint, and answers a question about your content.
The same code works whether the endpoint uses Knowledge Base sources, a dataset source, or both. With Knowledge Base sources only, the tools are knowledge_base_search and knowledge_base_read instead of the dataset source tools, and the initial context is the Knowledge Base outline instead of your schema. With both source types, the endpoint serves the dataset source tools and the Knowledge Base source tools, and its initial context contains both the schema overview and the Knowledge Base outline. See Context MCP source types.
Prerequisites
To follow this guide, you need:
- Context MCP endpoint URL: Shown on the MCP endpoint in the Context app in the Sanity Dashboard. To create an MCP endpoint, see Configure a Context MCP endpoint, or expand Create the endpoint with the Sanity CLI (optional) at the end of this section.
- Organization API token: Create one in Manage under API > Tokens at the organization level. Under Organization permissions, select Context with the Viewer role. Project tokens are refused.
- Anthropic API key: The AI SDK reads it from
ANTHROPIC_API_KEY. - Node.js 22.18 or later: Runs TypeScript files directly. On earlier Node.js 22 releases, run the example with
npx tsx --env-file=.env agent.tsinstead.
Create the endpoint with the Sanity CLI (optional)
You can create a Knowledge Base and an MCP endpoint from the Sanity CLI instead of the Dashboard. If you haven't signed in, run npx sanity@latest login. You still create the organization token in Manage. Replace ORGANIZATION_ID, PROJECT_ID, and KNOWLEDGE_BASE_ID with your own values:
# Create a Knowledge Base. The command prints its ID. npx sanity@latest context create --organization ORGANIZATION_ID --title "Support" --description "Answers to customer support questions" # Add sources: a dataset query, files, or a website to crawl (--url) npx sanity@latest context sources create KNOWLEDGE_BASE_ID --sanity-project-id PROJECT_ID --sanity-dataset-id production --query '*[_type == "article"]' npx sanity@latest context sources create KNOWLEDGE_BASE_ID --file ./returns-policy.pdf # Build it, then review anything the build flagged npx sanity@latest context build KNOWLEDGE_BASE_ID --watch npx sanity@latest context issues list KNOWLEDGE_BASE_ID --status open # Create the MCP endpoint and check that it's ready npx sanity@latest context mcp create support --title "Support" --organization ORGANIZATION_ID --knowledge-base KNOWLEDGE_BASE_ID npx sanity@latest context mcp status support --organization ORGANIZATION_ID
# Create a Knowledge Base. The command prints its ID. pnpm dlx sanity@latest context create --organization ORGANIZATION_ID --title "Support" --description "Answers to customer support questions" # Add sources: a dataset query, files, or a website to crawl (--url) pnpm dlx sanity@latest context sources create KNOWLEDGE_BASE_ID --sanity-project-id PROJECT_ID --sanity-dataset-id production --query '*[_type == "article"]' pnpm dlx sanity@latest context sources create KNOWLEDGE_BASE_ID --file ./returns-policy.pdf # Build it, then review anything the build flagged pnpm dlx sanity@latest context build KNOWLEDGE_BASE_ID --watch pnpm dlx sanity@latest context issues list KNOWLEDGE_BASE_ID --status open # Create the MCP endpoint and check that it's ready pnpm dlx sanity@latest context mcp create support --title "Support" --organization ORGANIZATION_ID --knowledge-base KNOWLEDGE_BASE_ID pnpm dlx sanity@latest context mcp status support --organization ORGANIZATION_ID
# Create a Knowledge Base. The command prints its ID. yarn dlx sanity@latest context create --organization ORGANIZATION_ID --title "Support" --description "Answers to customer support questions" # Add sources: a dataset query, files, or a website to crawl (--url) yarn dlx sanity@latest context sources create KNOWLEDGE_BASE_ID --sanity-project-id PROJECT_ID --sanity-dataset-id production --query '*[_type == "article"]' yarn dlx sanity@latest context sources create KNOWLEDGE_BASE_ID --file ./returns-policy.pdf # Build it, then review anything the build flagged yarn dlx sanity@latest context build KNOWLEDGE_BASE_ID --watch yarn dlx sanity@latest context issues list KNOWLEDGE_BASE_ID --status open # Create the MCP endpoint and check that it's ready yarn dlx sanity@latest context mcp create support --title "Support" --organization ORGANIZATION_ID --knowledge-base KNOWLEDGE_BASE_ID yarn dlx sanity@latest context mcp status support --organization ORGANIZATION_ID
# Create a Knowledge Base. The command prints its ID. bunx sanity@latest context create --organization ORGANIZATION_ID --title "Support" --description "Answers to customer support questions" # Add sources: a dataset query, files, or a website to crawl (--url) bunx sanity@latest context sources create KNOWLEDGE_BASE_ID --sanity-project-id PROJECT_ID --sanity-dataset-id production --query '*[_type == "article"]' bunx sanity@latest context sources create KNOWLEDGE_BASE_ID --file ./returns-policy.pdf # Build it, then review anything the build flagged bunx sanity@latest context build KNOWLEDGE_BASE_ID --watch bunx sanity@latest context issues list KNOWLEDGE_BASE_ID --status open # Create the MCP endpoint and check that it's ready bunx sanity@latest context mcp create support --title "Support" --organization ORGANIZATION_ID --knowledge-base KNOWLEDGE_BASE_ID bunx sanity@latest context mcp status support --organization ORGANIZATION_ID
mcp create prints the endpoint URL to use as SANITY_CONTEXT_MCP_URL. To serve a live dataset through a dataset source instead, replace --knowledge-base KNOWLEDGE_BASE_ID with -p PROJECT_ID -d production. See the Context CLI command reference for every flag.
Install dependencies
In a new project directory, install the AI SDK, its MCP client, and the Anthropic provider:
npm install ai@^7 @ai-sdk/mcp@^2 @ai-sdk/anthropic@^4
pnpm add ai@^7 @ai-sdk/mcp@^2 @ai-sdk/anthropic@^4
yarn add ai@^7 @ai-sdk/mcp@^2 @ai-sdk/anthropic@^4
bun add ai@^7 @ai-sdk/mcp@^2 @ai-sdk/anthropic@^4
This guide uses AI SDK v7. Keep the majors together: @ai-sdk/mcp shares an internal provider dependency with ai, so mismatched majors cause type errors on model and tools that look like mistakes in your own code.
All three packages are ESM-only. Set the module type in package.json so Node.js loads agent.ts as an ES module:
npm pkg set type=module
Set environment variables
Create a .env file next to agent.ts. Replace each placeholder with your own value:
SANITY_CONTEXT_MCP_URL=YOUR_MCP_ENDPOINT_URL SANITY_ORGANIZATION_TOKEN=YOUR_ORGANIZATION_TOKEN ANTHROPIC_API_KEY=YOUR_ANTHROPIC_API_KEY
Create the agent
Create agent.ts next to .env. The script works in three stages:
- Fetch initial context from the
/initial-contextHTTP endpoint and add it to the agent's instructions. The agent starts with a compressed schema or Knowledge Base outline, which saves a tool call on every conversation. For details, see Inline initial context into your system prompt. - Connect to the MCP endpoint and load its tools, authenticating with your organization API token. The script removes the
initial_contexttool only when the initial context fetch succeeded. If the fetch failed, the agent keeps the tool and calls it on the first message, so it never runs without your schema or outline. - Call the model with the tools and instructions. The AI SDK stops after one step by default, so
stopWhen: stepCountIs(20)lets the agent call tools and then write its answer.
import {anthropic} from '@ai-sdk/anthropic'
import {createMCPClient} from '@ai-sdk/mcp'
import {generateText, stepCountIs} from 'ai'
const MCP_URL = process.env.SANITY_CONTEXT_MCP_URL
const API_TOKEN = process.env.SANITY_ORGANIZATION_TOKEN
if (!MCP_URL || !API_TOKEN) {
throw new Error('Set SANITY_CONTEXT_MCP_URL and SANITY_ORGANIZATION_TOKEN')
}
// 1. Fetch initial context: your schema overview (dataset source) or Knowledge Base outline.
// Returns null on failure so the agent can fall back to the initial_context tool.
async function fetchInitialContext(mcpUrl: string, token: string): Promise<string | null> {
// Append to the path, not the whole URL, so any query parameters survive
const url = new URL(mcpUrl)
url.pathname = `${url.pathname.replace(/\/$/, '')}/initial-context`
try {
const res = await fetch(url, {headers: {Authorization: `Bearer ${token}`}})
if (res.ok) return await res.text()
console.error(`Initial context request failed: HTTP ${res.status} ${await res.text()}`)
} catch (error) {
console.error('Initial context request failed', error)
}
return null
}
// 2. Connect to Sanity Context MCP and fetch initial context in parallel
const [mcpClient, initialContext] = await Promise.all([
createMCPClient({
transport: {type: 'http', url: MCP_URL, headers: {Authorization: `Bearer ${API_TOKEN}`}},
}),
fetchInitialContext(MCP_URL, API_TOKEN),
])
try {
const tools = await mcpClient.tools()
// Drop initial_context only when its payload is inlined in the instructions; otherwise the agent needs the tool
if (initialContext) delete tools.initial_context
const instructions = initialContext
? `You are a helpful assistant.\n\n# Data reference\n\n${initialContext}`
: 'You are a helpful assistant.'
// 3. Call the LLM with the tools and the initial context in its instructions
const {text} = await generateText({
model: anthropic('claude-sonnet-5-5'),
instructions,
tools,
prompt: 'What content do we have?',
// The AI SDK stops after one step by default. Without this the agent calls a tool and never answers.
stopWhen: stepCountIs(20),
})
console.log(text)
} finally {
await mcpClient.close()
}Run the agent
Run the script. Node.js reads the .env file with --env-file:
node --env-file=.env agent.tsThe agent calls the Context MCP tools to explore your content, then prints its answer to the terminal. If the run fails, match the message against the list in Troubleshoot common errors.
Troubleshoot common errors
These are the most common errors and how to fix them:
[MODULE_TYPELESS_PACKAGE_JSON] Warning: Module type of file:///…/agent.ts is not specified and it doesn't parse as CommonJS.: The agent still runs, butpackage.jsondoesn't set the module type. Runnpm pkg set type=module. Editors andtscreport the same cause aserror TS1309: The current file is a CommonJS module and cannot use 'await' at the top level.Error: Set SANITY_CONTEXT_MCP_URL and SANITY_ORGANIZATION_TOKEN: The environment variables aren't loaded. Run the agent with--env-file=.envand check that the.envfile is next toagent.ts.Anthropic API key is missing. Pass it using the 'apiKey' parameter or the ANTHROPIC_API_KEY environment variable.: AddANTHROPIC_API_KEYto the.envfile.Initial context request failed: HTTP 403from the/initial-contextfetch, with codecontextGrantRequired(dataset source) orknowledgeBaseAccessDenied(Knowledge Base sources only) in the logged body, then JSON-RPC error-32007or-32006from the MCP connection. Both routes carry the same message, "Serving a dataset requires an organization API token with Context access ('sanity.knowledge-base.read'). Create one under your organization's API settings in Manage." or "No access to knowledge base '<knowledge base ID>'. Requires one of: sanity.knowledge-base.read." (<knowledge base ID>is a placeholder for the Knowledge Base's ID): With the dataset message, the token isn't an organization API token with Context Viewer permissions; with the Knowledge Base message, the token has no read access to that Knowledge Base. Project tokens are refused however broad their permissions. Create an organization token as described in Prerequisites. A 403 that names a Knowledge Base means the token can't read a Knowledge Base the endpoint serves.
Next steps
- Sanity Context patterns and best practices: Production patterns for public assistants, personalized agents, and multi-backend setups.
- Inline initial context into your system prompt: Control what the inlined payload contains and keep it fresh in long-running agents.
- Add insights to Sanity Context: Track and analyze agent conversations.
- AI shopping assistant walkthrough: A full reference implementation using Next.js and the Vercel AI SDK.