@bettercms-ai/mcp 0.56.4 → 0.57.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.
package/dist/index.js CHANGED
@@ -2000,6 +2000,8 @@ import { DeviceAuthPendingError } from "@bettercms-ai/device-auth";
2000
2000
  var STRUCTURE_PLAYBOOK_URI = "bettercms://playbook/structure";
2001
2001
  var STRUCTURE_DEFAULT_INSTRUCTION = `After you create collections or pages, organise them per the structure playbook: read ${STRUCTURE_PLAYBOOK_URI}, call suggest_content_structure (read-only), show the user its outline, then apply it with set_content_structure and the version it returned (the If-Match). A project that already has a structure keeps it: file only what you created, with move_to_folder, unless the user asks for a full re-organisation.`;
2002
2002
  var SKILLS_ROUTING_INSTRUCTION = "Before writing code in a repo that uses BetterCMS, explore the repo, then read the installed `bettercms` skill (`npx @bettercms-ai/install --project -y` adds it if missing): its table turns what you found into the one reference the task needs \u2014 read only that.";
2003
+ var RECEIPT_FIRST_INSTRUCTION = "Start every project with get_next_steps: its `receipt` lists what is already done (`done`), what is still missing (`missing`, each item citing the count it reacted to) and the one `nextAction`. Work from that receipt instead of re-reading the site, call get_next_steps again after each batch of edits, and before you tell the user you are finished. Fix what it lists, or say why you are leaving it.";
2004
+ var NEXT_STEPS_DESCRIPTION = `Call this FIRST on a project. Returns \`receipt\` \u2014 \`done\` (what the platform already sees as finished: live release, bound elements, conversion coverage, pages composed from components, published components and Layout), \`missing\` and \`nextAction\` \u2014 plus \`data\`, the unfinished items: pages without a meta description, drafts never published, collections with no entries, forms nobody is notified about, writes waiting for human approval, bindings or sections the build has not stamped. Each item cites the count it reacted to. Call it again AFTER a batch of edits to catch what you left behind, and before telling the user you are done. When it lists \`organise-content\`, the project's pages and collections are in no folder: read ${STRUCTURE_PLAYBOOK_URI}, call suggest_content_structure and apply it with set_content_structure once the user agrees.`;
2003
2005
  var STRUCTURE_EXAMPLE_PAYLOAD = {
2004
2006
  version: 0,
2005
2007
  doc: {
@@ -2449,6 +2451,11 @@ var GIT_TEXT = {
2449
2451
  create_github_pull_request: "Open a pull request on the connected repository. `head` is the branch you pushed; `base` defaults to the build branch, so merging it is what ships the change. Use this instead of pushing straight to the build branch whenever a human should review first, or when that branch is protected. Returns the number and the url to hand the user.",
2450
2452
  list_github_pull_requests: "Pull requests on the connected repository: number, title, state, whether it merged, draft, head, base and url. `state` is 'open' (the default), 'closed' or 'all'. Poll it to find out whether the pull request you opened has landed."
2451
2453
  };
2454
+ var HOSTING_TEXT = {
2455
+ list_hosting_connections: "The Vercel, Netlify and Cloudflare accounts connected to this workspace (id, provider, accountLabel, status; never a token), plus `connectUrl`, the dashboard page where a person connects one. Call it before deploy_to_host. If the provider the user wants has no connection with status `ok`, give the user `connectUrl` to connect it in their browser and stop until they have: you never handle OAuth or a host token yourself.",
2456
+ deploy_to_host: "Deploy this project to the user's own Vercel or Netlify account through their connection. BetterCMS builds the site and the host serves that build, so there is no host CLI to run, no token to paste and no vercel.json rewrite to write; forms keep working because they post to the BetterCMS API. The first call creates the site on the host and makes it the project's host; a later call for the same provider redeploys that site (`redeployed: true`) instead of creating another. `connectionId` (from list_hosting_connections) defaults to the newest working one, `siteName` to the project's handle. A refusal carries a `code` and a `fixUrl` (not_connected, reconnect, pick_existing_site, grant_required, ADMIN_REQUIRED): each is fixed by the user at `fixUrl`, so relay it and stop. `deploymentQueued: false` means the project has no live build yet: deploy_project first, and that release reaches the host on its own. Never run the Vercel or Netlify CLI while a connection exists. Then poll get_host_deploy_status. Needs artifact:write, like deploy_project.",
2457
+ get_host_deploy_status: "The connected project's recent deployments to Vercel, Netlify or Cloudflare, newest first: state (queued|deploying|live|failed), providerUrl, error, sha and targetName. Poll it after deploy_to_host until the newest one is `live`, whose `providerUrl` is the live URL to hand the user, or `failed`, whose `error` you read back to them."
2458
+ };
2452
2459
  function ok(summary, data) {
2453
2460
  return {
2454
2461
  content: [
@@ -2511,7 +2518,10 @@ function refusalDetail(err) {
2511
2518
  const lines = [
2512
2519
  code ? `code: ${code}` : "",
2513
2520
  body.readiness !== void 0 ? `readiness: ${JSON.stringify(body.readiness)}` : "",
2514
- body.issues !== void 0 ? `issues: ${JSON.stringify(body.issues)}` : ""
2521
+ body.issues !== void 0 ? `issues: ${JSON.stringify(body.issues)}` : "",
2522
+ // The link a person follows to fix it (connect a host, create a Vercel project): an agent
2523
+ // that only sees the sentence has nothing to hand the user.
2524
+ typeof body.fixUrl === "string" ? `fixUrl: ${body.fixUrl}` : ""
2515
2525
  ].filter(Boolean);
2516
2526
  return lines.length ? `
2517
2527
  ${lines.join("\n")}` : "";
@@ -3779,9 +3789,10 @@ ${res.warnings.join("\n")}` : summary, res.data);
3779
3789
  def(
3780
3790
  "get_next_steps",
3781
3791
  "Get what to do next",
3782
- `What is still unfinished in the connected project, as the platform sees it \u2014 pages you created without a meta description, drafts never published, collections with no entries, forms nobody is notified about, writes waiting for human approval. Each item cites the count it reacted to. Call it AFTER a batch of edits to catch what you left behind, and before telling the user you are done. When it lists \`organise-content\`, the project's pages and collections are in no folder: read ${STRUCTURE_PLAYBOOK_URI}, call suggest_content_structure and apply it with set_content_structure once the user agrees.`,
3792
+ NEXT_STEPS_DESCRIPTION,
3783
3793
  z.object({}).shape,
3784
- async (c) => ok("Next steps.", await data(c, "GET", `/management/insights/next-steps`))
3794
+ // The whole body: `receipt` rides beside `data`, and `data()` would drop it.
3795
+ async (c) => ok("Next steps.", await c.fetchJSON(c.url(`/management/insights/next-steps`), { method: "GET" }))
3785
3796
  ),
3786
3797
  def(
3787
3798
  "get_binding_report",
@@ -4149,6 +4160,34 @@ ${res.warnings.join("\n")}` : summary, res.data);
4149
4160
  "Get the connected project's deploy/build status: state (idle|queued|building|categorizing|failed), whether it's publishing, the live commit sha, when it went live, and any build error. `categorizing` means the bytes are live but the import's setup lanes (content, pages, bindings) are still running, so `publishing` is still true and the site is not ready to edit yet. Poll this after deploy_project until state is idle with your sha live. Also returns `canvas.lane` (the editor's live-preview lane for this site: `bridge` / `draft-route` / `none`) and `editorUrl`, the visual editor to hand the user.",
4150
4161
  z.object({}).shape,
4151
4162
  async (c) => ok("Deploy status.", await data(c, "GET", `/management/projects/deploy-status`))
4163
+ ),
4164
+ // ── Deploy to the user's own host (parity with remote /mcp) ──
4165
+ // A person connects Vercel or Netlify in the dashboard; nothing here touches OAuth or a host
4166
+ // token. deploy_to_host takes artifact:write like deploy_project. @see management/deploy-targets.ts
4167
+ def(
4168
+ "list_hosting_connections",
4169
+ "List hosting connections",
4170
+ HOSTING_TEXT.list_hosting_connections,
4171
+ z.object({}).shape,
4172
+ async (c) => ok("Hosting connections.", await data(c, "GET", `/management/hosting/connections`))
4173
+ ),
4174
+ def(
4175
+ "deploy_to_host",
4176
+ "Deploy to Vercel or Netlify",
4177
+ HOSTING_TEXT.deploy_to_host,
4178
+ z.object({
4179
+ provider: z.enum(["vercel", "netlify"]),
4180
+ connectionId: z.string().min(1).optional().describe("a connection id from list_hosting_connections; defaults to the newest working one"),
4181
+ siteName: z.string().min(1).max(63).optional().describe("lowercase letters, numbers and hyphens; defaults to the project's handle")
4182
+ }).shape,
4183
+ async (c, a) => ok("Host deploy.", await data(c, "POST", `/management/deploy-targets/provision`, { provider: a.provider, connectionId: a.connectionId, siteName: a.siteName }))
4184
+ ),
4185
+ def(
4186
+ "get_host_deploy_status",
4187
+ "Get host deploy status",
4188
+ HOSTING_TEXT.get_host_deploy_status,
4189
+ z.object({}).shape,
4190
+ async (c) => ok("Host deployments.", await data(c, "GET", `/management/hosting/external-deployments`))
4152
4191
  )
4153
4192
  ];
4154
4193
  }
@@ -5933,12 +5972,12 @@ Do not stop at the plan or at a partial receipt \u2014 finish the whole site, ne
5933
5972
  with no \`fix\` is still yours. Then rerun step 4 until \`paths.pending\` is EMPTY.
5934
5973
  6. \`npx @bettercms-ai/convert --verify-styles --base <commit before step 4>\`, restore what it lists, then
5935
5974
  \`submit_conversion_receipt { briefDigest, receipt }\` with its \`styleEdits\`: only \`complete: true\` ends it (else step 5).
5936
- 7. Deploy (push, or \`deploy_project\`) and poll \`get_deploy_status\` until the release is live.
5937
- 8. \`get_binding_report\` must read \`unmatched\` 0 and \`unaddressable\` under 2% of each route's
5938
- visible text. Fix what it names in the SOURCE, deploy, re-read (playbook section 11).
5939
- 9. \`set_binding_mode { declaredBindings: true }\`, deploy AGAIN and poll \u2014 the mode applies to the
5940
- NEXT release \u2014 then confirm \`get_binding_report\` reads mode "declared", unmatched 0, bound
5941
- above 0, \`coverage.pending\` empty. That report is your final answer to me.`;
5975
+ 7. Deploy the working tree (\`create_deploy_upload\` + \`deploy_from_upload\`); poll \`get_deploy_status\` until live. No git yet.
5976
+ 8. \`get_binding_report\`: \`unmatched\` 0, \`unaddressable\` under 2% per route; fix the SOURCE, deploy, re-read (playbook \xA711).
5977
+ 9. \`set_binding_mode { declaredBindings: true }\`, deploy AGAIN and poll, then confirm \`get_binding_report\`
5978
+ reads mode "declared", unmatched 0, bound above 0, \`coverage.pending\` empty. Send me that report.
5979
+ 10. Ask me whether to commit and push to my repository, commit only, or leave it uncommitted (unpushed, the
5980
+ next rebuild from my repo drops it). Touch git only as I answer.`;
5942
5981
  var SCHEMA_PROPOSAL_FLOW = `### Whole-project design (confirm-first) \u2192 \`create_component\` / \`create_page\` / \`create_content_model\`
5943
5982
  Design the WHOLE project from its brief or its code, and **confirm the shape with the user
5944
5983
  BEFORE creating anything**. Never silently guess.
@@ -6603,7 +6642,7 @@ function buildServer(deps) {
6603
6642
  // 🔴 The plain-language ask, routed — the stdio twin of the hosted connector's line
6604
6643
  // (src/routes/mcp/index.ts MCP_INSTRUCTIONS). "Make my site editable" has one recipe and
6605
6644
  // one definition of done; without this an agent converts the page it landed on and stops.
6606
- instructions: "When the user asks to make a site or all of its pages editable, to convert it, or to bind its fields: this is playbook \xA713. Read `bettercms://playbook/schema` \xA713, call get_binding_report and get_conversion_brief { complete: true }, convert EVERY route the brief lists, and finish only when get_binding_report shows coverage.pending empty on every route \u2014 not when the first page works. On a workspace-wide connection pass projectId on every call; never ask the user to re-scope the connection. When the user asks to componentize the whole site, to turn every section into a component, or to build a component library from the site: this is playbook \xA712. Read `bettercms://playbook/schema` \xA712, start with get_site_composition, and use the batch tools \u2014 create_components, compose_pages, update_layout with `commands`, publish_components \u2014 rather than one call per component. Finish with get_site_composition and tell the user what the platform does not model (cookie banners, modals, breadcrumbs, pagination) and which components still need the owner's approval in the dashboard before they can be published. BetterCMS never executes a customer's Section renderer or app code. An ordinary MCP connection is not a push runner: explicitly poll list_section_validation_requests, claim one request at an exact git commit, run implementation and responsive checks inside the user's own repository and real app shell, then submit manifest + validation with that requestId and complete it\u2014or truthfully fail it when implementation/evidence is missing. Never invent a manifest, a passing validation, or visual evidence; these tools cannot grant the separate human Visual Approval required for publication. " + // The default after authoring (the structure standard): organise what you made. Same
6645
+ instructions: RECEIPT_FIRST_INSTRUCTION + " When the user asks to make a site or all of its pages editable, to convert it, or to bind its fields: this is playbook \xA713. Read `bettercms://playbook/schema` \xA713, call get_binding_report and get_conversion_brief { complete: true }, convert EVERY route the brief lists, and finish only when get_binding_report shows coverage.pending empty on every route \u2014 not when the first page works. On a workspace-wide connection pass projectId on every call; never ask the user to re-scope the connection. When the user asks to componentize the whole site, to turn every section into a component, or to build a component library from the site: this is playbook \xA712. Read `bettercms://playbook/schema` \xA712, start with get_site_composition, and use the batch tools \u2014 create_components, compose_pages, update_layout with `commands`, publish_components \u2014 rather than one call per component. Finish with get_site_composition and tell the user what the platform does not model (cookie banners, modals, breadcrumbs, pagination) and which components still need the owner's approval in the dashboard before they can be published. BetterCMS never executes a customer's Section renderer or app code. An ordinary MCP connection is not a push runner: explicitly poll list_section_validation_requests, claim one request at an exact git commit, run implementation and responsive checks inside the user's own repository and real app shell, then submit manifest + validation with that requestId and complete it\u2014or truthfully fail it when implementation/evidence is missing. Never invent a manifest, a passing validation, or visual evidence; these tools cannot grant the separate human Visual Approval required for publication. " + // The default after authoring (the structure standard): organise what you made. Same
6607
6646
  // sentence as the hosted connector's MCP_INSTRUCTIONS.
6608
6647
  STRUCTURE_DEFAULT_INSTRUCTION + " " + SKILLS_ROUTING_INSTRUCTION
6609
6648
  }