Contentrain MCP
Extraia, governe e envie conteúdo estruturado do seu código-fonte.
Documentação
@contentrain/mcp
Mecanismo MCP agnóstico de provedor para Contentrain — local-first por padrão, com backends opcionais para GitHub e GitLab e transporte HTTP para drivers remotos como o Studio.
Comece por aqui:
Contentrain é uma infraestrutura de governança de conteúdo gerado por IA:
- o agente produz decisões de conteúdo
- o MCP aplica fluxos de trabalho determinísticos de sistema de arquivos e git
- humanos revisam e mesclam
- o sistema mantém schema, locale e serialização consistentes
Este pacote é o núcleo de runtime por trás da integração MCP da Contentrain. Ele pode ser usado como:
- um servidor MCP stdio (
contentrain-mcp) - um servidor incorporável (
createServer(projectRoot)) - um kit de ferramentas de baixo nível para config, modelos, conteúdo, validação, varredura e fluxo de transações git
Instalação
pnpm add @contentrain/mcp
Requisitos:
- Node.js
22+ - git disponível na máquina
Suporte opcional de parser para varredura de código-fonte de maior qualidade:
@vue/compiler-sfc@astrojs/compilersvelte
Eles estão listados como dependências opcionais. O scanner ainda funciona sem eles, mas a detecção de Vue/Astro/Svelte é mais forte quando estão instalados.
O Que Ele Faz
@contentrain/mcp gerencia um diretório .contentrain/ no seu projeto e expõe ferramentas MCP para:
- inicialização de projeto
- criação e exclusão de modelos
- salvar, excluir e listar conteúdo
- validação e correção automática
- fluxos de varredura e aplicação de normalização
- operações em lote
- envio de branch, merge em modo de revisão e conscientização de saúde de branch
- verificação de saúde do projeto (doctor)
Todas as operações de escrita são projetadas em torno da segurança baseada em git:
- um branch dedicado
contentrainserve como fonte única de verdade do estado do conteúdo - cada escrita cria um worktree temporário em um branch de feature bifurcado de
contentrain(nome do branch:cr/{operation}/{model}/{locale}/{timestamp}-{suffix}) - auto-merge: o feature é mesclado em
contentrain, o baseBranch é avançado via update-ref, os arquivos.contentrain/são sincronizados seletivamente para a árvore de trabalho do desenvolvedor quando o branch base é o que está com checkout - baseBranch = env
CONTENTRAIN_BRANCH→repository.default_branch→ HEAD remoto →main→master→ branch com checkout (último recurso). Uma escrita feita em um branch de feature nunca mescla, move ou envia esse branch - os planos são lidos da árvore de trabalho, mas commitados no tip do
contentrainbuscado: as mudanças JSON são transportadas chave por chave, então entradas enviadas por outro escritor são mantidas; um conflito de mesmo valor não escreve nada e retornaCONTENT_WORKING_TREE_STALE - em um branch de feature com checkout, onde escritas não atualizam,
.contentrain/**é lido da refcontentrain(arquivos de origem ainda vêm da árvore de trabalho); ferramentas de leitura o reportam comocontent_source - revisão: branch de feature enviado para o remoto para revisão da equipe; uma vez mesclado (ou excluído), sua cópia remota também é removida — melhor esforço, opte por sair com
remoteBranchCleanup: falseno config.json - a detecção de branch mesclado sobrevive a reescritas do histórico da base (verificação de ancestralidade com fallback de patch-id), então rebases/squashes não deixam branches obsoletos presos
- a árvore de trabalho do desenvolvedor nunca é mutada durante operações git do MCP (sem stash, sem checkout, sem merge)
- context.json nunca chega a branches de feature — ele é regenerado no branch
contentrainapós o merge (localmente pela camada de transação; em fluxos remotos pelo orquestrador que possui o merge) - saída JSON canônica — chaves ordenadas, indentação de 2 espaços, nova linha final
- validação + dicas de próximos passos exibidas ao chamador
Superfície de Ferramentas
27 ferramentas MCP — 22 principais + 5 de mídia — com anotações (readOnlyHint, destructiveHint, idempotentHint e openWorldHint: false em todos os lugares, exceto contentrain_media_ingest, que busca uma URL fornecida pelo chamador no lado do servidor) para dicas de segurança do cliente.
A listagem de ferramentas é consciente de capacidade. tools/list só anuncia ferramentas que o par provedor resolvido + projectRoot pode realmente atender. Um servidor stdio local lista as 22 ferramentas principais; uma sessão dirigida por um provedor remoto (GitHub/GitLab, sem checkout local) lista apenas o subconjunto seguro para remoto — status, describe, describe_format, model_save, model_delete, content_save, content_delete, content_list, validate. O mapa de requisitos vive em TOOL_REQUIREMENTS (@contentrain/mcp/tools/availability).
| Ferramenta | Propósito | Somente leitura | Destrutiva |
|---|---|---|---|
contentrain_status | Status do projeto, config, modelos, saúde de branch, contexto | Sim | — |
contentrain_describe | Schema completo e dados de exemplo para um modelo | Sim | — |
contentrain_describe_format | Referência de contrato de formato de arquivo e armazenamento | Sim | — |
contentrain_doctor | Relatório de saúde do projeto (env, estrutura, modelos, órfãos, branches locais + remotos, SDK) | Sim | — |
contentrain_init | Criar estrutura .contentrain/ e config base | — | — |
contentrain_scaffold | Aplicar um template inicial como blog, docs, landing, saas | — | — |
contentrain_model_save | Criar ou atualizar uma definição de modelo | — | — |
contentrain_model_delete | Excluir uma definição de modelo | — | Sim |
contentrain_content_save | Salvar entradas de conteúdo para qualquer tipo de modelo | — | — |
contentrain_content_delete | Excluir entradas de conteúdo | — | Sim |
contentrain_content_list | Ler entradas de conteúdo | Sim | — |
contentrain_validate | Validar conteúdo do projeto, opcionalmente corrigir automaticamente problemas estruturais | — | — |
contentrain_submit | Enviar branches cr/* para o remoto, depois podar preguiçosamente sobras locais + remotas mescladas | — | — |
contentrain_merge | Mesclar um branch em modo de revisão em contentrain localmente (por branch exato ou modelo); exclui sua cópia remota | — | — |
contentrain_reconcile | Merge de três vias consciente de conteúdo de um par divergente contentrain ↔ base (dry_run primeiro, resoluções depois) | — | — |
contentrain_branch_list | Listar branches cr/* pendentes com status de merge (remote: true adiciona visão remota) | Sim | — |
contentrain_branch_delete | Excluir um branch cr/* obsoleto/falho localmente e no remoto (branch contentrain protegido) | — | Sim |
contentrain_scan | Varredura de strings hardcoded baseada em grafo e candidatos | Sim | — |
contentrain_apply | Execução de extração/reutilização de normalização com suporte a dry-run | — | — |
contentrain_bulk | Cópia de locale em lote, atualizações de status e exclusões (dry_run pré-visualiza) | — | — |
contentrain_media_list | Listar ativos de mídia (busca, filtro de tag, paginação por cursor) | Sim | — |
contentrain_media_get | Obter um ativo de mídia por id | Sim | — |
contentrain_media_ingest | Ingerir um ativo de uma URL de origem (provedor busca no lado do servidor) | — | — |
contentrain_media_update | Atualizar metadados do ativo (alt, tags, nome do arquivo) | — | — |
contentrain_media_delete | Excluir um ativo da pilha de mídia | — | Sim |
As cinco ferramentas contentrain_media_* são um passthrough determinístico para a faceta de mídia opcional do provedor (RepoProvider.media) e são registradas somente quando o provedor expõe uma (ex.: Studio MCP Cloud). Servidores stdio locais e provedores GitHub/GitLab simples nunca as listam. A ingestão é baseada em URL (MCP não tem canal binário); a implementação do provedor é dona da política de SSRF/MIME/tamanho para a busca.
Início Rápido
Configurar via CLI (recomendado)
npx contentrain setup claude-code # or: cursor, vscode, windsurf, copilot
Isso cria automaticamente o arquivo de config MCP correto para sua IDE. Veja documentação da CLI para detalhes.
Executar como servidor MCP autônomo
CONTENTRAIN_PROJECT_ROOT=/path/to/project npx contentrain-mcp
Se CONTENTRAIN_PROJECT_ROOT for omitido, o diretório de trabalho atual é usado.
Incorporar o servidor no seu próprio processo
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)
createServer também aceita um objeto de opções: { provider, projectRoot?, instructions? }. instructions define a string instructions do MCP que os clientes recebem em initialize (padrão para um DEFAULT_INSTRUCTIONS embutido, mantido abaixo de 512 caracteres; passe '' para omitir).
Exemplo de Fluxo MCP
Fluxo de trabalho típico do agente:
- Chame
contentrain_status - Se necessário, chame
contentrain_init - Crie modelos com
contentrain_model_saveoucontentrain_scaffold - Salve conteúdo com
contentrain_content_save - Valide com
contentrain_validate - Para strings hardcoded, use
contentrain_scane depoiscontentrain_apply - Envie branches de revisão com
contentrain_submit
Fluxo de Normalização
A normalização é intencionalmente dividida em duas fases:
1. Extração
contentrain_scan encontra strings candidatas.
contentrain_apply com mode: "extract":
- cria ou atualiza modelos
- escreve entradas de conteúdo
- registra rastreamento de origem
- cria um branch de revisão (
cr/normalize/extract/{domain}/{timestamp})
2. Reutilização
contentrain_apply com mode: "reuse":
- aplica patches em arquivos de origem usando expressões fornecidas pelo agente
- adiciona imports quando necessário
- aplica segurança de caminho de patch e verificações de escopo
- cria um branch de revisão separado (
cr/normalize/reuse/{model}/{locale}/{timestamp})
Essa divisão mantém a extração de conteúdo separada da reescrita de código-fonte.
Requisitos de transporte / provedor
A normalização (contentrain_scan e contentrain_apply) requer acesso ao disco local — scanners AST percorrem a árvore de origem e aplicam patches nos arquivos no lugar. Ela roda apenas em um LocalProvider (transporte stdio, ou transporte HTTP configurado com um LocalProvider).
Provedores remotos como GitHubProvider expõem astScan: false, sourceRead: false e sourceWrite: false. Chamar essas ferramentas através de um provedor remoto retorna um erro de capacidade uniforme:
{
"error": "contentrain_scan requires local filesystem access.",
"capability_required": "astScan",
"hint": "This tool is unavailable when MCP is driven by a remote provider (e.g. GitHubProvider). Use a LocalProvider or the stdio transport."
}
Agentes dirigindo um transporte remoto devem recorrer a um transporte local (ou um checkout local) antes de invocar a normalização.
Provedores Remotos
O MCP suporta três backends por trás do mesmo contrato RepoProvider:
- LocalProvider — simple-git + worktree. Toda ferramenta (normalização incluída) funciona nele. O transporte stdio usa este por padrão.
- GitHubProvider — Octokit sobre as APIs Git Data + Repos. Sem clone, sem worktree.
@octokit/resté enviado como dependência opcional de peer. - GitLabProvider — gitbeaker sobre a API REST do GitLab. Sem clone, sem worktree.
@gitbeaker/resté enviado como dependência opcional de peer. Suporta gitlab.com e CE / EE auto-hospedados.
Cada provedor remoto implementa a mesma superfície: leitor (readFile / listDirectory / fileExists), escritor (applyPlan — um commit atômico), operações de branch (list / create / delete / diff / merge / isMerged / getDefaultBranch). mergeBranch passa direto no GitHub; no GitLab ele abre um MR e imediatamente o aceita para que a forma final do MergeResult corresponda de qualquer maneira. O provedor GitHub também aceita um SHA de commit completo como applyPlan do base (e createBranch do fromRef) para escritas compare-and-set: um branch ausente bifurca desse commit, e um branch que se moveu para longe dele recusa a escrita com PROVIDER_CONFLICT.
GitLab — instalação e uso
pnpm add @gitbeaker/rest
import { createGitLabProvider } from '@contentrain/mcp/providers/gitlab'
import { createServer } from '@contentrain/mcp/server'
const provider = await createGitLabProvider({
auth: { type: 'pat', token: process.env.GITLAB_TOKEN! },
project: {
projectId: 'acme/site', // or numeric project ID
host: 'https://gitlab.company.com', // omit for gitlab.com
},
})
const server = createServer({ provider })
// serve over stdio or the HTTP transport from @contentrain/mcp/server/http
Capacidades: sourceRead, sourceWrite, astScan, localWorktree são todos false; pushRemote, branchProtection, pullRequestFallback são true. Normalização / varredura / aplicação rejeitam com erro de capacidade no GitLabProvider — recorra a um transporte local para esses fluxos.
Bitbucket — em breve
Suporte para Bitbucket Cloud + Data Center está no roadmap. Até o provedor ser lançado, use a ferramenta contentrain_describe_format para dirigir operações de conteúdo da Contentrain manualmente a partir de um checkout Bitbucket via caminho LocalProvider.
Exportações Principais
O pacote também expõe módulos de baixo nível para incorporação e uso avançado:
@contentrain/mcp/server@contentrain/mcp/server/http@contentrain/mcp/core/config@contentrain/mcp/core/context@contentrain/mcp/core/model-manager@contentrain/mcp/core/content-manager@contentrain/mcp/core/validator@contentrain/mcp/core/scanner@contentrain/mcp/core/graph-builder@contentrain/mcp/core/apply-manager@contentrain/mcp/core/scan-config@contentrain/mcp/core/doctor@contentrain/mcp/core/contracts@contentrain/mcp/core/ops— APIs de plano (incluindoplanReconcilee seu adaptador de leiturabindRef) além de auxiliares de caminho relativos à raiz de conteúdo:contentDirPath,contentFilePath,documentFilePath,metaFilePath@contentrain/mcp/core/overlay-reader@contentrain/mcp/core/migration— o caminho de escrita de migração na lista de permissões:createMigrationWriter,scopeHash,decide. Veja Escritas de migração abaixo@contentrain/mcp/util/detect@contentrain/mcp/util/fs@contentrain/mcp/git/transaction@contentrain/mcp/git/branch-lifecycle— saúde/limpeza de branch além do ciclo de vida remoto cr/*:deleteRemoteBranch,listRemoteCrBranches,pruneMergedRemoteBranches,isRefMerged,classifyMergedBranches@contentrain/mcp/git/base-branch—resolveBaseBranch, o único resolvedor de branch base que toda escrita MCP econtentrain status/serveusam (env →repository.default_branch→origin/HEAD→main→master→ branch com checkout);resolveBaseBranchSource(o mesmo, mais qual degrau respondeu);resolveInitDefaultBranch(o queinitregistra comorepository.default_branch, ounull)@contentrain/mcp/git/errors@contentrain/mcp/git/reconcile—reconcileBranches, o executor de reconciliação local@contentrain/mcp/tools/annotations@contentrain/mcp/templates@contentrain/mcp/providers/local@contentrain/mcp/providers/github@contentrain/mcp/providers/gitlab
Estes são destinados às ferramentas do Contentrain e integrações avançadas, não para edição manual direta de arquivos .contentrain/.
Escritas de migração
Uma migração não entrega conteúdo, ela entrega um codebase: src/, public/,
package.json, um lockfile, configuração de deploy. O caminho de escrita de conteúdo
nunca foi construído para nada disso, e ampliá-lo moveria silenciosamente uma
fronteira de segurança na qual todo o produto se apoia — "Contentrain só escreve .contentrain/"
é uma promessa, não um detalhe de implementação.
@contentrain/mcp/core/migration é o portão em vez disso. Ele envolve um provedor cujo
applyPlan já pode escrever qualquer caminho, e coloca consentimento na frente dele.
import { createMigrationWriter, scopeHash } from '@contentrain/mcp/core/migration'
const scope = {
allow: ['src/**', 'public/**', 'package.json', 'astro.config.mjs'],
branch: 'migration/acme',
base: 'main',
}
// Show the user `scope`, not the hash. Then bind their consent to it:
const approval = {
scope_hash: await scopeHash(scope),
approver: { kind: 'human', id: userId, role: 'owner' },
approved_at: new Date().toISOString(),
}
const writer = createMigrationWriter(provider, scope, approval)
await writer.applyPlan({ ...plan, step: 'emit', actor })
writer.audit // which file, in which step, by which actor, in which commit
O que ele garante:
| Escopo | Apenas caminhos cobertos por um padrão da lista de permissões. .contentrain/** não é implícito — uma migração que quer a loja pede por ela, e a pessoa que aprova vê que ela pede |
| Consentimento | Uma aprovação, vinculada ao escopo exato por scope_hash. Uma aprovação de src/** não pode ser reproduzida contra um escopo que também tenha .github/workflows/** |
| Branch | Uma ref migration/*. O branch contentrain nunca é um alvo e nunca é uma base — inclusive através do padrão de ApplyPlanInput, que uma migração não deve herdar |
| Trilha | Um MigrationAuditEntry por arquivo: etapa, caminho, ação, o padrão que permitiu, ator, timestamp, commit |
| Desfazer | Um branch, entregue como um PR, revertível com um único git revert |
Toda recusa acontece antes de o provedor ser chamado, e um plano é recusado inteiro: um plano com um caminho fora do escopo não escreve nada, nem mesmo sua parte permitida. Uma migração meio aplicada é mais difícil de recuperar do que uma que nunca começou.
O correspondente de caminhos é um controle de segurança e foi escrito para falhar fechado. Travessia,
caminhos absolutos, separadores de barra invertida, codificação percentual, segmentos vazios e
caracteres de controle são recusados antes de qualquer padrão ser consultado; padrões são
ancorados em ambas as extremidades, então src/* não cobre src/a/b e nada corresponde
por ser um prefixo; e metacaracteres regex em um padrão são literais, então uma
entrada da lista de permissões não pode silenciosamente cobrir mais do que lê.
Restrições de design
Decisões-chave de design neste pacote:
- local-first por padrão — transporte stdio + LocalProvider funciona sem qualquer dependência de rede
- motor agnóstico de provedor — as mesmas ferramentas principais rodam sobre LocalProvider, GitHubProvider ou GitLabProvider atrás de um único contrato
RepoProvider; ferramentas de mídia usam a faceta de mídia opcional do provedor - SDKs de provedores remotos (
@octokit/rest,@gitbeaker/rest) são dependências pares opcionais — puxadas apenas quando seu provedor é usado - armazenamento de conteúdo somente JSON
- fluxo de escrita apoiado em git (transação de worktree localmente, commit atômico único sobre as APIs Git Data / REST remotamente)
- serialização canônica — saída deterministicamente em bytes, chaves ordenadas, nova linha final
- camada MCP agnóstica de framework
- o agente decide semântica de conteúdo, MCP impõe execução determinística
- portões de capacidade — ferramentas que precisam de acesso à árvore de origem (normalize, scan, apply, doctor) rejeitam com um erro uniforme
capability_requiredem provedores remotos
Desenvolvimento
Da raiz do monorepo:
pnpm --filter @contentrain/mcp build
pnpm --filter @contentrain/mcp test
pnpm --filter @contentrain/mcp typecheck
pnpm exec oxlint packages/mcp/src packages/mcp/tests
Pacotes relacionados
contentrain— CLI e ferramentas de revisão local@contentrain/query— SDK de consulta de runtime gerado@contentrain/rules— regras e prompts de IDE/agente@contentrain/types— tipos de esquema e modelo compartilhados
Documentação
Documentação completa em ai.contentrain.io/packages/mcp.
Licença
MIT
Cobertura de locale (model.locales)
contentrain_validate verifica a paridade de um modelo i18n: true contra cada locale
em config.locales.supported. Um modelo que declara locales — um subconjunto dessa
lista — é verificado contra o subconjunto em vez disso, que é como um site
parcialmente traduzido declara a verdade em vez de falhar em traduções que nunca teve. Ausente, como
em todo modelo que precede o campo, significa a lista inteira do projeto.
A severidade é inalterada e ainda segue o tipo: uma tradução ausente é um
aviso em um modelo document e um erro em um modelo collection. Cada mensagem
nomeia a lista contra a qual foi avaliada, então os dois casos se leem separados:
Locale file missing: tr.json (checked against the model's own locales [en, tr])
Entry parity: entry "a1b2c3" exists in en but missing in tr (checked against the project's supported locales [en, tr, da])
contentrain_model_save aceita locales e rejeita um locale fora de
config.locales.supported. contentrain_validate fix:true relata uma
declaração quebrada, mas nunca inventa uma: estreitar a cobertura de um modelo é uma
decisão de conteúdo, e o único valor que a ferramenta poderia derivar — os locales que por acaso têm
arquivos hoje — escreveria as lacunas atuais no esquema e silenciaria os
erros que as revelam.
Configuração de modelo em runtime
Edições estruturais de contentrain_model_save preservam blocos form e
comments de nível superior existentes. Esses blocos pertencem ao provedor de runtime; a ferramenta
estrutural não os habilita ou altera. Sua resposta lista preserved_blocks quando
a configuração foi transportada adiante.