@bettercms-ai/mcp 0.67.3 → 0.68.1

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.
@@ -204,3 +204,6 @@ still renders hard-coded copy is not connected. Client components never receive
204
204
  - No public secrets, wrong media hosts, unscoped instance ids or hard-coded shadow values.
205
205
  - `get_binding_report` for each route is clean, and one value of each bound kind opens the right
206
206
  editor in the Visual Editor.
207
+ - `get_binding_report`'s `help.percent` is 100: every bound field also tells its editor what it
208
+ is for. Binding a leaf makes it editable; help text makes it usable
209
+ ([content-modeling.md](content-modeling.md), "Writing help text").
@@ -87,10 +87,11 @@ Hero / Split
87
87
  Expose variants and style tokens, never raw class names, CSS strings or HTML.
88
88
 
89
89
  **Name props from the code, not the copy.** An import labels a prop by its role (`Text`,
90
- `Heading`) with its copy as help text (`e.g. "49"`), and older imports by the copy itself (`.00`).
90
+ `Heading`) and writes its help from that role, and older imports by the copy itself (`.00`).
91
91
  Read the section's source and use its own names: `pricing.starterKit.cents` → `Cents`,
92
- `billingFrequency` → `Billing frequency`. Give every prop help text showing its shape
93
- (`e.g. "USD / monthly"`). Apply both in one `update_component` call: `propLabel` and
92
+ `billingFrequency` → `Billing frequency`. Where you know more than the role does, write the
93
+ prop's help text: what it is for, where it shows, any limit ("Shown after the price, such as per
94
+ month."), never its label or value again. Apply both in one `update_component` call: `propLabel` and
94
95
  `propHelpText`, keyed by prop key. Repeated cards (plans, features, team members) are ONE `table`
95
96
  prop whose rows are the cards (`Plans`: Name · Description · Price · Cents · Billing frequency ·
96
97
  Features · Button), never a set of props per card, so an editor opens one plan at a time and can
@@ -20,6 +20,9 @@ defaultValue? }`.
20
20
  - `target.blockId` + `target.path` must point at a real block and property inside the
21
21
  component's own `blockJson`. Why: rendering copies each prop's value to that target; a target
22
22
  that does not exist renders the default and the edit goes nowhere.
23
+ - Every prop takes `helpText` and the component a `description` ("Hero with a heading,
24
+ supporting text and two buttons."). Leave them out and the platform writes them; write your
25
+ own by the rules in [content-modeling.md](content-modeling.md) ("Writing help text").
23
26
  - `update_component` replaces the whole `props` array. Read with `get_component`, change, write
24
27
  all props back.
25
28
  - `select` needs `config.options`; `slot` holds one nested component instance; `form` holds one
@@ -193,6 +196,20 @@ A code-built site ships only what its templates draw, whatever the page's `block
193
196
  the page: the anchor carries `data-bcms-button="<key>"` and `get_binding_report` lists no
194
197
  unmatched path for it. The button field is added by that build and starts from the pair's
195
198
  label and link.
199
+ - **Read a published value where the app renders the page** (the fix a publish that fails with
200
+ "Published, but this page's code doesn't read this field yet: `<key>`" names). On a route the
201
+ site's app renders, a stamp (`data-bcms-field`, a `bcmsBindings` entry) only says where a field
202
+ IS; the page shows a publish only when its code READS the value. In code, on a branch:
203
+ 1. Read through the helper the conversion wrote (`bcms`, `bcmsRows`, `bcmsImage`, `bcmsLayout`
204
+ from `src/bcms-content.ts`) or the SDK's `readPublishedContent` / `publishedEntry`. Never read
205
+ a row of `bcms-content.json` by hand, and never bundle the file (`import`, `import.meta.glob`).
206
+ 2. An image the page imports and passes on (`src={heroImage}` beside
207
+ `bcmsBindings={{ image: "<key>" }}`): pass `src={bcmsImage(<page snapshot>, "<key>", heroImage)}`.
208
+ The import stays the fallback; a published image is served from the copy BetterCMS places
209
+ beside the app. `npx @bettercms-ai/convert` makes this edit for every such call site.
210
+ 3. Keep the hard-coded copy as the fallback argument, so a build with no content renders as today.
211
+ 4. Open a pull request. After it is merged and the site rebuilt, publish the field again: the
212
+ toast reads "Live".
196
213
 
