
Your agent needs to read and write Sanity. Sanity ships a hosted MCP server at mcp.sanity.io and a full HTTP API across Content Lake, the Management API, and Agent Actions. They are not two views of the same thing. They cover different surface area, they authenticate differently, and the difference matters most in exactly the case most teams are building for: a multi-tenant product where each customer has their own Sanity project. Here is how to pick.
Two objects are being compared, plus a third that agent builders keep confusing with the first. Establishing what each one is takes about a minute, and it saves an afternoon of chasing the wrong integration.
Sanity hosts its MCP server on its own infrastructure at https://mcp.sanity.io. The server speaks the standard Model Context Protocol (MCP) over HTTP and works with any compliant client. Authentication is OAuth by default, with the option to pass an API token in an Authorization: Bearer header instead, in which case tool calls run with that token's role and permissions rather than the signed-in user's.
The older local server, @sanity/mcp-server, is deprecated and its repository is archived. For new agent work, the remote server is the only relevant object.
The MCP tools cover the part of Sanity that is genuinely annoying to hand-roll: drafts, versions, and content releases. create_version, patch_documents, and publish_documents encode Sanity's rule that published content is never mutated directly, so your agent gets correct draft-and-release behavior without you writing it. Responses also paginate against the client's context budget, and the server fetches Sanity's current agent rules on demand instead of relying on a stale rules file in your repo.
Every Sanity API request is pinned to a date-based version in the URL path, as in https://<projectId>.api.sanity.io/v2026-07-28/data/query/production. That pinning is the API path's headline property: you choose when behavior changes, and removed versions fail loudly with a 410 rather than drifting underneath you.
The surface is wide. Content Lake covers query, mutation, actions, assets, export, history, listen, live, and backups. GROQ-powered webhooks fire on document create, update, and delete with GROQ filters and custom projections. The Management API covers projects, roles, and the Access API for robot tokens. Agent Actions exposes generate, transform, translate, prompt, and a schema-aware patch, currently on the experimental vX version.
Sanity also ships Agent Context, backed by a separate hosted Context MCP endpoint. It gives agents structured, read-only access to a configured slice of a dataset, in GROQ mode or Knowledge Base mode, and it cannot write. If you are building a customer-facing assistant that answers from your content, that is the right object. If you are building an agent that edits content, it is not, and the rest of this article is about the two surfaces that can write.
The capability gap runs in both directions here, which is unusual. The MCP server is missing things a production content pipeline needs, and it also exposes things a content agent has no business holding.
Sanity's tool reference currently documents 37 tools on the hosted server. Scalekit's connector catalog lists 45 for the same connector, including JSON and Markdown variants of the create and patch tools. Sanity notes directly in its docs that the available tool set may vary as it ships server updates, which is worth holding onto for the versioning discussion below.
The absent capabilities cluster around two themes: reacting to change, and moving bytes. If your agent needs to fire when an editor publishes something, you need webhooks or the Live Content API, and neither has an MCP tool. If it needs to put an image into Content Lake, dataset_assets_upload will hand it CLI instructions rather than uploading anything.
The third gap is the text-generating half of Agent Actions. Translating a document into eight locales, generating field content from a schema-aware instruction, or running a targeted prompt call are all HTTP-only. An editorial agent that localizes content is an HTTP-API agent, not an MCP agent, no matter how much of the rest of its work the MCP tools cover.
The other direction is the one that should worry you more. create_project, create_dataset, update_dataset, add_cors_origin, cors_origins_delete, deploy_schema, deploy_studio, and run_sanity_cli all sit on the same server as query_documents. Sanity's reference describes create_project as creating a project and initializing it with a dataset and API tokens.
Connect a content agent to the full server and it holds every one of those. A prompt injection inside a document body now has a path to adding a CORS origin, deploying a schema, or minting credentials. This is not a Sanity flaw; it is a general-purpose developer and editor server doing what it was designed to do. It is a reason to put something between your agent and that server. For a broader look at these risks, see MCP Security Risks in the Enterprise.
This is where Sanity breaks the pattern most MCP comparisons follow. Everywhere else, MCP means OAuth and the direct API means you get your pick of credential types. On Sanity it runs the other way.
The hosted server uses OAuth by default and attributes what the agent does to the signed-in Sanity user, so edits land in revision history under a real identity. Scalekit's connector catalog lists the connection type as OAuth 2.1 with Dynamic Client Registration (DCR), which means you are not filing a partner request to get a client.
You can opt out by setting an Authorization header with an API token, and the server then skips OAuth entirely and runs with that token's role. That is the escape hatch for headless MCP use, and it is also the point at which per-user identity disappears. Sanity documents OAuth sessions as typically expiring after about 7 days, with the client expected to prompt for re-authentication.
The HTTP API authenticates with bearer tokens: personal tokens, which carry your own role and link changes to you in revision history, and robot tokens, which are project-scoped or organization-scoped service credentials. Personal tokens last a year by default, shorter under SAML SSO. Robot tokens last until deleted unless you set an expiry, which since June 2026 can be a 30, 60, or 90 day preset or a custom date.
Sanity does publish an OAuth2 integration for acting on behalf of a user, and its state matters. The docs mark it experimental, describe it as intended for technology partners, require Sanity to provision your application credentials manually, support only the authorization_code grant, and state that refresh tokens are not supported: renewal means sending the user back through authentication. For a self-serve product onboarding customers this week, that is not a viable per-user credential path.
Put those two paragraphs together and the decision sharpens. If your agent must act as each individual user in each customer's Sanity project, the MCP server's OAuth flow is the practical way to get there. If you go direct to the HTTP API without a partner arrangement, you are issuing a robot token per customer project, which means every edit your agent makes is attributed to that robot and not to the person who asked for it.
Robot tokens are the correct answer for genuinely headless work: a nightly sync, a migration, a build-time export. They are the wrong answer when an auditor asks which human authorized a publish. Choose deliberately rather than by default, because the Access API will happily let you mint one credential and forget the question. Understanding credential ownership across agent tool-calling patterns helps teams make this choice with their eyes open.
Both paths leave real operational work on your side. The specific work differs, and two of the differences bite harder than teams expect.
Sanity enforces Content Lake rate limits per client IP address per second: 25 requests per second for mutations (combined across /data/mutate and /data/actions), 25 per second for asset uploads, and 500 per second globally. Concurrency is capped per dataset at 500 queries and 100 mutations.
The per-IP part is the one to internalize. Concurrency scales with your customer count because each customer has their own dataset. The mutation rate limit does not. Fifty tenants running publish-heavy agents out of the same egress IPs share one 25 requests per second bucket, and one customer's bulk operation can push everyone into 429. The official client retries queries with exponential backoff but never retries mutations, so that queue is yours to build. This is one of the harder auth challenges when moving from single-tenant to multi-tenant tool calling.
The HTTP API is date-versioned in the URL, with X-Sanity-Warning and X-Sanity-Deprecated response headers and a 410 once a version is removed. You pin a static date string, and you move when you choose to move. For a deterministic pipeline where an unexpected schema change is an incident, that is the property you are buying.
MCP tool schemas carry no such contract. Sanity ships server releases with changelogs, and its documentation says the available tool set may vary as updates land. The 37-versus-45 count between Sanity's reference and a connector catalog illustrates the same thing. Your agent picks up capability changes without a redeploy, which is a feature for fast-moving products and a liability for pipelines you expect to behave identically next quarter.
Every tool definition on an MCP server costs context on every turn. Using Scalekit's published working estimate of roughly 200 tokens per tool, a full 45-tool Sanity connection costs somewhere near 9,000 tokens before the agent reads a single document. At a few thousand runs a day that is a real line item. This is exactly the problem explored in MCP is up to 32× more expensive than CLI.
An editorial agent needs perhaps five of those tools. The gap between five and forty-five is both the token bill and, as covered above, the blast radius.
Neither path wins outright, and most production Sanity agents end up running both. The split is cleaner than usual because the auth story and the capability story point in the same direction.
Use Sanity MCP when:
Use the Sanity HTTP API when:
Scalekit ships Sanity as an MCP connector, which means the OAuth dance, the token vault, and the tool execution all sit behind one interface. For the HTTP-API-only capabilities above, you add a second connector through bring-your-own-connector carrying a robot token, and both live on the same connected-account model.
The first call establishes the connected account for a specific user. Nothing downstream works until that account is ACTIVE, and the connection_name string has to match the connection you configured in the Scalekit dashboard exactly, which is the single most common integration error.
list_scoped_tools is not a catalog browse. It returns the tools bound to this identifier's connected account, which is the surface that user's Sanity role actually permits. An editor and a developer on the same product get different lists from the same call, and that is the distinction between a per-user agent and a shared-credential one.
The LangChain adapter returns native StructuredTool objects, so the model fills each tool's input schema and you never hand-write Sanity's resource and workspaceName arguments. The full schemas live on the connector's docs page if you need to read them.
For a deeper look at how LangChain's tool calling model works end to end, see LangChain Tool Calling: How It Works, Where It Stops, and How Scalekit Completes It.
Not every step belongs in a reasoning loop. When your pipeline already knows what it wants, execute_tool runs one tool against one user's credentials with no model in the path.
This is the answer to both problems raised earlier: the context cost and the fact that a content agent should never see create_project or run_sanity_cli. A Virtual MCP server is a scoped endpoint that declares exactly which connections and which tools are exposed. You create it once per agent role, not once per user.
The server URL is static and safe to share. The session token is what carries user identity, and any request holding it runs as that user. Default expiry is about an hour; create_session_token is also the remint call, because there is no refresh endpoint and a token cannot be extended in place.
Mastra has native MCP support, so it reads the tool list and schemas from the Virtual MCP server directly. Pass the static URL and the user's session token as bearer auth, minted server-side and never placed in client code.
Sanity's revision history tells you a document changed and which identity changed it. It does not tell you which agent run did it, which tool was called with which arguments, or whether the credential was still valid at that moment. Scalekit's agent logs carry the full delegation chain: who authorized the call, which agent ran it, which tool executed, and what came back, queryable in the dashboard and exportable to your SIEM.
That matters most in the failure case. When a publish goes out that nobody expected, the question is whether the agent misbehaved, the model chose wrong, or a stale token silently broke a step. Distinguishing those three from application logs alone is close to impossible if the credential lived outside any observability layer. This is why agent tool observability is worth investing in from the start, not as an afterthought.
Whichever path you pick, you end up holding one credential per user or per customer project. Fifty customers means fifty credential lifecycles, and Sanity manages exactly none of them for you.
The MCP OAuth flow hands you a session per user that Sanity documents as expiring after roughly 7 days. The API path hands you a robot token per project that either never expires or expires on a date you set and then cannot unset. Both need somewhere to live: encrypted at rest, isolated per tenant, never in the agent process, never in a log line, never in an LLM context window.
Both also need a revocation story. When a customer churns or an editor leaves, you have to enumerate every live Sanity credential tied to that identity and kill it. Sanity's Access API gives you the delete endpoint; the inventory, the trigger, and the cleanup are yours. The token type differs between the paths. The infrastructure they demand does not. For a detailed breakdown of what secure token management for AI agents at scale actually requires, that piece covers the full lifecycle.
Scalekit's Sanity MCP connector runs the OAuth flow, stores each user's credential in an AES-256 encrypted vault isolated per tenant, and refreshes it without your agent ever seeing the token. Credentials never touch the agent runtime. Virtual MCP servers then scope what that credential can reach, which is the piece that makes a multi-tool, multi-tenant Sanity agent something you can put in front of an auditor.
If your agent acts as individual editors and its job is drafts, patches, releases, and publishing, build against the MCP server. It is the only Sanity surface where per-user OAuth is self-serve, and that identity is worth more than the coverage you give up.
If your agent reacts to content events, moves assets, translates documents, or runs headless on a schedule, build against the HTTP API with a scoped robot token and a pinned version. Accept that the actor in revision history is a robot, and log the human intent on your side.
Most production Sanity agents run both. The question that decides each path is whether a human needs to be the actor of record, and the credential infrastructure underneath does not change either way.
Browse the Sanity connector on Scalekit, or the full connector catalog if your agent touches more than one tool. Framework code samples for LangChain and Mastra run end to end, and AgentKit pricing covers tool calling and audit logs on the free tier.
Building something Sanity-shaped and want a second opinion on the auth model? Join the Scalekit Slack community, or talk to an engineer if you need an answer today.
Sanity MCP provides a self-serve OAuth 2.1 flow that attributes agent actions to real user identities. The HTTP API uses bearer tokens (personal or robot), with OAuth2 marked experimental and requiring manual provisioning by Sanity. MCP covers drafts, patches, releases, and publishing; the HTTP API covers webhooks, asset upload, document history, export, and text-generating Agent Actions.
On most platforms, the direct API offers more flexible auth options including OAuth. Sanity is the exception: its hosted MCP server is the only surface with a practical, self-serve per-user OAuth flow. The direct HTTP API's OAuth2 integration is experimental, partner-gated, and issues no refresh tokens, making it unsuitable for self-serve multi-tenant products.
Sanity MCP does not support GROQ-powered webhooks, the Live Content API, document history, dataset export, asset uploads, robot token lifecycle management, or the text-generating Agent Actions endpoints (generate, transform, translate, prompt). These are all HTTP API only.
Content agents should not hold tools like create_project, create_dataset, update_dataset, add_cors_origin, cors_origins_delete, deploy_schema, deploy_studio, and run_sanity_cli. These administrative tools dramatically increase blast radius and create a path for prompt injection attacks to cause serious infrastructure changes.
Rate limits are enforced per client IP address per second — not per tenant or per token. Fifty tenants sharing one egress IP share a single 25 mutations/second bucket. One customer's bulk operation can push all others into 429 errors. The official client never retries mutations automatically, so queue management is the developer's responsibility.
A Virtual MCP server is a scoped endpoint that exposes only the specific connections and tools you define. For Sanity, it lets you cut a 45-tool server down to the 5 tools a content agent actually needs. This reduces both context token cost and blast radius, and is created once per agent role rather than once per user.
Use MCP when the agent acts on behalf of individual editors and actions must be attributed to real user identities, or when the work is limited to drafts, patches, releases, and publishing. Use the HTTP API when the agent reacts to content events via webhooks, uploads assets, calls text-generating Agent Actions, runs headlessly on a schedule, or requires version pinning for deterministic pipelines.
Scalekit runs the OAuth flow, stores each user's credential in an AES-256 encrypted vault isolated per tenant, and handles token refresh without the agent ever seeing the raw token. Credentials never enter the agent runtime, log lines, or LLM context windows. Virtual MCP servers then enforce which tools each credential can reach.