@contentrain/mcp 1.2.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (154) hide show
  1. package/README.md +93 -25
  2. package/dist/annotations-Clhbw2lh.mjs +126 -0
  3. package/dist/annotations-Clhbw2lh.mjs.map +1 -0
  4. package/dist/{apply-manager-BkPMfpsN.mjs → apply-manager-D5ym5Jba.mjs} +7 -7
  5. package/dist/{apply-manager-BkPMfpsN.mjs.map → apply-manager-D5ym5Jba.mjs.map} +1 -1
  6. package/dist/{astro-parser-BJ-54JGe.mjs → astro-parser-B-nLl0zE.mjs} +3 -3
  7. package/dist/{astro-parser-BJ-54JGe.mjs.map → astro-parser-B-nLl0zE.mjs.map} +1 -1
  8. package/dist/{branch-lifecycle-wGJg25LT.mjs → branch-lifecycle-CFVpTpNT.mjs} +33 -3
  9. package/dist/{branch-lifecycle-wGJg25LT.mjs.map → branch-lifecycle-CFVpTpNT.mjs.map} +1 -1
  10. package/dist/{compiler-rIC4ETHv.mjs → compiler-k4yttlzM.mjs} +2 -2
  11. package/dist/{compiler-rIC4ETHv.mjs.map → compiler-k4yttlzM.mjs.map} +1 -1
  12. package/dist/{compiler-sfc.cjs-BbD04rn_.mjs → compiler-sfc.cjs-D0d_OicF.mjs} +2 -2
  13. package/dist/{compiler-sfc.cjs-BbD04rn_.mjs.map → compiler-sfc.cjs-D0d_OicF.mjs.map} +1 -1
  14. package/dist/config-BIl5Ybj0.mjs +40 -0
  15. package/dist/config-BIl5Ybj0.mjs.map +1 -0
  16. package/dist/content-manager-DqDLSNQ-.d.mts +63 -0
  17. package/dist/content-manager-DqDLSNQ-.d.mts.map +1 -0
  18. package/dist/context-J0OU9Nfp.mjs +102 -0
  19. package/dist/context-J0OU9Nfp.mjs.map +1 -0
  20. package/dist/contracts-DfL0BfrD.mjs +2 -0
  21. package/dist/core/apply-manager.mjs +10 -10
  22. package/dist/core/config.d.mts +13 -0
  23. package/dist/core/config.d.mts.map +1 -1
  24. package/dist/core/config.mjs +2 -3
  25. package/dist/core/content-manager.d.mts +2 -45
  26. package/dist/core/content-manager.mjs +3 -4
  27. package/dist/core/context.d.mts +32 -2
  28. package/dist/core/context.d.mts.map +1 -1
  29. package/dist/core/context.mjs +7 -7
  30. package/dist/core/contracts/index.d.mts +2 -0
  31. package/dist/core/contracts/index.mjs +2 -0
  32. package/dist/core/doctor.d.mts +76 -0
  33. package/dist/core/doctor.d.mts.map +1 -0
  34. package/dist/core/doctor.mjs +8 -0
  35. package/dist/core/graph-builder.mjs +3 -4
  36. package/dist/core/meta-manager.mjs +2 -3
  37. package/dist/core/model-manager.d.mts +34 -1
  38. package/dist/core/model-manager.d.mts.map +1 -1
  39. package/dist/core/model-manager.mjs +3 -4
  40. package/dist/core/ops/index.d.mts +137 -0
  41. package/dist/core/ops/index.d.mts.map +1 -0
  42. package/dist/core/ops/index.mjs +4 -0
  43. package/dist/core/overlay-reader.d.mts +42 -0
  44. package/dist/core/overlay-reader.d.mts.map +1 -0
  45. package/dist/core/overlay-reader.mjs +2 -0
  46. package/dist/core/scan-config.mjs +2 -3
  47. package/dist/core/scanner.mjs +4 -5
  48. package/dist/core/validator/index.d.mts +129 -0
  49. package/dist/core/validator/index.d.mts.map +1 -0
  50. package/dist/core/validator/index.mjs +6 -0
  51. package/dist/{detect-DinOQAmK.mjs → detect-DL9mFmaS.mjs} +2 -2
  52. package/dist/{detect-DinOQAmK.mjs.map → detect-DL9mFmaS.mjs.map} +1 -1
  53. package/dist/doctor-CgBoT6h1.mjs +338 -0
  54. package/dist/doctor-CgBoT6h1.mjs.map +1 -0
  55. package/dist/{fs-BnIQ4dKj.mjs → fs-DLbVB-Ek.mjs} +2 -2
  56. package/dist/fs-DLbVB-Ek.mjs.map +1 -0
  57. package/dist/git/branch-lifecycle.d.mts +30 -1
  58. package/dist/git/branch-lifecycle.d.mts.map +1 -1
  59. package/dist/git/branch-lifecycle.mjs +4 -5
  60. package/dist/git/transaction.d.mts +2 -2
  61. package/dist/git/transaction.d.mts.map +1 -1
  62. package/dist/git/transaction.mjs +8 -8
  63. package/dist/{graph-builder-tM7zj-SX.mjs → graph-builder-DXv2JEp-.mjs} +3 -3
  64. package/dist/{graph-builder-tM7zj-SX.mjs.map → graph-builder-DXv2JEp-.mjs.map} +1 -1
  65. package/dist/{id-DV_T9Ic8.mjs → id-CIO9s0x_.mjs} +1 -1
  66. package/dist/{id-DV_T9Ic8.mjs.map → id-CIO9s0x_.mjs.map} +1 -1
  67. package/dist/index-D0wQJSgs.d.mts +2 -0
  68. package/dist/index.mjs +22 -17
  69. package/dist/index.mjs.map +1 -1
  70. package/dist/local-DvP4Y4T-.mjs +182 -0
  71. package/dist/local-DvP4Y4T-.mjs.map +1 -0
  72. package/dist/{meta-manager--0IwAPCl.mjs → meta-manager-C900rEyG.mjs} +2 -2
  73. package/dist/{meta-manager--0IwAPCl.mjs.map → meta-manager-C900rEyG.mjs.map} +1 -1
  74. package/dist/{model-manager-DW_fOGRM.mjs → model-manager-BhLsUgaB.mjs} +241 -49
  75. package/dist/model-manager-BhLsUgaB.mjs.map +1 -0
  76. package/dist/{node-Cbq5eR5i.mjs → node-DN9hZeil.mjs} +1 -1
  77. package/dist/{node-Cbq5eR5i.mjs.map → node-DN9hZeil.mjs.map} +1 -1
  78. package/dist/ops-DjEWi5Wa.mjs +486 -0
  79. package/dist/ops-DjEWi5Wa.mjs.map +1 -0
  80. package/dist/overlay-reader-DOdyDRIv.mjs +74 -0
  81. package/dist/overlay-reader-DOdyDRIv.mjs.map +1 -0
  82. package/dist/paths-C3xNyc7z.mjs +52 -0
  83. package/dist/paths-C3xNyc7z.mjs.map +1 -0
  84. package/dist/paths-CYl5vCBD.mjs +54 -0
  85. package/dist/paths-CYl5vCBD.mjs.map +1 -0
  86. package/dist/providers/github/index.d.mts +144 -0
  87. package/dist/providers/github/index.d.mts.map +1 -0
  88. package/dist/providers/github/index.mjs +414 -0
  89. package/dist/providers/github/index.mjs.map +1 -0
  90. package/dist/providers/gitlab/index.d.mts +158 -0
  91. package/dist/providers/gitlab/index.d.mts.map +1 -0
  92. package/dist/providers/gitlab/index.mjs +361 -0
  93. package/dist/providers/gitlab/index.mjs.map +1 -0
  94. package/dist/providers/local/index.d.mts +106 -0
  95. package/dist/providers/local/index.d.mts.map +1 -0
  96. package/dist/providers/local/index.mjs +12 -0
  97. package/dist/{scan-config-QgnJ1-52.mjs → scan-config-jC6XmiqF.mjs} +2 -2
  98. package/dist/{scan-config-QgnJ1-52.mjs.map → scan-config-jC6XmiqF.mjs.map} +1 -1
  99. package/dist/{scanner-CQOxARUU.mjs → scanner-DKMwc03k.mjs} +26 -8
  100. package/dist/scanner-DKMwc03k.mjs.map +1 -0
  101. package/dist/serialization-B1CEzR4H.mjs +2 -0
  102. package/dist/server/http/index.d.mts +65 -0
  103. package/dist/server/http/index.d.mts.map +1 -0
  104. package/dist/server/http/index.mjs +137 -0
  105. package/dist/server/http/index.mjs.map +1 -0
  106. package/dist/{server-DfWRpzdP.mjs → server-B1OJrUQ9.mjs} +486 -355
  107. package/dist/server-B1OJrUQ9.mjs.map +1 -0
  108. package/dist/server-WqGx6ait.d.mts +50 -0
  109. package/dist/server-WqGx6ait.d.mts.map +1 -0
  110. package/dist/server.d.mts +2 -7
  111. package/dist/server.mjs +22 -17
  112. package/dist/{source-map-generator-DpO-ejrt.mjs → source-map-generator-BWDva49I.mjs} +1 -1
  113. package/dist/{source-map-generator-DpO-ejrt.mjs.map → source-map-generator-BWDva49I.mjs.map} +1 -1
  114. package/dist/{svelte-parser-1bBcMx3T.mjs → svelte-parser-Dr9mmZuk.mjs} +3 -3
  115. package/dist/{svelte-parser-1bBcMx3T.mjs.map → svelte-parser-Dr9mmZuk.mjs.map} +1 -1
  116. package/dist/templates/index.mjs +1 -1
  117. package/dist/{templates-bRPzYq4M.mjs → templates-VrLVqfe5.mjs} +1 -1
  118. package/dist/{templates-bRPzYq4M.mjs.map → templates-VrLVqfe5.mjs.map} +1 -1
  119. package/dist/tools/annotations.d.mts +24 -0
  120. package/dist/tools/annotations.d.mts.map +1 -0
  121. package/dist/tools/annotations.mjs +2 -0
  122. package/dist/{transaction-C_Pvux78.mjs → transaction-DgkNgWSI.mjs} +61 -32
  123. package/dist/transaction-DgkNgWSI.mjs.map +1 -0
  124. package/dist/tsx-parser-BOMZE_yQ.mjs +2 -0
  125. package/dist/{tsx-parser-BWiMGAIR.mjs → tsx-parser-CQc6nr-o.mjs} +1 -1
  126. package/dist/{tsx-parser-BWiMGAIR.mjs.map → tsx-parser-CQc6nr-o.mjs.map} +1 -1
  127. package/dist/util/detect.mjs +2 -3
  128. package/dist/util/fs.mjs +1 -2
  129. package/dist/util/id.mjs +1 -1
  130. package/dist/validator-B0nNRFeU.mjs +906 -0
  131. package/dist/validator-B0nNRFeU.mjs.map +1 -0
  132. package/dist/{vue-parser-DTPTN3Yb.mjs → vue-parser-COgjArqv.mjs} +3 -3
  133. package/dist/{vue-parser-DTPTN3Yb.mjs.map → vue-parser-COgjArqv.mjs.map} +1 -1
  134. package/package.json +75 -21
  135. package/dist/config-B5kc2oeV.mjs +0 -27
  136. package/dist/config-B5kc2oeV.mjs.map +0 -1
  137. package/dist/context-DIDt_TxX.mjs +0 -46
  138. package/dist/context-DIDt_TxX.mjs.map +0 -1
  139. package/dist/core/content-manager.d.mts.map +0 -1
  140. package/dist/core/validator.d.mts +0 -23
  141. package/dist/core/validator.d.mts.map +0 -1
  142. package/dist/core/validator.mjs +0 -7
  143. package/dist/fs-BnIQ4dKj.mjs.map +0 -1
  144. package/dist/model-manager-DW_fOGRM.mjs.map +0 -1
  145. package/dist/scanner-CQOxARUU.mjs.map +0 -1
  146. package/dist/serializer-CnHTtmc1.mjs +0 -2
  147. package/dist/server-DfWRpzdP.mjs.map +0 -1
  148. package/dist/server.d.mts.map +0 -1
  149. package/dist/transaction-C_Pvux78.mjs.map +0 -1
  150. package/dist/tsx-parser-BFLv292Y.mjs +0 -2
  151. package/dist/util/serializer.d.mts +0 -2
  152. package/dist/util/serializer.mjs +0 -2
  153. package/dist/validator-SQYUV2JP.mjs +0 -581
  154. package/dist/validator-SQYUV2JP.mjs.map +0 -1