197
214
  ## 6. Preview source
198
215
 
@@ -117,12 +117,39 @@ fail, because the next redesign makes them lie.
117
117
 
118
118
  Short labels named for what the editor sees: Heading, Body, Primary button, Label, Link, Image,
119
119
  Alt text — or the name the site's code already uses (`cents` → Cents), never the copy itself
120
- (`.00`). Every field gets help text showing its shape (`e.g. "49"`). Group by what renders
121
- together, not by the DOM or the source file: core content first, optional appearance second, technical fields hidden. Help text states an effect ("Shown below the
122
- heading on this page"). Repeatable items need a meaningful preview label (the FAQ question, the
120
+ (`.00`). Every field gets help text (below). Group by what renders
121
+ together, not by the DOM or the source file: core content first, optional appearance second, technical fields hidden. Repeatable items need a meaningful preview label (the FAQ question, the
123
122
  button label), reorder, and stable item ids. An empty optional field removes its element without
124
123
  leaving a gap; a long value wraps, and clamps only where the design intends it.
125
124
 
125
+ ### Writing help text
126
+
127
+ Every field, prop, component, collection and Global section carries help an editor reads under
128
+ its name: `helpText` on a field or prop, `description` on a component, a collection and a Layout
129
+ Section (`update-section`). Write it the way a Sanity schema writes `description`:
130
+
131
+ - **Purpose, placement, constraint.** What it is for, where it shows, and a limit when one is
132
+ real. One or two sentences, plain words, sentence case.
133
+ - **Never the label or the value again.** `e.g. "Starter Kit"` under an input holding "Starter
134
+ Kit" tells the editor nothing, and the API refuses help that echoes the value. An example may
135
+ follow a real sentence when it shows a format.
136
+
137
+ | Element | Good | Bad |
138
+ |---|---|---|
139
+ | Hero heading | The page's main heading. One per page; keep it under about 60 characters. | Heading |
140
+ | Button label | Text on the button. Two to four words works best. | e.g. "Get started" |
141
+ | Meta description | Shown in search results under the page title. Aim for 120–160 characters. | The meta description. |
142
+ | Logo | Logo shown in the header. An SVG or transparent PNG works best. | Image |
143
+ | Component | Hero with a heading, supporting text, two buttons and an image. | Hero |
144
+
145
+ Leave it out and the platform writes a line from the element's role, and says so
146
+ (`helpText: { source: "auto" }` in the response, `helpSource: "auto"` on the stored field).
147
+ Text you send is stored as yours (`helpSource: "agent"`) and is never rewritten; `editor_setup`
148
+ rewrites only its own lines and never a person's. `get_next_steps` lists anything left without
149
+ help as `help-text-missing`, and `get_binding_report` and `get_site_composition` carry the
150
+ coverage as `help`: under 100% is a finding. Write your own line wherever the generated one
151
+ is generic and you know more: the audience, the tone, who signs off, what breaks the layout.
152
+
126
153
  ## 6. Changing a schema safely
127
154
 
128
155
  A schema write alone is not a release. Before one, read the model with `get_content_model`, a few
@@ -72,7 +72,7 @@ and add the new result. Update the file as each row moves, so a reset loses at m
72
72
  | 0 | Editor setup: `editor_setup { check: true }` reads `ready` for the live build (run `editor_setup` when it does not) | [getting-started.md](getting-started.md) |
73
73
  | 1 | Routing and data shape: page / collection / entry classification and folders; keep public URLs | [content-modeling.md](content-modeling.md) |
74
74
  | 2 | Sections and reuse: every band a section; dedupe compatible patterns into variants and overrides; nav and footer as globals (`get_componentize_plan`, `componentize_sections` on a components project) | [components.md](components.md), [componentize.md](componentize.md) |
75
- | 3 | Editor contract: field types, labels, validation, Portable Text accept lists, nested groups | [portable-text.md](portable-text.md) |
75
+ | 3 | Editor contract: field types, labels, help text on every element (`get_next_steps` shows no `help-text-missing`), validation, Portable Text accept lists, nested groups | [portable-text.md](portable-text.md) |
76
76
  | 4 | Design: media, logo roles, fonts and brand tokens, without changing visual intent | [media-and-brand.md](media-and-brand.md) |
77
77
  | 5 | Bindings: the site reads BetterCMS data and each intended leaf or attribute is bound; build, preview and runtime agree | [bindings.md](bindings.md), [frameworks.md](frameworks.md) |
78
78
  | 6 | Behaviour: forms, links, menus, accordions, modals, consent, custom code | [forms-and-interactions.md](forms-and-interactions.md) |
@@ -127,6 +127,13 @@ generated reader. A build that fetches the snapshot and never reads it still ren
127
127
  hard-coded copy, so every edit saves, publishes and changes nothing on the page. Grep the source
128
128
  for a reader before calling a site wired.
129
129
 
130
+ Read it through one of those, the converted-site helper (`bcms`, `bcmsRows`, `bcmsImage`) or
131
+ `publishedEntry(slug)`. Never hand-write a parser of the file: each row holds its field values
132
+ under `data` (`row.data.title`), so code that reads `row.title` gets `undefined` and renders its
133
+ fallback on every publish. An editable image is `bcmsImage(page, path, importedImage)`: the bare
134
+ import with only a stamp never shows a published image on a route the app renders. An old
135
+ `src/utils/bcms.ts` with `pageEntry()` is that parser: replace its reads with `publishedEntry`.
136
+
130
137
  Build with the repo's own `build` script (`pnpm build`, `bun run build`), never the framework CLI
131
138
  directly: a repo's script often adds a type check or a post-process step the CLI skips.
132
139
 
@@ -82,6 +82,9 @@ Rules:
82
82
  a live fetch would turn pages into dynamic routes, and a static export silently leaves them out
83
83
  of `out/`.
84
84
  - A preview build that must read live sets `BETTERCMS_PREVIEW=1`.
85
+ - On a BetterCMS build the platform's own `bcms-content.json` is already in the project root.
86
+ `bettercms-snapshot` keeps it and `getContent` reads it: one file feeds `getContent`, `readPages`,
87
+ `readForms` and `readComponents`.
85
88
  - Draft mode and the revalidation route need a server; a static export has neither. Content
86
89
  changes reach a static site only by rebuilding it.
87
90
 
@@ -17,7 +17,7 @@ each report was generated:
17
17
 
18
18
  | Read | Tells you |
19
19
  |---|---|
20
- | `get_site_composition` | Which pages are made of sections, and which components they use |
20
+ | `get_site_composition` | Which pages are made of sections, and which components they use; `help`: how much of the schema carries help text, and what does not (under 100% is a finding) |
21
21
  | `get_binding_report` | Per route: `mode` (`declared` or `text-match`), `coverage.pending`, and `refreshReason` when there is no current report |
22
22
  | `list_seo_issues` | Native SEO problems per page |
23
23
  | `get_component_readiness` | Per component: validation and Output state |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bettercms-ai/mcp",
3
- "version": "0.67.3",
3
+ "version": "0.68.1",
4
4
  "type": "module",
5
5
  "description": "BetterCMS MCP server — schema, content, forms + components authoring tools over the Management API, authed via OAuth device-code.",
6
6
  "bin": {
@@ -32,7 +32,7 @@
32
32
  },
33
33
  "dependencies": {
34
34
  "@bettercms-ai/device-auth": "^0.2.0",
35
- "@bettercms-ai/sdk": "^1.26.2",
35
+ "@bettercms-ai/sdk": "^1.26.3",
36
36
  "@modelcontextprotocol/sdk": "^1.30.0",
37
37
  "zod": "^4.3.6"
38
38
  },