From c189b6f8d000f3b37a233268f58009da57ebac97 Mon Sep 17 00:00:00 2001 From: AHMET BAYHAN BAYRAMOGLU <49499275+ABB65@users.noreply.github.com> Date: Fri, 17 Jul 2026 20:45:02 +0300 Subject: [PATCH] fix(mcp): stop DEFAULT_INSTRUCTIONS advertising a universal dry_run MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The server instructions told clients to preview every write with dry_run:true — but dry_run exists only on contentrain_apply. On other write tools the unknown key is stripped by the Zod schema, so an agent following the instructions performed a real write while believing it had previewed. The text now states the actual safety model: isolated cr/* branches, the content_save validation gate, confirm:true on destructive tools, and dry_run as the apply preview. 507 chars, under the 512 client-UI budget asserted by the test. oxlint 0/0, tsc clean, tool-availability suite 12/12. --- .changeset/server-instructions-dry-run.md | 15 +++++++++++++++ packages/mcp/src/server.ts | 12 ++++++------ 2 files changed, 21 insertions(+), 6 deletions(-) create mode 100644 .changeset/server-instructions-dry-run.md diff --git a/.changeset/server-instructions-dry-run.md b/.changeset/server-instructions-dry-run.md new file mode 100644 index 0000000..1175e6c --- /dev/null +++ b/.changeset/server-instructions-dry-run.md @@ -0,0 +1,15 @@ +--- +"@contentrain/mcp": patch +--- + +fix(mcp): stop DEFAULT_INSTRUCTIONS advertising a universal dry_run + +The MCP server instructions told every client to "preview writes with +dry_run:true, then re-run with dry_run:false" — but `dry_run` exists only on +`contentrain_apply`. On every other write tool the unknown key is stripped by +the schema, so an agent following the instructions performed a real write +while believing it had previewed. The instructions now state the actual +safety model: writes land on isolated `cr/*` branches, `content_save` +validates before committing, destructive tools require `confirm:true`, and +`dry_run` is the `contentrain_apply` preview. Still under the 512-character +client-UI budget; no tool behavior changes. diff --git a/packages/mcp/src/server.ts b/packages/mcp/src/server.ts index 08911ca..2687cbe 100644 --- a/packages/mcp/src/server.ts +++ b/packages/mcp/src/server.ts @@ -29,12 +29,12 @@ import packageJson from '../package.json' with { type: 'json' } */ export const DEFAULT_INSTRUCTIONS = 'Contentrain is git-native content governance: models define structure; ' - + 'content is canonical JSON/Markdown on a dedicated branch. Call ' - + 'contentrain_describe_format before creating models or content. Preview ' - + 'writes with dry_run:true, review the plan, then re-run with ' - + 'dry_run:false. Start with contentrain_status for models, locales, and ' - + 'workflow; inspect a model with contentrain_describe before editing its ' - + 'entries. Tools are deterministic infrastructure — content decisions ' + + 'content is canonical JSON/Markdown on a dedicated branch. Start with ' + + 'contentrain_status; call contentrain_describe_format before creating ' + + 'models or content, and contentrain_describe before editing a model\'s ' + + 'entries. Every write lands on an isolated cr/* branch and content_save ' + + 'validates before committing. Destructive tools require confirm:true; ' + + 'preview contentrain_apply with dry_run:true first. Content decisions ' + 'stay with the agent.' export interface CreateServerOptions {