MCP endpoint
@evolve-framework/authoring-server mounts an opt-in /mcp route
alongside the existing /chat route. Same tools, same auth, same
session — different transport. Headless AI clients connect to it the
way mcp-customer already does for the storefront’s commerce
surface.
The tools the endpoint serves are not hardcoded in the package.
The framework ships a small set of built-ins (page generation, image
and video generation, block-path lookup) and the host project owns
the GraphQL-backed ones via an authoring-operations.graphql file
that gets compiled to typed MCP tools by @evolve-framework/mcp-core’s
codegen.
Why a project-owned operations file
Section titled “Why a project-owned operations file”Every Evolve project has a slightly different commerce schema, content model, and AI surface. Hardcoding the GraphQL queries in the package would force every customer onto the reference shape — and would mean shipping a new package version every time anyone wanted to extend the toolset.
Putting authoring-operations.graphql in the host service flips the
ownership: the framework ships the tool runtime and the built-ins,
the project ships its own queries. Codegen turns those queries into
typed tool definitions at build time, so no GraphQL strings ride
along in the published packages.
It’s the same pattern @evolve-platform/mcp-customer already uses
for the storefront. The authoring layer now reuses
@evolve-framework/mcp-core’s codegen pipeline directly — see
mcp-core for the directive
reference.
Tool split
Section titled “Tool split”The 14 tools the authoring AI uses break down into two groups:
| Side | Tools | Why |
|---|---|---|
| Framework built-ins | generate-page, patch-page, find-block-path, generate-image, generate-video |
Pure functions on PageData or AI provider calls. No GraphQL, no customer schema. |
| Project-owned (codegen) | search-products, search-categories, search-entries, search-assets, load-page, push-page, prepare-publish, publish-page, catalog |
Commerce/CMS schema is customer-specific. Each project tunes the queries to its own page types and content model. |
The framework set is mounted via buildBuiltinAuthoringTools. The
project set is mounted via createAuthoringToolFromGenerated over
the codegen output.
Architecture
Section titled “Architecture”graph LR
Headless["Claude Desktop /<br/>Cursor / agents"] --> MCP
Chrome["In-browser chat<br/>authoring-chrome"] --> Chat
Chat["/chat — ai-sdk"] --> Tools["Shared tool runtime"]
MCP["/mcp — mcp-core"] --> Tools
Tools --> Gateway[GraphQL gateway]
Tools --> AI[AI providers]
/chat and /mcp live side-by-side on the same Fastify host and
share the same tool implementations. The chrome keeps using /chat
(streaming SSE for the chat panel); headless clients use /mcp.
Codegen pipeline
Section titled “Codegen pipeline”The project runs two codegen passes against the federation gateway’s
supergraph. Both live in the host service (typically
backend/services/authoring/):
codegen.ts— produces typed documents and persisted-document hashes for every operation inauthoring-operations.graphql. Uses themcpToolTransformfrom@evolve-framework/mcp-core/codegenso the client-preset learns to read the@mcpTooldirective and carry MCP metadata through to the next pass.codegen.tools.ts— reads the persisted-documents output of pass one and emitssrc/generated/authoring-tools.generated.tswith thegeneratedMcpToolsarray, ready to mount.
import { mcpToolTransform } from "@evolve-framework/mcp-core/codegen";import type { CodegenConfig } from "@graphql-codegen/cli";
export const documentPaths = ["./authoring-operations.graphql"];export const schemaPaths = [ "../graphql-gateway/supergraph.generated.graphql", "./node_modules/@evolve-framework/mcp-core/directives.graphql",];
const config: CodegenConfig = { schema: schemaPaths, generates: { "./src/generated/": { documents: documentPaths, preset: "client", documentTransforms: [mcpToolTransform], presetConfig: { fragmentMasking: false, persistedDocuments: { mode: "embedHashInDocument", hashPropertyName: "documentId", }, }, }, },};
export default config;import type { CodegenConfig } from "@graphql-codegen/cli";import { documentPaths, schemaPaths } from "./codegen.ts";
const config: CodegenConfig = { schema: schemaPaths, documents: documentPaths, generates: { "./src/generated/authoring-tools.generated.ts": { plugins: ["@evolve-framework/mcp-core/codegen/tools"], config: { persistedDocumentsPath: "./src/generated/persisted-documents.json", }, }, },};
export default config;Both passes run from pnpm codegen.
Defining a tool
Section titled “Defining a tool”Every operation in authoring-operations.graphql becomes a typed MCP
tool through two directives:
query SearchProducts( $searchTerm: String @mcpToolVariable( description: "Search term, e.g. 'sneakers' or 'winter coat'." ) $categoryId: String @mcpToolVariable( description: "Filter by category id. Call search-categories first for a valid id." ) $pageSize: Int! = 8)@mcpTool( description: "Search products in the commerce catalog. Use when a ProductBlock needs SKUs.") { productSearch( searchTerm: $searchTerm categoryId: $categoryId pageSize: $pageSize ) { total results { variant { sku name primaryImage { url } } } }}The framework ships an examples/authoring-operations.graphql with
the standard Evolve toolset as a starting point. Copy it, prune the
tools you don’t want, and tune the queries to your own content
shape.
Mounting the endpoint
Section titled “Mounting the endpoint”Mount the MCP route on the same Fastify host as the editor server,
after mountAuthoringEditor so the session signer is ready:
import { aiTextOneShot, generateImageBytes, generateVideoBytes,} from "@evolve-framework/authoring-ai-providers";import { buildBuiltinAuthoringTools, createAuthoringToolFromGenerated, mountAuthoringEditor, registerAuthoringMcp,} from "@evolve-framework/authoring-server";import { generatedMcpTools } from "./generated/authoring-tools.generated.ts";
await mountAuthoringEditor(app, { /* ...existing config */ });
registerAuthoringMcp(app, { tools: [ ...buildBuiltinAuthoringTools({ gatewayUrl: config.GATEWAY_URL, locale: config.CONTENTFUL_LOCALE, contentfulSpaceId: config.CONTENTFUL_SPACE_ID, imageGenerator: generateImageBytes, videoGenerator: generateVideoBytes, aiText: aiTextOneShot, }), ...generatedMcpTools.map((tool) => createAuthoringToolFromGenerated(tool, { gatewayUrl: config.GATEWAY_URL, locale: config.CONTENTFUL_LOCALE, }), ), ], gatewayEndpoint: config.GATEWAY_URL,});That’s it: the endpoint serves the built-ins, your project’s
generated tools, and shares the session machinery /chat already
uses.
Authentication
Section titled “Authentication”/mcp accepts the same two credentials the rest of the authoring
server understands:
__authoring_sessioncookie — the browser path. The MCP inspector and any in-page tooling pick this up automatically once the editor is signed in.X-Authoring-Cms-Tokenheader — the headless path. The value can be either an editor’s CMS OAuth token (paste once into the Claude Desktop config) or a service-account CMS management token (the same token the workflows addon uses for unattended runs).
No separate PAT infrastructure: the existing CMS token is the identity carrier. When it expires, the editor pastes a fresh one.
Headless client setup
Section titled “Headless client setup”For Claude Desktop, point the MCP client at the authoring service’s
/mcp URL with the CMS token as a header. Example fragment for
claude_desktop_config.json against a local dev environment:
{ "mcpServers": { "evolve-authoring": { "url": "https://authoring.evolve.localhost/mcp", "headers": { "X-Authoring-Cms-Token": "<your CMS OAuth or management token>" } } }}For local development the URL above lines up with the Portless setup that gives the authoring service a stable HTTPS hostname.
Side-by-side with /chat
Section titled “Side-by-side with /chat”The existing /chat ai-sdk route is unchanged. The chrome continues
to use it for the streaming chat panel because ai-sdk’s streaming
contract is what the chrome’s transcript renderer consumes. /mcp is
purely additive: turn it off (don’t call registerAuthoringMcp) and
the chrome works exactly as before.
The two routes share the same underlying tool implementations through a small adapter layer, so a fix to a tool lands in both transports at once.
Where to next
Section titled “Where to next”- mcp-core — directive reference, type mapping, query-security model.
- mcp-customer — the reference MCP service that uses the same codegen pipeline for storefront commerce tools.
- Packages —
authoring-serverAPI surface.

