Skip to content

MCP Tools

npm version npm downloads

Contentrain's MCP (Model Context Protocol) package is the deterministic execution layer that sits between your AI agent and your filesystem. While the agent makes intelligent content decisions, @contentrain/mcp enforces consistent file operations, canonical serialization, and git-backed safety.

Why MCP?

Traditional content management relies on APIs, dashboards, and manual workflows. Contentrain inverts this:

  • Agent produces content decisions (what to write, where, in what structure)
  • MCP applies deterministic filesystem and git operations (how to write it safely)
  • Humans review and merge through git workflows
  • The system guarantees schema, locale, and serialization consistency

This separation means your AI agent never directly touches files. Every write goes through MCP's validation, canonical serialization, and git transaction pipeline.

Why not just let the agent write files?

Agents are non-deterministic. The same prompt can produce different file formats, inconsistent JSON ordering, or broken git state. MCP is the deterministic guardrail that makes AI-generated content safe for production.

Install

bash
pnpm add @contentrain/mcp

Requirements:

  • Node.js 22+
  • Git available on the machine

Optional parser support for higher-quality source scanning:

  • @vue/compiler-sfc — Vue SFC parsing
  • @astrojs/compiler — Astro component parsing
  • svelte — Svelte component parsing

Discovery

@contentrain/mcp is published for both package-based and registry-based MCP discovery:

  • npm package: @contentrain/mcp
  • MCP Registry name: io.github.Contentrain/contentrain
  • Local server binary: contentrain-mcp
  • CLI stdio entrypoint: contentrain serve --stdio
  • Hosted remote endpoint: Contentrain Studio MCP Cloud at https://studio.contentrain.io/api/mcp/v1/{projectId}/mcp

Use the local stdio server when the agent should work against a checkout on your machine. Use Studio MCP Cloud when an external agent should operate a connected Studio project through a project-scoped API key.

Tool Catalog

The MCP server exposes 24 tools — 19 core + 5 media — organized by function. Each tool includes MCP annotations (readOnlyHint, destructiveHint, idempotentHint, and openWorldHint: false everywhere except contentrain_media_ingest, which fetches a caller-supplied URL server-side) so clients can distinguish safe reads from writes and destructive operations.

Capability-aware listing

tools/list is filtered per session: tools whose requirements (local project root, provider capabilities) cannot be met are not registered at all. A local stdio server lists the 19 core tools; a remote-provider session lists the remote-safe subset plus — on media-capable providers like Studio MCP Cloud — the 5 contentrain_media_* tools. Core remote-safe subset — status, describe, describe_format, model_save, model_delete, content_save, content_delete, content_list, validate. See TOOL_REQUIREMENTS in @contentrain/mcp/tools/availability.

ToolTitleRead-onlyDestructive
contentrain_statusProject StatusYes
contentrain_describeDescribe ModelYes
contentrain_describe_formatDescribe FormatYes
contentrain_doctorProject Health ReportYes
contentrain_initInitialize Project
contentrain_scaffoldScaffold Template
contentrain_model_saveSave Model
contentrain_model_deleteDelete ModelYes
contentrain_content_saveSave Content
contentrain_content_deleteDelete ContentYes
contentrain_content_listList ContentYes
contentrain_validateValidate Project
contentrain_submitSubmit Branches
contentrain_mergeMerge Branch
contentrain_branch_listList BranchesYes
contentrain_branch_deleteDelete BranchYes
contentrain_scanScan Source CodeYes
contentrain_applyApply Normalize
contentrain_bulkBulk Operations
contentrain_media_listList Media AssetsYes
contentrain_media_getGet Media AssetYes
contentrain_media_ingestIngest Media From URL
contentrain_media_updateUpdate Media Metadata
contentrain_media_deleteDelete Media AssetYes

Detailed Reference

Read Tools (Safe, No Side Effects)

