@mapled/mcp 0.10.0 → 0.12.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/README.md CHANGED
@@ -64,9 +64,9 @@ For the first integration, propose one plan and let the owner approve it on a tr
64
64
  | `list_records` | Read a collection's draft records, newest edit first — `query` searches their content, `limit` (1–200) and `cursor` (the previous answer's `nextCursor`) page through them; `total` counts every match |
65
65
  | `create_form` / `list_forms` | Set up public forms with spam protection |
66
66
  | `get_connection` (image values → `assetUrl(id, { width })` from @mapled/next) | Delivery key + API URL for wiring the site (`@mapled/next`) |
67
- | `push_site_manifest` / `list_bindings` | Tell Mapled where each field is rendered; read every binding's health (type mismatch, outdated, missing on site). Keep the repository's copy in `mapled/manifest.json` — `npx @mapled/cli scan --write` derives it from the code and `bindings push` / `bindings pull` exchange it with Mapled |
67
+ | `push_site_manifest` / `list_bindings` | Tell Mapled where each field is rendered; read every binding's health (type mismatch, outdated, missing on site). Keep the repository's copy in `mapled/manifest.json` — `npx @mapled/cli scan --write` derives it from the code and `bindings push` / `bindings pull` exchange it with Mapled. A push records the integration hash — the schema and these bindings — and `list_bindings` says whether it still matches (`integration.inSync`, with `schemaChanged` / `bindingsChanged` naming what moved) |
68
68
  | `configure_revalidation` | Point the publish webhook at the site, get the signing secret |
69
- | `check_integration` | The site's integration as Mapled sees it — delivery reads, the webhook and its last delivery, the bindings summary, current package versions; `npx @mapled/cli doctor` shows the same from inside the repository |
69
+ | `check_integration` | The site's integration as Mapled sees it — delivery reads, the webhook and its last delivery, the bindings summary, the integration hash (is the last push still in step with the schema and the bindings?), current package versions; `npx @mapled/cli doctor` shows the same from inside the repository |
70
70
  | `get_mapled_md` | `MAPLED.md` rendered from the project — the guide for the next agent: project, how the site reads it, content model, bindings by page, last setup run, working rules, verification commands. Never a secret. `npx @mapled/cli md pull` writes the same file; `mapled doctor` says when it is out of date |
71
71
 
72
72
  Agents write drafts only — publishing stays with humans in the Mapled app, and nothing changes on the live site until someone presses Publish.
package/dist/tools.d.ts CHANGED
@@ -5,7 +5,7 @@ export type ApiClient = {
5
5
  request: (method: "GET" | "POST" | "PATCH", path: string, body?: unknown) => Promise<unknown>;
6
6
  };
7
7
  export declare function createApiClient(baseUrl: string, token: string): ApiClient;