package/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
  [![GitHub source](https://img.shields.io/badge/source-Contentrain%2Fai-181717?logo=github)](https://github.com/Contentrain/ai/tree/main/packages/mcp)
5
5
  [![Docs](https://img.shields.io/badge/docs-ai.contentrain.io-0f172a)](https://ai.contentrain.io/packages/mcp)
6
6
 
7
- Local-first MCP server and core primitives for Contentrain.
7
+ Provider-agnostic MCP engine for Contentrain — local-first by default, with optional GitHub and GitLab backends and an HTTP transport for remote drivers such as Studio.
8
8
 
9
9
  Start here:
10
10
 
@@ -25,7 +25,7 @@ This package is the runtime core behind Contentrain's MCP integration. It can be
25
25
  - an embeddable server (`createServer(projectRoot)`)
26
26
  - a low-level toolkit for config, models, content, validation, scanning, and git transaction flow
27
27
 
28
- ## 🚀 Install
28
+ ## Install
29
29
 
30
30
  ```bash
31
31
  pnpm add @contentrain/mcp
@@ -44,7 +44,7 @@ Optional parser support for higher-quality source scanning:
44
44
 
45
45
  They are listed as optional dependencies. The scanner still works without them, but Vue/Astro/Svelte detection is stronger when they are installed.
46
46
 
47
- ## ✨ What It Does
47
+ ## What It Does
48
48
 
49
49
  `@contentrain/mcp` manages a `.contentrain/` directory in your project and exposes MCP tools for:
50
50
 
@@ -54,28 +54,30 @@ They are listed as optional dependencies. The scanner still works without them,
54
54
  - validation and auto-fix
55
55
  - normalize scan and apply flows
56
56
  - bulk operations
57
- - branch submission and branch-health awareness
57
+ - branch submission, review-mode merge, and branch-health awareness
58
+ - project health checking (doctor)
58
59
 
59
60
  All write operations are designed around git-backed safety:
60
61
 
61
62
  - a dedicated `contentrain` branch serves as the content state single source of truth
62
- - each write creates a temporary worktree on a feature branch forked from `contentrain`
63
+ - each write creates a temporary worktree on a feature branch forked from `contentrain` (branch name: `cr/{operation}/{model}/{locale}/{timestamp}-{suffix}`)
63
64
  - auto-merge: feature merges into `contentrain`, baseBranch advanced via update-ref, `.contentrain/` files selectively synced to developer's working tree
64
65
  - review: feature branch pushed to remote for team review
65
66
  - developer's working tree is never mutated during MCP git operations (no stash, no checkout, no merge)
66
67
  - context.json is committed together with content changes, not as a separate commit
67
- - keep canonical JSON output
68
- - surface validation and next-step hints to the caller
68
+ - canonical JSON output — sorted keys, 2-space indent, trailing newline
69
+ - validation + next-step hints surfaced to the caller
69
70
 
70
- ## 🧰 Tool Surface
71
+ ## Tool Surface
71
72
 
72
- 16 MCP tools with [annotations](https://spec.modelcontextprotocol.io/specification/2025-03-26/server/tools/#annotations) (`readOnlyHint`, `destructiveHint`, `idempotentHint`) for client safety hints:
73
+ 17 MCP tools with [annotations](https://spec.modelcontextprotocol.io/specification/2025-03-26/server/tools/#annotations) (`readOnlyHint`, `destructiveHint`, `idempotentHint`) for client safety hints:
73
74
 
74
75
  | Tool | Purpose | Read-only | Destructive |
75
76
  | --- | --- | --- | --- |
76
77
  | `contentrain_status` | Project status, config, models, branch health, context | Yes | — |
77
78
  | `contentrain_describe` | Full schema and sample data for a model | Yes | — |
78
79
  | `contentrain_describe_format` | File-format and storage contract reference | Yes | — |
80
+ | `contentrain_doctor` | Project health report (env, structure, models, orphans, branches, SDK) | Yes | — |
79
81
  | `contentrain_init` | Create `.contentrain/` structure and base config | — | — |
80
82
  | `contentrain_scaffold` | Apply a starter template such as blog, docs, landing, saas | — | — |
81
83
  | `contentrain_model_save` | Create or update a model definition | — | — |
@@ -84,13 +86,13 @@ All write operations are designed around git-backed safety:
84
86
  | `contentrain_content_delete` | Delete content entries | — | **Yes** |
85
87
  | `contentrain_content_list` | Read content entries | Yes | — |
86
88
  | `contentrain_validate` | Validate project content, optionally auto-fix structural issues | — | — |
87
- | `contentrain_submit` | Push `contentrain/*` branches to remote | — | — |
89
+ | `contentrain_submit` | Push `cr/*` branches to remote | — | — |
88
90
  | `contentrain_merge` | Merge a review-mode branch into contentrain locally | — | — |
89
91
  | `contentrain_scan` | Graph- and candidate-based hardcoded string scan | Yes | — |
90
92
  | `contentrain_apply` | Normalize extract/reuse execution with dry-run support | — | — |
91
93
  | `contentrain_bulk` | Bulk locale copy, status updates, and deletes | — | — |
92
94
 
93
- ## 🚀 Quick Start
95
+ ## Quick Start
94
96
 
95
97
  ### Configure via CLI (recommended)
96
98
 
@@ -120,7 +122,7 @@ const transport = new StdioServerTransport()
120
122
  await server.connect(transport)
121
123
  ```
122
124
 
123
- ## 🔄 Example MCP Flow
125
+ ## Example MCP Flow
124
126
 
125
127
  Typical agent workflow:
126
128
 
@@ -132,7 +134,7 @@ Typical agent workflow:
132
134
  6. For hardcoded strings, use `contentrain_scan` then `contentrain_apply`
133
135
  7. Push review branches with `contentrain_submit`
134
136
 
135
- ## 🧪 Normalize Flow
137
+ ## Normalize Flow
136
138
 
137
139
  Normalize is intentionally split into two phases:
138
140
 
@@ -145,7 +147,7 @@ Normalize is intentionally split into two phases:
145
147
  - creates or updates models
146
148
  - writes content entries
147
149
  - records source tracking
148
- - creates a review branch
150
+ - creates a review branch (`cr/normalize/extract/{domain}/{timestamp}`)
149
151
 
150
152
  ### 2. Reuse
151
153
 
@@ -154,15 +156,70 @@ Normalize is intentionally split into two phases:
154
156
  - patches source files using agent-provided expressions
155
157
  - adds imports when needed
156
158
  - enforces patch path safety and scope checks
157
- - creates a separate review branch
159
+ - creates a separate review branch (`cr/normalize/reuse/{model}/{locale}/{timestamp}`)
158
160
 
159
161
  This split keeps content extraction separate from source rewriting.
160
162
 
161
- ## 📦 Core Exports
163
+ ### Transport / provider requirements
164
+
165
+ Normalize (`contentrain_scan` and `contentrain_apply`) requires local disk access — AST scanners walk the source tree and patch files in place. It runs only on a `LocalProvider` (stdio transport, or HTTP transport configured with a `LocalProvider`).
166
+
167
+ Remote providers such as `GitHubProvider` expose `astScan: false`, `sourceRead: false`, and `sourceWrite: false`. Calling these tools over a remote provider returns a uniform capability error:
168
+
169
+ ```json
170
+ {
171
+ "error": "contentrain_scan requires local filesystem access.",
172
+ "capability_required": "astScan",
173
+ "hint": "This tool is unavailable when MCP is driven by a remote provider (e.g. GitHubProvider). Use a LocalProvider or the stdio transport."
174
+ }
175
+ ```
176
+
177
+ Agents driving a remote transport should fall back to a local transport (or a local checkout) before invoking normalize.
178
+
179
+ ## Remote Providers
180
+
181
+ MCP supports three backends behind the same `RepoProvider` contract:
182
+
183
+ - **LocalProvider** — simple-git + worktree. Every tool (normalize included) works on it. Stdio transport defaults to this.
184
+ - **GitHubProvider** — Octokit over the Git Data + Repos APIs. No clone, no worktree. `@octokit/rest` ships as an optional peer dependency.
185
+ - **GitLabProvider** — gitbeaker over the GitLab REST API. No clone, no worktree. `@gitbeaker/rest` ships as an optional peer dependency. Supports gitlab.com and self-hosted CE / EE.
186
+
187
+ Each remote provider implements the same surface: reader (readFile / listDirectory / fileExists), writer (applyPlan — one atomic commit), branch ops (list / create / delete / diff / merge / isMerged / getDefaultBranch). `mergeBranch` goes straight through on GitHub; on GitLab it opens an MR and immediately accepts it so the final `MergeResult` shape matches either way.
188
+
189
+ ### GitLab — installation & usage
190
+
191
+ ```bash
192
+ pnpm add @gitbeaker/rest
193
+ ```
194
+
195
+ ```ts
196
+ import { createGitLabProvider } from '@contentrain/mcp/providers/gitlab'
197
+ import { createServer } from '@contentrain/mcp/server'
198
+
199
+ const provider = await createGitLabProvider({
200
+ auth: { type: 'pat', token: process.env.GITLAB_TOKEN! },
201
+ project: {
202
+ projectId: 'acme/site', // or numeric project ID
203
+ host: 'https://gitlab.company.com', // omit for gitlab.com
204
+ },
205
+ })
206
+
207
+ const server = createServer({ provider })
208
+ // serve over stdio or the HTTP transport from @contentrain/mcp/server/http
209
+ ```
210
+
211
+ Capabilities: `sourceRead`, `sourceWrite`, `astScan`, `localWorktree` are all `false`; `pushRemote`, `branchProtection`, `pullRequestFallback` are `true`. Normalize / scan / apply reject with a capability error on GitLabProvider — fall back to a local transport for those flows.
212
+
213
+ ### Bitbucket — coming soon
214
+
215
+ Bitbucket Cloud + Data Center support is on the roadmap. Until the provider ships, use the `contentrain_describe_format` tool to drive Contentrain content operations manually from a Bitbucket checkout via the LocalProvider path.
216
+
217
+ ## Core Exports
162
218
 
163
219
  The package also exposes low-level modules for embedding and advanced use:
164
220
 
165
221
  - `@contentrain/mcp/server`
222
+ - `@contentrain/mcp/server/http`
166
223
  - `@contentrain/mcp/core/config`
167
224
  - `@contentrain/mcp/core/context`
168
225
  - `@contentrain/mcp/core/model-manager`
@@ -171,27 +228,38 @@ The package also exposes low-level modules for embedding and advanced use:
171
228
  - `@contentrain/mcp/core/scanner`
172
229
  - `@contentrain/mcp/core/graph-builder`
173
230
  - `@contentrain/mcp/core/apply-manager`
231
+ - `@contentrain/mcp/core/scan-config`
232
+ - `@contentrain/mcp/core/doctor`
233
+ - `@contentrain/mcp/core/contracts`
234
+ - `@contentrain/mcp/core/ops`
235
+ - `@contentrain/mcp/core/overlay-reader`
174
236
  - `@contentrain/mcp/util/detect`
175
237
  - `@contentrain/mcp/util/fs`
176
238
  - `@contentrain/mcp/git/transaction`
177
239
  - `@contentrain/mcp/git/branch-lifecycle`
240
+ - `@contentrain/mcp/tools/annotations`
178
241
  - `@contentrain/mcp/templates`
242
+ - `@contentrain/mcp/providers/local`
243
+ - `@contentrain/mcp/providers/github`
244
+ - `@contentrain/mcp/providers/gitlab`
179
245
 
180
246
  These are intended for Contentrain tooling and advanced integrations, not for direct manual editing of `.contentrain/` files.
181
247
 
182
- ## 🧠 Design Constraints
248
+ ## Design Constraints
183
249
 
184
250
  Key design decisions in this package:
185
251
 
186
- - local-first, filesystem-based MCP
187
- - no GitHub API dependency in MCP
252
+ - local-first **by default** — stdio transport + LocalProvider works without any network dependency
253
+ - provider-agnostic engine — the same 17 tools run over LocalProvider, GitHubProvider, or GitLabProvider behind a single `RepoProvider` contract
254
+ - remote provider SDKs (`@octokit/rest`, `@gitbeaker/rest`) are optional peer dependencies — pulled in only when their provider is used
188
255
  - JSON-only content storage
189
- - git-backed write workflow
190
- - canonical serialization
256
+ - git-backed write workflow (worktree transaction locally, single atomic commit over the Git Data / REST APIs remotely)
257
+ - canonical serialization — byte-deterministic output, sorted keys, trailing newline
191
258
  - framework-agnostic MCP layer
192
259
  - agent decides content semantics, MCP enforces deterministic execution
260
+ - capability gates — tools that need source-tree access (normalize, scan, apply, doctor) reject with a uniform `capability_required` error on remote providers
193
261
 
194
- ## 🛠 Development
262
+ ## Development
195
263
 
196
264
  From the monorepo root:
197
265
 
@@ -202,17 +270,17 @@ pnpm --filter @contentrain/mcp typecheck
202
270
  pnpm exec oxlint packages/mcp/src packages/mcp/tests
203
271
  ```
204
272
 
205
- ## 🔗 Related Packages
273
+ ## Related Packages
206
274
 
207
275
  - `contentrain` — CLI and local review tooling
208
276
  - `@contentrain/query` — generated runtime query SDK
209
277
  - `@contentrain/rules` — IDE/agent rules and prompts
210
278
  - `@contentrain/types` — shared schema and model types
211
279
 
212
- ## 📚 Documentation
280
+ ## Documentation
213
281
 
214
282
  Full documentation at **[ai.contentrain.io/packages/mcp](https://ai.contentrain.io/packages/mcp)**.
215
283
 
216
- ## 📄 License
284
+ ## License
217
285
 
218
286
  MIT
@@ -0,0 +1,126 @@
1
+ //#region src/tools/annotations.ts
2
+ /**
3
+ * Centralized tool annotations registry.
4
+ * MCP clients use these hints to distinguish read-only vs. write vs. destructive tools.
5
+ *
6
+ * Also serves as the **single source of truth for the tool name list**. Consumers
7
+ * that need to enumerate every registered tool (e.g. parity tests in
8
+ * `@contentrain/rules` / `@contentrain/skills`) should import `TOOL_NAMES` below
9
+ * rather than hardcoding the list.
10
+ */
11
+ const TOOL_ANNOTATIONS = {
12
+ contentrain_status: {
13
+ title: "Project Status",
14
+ readOnlyHint: true,
15
+ destructiveHint: false,
16
+ idempotentHint: true
17
+ },
18
+ contentrain_describe: {
19
+ title: "Describe Model",
20
+ readOnlyHint: true,
21
+ destructiveHint: false,
22
+ idempotentHint: true
23
+ },
24
+ contentrain_describe_format: {
25
+ title: "Describe Format",
26
+ readOnlyHint: true,
27
+ destructiveHint: false,
28
+ idempotentHint: true
29
+ },
30
+ contentrain_doctor: {
31
+ title: "Project Health Report",
32
+ readOnlyHint: true,
33
+ destructiveHint: false,
34
+ idempotentHint: true
35
+ },
36
+ contentrain_init: {
37
+ title: "Initialize Project",
38
+ readOnlyHint: false,
39
+ destructiveHint: false,
40
+ idempotentHint: false
41
+ },
42
+ contentrain_scaffold: {
43
+ title: "Scaffold Template",
44
+ readOnlyHint: false,
45
+ destructiveHint: false,
46
+ idempotentHint: false
47
+ },
48
+ contentrain_model_save: {
49
+ title: "Save Model",
50
+ readOnlyHint: false,
51
+ destructiveHint: false,
52
+ idempotentHint: true
53
+ },
54
+ contentrain_model_delete: {
55
+ title: "Delete Model",
56
+ readOnlyHint: false,
57
+ destructiveHint: true,
58
+ idempotentHint: false
59
+ },
60
+ contentrain_content_save: {
61
+ title: "Save Content",
62
+ readOnlyHint: false,
63
+ destructiveHint: false,
64
+ idempotentHint: true
65
+ },
66
+ contentrain_content_delete: {
67
+ title: "Delete Content",
68
+ readOnlyHint: false,
69
+ destructiveHint: true,
70
+ idempotentHint: false
71
+ },
72
+ contentrain_content_list: {
73
+ title: "List Content",
74
+ readOnlyHint: true,
75
+ destructiveHint: false,
76
+ idempotentHint: true
77
+ },
78
+ contentrain_validate: {
79
+ title: "Validate Project",
80
+ readOnlyHint: false,
81
+ destructiveHint: false,
82
+ idempotentHint: true
83
+ },
84
+ contentrain_submit: {
85
+ title: "Submit Branches",
86
+ readOnlyHint: false,
87
+ destructiveHint: false,
88
+ idempotentHint: true
89
+ },
90
+ contentrain_merge: {
91
+ title: "Merge Branch",
92
+ readOnlyHint: false,
93
+ destructiveHint: false,
94
+ idempotentHint: false
95
+ },
96
+ contentrain_scan: {
97
+ title: "Scan Source Code",
98
+ readOnlyHint: true,
99
+ destructiveHint: false,
100
+ idempotentHint: true
101
+ },
102
+ contentrain_apply: {
103
+ title: "Apply Normalize",
104
+ readOnlyHint: false,
105
+ destructiveHint: false,
106
+ idempotentHint: false
107
+ },
108
+ contentrain_bulk: {
109
+ title: "Bulk Operations",
110
+ readOnlyHint: false,
111
+ destructiveHint: false,
112
+ idempotentHint: false
113
+ }
114
+ };
115
+ /**
116
+ * Canonical list of every registered MCP tool name, derived from the
117
+ * single source of truth above. Re-exported here with a stable name so
118
+ * parity tests in sibling packages (`@contentrain/rules`,
119
+ * `@contentrain/skills`) can assert against it without depending on
120
+ * `TOOL_ANNOTATIONS` internals.
121
+ */
122
+ const TOOL_NAMES = Object.freeze(Object.keys(TOOL_ANNOTATIONS));
123
+ //#endregion
124
+ export { TOOL_NAMES as n, TOOL_ANNOTATIONS as t };
125
+
126
+ //# sourceMappingURL=annotations-Clhbw2lh.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"annotations-Clhbw2lh.mjs","names":[],"sources":["../src/tools/annotations.ts"],"sourcesContent":["import type { ToolAnnotations } from '@modelcontextprotocol/sdk/types.js'\n\n/**\n * Centralized tool annotations registry.\n * MCP clients use these hints to distinguish read-only vs. write vs. destructive tools.\n *\n * Also serves as the **single source of truth for the tool name list**. Consumers\n * that need to enumerate every registered tool (e.g. parity tests in\n * `@contentrain/rules` / `@contentrain/skills`) should import `TOOL_NAMES` below\n * rather than hardcoding the list.\n */\nexport const TOOL_ANNOTATIONS: Record<string, ToolAnnotations> = {\n // ─── Context (read-only) ───\n contentrain_status: {\n title: 'Project Status',\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n },\n contentrain_describe: {\n title: 'Describe Model',\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n },\n contentrain_describe_format: {\n title: 'Describe Format',\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n },\n contentrain_doctor: {\n title: 'Project Health Report',\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n },\n\n // ─── Setup (write + git) ───\n contentrain_init: {\n title: 'Initialize Project',\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n },\n contentrain_scaffold: {\n title: 'Scaffold Template',\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n },\n\n // ─── Model (write + git) ───\n contentrain_model_save: {\n title: 'Save Model',\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: true,\n },\n contentrain_model_delete: {\n title: 'Delete Model',\n readOnlyHint: false,\n destructiveHint: true,\n idempotentHint: false,\n },\n\n // ─── Content (mixed) ───\n contentrain_content_save: {\n title: 'Save Content',\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: true,\n },\n contentrain_content_delete: {\n title: 'Delete Content',\n readOnlyHint: false,\n destructiveHint: true,\n idempotentHint: false,\n },\n contentrain_content_list: {\n title: 'List Content',\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n },\n\n // ─── Workflow (mixed) ───\n contentrain_validate: {\n title: 'Validate Project',\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: true,\n },\n contentrain_submit: {\n title: 'Submit Branches',\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: true,\n },\n contentrain_merge: {\n title: 'Merge Branch',\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n },\n\n // ─── Normalize (mixed) ───\n contentrain_scan: {\n title: 'Scan Source Code',\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n },\n contentrain_apply: {\n title: 'Apply Normalize',\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n },\n\n // ─── Bulk (write + git) ───\n contentrain_bulk: {\n title: 'Bulk Operations',\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n },\n}\n\n/**\n * Canonical list of every registered MCP tool name, derived from the\n * single source of truth above. Re-exported here with a stable name so\n * parity tests in sibling packages (`@contentrain/rules`,\n * `@contentrain/skills`) can assert against it without depending on\n * `TOOL_ANNOTATIONS` internals.\n */\nexport const TOOL_NAMES: readonly string[] = Object.freeze(Object.keys(TOOL_ANNOTATIONS))\n"],"mappings":";;;;;;;;;;AAWA,MAAa,mBAAoD;CAE/D,oBAAoB;EAClB,OAAO;EACP,cAAc;EACd,iBAAiB;EACjB,gBAAgB;EACjB;CACD,sBAAsB;EACpB,OAAO;EACP,cAAc;EACd,iBAAiB;EACjB,gBAAgB;EACjB;CACD,6BAA6B;EAC3B,OAAO;EACP,cAAc;EACd,iBAAiB;EACjB,gBAAgB;EACjB;CACD,oBAAoB;EAClB,OAAO;EACP,cAAc;EACd,iBAAiB;EACjB,gBAAgB;EACjB;CAGD,kBAAkB;EAChB,OAAO;EACP,cAAc;EACd,iBAAiB;EACjB,gBAAgB;EACjB;CACD,sBAAsB;EACpB,OAAO;EACP,cAAc;EACd,iBAAiB;EACjB,gBAAgB;EACjB;CAGD,wBAAwB;EACtB,OAAO;EACP,cAAc;EACd,iBAAiB;EACjB,gBAAgB;EACjB;CACD,0BAA0B;EACxB,OAAO;EACP,cAAc;EACd,iBAAiB;EACjB,gBAAgB;EACjB;CAGD,0BAA0B;EACxB,OAAO;EACP,cAAc;EACd,iBAAiB;EACjB,gBAAgB;EACjB;CACD,4BAA4B;EAC1B,OAAO;EACP,cAAc;EACd,iBAAiB;EACjB,gBAAgB;EACjB;CACD,0BAA0B;EACxB,OAAO;EACP,cAAc;EACd,iBAAiB;EACjB,gBAAgB;EACjB;CAGD,sBAAsB;EACpB,OAAO;EACP,cAAc;EACd,iBAAiB;EACjB,gBAAgB;EACjB;CACD,oBAAoB;EAClB,OAAO;EACP,cAAc;EACd,iBAAiB;EACjB,gBAAgB;EACjB;CACD,mBAAmB;EACjB,OAAO;EACP,cAAc;EACd,iBAAiB;EACjB,gBAAgB;EACjB;CAGD,kBAAkB;EAChB,OAAO;EACP,cAAc;EACd,iBAAiB;EACjB,gBAAgB;EACjB;CACD,mBAAmB;EACjB,OAAO;EACP,cAAc;EACd,iBAAiB;EACjB,gBAAgB;EACjB;CAGD,kBAAkB;EAChB,OAAO;EACP,cAAc;EACd,iBAAiB;EACjB,gBAAgB;EACjB;CACF;;;;;;;;AASD,MAAa,aAAgC,OAAO,OAAO,OAAO,KAAK,iBAAiB,CAAC"}
@@ -1,9 +1,9 @@
1
- import { c as writeText, o as readText, r as pathExists } from "./fs-BnIQ4dKj.mjs";
2
- import { t as readConfig } from "./config-B5kc2oeV.mjs";
3
- import { S as writeContent, _ as resolveMdFilePath, c as validateModelDefinition, h as resolveJsonFilePath, l as writeModel, m as resolveContentDir, o as listModels, s as readModel } from "./model-manager-DW_fOGRM.mjs";
4
- import { n as writeContext } from "./context-DIDt_TxX.mjs";
5
- import { t as checkBranchHealth } from "./branch-lifecycle-wGJg25LT.mjs";
6
- import { n as createTransaction, t as buildBranchName } from "./transaction-C_Pvux78.mjs";
1
+ import { c as writeText, o as readText, r as pathExists } from "./fs-DLbVB-Ek.mjs";
2
+ import { t as readConfig } from "./config-BIl5Ybj0.mjs";
3
+ import { S as writeContent, _ as resolveMdFilePath, c as validateModelDefinition, h as resolveJsonFilePath, l as writeModel, m as resolveContentDir, o as listModels, s as readModel } from "./model-manager-BhLsUgaB.mjs";
4
+ import { r as writeContext } from "./context-J0OU9Nfp.mjs";
5
+ import { n as createTransaction, t as buildBranchName } from "./transaction-DgkNgWSI.mjs";
6
+ import { n as checkBranchHealth } from "./branch-lifecycle-CFVpTpNT.mjs";
7
7
  import { extname, join } from "node:path";
8
8
  //#region src/core/apply-manager.ts
9
9
  const MAX_PATCHES = 100;
@@ -753,4 +753,4 @@ function addImportsToLines(lines, imports) {
753
753
  //#endregion
754
754
  export { detectFileFramework as a, validatePatchPath as c, checkSyntax as i, applyExtract as n, replaceInLine as o, applyReuse as r, validateFrameworkExpression as s, PATCHABLE_EXTENSIONS as t };
755
755
 
756
- //# sourceMappingURL=apply-manager-BkPMfpsN.mjs.map
756
+ //# sourceMappingURL=apply-manager-D5ym5Jba.mjs.map