ToolPurposeDescription
contentrain_statusProject overviewConfig, models, branch health, context, validation summary
contentrain_describeModel deep-diveFull schema, sample data, field types for any model
contentrain_describe_formatFormat referenceFile structure, JSON formats, markdown conventions, locale strategies
contentrain_doctorHealth diagnosticsSetup validation, SDK freshness, orphan content, local branch limits, remote cr/* count, unused keys, missing translations
contentrain_content_listRead contentList entries with filter, optional relation resolution (resolve), and limit/offset pagination

Write Tools (Git-Backed, Branch-Isolated)

ToolPurposeDescription
contentrain_initBootstrap projectCreates .contentrain/ structure, config, and git setup
contentrain_scaffoldApply templatesStarter templates: blog, landing, docs, ecommerce, saas, i18n, mobile
contentrain_model_saveDefine schemasCreate or update model definitions with field types and constraints
contentrain_model_deleteRemove modelsDelete a model definition and its content
contentrain_content_saveWrite contentSave entries for any model kind (collection, singleton, dictionary, document)
contentrain_content_deleteRemove contentDelete specific content entries
contentrain_validateCheck & fixValidate content against schemas, optionally auto-fix structural issues
contentrain_submitPush branchesPush cr/* review branches to remote, then lazily prune merged local + remote leftovers
contentrain_mergeMerge branchesMerge a review-mode branch into contentrain locally (by exact branch or model; no external platform needed); deletes the branch's remote copy
contentrain_branch_listInspect branchesList pending cr/* branches with merge status and branch-health pressure (remote: true adds a remote view + remote-only leftovers)
contentrain_branch_deleteClean up branchesDelete a stale/failed cr/* branch locally and on the remote (the contentrain branch is protected; supports remote-only deletion)

Normalize Tools (Scan + Apply)

ToolPurposeDescription
contentrain_scanFind hardcoded stringsGraph-based component scan with candidate detection
contentrain_applyExtract or reuseTwo-phase normalize: extract content or patch source files
contentrain_bulkBatch operationsBulk locale copy, status updates, and deletes

Field constraints

Fields draw from a 27-type catalog — see Field Types for the full list and per-type constraint enforcement.

contentrain_content_save validates before it writes. A severity: error issue on any entry in the call means nothing is committed — no branch, nothing to clean up. Fix the values and call again. Warnings pass and come back in the response.

The split is deliberate:

  • Errors are definitional. A slug that does not match SLUG_PATTERN is not a slug; an unparseable date is not a date; 3.7 is not an integer.
  • Warnings are heuristics. email, url, color and phone patterns are approximations, and a legitimate value can sit outside one.

Only the entries in the call are fatal. A pre-existing bad entry elsewhere in the model is reported but does not block your save.

Array items are validated by the same rules as a scalar of that type, so items: { type: 'string', max: 50 } means what it looks like it means.

What MCP does not enforce

maxSize is the one constraint MCP accepts but cannot check — it stores a path and never sees the file. Your media provider enforces it at ingest, and model_save returns a schema_warnings entry saying so. accept is checked, but against the file extension only, which is why it warns rather than errors.

model_save rejects a constraint declared where it cannot apply — options on a non-select, items on a non-array, accept on a non-media field, unique on a singleton, min > max, an uncompilable pattern — instead of storing it and doing nothing. Unknown keys are rejected too, so a typo'd requird: true is an error rather than a silent no-op.

Publish status

Entry status lives in .contentrain/meta/, not in content, and it decides CDN delivery: a collection entry is served only when its status is published.

  • contentrain_content_save never changes status. Editing a field is not a publish decision — an existing entry keeps its status, approved_by, and version. Only a brand-new entry starts at draft.
  • contentrain_bulk update_status is the only way to publish. Pass entry_ids for collections; omit them for singletons and dictionaries, which have one meta record per locale. Pass locale to scope the change, or every supported locale is rewritten.
  • contentrain_validate flags publish-state drift — drafts sitting beside published entries in one collection — as a notice. It never auto-fixes it: publishing is a content decision, and MCP does not make those.
  • Scheduled publishing lives in meta too. contentrain_content_save accepts optional publish_at / expire_at (ISO 8601) per entry; expire_at must be after publish_at.

Non-i18n models

A model with i18n: false keeps all content in one data.json, so it has exactly one meta record — at the default locale, never data.json.

  • A locale is meaningless here, so it is rejected, not guessed.contentrain_content_delete refuses a locale-scoped delete on an i18n: false model: the locale would otherwise map onto data.json and the default-locale meta, deleting the shared content and the wrong meta while a stray per-locale meta stayed behind. Omit locale to delete the entry.
  • contentrain_validate warns about stray per-locale meta left by older versions, and fix: true cleans it up deterministically: when the default-locale meta is authoritative it prunes the extras (no status is merged, so a published record is never downgraded); when only a stray exists it is migrated to the default path so the record is preserved. Several strays with no default is ambiguous — it is left for you to resolve by hand.

Media Tools (Provider Media Facet)

A deterministic passthrough to the provider's optional media stack (RepoProvider.media) — registered only when the provider exposes one (e.g. Studio MCP Cloud). The flow: list assets → pick a media/... path → reference it via contentrain_content_save (normalized to absolute delivery URLs when mediaBaseUrl is set).

ToolPurposeDescription
contentrain_media_listDiscover assetsSearch, tag filter, cursor pagination — returns storage paths + delivery URLs
contentrain_media_getInspect one assetPath, URL, mime, size, alt, tags, provider metadata
contentrain_media_ingestAdd from URLProvider fetches the URL server-side under its own SSRF/MIME/size policy (MCP never fetches; the only openWorldHint: true tool)
contentrain_media_updateEdit metadataAlt text, tags, filename — never touches the binary
contentrain_media_deleteRemove assetDestructive; content references are NOT rewritten

Key Principles

1. Deterministic Infrastructure

MCP is infrastructure, not intelligence. It does not decide what content to write — the agent does. MCP guarantees:

  • Canonical JSON — sorted keys, 2-space indent, trailing newline
  • Consistent file paths — locale strategy determines where files live
  • Atomic git transactions — every write is committed to a branch
  • Schema enforcement — content is validated against model definitions

2. Preview Where It Counts

dry_run belongs to contentrain_apply — the one tool that can modify your source files. The normalize pattern is always:

  1. Run contentrain_apply with dry_run: true (the default) to preview the plan
  2. Review the output
  3. Run with dry_run: false to commit

The other write tools do not take a dry_run parameter. They are made safe by different guarantees: every write lands on an isolated cr/* branch, contentrain_content_save validates before committing (an error means nothing is written), and destructive tools (content_delete, model_delete, branch_delete, merge, bulk delete_entries) require an explicit confirm: true.

Never Skip the Apply Preview

Always call contentrain_apply with dry_run: true first and review the plan. It is the only tool that can touch source code — skipping the preview risks unreviewed source patches.

3. Git-Native Workflow

All write operations create or update cr/* branches:

  • Content changes go to isolated branches (cr/{scope}/{target}[/{locale}]/{timestamp}-{suffix})
  • Humans review via contentrain diff or the serve UI
  • Approved changes merge into the contentrain branch, baseBranch is advanced via update-ref
  • Merging (or deleting) a branch also removes its copy on the remote, so merged branches don't pile up as phantom pending reviews — best-effort, opt out with remoteBranchCleanup: false in config.json. Drain an existing backlog with contentrain prune
  • Merged-branch detection survives base-history rewrites (ancestry check with a patch-id fallback)
  • Branch health is tracked and surfaced via contentrain_status (warning at 50, blocked at 80 active branches); contentrain_doctor adds a remote cr/* count
  • Legacy contentrain/* branches are auto-migrated on first init

4. Local-First by Default, Remote Providers Opt-In

The default shape — stdio transport + LocalProvider — operates entirely on the local filesystem. No GitHub API, no cloud service, no external dependency.

Remote providers (GitHubProvider via @octokit/rest, GitLabProvider via @gitbeaker/rest) are optional peer dependencies. They are installed only when Studio, CI, or a remote agent needs to drive MCP over an HTTP transport against a hosted git repo. A session that uses LocalProvider never loads these SDKs.

That means:

  • Default install works offline and needs no API keys
  • Optional remote backends ship on the same tool contract — see Providers and transports for the full capability matrix
  • Normalize, scan, and apply always need a LocalProvider — they return a capability_required error on remote providers

5. Capability Gates

Every tool declares the capabilities it needs. Tools that require astScan, sourceRead, sourceWrite, or localWorktree reject on providers that do not expose them with a uniform error:

json
{
  "error": "contentrain_scan requires local filesystem access.",
  "capability_required": "astScan",
  "hint": "This tool is unavailable when MCP is driven by a remote provider. Use a LocalProvider or the stdio transport."
}

Agent drivers treat capability_required as a retry signal. See Providers & Transports for the full capability matrix.

Transports

  • stdiocontentrain serve --stdio or npx contentrain-mcp. IDE agents (Claude Code, Cursor, Windsurf) connect over stdin/stdout.
  • HTTPcontentrain serve --mcpHttp --authToken $TOKEN or the programmatic startHttpMcpServer({...}) / startHttpMcpServerWith({ provider }) exports. Streamable HTTP at POST /mcp with secure-by-default Bearer auth. See the HTTP Transport guide.

Both transports serve the same tool surface and the same JSON response shapes.

Providers

@contentrain/mcp ships three RepoProvider implementations behind a single contract:

  • LocalProvider — simple-git + temporary worktree on your disk
  • GitHubProvider — Octokit over the Git Data + Repos APIs (no clone)
  • GitLabProvider — gitbeaker over the GitLab REST API (no clone; supports self-hosted)

Bitbucket is on the roadmap. See Providers & Transports for the capability matrix and RepoProvider Reference for the interface definitions.

Studio Bridge

@contentrain/mcp is the local execution layer for the ecosystem. It is where agents do deterministic work such as init, schema changes, validation, and normalize.

When a project moves from solo or IDE-led work into team review and delivery, Contentrain Studio becomes the authenticated web surface on top of the same .contentrain/ contract:

  • MCP keeps local writes deterministic and git-safe
  • Studio adds team roles, review UI, media, forms, APIs, and CDN delivery
  • both surfaces should describe the same models, locales, and branch semantics

Use the Ecosystem Map when you need the full package-to-product relationship, or jump to the Studio docs for the team-facing workflow:

Usage Examples

Check Project Status

Ask your agent: "What's the current state of my Contentrain project?" — triggers contentrain_status. Returns config, models list, branch health, pending changes, validation state.

Run Health Checks

Ask your agent: "Is my Contentrain setup healthy?" — triggers contentrain_doctor. Returns structured checks (env, structure, models, orphans, branches, SDK freshness). With usage: true, also analyzes unused keys, duplicates, missing translations.

Create a Model

ts
// Agent calls contentrain_model_save
{
  "id": "blog-post",
  "name": "Blog Posts",
  "kind": "collection",
  "domain": "content",
  "i18n": true,
  "fields": {
    "title": { "type": "string", "required": true },
    "excerpt": { "type": "text" },
    "author": { "type": "relation", "model": "team-members" },
    "published": { "type": "boolean" }
  }
}

Ask your agent: "Create a blog post model with title, excerpt, author relation, and published flag"

Save Content

ts
// Agent calls contentrain_content_save
{
  "model": "blog-post",
  "entries": [{
    "locale": "en",
    "data": {
      "title": "Getting Started with Contentrain",
      "excerpt": "Learn how to set up AI-powered content management",
      "published": true
    }
  }]
}

Ask your agent: "Add a new blog post about getting started"

Media in cloud mode

For image/video/file fields (and media/... references in markdown bodies), pass either the media-library storage path (media/...) or a URL. When the server runs in cloud mode with a delivery base (Studio's MCP Cloud supplies one per project), contentrain_content_save normalizes those references to absolute public delivery URLs on save, so committed content renders anywhere with no SDK. In local mode the relative path is kept verbatim, and external URLs always pass through untouched.

Normalize Flow (Scan + Extract + Reuse)

ts
// Phase 1: Scan for hardcoded strings
// Agent calls contentrain_scan → gets candidates

// Phase 2: Extract content
// Agent calls contentrain_apply with mode: "extract"
// Creates models, writes content entries, tracks sources (cr/normalize/extract/*)

// Phase 3: Reuse in source
// Agent calls contentrain_apply with mode: "reuse"
// Patches source files with i18n function calls (cr/normalize/reuse/*)

Ask your agent: "Scan my landing page for hardcoded strings and extract them"

Agent Configuration

The fastest way to connect your IDE agent:

bash
npx contentrain setup claude-code   # or: cursor, vscode, windsurf, copilot

This auto-creates the correct MCP config file and installs AI rules/skills.

Manual configuration (all IDEs use the same JSON)
json
{
  "mcpServers": {
    "contentrain": {
      "command": "npx",
      "args": ["contentrain", "serve", "--stdio"]
    }
  }
}
IDEConfig file
Claude Code.mcp.json
Cursor.cursor/mcp.json
VS Code.vscode/mcp.json
Windsurf.windsurf/mcp.json

Once connected, the agent has access to the full MCP tool surface and can manage your content through natural language.

OpenAI Codex

Codex uses ~/.codex/config.toml or a trusted project-scoped .codex/config.toml.

bash
codex mcp add contentrain -- npx -y contentrain serve --stdio

Equivalent config.toml:

toml
[mcp_servers.contentrain]
command = "npx"
args = ["-y", "contentrain", "serve", "--stdio"]

For Studio MCP Cloud, configure a Streamable HTTP server with the project endpoint and Bearer token:

toml
[mcp_servers.contentrain]
url = "https://studio.contentrain.io/api/mcp/v1/{projectId}/mcp"
http_headers = { Authorization = "Bearer <mcp-cloud-key>" }

Claude Desktop

Claude Desktop reads claude_desktop_config.json. For a local checkout:

json
{
  "mcpServers": {
    "contentrain": {
      "command": "npx",
      "args": ["-y", "contentrain", "serve", "--stdio"]
    }
  }
}

For Studio MCP Cloud:

json
{
  "mcpServers": {
    "contentrain": {
      "type": "http",
      "url": "https://studio.contentrain.io/api/mcp/v1/{projectId}/mcp",
      "headers": {
        "Authorization": "Bearer <mcp-cloud-key>"
      }
    }
  }
}

Claude Code

Claude Code can use the project .mcp.json generated by contentrain setup claude-code, or add the hosted endpoint directly:

bash
claude mcp add --transport http contentrain \
  https://studio.contentrain.io/api/mcp/v1/{projectId}/mcp \
  --header "Authorization: Bearer <mcp-cloud-key>"

Trust Model

Trust LevelToolsRiskNotes
HIGH (read-only)status, describe, describe_format, doctor, content_list, branch_list, scan, media_list, media_getNoneSafe to call anytime, no side effects — scan reads source but never writes
MEDIUM (git-isolated writes)init, scaffold, model_save, model_delete, content_save, content_delete, validate, bulkLowWrites go through git transactions on isolated cr/* branches; destructive tools require confirm: true
MEDIUM (branch lifecycle)submit, merge, branch_deleteMediumsubmit pushes to the remote (requires network); merge and branch_delete are local git operations — network is used only for best-effort remote-copy cleanup
MEDIUM (provider media)media_ingest, media_update, media_deleteMediumProvider-side media stack; media_delete is destructive and does not rewrite content references
LOW (source modification)applyMediummode: "reuse" patches source files — always run dry_run: true first

Source Modifications

The contentrain_apply tool with mode: "reuse" modifies your source code files. Always run with dry_run: true first, review the patches carefully, and use the review workflow before merging.

Typical Agent Workflow

1. contentrain_status          → understand project state
2. contentrain_doctor          → validate setup health
3. contentrain_init            → bootstrap if needed
4. contentrain_describe_format → understand storage contract
5. contentrain_model_save      → define content schemas
6. contentrain_content_save    → write content entries
7. contentrain_validate        → check everything is valid
8. contentrain_submit          → push for review

Core Exports

For advanced integrations, the package exports low-level modules:

ts
import { createServer } from '@contentrain/mcp/server'
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'

const server = createServer(process.cwd())
const transport = new StdioServerTransport()
await server.connect(transport)

Available subpath exports:

  • @contentrain/mcp (root) — stdio server entrypoint (what the contentrain-mcp bin runs)
  • @contentrain/mcp/server — MCP server factory and stdio setup
  • @contentrain/mcp/server/http — HTTP transport server factory
  • @contentrain/mcp/core/config — Config manager
  • @contentrain/mcp/core/context — Context JSON manager
  • @contentrain/mcp/core/model-manager — Model CRUD
  • @contentrain/mcp/core/content-manager — Content CRUD
  • @contentrain/mcp/core/validator — Validation engine
  • @contentrain/mcp/core/scanner — Source code scanner
  • @contentrain/mcp/core/graph-builder — Component graph
  • @contentrain/mcp/core/apply-manager — Normalize apply
  • @contentrain/mcp/core/doctor — Health check engine
  • @contentrain/mcp/core/contracts — RepoProvider interface types
  • @contentrain/mcp/core/ops — Git operation utilities
  • @contentrain/mcp/core/overlay-reader — Overlay file reading
  • @contentrain/mcp/core/scan-config — Scan configuration
  • @contentrain/mcp/git/transaction — Git transaction flow
  • @contentrain/mcp/git/branch-lifecycle — Branch health tracking
  • @contentrain/mcp/templates — Scaffold templates
  • @contentrain/mcp/tools/annotations — Tool metadata (TOOL_NAMES, TOOL_ANNOTATIONS)
  • @contentrain/mcp/tools/availability — Per-tool capability requirements (TOOL_REQUIREMENTS)
  • @contentrain/mcp/testing/conformance — Provider conformance test harness
  • @contentrain/mcp/util/detect — Framework detection
  • @contentrain/mcp/util/fs — File system utilities
  • @contentrain/mcp/providers/local — LocalProvider implementation
  • @contentrain/mcp/providers/github — GitHubProvider implementation
  • @contentrain/mcp/providers/gitlab — GitLabProvider implementation
  • CLI — Human-facing companion for local operations
  • Query SDK — Generated runtime client for consuming content
  • Rules & Skills — Agent behavior policies and workflow playbooks
  • Contentrain Studio — Hosted workspace, review, chat-first operations, and content CDN