Sanity connector
Connect your own Sanity project as an MCP Tool so the marketing agent can publish content straight into it. Once connected, the agent can push content it creates in the app into your Sanity dataset instead of (or in addition to) keeping it only inside the app.
What it does
- Blog posts, case studies, white papers, and markdown documents publish as structured Sanity documents — real content your Sanity-powered site can query, render, and index like any other Sanity content.
- Landing pages and web forms publish as reference documents that stay hosted by the app. Sanity holds a pointer to the page (its live URL and embed URL), but the page itself (and its form) keeps running here — submissions keep flowing through the app's own submission endpoint via the embed.
Connecting Sanity
- Open Settings and go to the Connectors tab (labeled "MCP Tools").
- Choose Sanity from the catalog and click Connect.
- Enter:
- Your Project ID and Dataset name, both found in your Sanity project.
- An API token created at
sanity.io/manage→ your project → API → Tokens. The token needs Editor (write) access so the agent can create and update documents. - MCP user role (optional) — leave blank to use the token's own role.
Set it only if your Sanity setup expects a specific role name (e.g.
developeroreditor) for write access.
- Assign the connection to the Marketing area so the agent can use it when publishing campaign content.
What you can publish
| Mode | Content types | Where it lives |
|---|---|---|
Structured document (thoughtfulyPost) | Blog posts, case studies, white papers, markdown documents | Fully in Sanity, as a real document |
Reference document (thoughtfulyHostedPage) | Landing pages, web forms | Hosted in the app; Sanity holds a reference (title, live URL, embed URL) |
The schema: thoughtfulyPost and thoughtfulyHostedPage
The connector uses two document types — thoughtfulyPost for structured
content and thoughtfulyHostedPage for hosted-page references.
You usually don't have to create these by hand. When it publishes, the agent checks whether the two types already exist in your project and, if they don't, registers them for you — additively, so it never drops document types your project already has. (If the agent can't safely read your current schema to add to it, it stops and asks you to add the types yourself rather than risk overwriting your schema.)
Registering the schema is what lets Sanity Studio recognize and validate these documents. Your front-end site still needs components to render them (see Rendering below).
If you prefer to manage schema in your own Studio repo, add these type definitions yourself:
// schemaTypes/thoughtfulyPost.ts
import {defineType, defineField} from 'sanity'
import {DocumentTextIcon} from '@sanity/icons'
export const thoughtfulyPost = defineType({
name: 'thoughtfulyPost',
title: 'Post',
type: 'document',
icon: DocumentTextIcon,
fields: [
defineField({name: 'title', type: 'string'}),
defineField({name: 'slug', type: 'slug', options: {source: 'title'}}),
defineField({name: 'excerpt', type: 'text'}),
defineField({name: 'publishedAt', type: 'datetime'}),
defineField({name: 'heroImage', type: 'image'}),
defineField({
name: 'body',
type: 'text',
description: 'Markdown — render with a Markdown component',
}),
defineField({
name: 'docKind',
type: 'string',
options: {
list: [
{title: 'Post', value: 'post'},
{title: 'Case study', value: 'caseStudy'},
{title: 'White paper', value: 'whitePaper'},
],
layout: 'radio',
},
}),
defineField({
name: 'sourceArtifactId',
type: 'string',
description: 'Originating app artifact id — used to update the same document on re-publish.',
readOnly: true,
}),
],
})
// schemaTypes/thoughtfulyHostedPage.ts
import {defineType, defineField} from 'sanity'
import {DocumentIcon} from '@sanity/icons'
export const thoughtfulyHostedPage = defineType({
name: 'thoughtfulyHostedPage',
title: 'Hosted page',
type: 'document',
icon: DocumentIcon,
fields: [
defineField({name: 'title', type: 'string'}),
defineField({name: 'slug', type: 'slug', options: {source: 'title'}}),
defineField({name: 'externalUrl', type: 'url', description: 'Live page URL (hosted by the app)'}),
defineField({name: 'embedUrl', type: 'url', description: 'Iframe embed URL (externalUrl + /embed.js)'}),
defineField({name: 'description', type: 'text'}),
defineField({name: 'ogImage', type: 'image', title: 'Social share image'}),
defineField({
name: 'sourceArtifactId',
type: 'string',
description: 'Originating app artifact id — used to update the same document on re-publish.',
readOnly: true,
}),
],
})
Rendering
Sanity stores content but doesn't render it — your deployed Sanity front-end does. Add rendering for both types:
- Render
thoughtfulyHostedPageas an iframe ofembedUrl. Forms inside the iframe keep posting back to the app's own submission endpoint, so they keep working exactly as they do today — Sanity only holds the reference, not the form itself.externalUrlis the direct link to the live page. - Render
thoughtfulyPost.bodywith your Markdown component, the same way you'd render any other Markdown field.
Notes / limits
- No duplicates on re-publish. The agent stamps each document with a
sourceArtifactIdand looks it up before writing, so re-publishing the same artifact updates the same Sanity document (Sanity assigns the document_id). - Schema registration is additive. The agent only ever adds the two types to your schema; it never removes types you already have.
- The app keeps hosting landing pages and web forms. Sanity only holds a reference document for these; it never becomes the source of truth for the page or its form.
- Your API token needs write access to publish. A read-only token will connect but publishing will fail.