8
- export declare const FIELD_TYPES: readonly ["short_text", "long_text", "rich_text", "slug", "image", "number", "boolean", "date", "relation", "enum", "url", "email", "group", "datetime", "file", "color", "json", "location"];
8
+ export declare const FIELD_TYPES: readonly ["short_text", "long_text", "rich_text", "slug", "image", "number", "boolean", "date", "relation", "enum", "url", "email", "group", "datetime", "file", "color", "json", "location", "computed"];
9
9
  export type ToolDef = {
10
10
  name: string;
11
11
  description: string;
package/dist/tools.js CHANGED
@@ -37,12 +37,19 @@ export const FIELD_TYPES = [
37
37
  "color",
38
38
  "json",
39
39
  "location",
40
+ "computed",
40
41
  ];
42
+ /** What add_field and propose_setup_plan say about formulas (§14.9). */
43
+ const COMPUTED_HELP = "For type computed only: { expression } — a formula over the record's other fields that Mapled evaluates when a record is read or published (read-only for editors and agents; the site reads the value like any field of the result type, filters and sorts included; writes ignore it). " +
44
+ "Field keys as written (price, unit-cost — put spaces around a minus to subtract: price - cost); one link deep through relations: author.name, and lists over many-relations for aggregates: sum(items.price), count(tags), join(tags.name, \", \"). " +
45
+ "Numbers: + - * / %, round(x, digits), floor, ceil, abs, min, max, sum, avg, count, fixed(x, digits) → text. Text: & joins (empty counts as \"\"), concat, upper, lower, trim, length, left(s, n), right(s, n), replace(s, from, to), contains(s, part), slug(s), text(x), number(s). " +
46
+ "Logic: = != < <= > >=, and, or, not, if(cond, a, b), coalesce(a, b), empty(x). Dates: year, month, day, date(datetime), daysBetween(a, b), addDays(d, n). Literals: 12, 2.5, \"text\", true, false, null. " +
47
+ "Sensitive fields, groups, JSON and location can't be read; there is no now(). The result type (number, text, boolean, date, datetime) follows from the formula.";
41
48
  export function createTools(api) {
42
49
  return [
43
50
  {
44
51
  name: "get_schema",
45
- description: "Read the project's full content schema: collections with their fields.",
52
+ description: "Read the project's full content schema: collections with their fields (a computed field carries its formula and result type under `computed`).",
46
53
  schema: {},
47
54
  handler: async () => api.request("GET", "/v1/agent/schema"),
48
55
  },
@@ -82,6 +89,10 @@ export function createTools(api) {
82
89
  .max(50)
83
90
  .optional()
84
91
  .describe("For type enum only: the values a record may hold, in display order."),
92
+ computed: z
93
+ .object({ expression: z.string().min(1).max(500) })
94
+ .optional()
95
+ .describe(`${COMPUTED_HELP} In a plan the formula may read fields of this plan (this collection, or another one through a relation); one that doesn't check is skipped with a warning when the plan is applied.`),
85
96
  relation: z
86
97
  .object({
87
98
  target: z
@@ -206,7 +217,7 @@ export function createTools(api) {
206
217
  },
207
218
  {
208
219
  name: "clear_records",
209
- description: "Destructive: move every record of a collection to Trash (kept 7 days), e.g. before re-importing content. " +
220
+ description: "Destructive: move every record of a collection to Trash (kept 7 to 90 days by the project's plan), e.g. before re-importing content. " +
210
221
  "Needs a person's confirmation on a trusted Mapled screen (returns a reviewUrl to send to the user); poll " +
211
222
  "get_confirmation.",
212
223
  schema: { collectionKey: z.string().min(1).max(120) },
@@ -229,7 +240,9 @@ export function createTools(api) {
229
240
  "image_alt, link, number, date, boolean, collection for a repeated list, route_param, form_field). " +
230
241
  "Push the full list every time; bindings you leave out are marked missing on the site. Mapled grades " +
231
242
  "each binding against the schema (healthy, type mismatch, outdated) and returns warnings for unknown " +
232
- "collections or fields. Needs the builder plan.",
243
+ "collections or fields. The answer's manifest.integrationHash is the hash of the schema and these " +
244
+ "bindings — what the site is synced with from now on; check_integration reports inSync against it. " +
245
+ "Needs the builder plan.",
233
246
  schema: {
234
247
  framework: z.string().max(40).optional(),
235
248
  pages: z.array(z.object({ route: z.string().max(200), file: z.string().max(300).optional() })).max(200).optional(),
@@ -266,7 +279,11 @@ export function createTools(api) {
266
279
  name: "list_bindings",
267
280
  description: "Read the bindings with their health: healthy, missing_on_site, type_mismatch, outdated (the field or " +
268
281
  "collection changed since the manifest), not_checked, disabled. Fix the site or the schema, then push " +
269
- "the manifest again.",
282
+ "the manifest again. `integration` says whether the last push still matches Mapled: inSync false with " +
283
+ "schemaChanged means the schema moved after the site was wired — run `npx @mapled/cli schema diff`, " +
284
+ "update the site, then `scan --write` and push the manifest again; bindingsChanged means someone " +
285
+ "replaced or deleted bindings in Mapled — `npx @mapled/cli bindings pull` brings them into the " +
286
+ "repository, then update the site to match.",
270
287
  schema: {},
271
288
  handler: async () => api.request("GET", "/v1/agent/bindings"),
272
289
  },
@@ -290,7 +307,7 @@ export function createTools(api) {
290
307
  },
291
308
  {
292
309
  name: "add_field",
293
- description: "Add a field to a collection. Types: short_text, long_text, rich_text (Markdown: headings, lists, links, bold/italic, images as ![alt](file URL)), slug, image, number, boolean, date, relation (a link to records of another collection: pass `relation`; values are record ids), enum (a choice: pass `options`), url, email, group (an object shaped by its own `group.fields`, or a list of them when repeatable — feature cards, FAQ items; values are objects / arrays of objects keyed by the sub-field keys), datetime (ISO 8601, stored in UTC), file (an asset id of any uploaded file), color (#rrggbb), json (any object or list up to 32 KB — settings, specs, structured data the site reads as is), location ({ lat, lng } in degrees).",
310
+ description: "Add a field to a collection. Types: short_text, long_text, rich_text (Markdown: headings, lists, links, bold/italic, images as ![alt](file URL)), slug, image, number, boolean, date, relation (a link to records of another collection: pass `relation`; values are record ids), enum (a choice: pass `options`), url, email, group (an object shaped by its own `group.fields`, or a list of them when repeatable — feature cards, FAQ items; values are objects / arrays of objects keyed by the sub-field keys), datetime (ISO 8601, stored in UTC), file (an asset id of any uploaded file), color (#rrggbb), json (any object or list up to 32 KB — settings, specs, structured data the site reads as is), location ({ lat, lng } in degrees), computed (a value derived from the record's other fields: pass `computed.expression`; never required or sensitive).",
294
311
  schema: {
295
312
  collectionKey: z.string().min(1).max(120),
296
313
  displayName: z.string().min(1).max(120),
@@ -354,6 +371,7 @@ export function createTools(api) {
354
371
  })
355
372
  .optional()
356
373
  .describe("For type group only. Sub-field keys are the lowercase, hyphenated names."),
374
+ computed: z.object({ expression: z.string().min(1).max(500) }).optional().describe(COMPUTED_HELP),
357
375
  },
358
376
  handler: async (args) => api.request("POST", `/v1/agent/collections/${encodeURIComponent(args.collectionKey)}/fields`, {
359
377
  displayName: args.displayName,
@@ -366,6 +384,7 @@ export function createTools(api) {
366
384
  ...(args.options ? { options: args.options } : {}),
367
385
  ...(args.sensitive !== undefined ? { sensitive: args.sensitive } : {}),
368
386
  ...(args.group ? { group: args.group } : {}),
387
+ ...(args.computed ? { computed: args.computed } : {}),
369
388
  }),
370
389
  },
371
390
  {
@@ -449,7 +468,8 @@ export function createTools(api) {
449
468
  "reads it, the content model, where the site renders each field, the last setup run, the working rules and " +
450
469
  "the verification commands, rendered from the project as it is now. Write `markdown` to MAPLED.md at the " +
451
470
  "repository root and commit it. If the file exists, replace everything above its `<!-- mapled:notes -->` " +
452
- "line and keep what is below — that part belongs to the repository. Refresh it after every schema or " +
471
+ "line and keep what is below — that part belongs to the repository. Its first line is a stamp with the " +
472
+ "schema hash, the manifest version and the integration hash. Refresh it after every schema or " +
453
473
  "manifest change and at the end of a setup; `npx @mapled/cli md pull` does the same from the repository " +
454
474
  "and `mapled doctor` says when it is out of date. It never contains a secret — don't add one.",
455
475
  schema: {},
@@ -459,9 +479,14 @@ export function createTools(api) {
459
479
  name: "check_integration",
460
480
  description: "See the site's integration as Mapled sees it: whether the site has read content with the delivery key " +
461
481
  "and when, the publish webhook's URL and its last delivery, the bindings summary of the last manifest, " +
462
- "the connection you hold and the package versions Mapled considers current (@mapled/next, @mapled/mcp, " +
463
- "the mapled CLI). Use it to find what is left to wire up; `npx @mapled/cli doctor` shows the same picture " +
464
- "from inside the repository, plus the local checks (env, routes, generated types, secrets in git).",
482
+ "the connection you hold, the package versions Mapled considers current (@mapled/next, @mapled/mcp, " +
483
+ "the mapled CLI) and `integration` — the integration hash: `hash` is the schema and the bindings as " +
484
+ "Mapled holds them now, `synced` what the last manifest push recorded; inSync false means the site was " +
485
+ "wired against an older schema (schemaChanged) or bindings were edited in Mapled (bindingsChanged) — " +
486
+ "re-sync it (schema diff, update the site, push the manifest again). The repository computes the same " +
487
+ "hash from mapled/schema.json and mapled/manifest.json, and `npx @mapled/cli doctor` compares the two in " +
488
+ "its Integration line. Use it to find what is left to wire up; doctor shows the same picture from inside " +
489
+ "the repository, plus the local checks (env, routes, generated types, secrets in git).",
465
490
  schema: {},
466
491
  handler: async () => api.request("GET", "/v1/agent/integration"),
467
492
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mapled/mcp",
3
- "version": "0.10.0",
3
+ "version": "0.12.0",
4
4
  "description": "Mapled MCP server: lets AI agents build schema and content for one Mapled project.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://mapled.io",