@bettercms-ai/mcp 0.80.1 → 0.81.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.
- package/dist/index.js +100 -11
- package/dist/index.js.map +1 -1
- package/dist/skills/bettercms/references/integrations.md +189 -4
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2915,6 +2915,11 @@ var LISTING_TAIL = /* @__PURE__ */ new Set([
|
|
|
2915
2915
|
"delete_integration",
|
|
2916
2916
|
"test_integration_fetch",
|
|
2917
2917
|
"run_integration_sync",
|
|
2918
|
+
"run_integration_function",
|
|
2919
|
+
"search_integration_reference",
|
|
2920
|
+
"start_integration_signin",
|
|
2921
|
+
"save_integration_template",
|
|
2922
|
+
"install_integration_template",
|
|
2918
2923
|
// The ABM campaign lane — also hidden from the default listing (ABM_TOOLS below).
|
|
2919
2924
|
"research_account",
|
|
2920
2925
|
"build_abm_page",
|
|
@@ -2999,12 +3004,17 @@ var NEW_TOOL_TEXT = {
|
|
|
2999
3004
|
editor_setup: "Make the live build editable: derives pages, collections, forms, bindings and components from the live release (skill bindings). Run it after an import or a rebuild, before the conversion brief. Idempotent: `ready` when it already ran for the live sha, else it starts (`running`; poll with `check: true`). `state`: never or stale (run it), running, ready, failed. 409 = nothing is live yet: deploy first. Then get_next_steps.",
|
|
3000
3005
|
transform_image: "Edit an existing Media Library image with an instruction (e.g. 'remove the background', 'make it dusk'); the result is saved as a NEW asset and the original is kept (5 AI credits). Returns the new asset (id, url, altText).",
|
|
3001
3006
|
write_alt_text: "Alt text for a Media Library image (mediaId) or an https image URL (url), written from its pixels (1 AI credit). A suggestion: save it with update_media.",
|
|
3002
|
-
list_integrations: "List the project's custom integrations (any vendor with a public API
|
|
3003
|
-
get_integration: "One integration (`integration`: id or slug)
|
|
3004
|
-
create_integration: "Declare a custom integration
|
|
3005
|
-
update_integration: "Change an integration (`integration`: id or slug); keys
|
|
3007
|
+
list_integrations: "List the project's custom integrations (any vendor with a public API) and the workspace's integration `templates`. Each has its hosts, secret NAMES with `secretsPresent` (never a value), syncs, hooks, endpoints, functions and `approved`. Read bettercms://skill/integrations first.",
|
|
3008
|
+
get_integration: "One integration (`integration`: id or slug): `hookUrls`, `endpointUrls`, `oauthStatus`, its last sync runs, write-backs (`pushes`), function runs, webhook deliveries and vendor calls (the call log).",
|
|
3009
|
+
create_integration: "Declare a custom integration. Shapes: bettercms://skill/integrations. Secret VALUES never pass through here (the user sets env vars; list_env_vars shows names). Until an admin approves it, every vendor call, sync, webhook, endpoint and function is refused: give the user `approval.approveUrl` and `approval.changes` in plain words. You cannot approve it.",
|
|
3010
|
+
update_integration: "Change an integration (`integration`: id or slug); parameters as create_integration, keys left out are kept, lists replace the stored ones whole. A change to hosts, secrets, inject, allowPost, auth, oauth, hooks, endpoints, references or functions withdraws its approval (`approval.approveUrl`); name, syncs, settings and panel never need it.",
|
|
3006
3011
|
delete_integration: "Delete an integration and its sync runs. Entries it synced stay (their provenance still names it); the env vars stay.",
|
|
3007
3012
|
run_integration_sync: "Run one of an integration's syncs now (`integration`, `sync`: its key): every page of the vendor list is fetched and each item is created or updated as a DRAFT entry, matched on its externalKey, so a re-run only changes what changed (`unchanged` counts the rest); `publish: true` on the sync publishes what changed. Answers with the run: queued, running, done (counts: created, updated, unchanged, failed, pages, items) or failed (error). `waitSeconds` (\u2264 20) waits for it to finish; else follow it with get_integration. A sync with `schedule` 'hourly' or 'daily' also runs on its own.",
|
|
3013
|
+
run_integration_function: "Run an integration's function (bettercms/functions/<name>.ts, trigger 'manual') with `input`. Its fetch() reaches only the integration's approved hosts and the server adds the secrets: the code never sees them. `waitSeconds` (\u2264 20) answers with output, logs or error.",
|
|
3014
|
+
search_integration_reference: "Search an integration's live reference (`reference`: its key) at the vendor: up to 20 {id, title, image}. Store the pick in a json field (skill \xA712); the site resolves it live.",
|
|
3015
|
+
start_integration_signin: "Start the vendor sign-in of an integration with `oauth`: a `url` the USER opens to sign in with their own OAuth app (register `redirectUri` in it first). Tokens stay on the server.",
|
|
3016
|
+
save_integration_template: "Save an integration as a workspace template: its shape, never a secret value or its settings, with copies of the collections its syncs write into.",
|
|
3017
|
+
install_integration_template: "Install a workspace template on this project: missing collections are created and the integration waits for approval (`approval.approveUrl`); `secretsNeeded` lists the env vars to set.",
|
|
3008
3018
|
test_integration_fetch: "Call the vendor once through the server, as the integration: an approved host only, with the integration's `inject` secrets added server-side and every secret redacted from the answer. The request itself takes no {{...}} templates, and the token endpoint cannot be called. Use it to read the response shape before writing a sync: `items`, `externalKey` and `map` are JSON Pointers into it. Bodies over 1 MB come back truncated. 409 integration_not_approved: an admin must approve it first."
|
|
3009
3019
|
};
|
|
3010
3020
|
var DELETE_PAGE_RUNTIME_BUNDLE = " Or, with no pageId, `runtimeBundle`: 'report' lists the duplicate pages derived from a server app's own bundle (`app/` folders); 'apply' retires them and their empty folders.";
|
|
@@ -3063,9 +3073,17 @@ var INTEGRATION_PARAM_TEXT = {
|
|
|
3063
3073
|
secrets: "template name (UPPER_SNAKE) -> project env var KEY, e.g. {TOKEN: 'SHOPIFY_ADMIN_TOKEN'}; never a value",
|
|
3064
3074
|
inject: "where the secrets go on every vendor request: {headers?: {name: template}, query?: {name: template}}, templates {{secret.NAME}} or {{token}}",
|
|
3065
3075
|
allowPost: "true lets requests other than GET through (vendor writes, POST search APIs such as Apollo's); GET only when omitted",
|
|
3066
|
-
auth: "optional token exchange
|
|
3076
|
+
auth: "optional token exchange (skill \xA75); its result is {{token}}",
|
|
3067
3077
|
settings: "non-secret JSON the panel reads and writes (store id, toggles); at most 16 KB",
|
|
3068
|
-
syncs: "[{key, contentModelId, request
|
|
3078
|
+
syncs: "vendor list -> collection [{key, contentModelId, request, items, externalKey, map, item?, writeBack?, publish?, schedule?}] (skill \xA76; two-way \xA715)",
|
|
3079
|
+
hooks: "vendor webhooks [{key, verify, action}] (skill \xA79); the vendor posts to `hookUrls`",
|
|
3080
|
+
endpoints: "public reads for the site [{key, request, params, pick, cacheSeconds?}] (skill \xA711); at `endpointUrls`",
|
|
3081
|
+
references: "live references [{key, label, search, lookup, items, id, title}] (skill \xA712)",
|
|
3082
|
+
functions: "[{name, triggers?, cpuMs?}]: bettercms/functions/<name>.ts (skill \xA710)",
|
|
3083
|
+
oauth: "sign-in with the customer's own OAuth app {authorizeUrl, tokenUrl, scopes, clientId, clientSecret} (secret NAMES; skill \xA713)",
|
|
3084
|
+
alertAfter: "tell admins after this many failed runs in a row (0 = never; 3 when omitted)",
|
|
3085
|
+
reference: "the reference's key (from the integration's references)",
|
|
3086
|
+
template: "the template's slug (from list_integrations `templates`)",
|
|
3069
3087
|
panel: "the custom panel's slug: bettercms/panels/<panel>.tsx in the site repo; null for the stock page",
|
|
3070
3088
|
url: "the full https URL on an allowed host (no templates in the URL)",
|
|
3071
3089
|
sync: "the sync's key (from the integration's syncs)",
|
|
@@ -3359,6 +3377,7 @@ var uiObject = z.strictObject({
|
|
|
3359
3377
|
placeholder: z.string().min(1).max(120).optional().describe("ghost text, a field of any type. A prop uses its own `placeholder`."),
|
|
3360
3378
|
synced: z.strictObject({ from: z.string().min(1).max(64) }).optional().describe("the value comes from this global; edits apply everywhere."),
|
|
3361
3379
|
valueShape: z.enum(["string", "object"]).optional().describe("a link / image / button writes a plain string or the object."),
|
|
3380
|
+
reference: z.object({ integration: z.string(), key: z.string() }).strict().optional().describe("a json field holding a live vendor item: the integration's slug and reference key."),
|
|
3362
3381
|
access: z.strictObject({ view: z.literal("schema.view").optional(), edit: z.literal("schema.manage").optional() }).optional().describe("who sees (view: developer-only) and who changes (edit) it, gated in the editor. The enforced lock is readOnly:'developer'."),
|
|
3363
3382
|
hidden: z.boolean().optional().describe("true: never shown in the form (a system value). A conditional hide is showIf."),
|
|
3364
3383
|
blocks: z.record(z.string(), z.strictObject({ icon: dockIconArg.optional(), preview: z.record(z.string(), z.string()).optional() })).optional().describe("modular only: per block slug, {icon?, preview?} for its rows."),
|
|
@@ -3551,8 +3570,17 @@ var integrationShape = {
|
|
|
3551
3570
|
auth: z.record(z.string(), z.unknown()).nullable().optional().describe(INTEGRATION_PARAM_TEXT.auth),
|
|
3552
3571
|
settings: z.record(z.string(), z.unknown()).optional().describe(INTEGRATION_PARAM_TEXT.settings),
|
|
3553
3572
|
syncs: z.array(z.record(z.string(), z.unknown())).max(20).optional().describe(INTEGRATION_PARAM_TEXT.syncs),
|
|
3554
|
-
panel: z.string().max(48).nullable().optional().describe(INTEGRATION_PARAM_TEXT.panel)
|
|
3573
|
+
panel: z.string().max(48).nullable().optional().describe(INTEGRATION_PARAM_TEXT.panel),
|
|
3574
|
+
hooks: z.array(z.record(z.string(), z.unknown())).max(20).optional().describe(INTEGRATION_PARAM_TEXT.hooks),
|
|
3575
|
+
endpoints: z.array(z.record(z.string(), z.unknown())).max(20).optional().describe(INTEGRATION_PARAM_TEXT.endpoints),
|
|
3576
|
+
references: z.array(z.record(z.string(), z.unknown())).max(10).optional().describe(INTEGRATION_PARAM_TEXT.references),
|
|
3577
|
+
functions: z.array(z.record(z.string(), z.unknown())).max(20).optional().describe(INTEGRATION_PARAM_TEXT.functions),
|
|
3578
|
+
oauth: z.record(z.string(), z.unknown()).nullable().optional().describe(INTEGRATION_PARAM_TEXT.oauth),
|
|
3579
|
+
alertAfter: z.number().int().min(0).max(50).optional().describe(INTEGRATION_PARAM_TEXT.alertAfter)
|
|
3555
3580
|
};
|
|
3581
|
+
var integrationShapeBare = Object.fromEntries(
|
|
3582
|
+
Object.entries(integrationShape).map(([k, v]) => [k, v.describe(void 0)])
|
|
3583
|
+
);
|
|
3556
3584
|
var DRY_RUN_SUMMARY = "Dry run: nothing was written.";
|
|
3557
3585
|
var dryRunOf = async (client, method, path, body, headers = {}) => ok(DRY_RUN_SUMMARY, await client.fetchJSON(client.url(path), { method, body: JSON.stringify({ ...body, dryRun: true }), ...withHeaders(headers) }));
|
|
3558
3586
|
function toField(f) {
|
|
@@ -5227,7 +5255,8 @@ ${d.outline}` : "Proposed Content structure.", d);
|
|
|
5227
5255
|
"List custom integrations",
|
|
5228
5256
|
NEW_TOOL_TEXT.list_integrations,
|
|
5229
5257
|
z.object({}).shape,
|
|
5230
|
-
|
|
5258
|
+
// The whole body: the workspace's `templates` ride beside `data`.
|
|
5259
|
+
async (c) => ok("Integrations.", await c.fetchJSON(c.url(`/management/integrations`), { method: "GET" }))
|
|
5231
5260
|
),
|
|
5232
5261
|
def(
|
|
5233
5262
|
"get_integration",
|
|
@@ -5255,9 +5284,9 @@ ${d.outline}` : "Proposed Content structure.", d);
|
|
|
5255
5284
|
NEW_TOOL_TEXT.update_integration,
|
|
5256
5285
|
z.object({
|
|
5257
5286
|
integration: z.string().min(1).describe(INTEGRATION_PARAM_TEXT.integration),
|
|
5258
|
-
name: z.string().min(1).max(120).optional()
|
|
5259
|
-
vendor: z.string().max(60).nullable().optional()
|
|
5260
|
-
...
|
|
5287
|
+
name: z.string().min(1).max(120).optional(),
|
|
5288
|
+
vendor: z.string().max(60).nullable().optional(),
|
|
5289
|
+
...integrationShapeBare
|
|
5261
5290
|
}).shape,
|
|
5262
5291
|
async (c, a) => {
|
|
5263
5292
|
const { integration, ...body } = a;
|
|
@@ -5282,6 +5311,66 @@ ${d.outline}` : "Proposed Content structure.", d);
|
|
|
5282
5311
|
}).shape,
|
|
5283
5312
|
async (c, a) => ok("Sync run.", await data(c, "POST", withWait(`/management/integrations/${s(a.integration)}/syncs/${s(a.sync)}/run`, a.waitSeconds)))
|
|
5284
5313
|
),
|
|
5314
|
+
def(
|
|
5315
|
+
"run_integration_function",
|
|
5316
|
+
"Run an integration's function",
|
|
5317
|
+
NEW_TOOL_TEXT.run_integration_function,
|
|
5318
|
+
z.object({
|
|
5319
|
+
integration: z.string().min(1).describe(INTEGRATION_PARAM_TEXT.integration),
|
|
5320
|
+
name: z.string().min(1).describe("the function's name"),
|
|
5321
|
+
input: z.unknown().optional().describe("the function's `event` (JSON)"),
|
|
5322
|
+
waitSeconds: z.number().min(0).max(50).optional().describe(PARAM_TEXT.waitSeconds)
|
|
5323
|
+
}).shape,
|
|
5324
|
+
async (c, a) => ok("Function run.", await data(c, "POST", withWait(`/management/integrations/${s(a.integration)}/functions/${s(a.name)}/run`, a.waitSeconds), { input: a.input }))
|
|
5325
|
+
),
|
|
5326
|
+
def(
|
|
5327
|
+
"search_integration_reference",
|
|
5328
|
+
"Search an integration's live reference",
|
|
5329
|
+
NEW_TOOL_TEXT.search_integration_reference,
|
|
5330
|
+
z.object({
|
|
5331
|
+
integration: z.string().min(1).describe(INTEGRATION_PARAM_TEXT.integration),
|
|
5332
|
+
reference: z.string().min(1).describe(INTEGRATION_PARAM_TEXT.reference),
|
|
5333
|
+
query: z.string().max(200).optional().describe("what to search for")
|
|
5334
|
+
}).shape,
|
|
5335
|
+
async (c, a) => ok("Vendor items.", await data(c, "POST", `/management/integrations/${s(a.integration)}/references/${s(a.reference)}/search`, { query: a.query ?? "" }))
|
|
5336
|
+
),
|
|
5337
|
+
def(
|
|
5338
|
+
"start_integration_signin",
|
|
5339
|
+
"Start an integration's vendor sign-in",
|
|
5340
|
+
NEW_TOOL_TEXT.start_integration_signin,
|
|
5341
|
+
z.object({ integration: z.string().min(1).describe(INTEGRATION_PARAM_TEXT.integration) }).shape,
|
|
5342
|
+
async (c, a) => ok("Sign-in URL: give it to the user to open.", await data(c, "POST", `/management/integrations/${s(a.integration)}/oauth/start`))
|
|
5343
|
+
),
|
|
5344
|
+
def(
|
|
5345
|
+
"save_integration_template",
|
|
5346
|
+
"Save an integration as a template",
|
|
5347
|
+
NEW_TOOL_TEXT.save_integration_template,
|
|
5348
|
+
z.object({
|
|
5349
|
+
integration: z.string().min(1).describe(INTEGRATION_PARAM_TEXT.integration),
|
|
5350
|
+
slug: z.string().min(1).max(48).optional().describe(INTEGRATION_PARAM_TEXT.slug),
|
|
5351
|
+
name: z.string().min(1).max(120).optional().describe("a label, 1-120 chars"),
|
|
5352
|
+
description: z.string().max(500).optional().describe("what it connects, for the people installing it")
|
|
5353
|
+
}).shape,
|
|
5354
|
+
async (c, a) => {
|
|
5355
|
+
const { integration, ...body } = a;
|
|
5356
|
+
return ok("Template saved.", await data(c, "POST", `/management/integrations/${s(integration)}/template`, body));
|
|
5357
|
+
}
|
|
5358
|
+
),
|
|
5359
|
+
def(
|
|
5360
|
+
"install_integration_template",
|
|
5361
|
+
"Install an integration template",
|
|
5362
|
+
NEW_TOOL_TEXT.install_integration_template,
|
|
5363
|
+
z.object({
|
|
5364
|
+
template: z.string().min(1).describe(INTEGRATION_PARAM_TEXT.template),
|
|
5365
|
+
slug: z.string().min(1).max(48).optional().describe(INTEGRATION_PARAM_TEXT.slug),
|
|
5366
|
+
name: z.string().min(1).max(120).optional().describe("a label, 1-120 chars")
|
|
5367
|
+
}).shape,
|
|
5368
|
+
// The whole body: `approval`, `secretsNeeded` and `collectionsCreated` ride beside `data`.
|
|
5369
|
+
async (c, a) => {
|
|
5370
|
+
const { template, ...body } = a;
|
|
5371
|
+
return ok("Template installed.", await c.fetchJSON(c.url(`/management/integrations/templates/${s(template)}/install`), { method: "POST", body: JSON.stringify(body) }));
|
|
5372
|
+
}
|
|
5373
|
+
),
|
|
5285
5374
|
def(
|
|
5286
5375
|
"test_integration_fetch",
|
|
5287
5376
|
"Call a vendor through an integration",
|