Skip to content
Conduit

mcp server

graft

The agent-native CMS. MDX in git, one Zod schema, a derived index that needs no database. Operated over MCP and the CLI.

AndersonDesign1/graftcommunitylistedunreviewed

Set up

Runs on your computer. Pick your agent and operating system.

Before you start

  • Node.js 20 or newer
~/Library/Application Support/Claude/claude_desktop_config.json
{
  "mcpServers": {
    "andersondesign1-graft": {
      "command": "npx",
      "args": [
        "-y",
        "@usegraft/mcp"
      ]
    }
  }
}

same format Cursor, GitHub Copilot CLI, Junie, JetBrains AI Assistant, Augment (Auggie CLI), Factory Droid, Kiro, Devin CLI +12

Values in angle brackets are placeholders. Restart Claude Desktop after editing its config.Claude Desktop docs

README

synced Oct 14, 2026

Most content systems put a dashboard between you and your content. Graft puts a schema and a filesystem there instead, then gives an agent the same operator surface a human gets.

Authored content is MDX in git. Your schema is a Zod-typed defineCollection call. The queryable index is derived, so when git and the index disagree, git wins and the compiler rebuilds. Everything a human can do in the optional Studio, an agent can do over MCP or the CLI, under the same access rules, the same audit trail, and the same human gate on anything destructive.

Start with no database

A content project needs no services at all. graft compile writes the index to a SQLite artifact, and your app reads it embedded.

npx @usegraft/cli@latest init      # schema, content/, llms.txt
npx @usegraft/cli@latest compile   # writes .graft/index.db
import { openStaticIndex } from "@usegraft/db";
import { createClient } from "@usegraft/sdk-core";
import { collections } from "./graft.config";

const index = await openStaticIndex(".graft/index.db");
const graft = createClient({ index, collections });

const home = await graft.getDocument("pages", "home");
//    ^? typed by your pages collection. No codegen step.

The artifact is derived from the files in git, so it is git-ignored and rebuilt in your build command: graft compile && next build. Preview branches are git branches, and each checkout compiles its own index. Full-text search comes with it, because search is a property of the artifact.

That deploys to Vercel, Netlify, or Cloudflare Pages with nothing attached.

Add Postgres when you need it

Postgres buys operational data (orders, submissions, comments), typed functions with auth, audit, rate limits, and approvals, and copy-on-write preview branches.

# set DATABASE_URL, then change one line: export const index = "postgres"
npx @usegraft/cli@latest db migrate
npx @usegraft/cli@latest compile

Graft tells you the moment you need it. Reaching for a Postgres-tier feature in static mode fails with NEEDS_DATABASE, and that error's fix field is the two commands above.

Agents operate it

graft mcp serves your project over MCP, on stdio or Streamable HTTP. An agent reads your real schema through describe_schema instead of guessing at it, and every error it can hit carries a fix it can act on.

// .mcp.json
{ "mcpServers": { "graft": { "command": "npx", "args": ["-y", "@usegraft/cli@latest", "mcp"] } } }

The agent surface is not a subset of the human one. It reads and writes content, uploads assets, browses and installs registry primitives, runs typed functions, and compiles. What an agent cannot do is decide its own approval.

Destructive operations are human-gated under every policy. The call returns 403 with a pending approval id, a human runs graft approve <id>, and the caller retries carrying that id. The deciding identity is derived from the verified caller and never read from the request, so no argument exists that an agent could set to approve itself. On Postgres, graft harden moves that guarantee below the application: the runtime role holds no UPDATE on approvals, which puts pending → approved out of reach even through raw SQL.

Primitives you own

graft add copies a primitive's files into your repository, shadcn-style. You own the copy and edit it like the rest of your code. No version of it sits in node_modules to fight with.

graft add commerce

Available today: seo, callout, faq, scoped-access, comments, and commerce (file-authoritative products, database-authoritative orders, and the place, list, update, and cancel functions).

Read it from your framework

PackageFramework
@usegraft/sdk-nextNext.js. React.cache-deduped reads, revalidateContent, and MdxBody
@usegraft/sdk-astroAstro. Typed reads plus graftRoute endpoint mounts
@usegraft/sdk-sveltekitSvelteKit. Typed reads plus graftRoute for +server.ts
@usegraft/sdk-tanstack-startTanStack Start. Typed reads plus graftRoute for server routes
@usegraft/sdk-react-routerReact Router v7 framework mode. Typed reads plus loader/action mounts
@usegraft/sdk-reactThe browser. Reads over HTTP, plus hooks
@usegraft/sdk-coreAnything else. The typed client the others wrap

Every adapter is typed structurally, so none of them depends on the framework it adapts. sdk-react is the one that does not read a database: it reads a @usegraft/content-api endpoint over HTTP, because a Postgres handle in a browser bundle is a database URL in a browser bundle.

Telemetry

None. Graft collects no analytics, sends no usage pings, and phones home from no command. The only network calls it makes are the ones your project configures: your database, your asset store, and, when you use them, Neon's branching API and your OIDC issuer.

Packages

PackagePurpose
@usegraft/coreSchema (defineCollection), typed functions, access, the function runtime
@usegraft/compilerValidate authored MDX and project it into the index
@usegraft/dbPostgres client, migrations, the static SQLite index, copy-on-write branches
@usegraft/contractsError codes and introspection schemas every package shares
@usegraft/sdk-coreFramework-agnostic typed read client and the cache-tag contract
@usegraft/content-apiRead-only HTTP transport for the authored-content index
@usegraft/sdk-nextNext.js adapter
@usegraft/sdk-astroAstro adapter
@usegraft/sdk-sveltekitSvelteKit adapter
@usegraft/sdk-tanstack-startTanStack Start adapter
@usegraft/sdk-react-routerReact Router v7 adapter, framework mode
@usegraft/sdk-reactBrowser client and hooks over the content API
@usegraft/cliThe graft command
@usegraft/mcpThe agent surface: content, functions, introspection
@usegraft/studioThe optional editing UI and approval queue
@usegraft/registryThe registry behind graft add
@usegraft/authOIDC verification, actor resolution, scope checks
@usegraft/assetsS3-compatible storage and agent upload primitives
@usegraft/mdx-safetyRefuses executable constructs in authored MDX
@usegraft/content-migrationsCodemod-style transforms for authored content
@usegraft/tokensThe design tokens the Studio and examples share

Self-host

One image runs the whole backend: Postgres, MinIO, and graft serve.

docker run -p 3903:3903 -v "$PWD:/project" graft

It migrates, compiles, and serves, then logs a generated bearer token. Anonymous MCP is never exposed. It serves under a hardened role wherever it owns its own database. Adapters for Railway, Fly, a plain VPS, and Vercel live in deploy/.

Documentation

Status

Pre-1.0. Packages are published under @usegraft/*, and the API can still change between minors when the change buys a better design. Every break is described in the changelog and in the pull request that makes it.

Contributing

Start with CONTRIBUTING.md. Engineering conventions live in CONVENTIONS.md.

Report a vulnerability through SECURITY.md, never a public issue. This project follows the Contributor Covenant.

License

MIT. See LICENSE.

↑↓ navigate openesc close