@mapled/mcp 0.15.0 → 0.17.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
@@ -63,14 +63,14 @@ A rename or a conversion Mapled wouldn't take is refused at once with the reason
63
63
  | `propose_setup_plan` / `get_setup_run` / `apply_setup_plan` / `report_setup` / `verify_setup` | One approved plan for the whole setup — every field type including relations (`$ref` handles between plan records, ids for existing collections) and groups — verified by Mapled (see above) |
64
64
  | `get_schema` | Read the project's collections and fields |
65
65
  | `create_collection` | Add a collection or single |
66
- | `add_field` | Add a field (short_text, long_text, rich_text, slug, image, number, boolean, date, datetime, relation, enum, url, email, group, file, color, json — an object or list up to 32 KB, location — { lat, lng }). Optional `validation` ({min, max, pattern}) and `defaultValue`; `relation` ({target, cardinality: one \| many, onDelete: restrict \| nullify}) is required for relation fields — values are record ids of the target collection, kept in the order given; `onDelete` says what a delete of a linked record does (restrict: it can't be deleted while linked, nullify: the links are cleared — the default is restrict for required fields and nullify otherwise); `options` (1–50 labels) is required for enum fields; `sensitive: true` keeps a field out of lists, history and delivery (a group's sub-fields take it too); `group` ({fields, repeatable, maxItems}) shapes a group field — its values are objects (or arrays of them) keyed by the sub-field keys. |
66
+ | `add_field` | Add a field (short_text, long_text, rich_text, slug, image, number, boolean, date, datetime, relation, enum, url, email, group, file, color, json — an object or list up to 32 KB, location — { lat, lng }, computed). Optional `validation` ({min, max, pattern}) and `defaultValue`; `relation` ({target, cardinality: one \| many, onDelete: restrict \| nullify}) is required for relation fields — values are record ids of the target collection, kept in the order given; `onDelete` says what a delete of a linked record does (restrict: it can't be deleted while linked, nullify: the links are cleared — the default is restrict for required fields and nullify otherwise); `options` (1–50 labels) is required for enum fields; `sensitive: true` keeps a field out of lists, history and delivery (a group's sub-fields take it too); `group` ({fields, repeatable, maxItems}) shapes a group field — its values are objects (or arrays of them) keyed by the sub-field keys; `computed` ({expression}) makes a computed field — a formula Mapled evaluates whenever a record is read or published, over the record's fields and up to two links through relations (`author.company.name`, `sum(items.product.price)`) or back along one and one link on (`count(@posts.author)`, `sum(@order-items.order.product.price)`), at most one list per path, never a sensitive field or relation; the site reads the value like any field of its result type. |
67
67
  | `add_records` | Insert draft records |
68
68
  | `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 |
69
69
  | `create_form` / `list_forms` | Set up public forms with spam protection |
70
70
  | `get_connection` | The delivery key and the API URL, plus — for the `framework` the agent names (`nextjs`, `react-spa`, `plain-html`, …) or the project's own — the package the site reads through (`@mapled/next`, `@mapled/react`, `@mapled/vanilla` — a script tag and `data-mapled-*` attributes for plain HTML — or `@mapled/client`), the env var of the key, whether the site renders on a server or in the browser, and the wire-up steps. Image values → `assetUrl(id, { width })` of the same package |
71
71
  | `set_site_url` | Where the site is deployed — for a site rendered in the browser (a React single-page app, plain HTML), which has no webhook to learn it from: Preview opens the site there, verification checks that it answers |
72
- | `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) |
73
- | `configure_revalidation` | Point the publish webhook at the site (one with a server that caches what it reads), get the signing secret; the description also tells the agent how to add live updates for tabs that are already open (`createReleaseHandler` and `<MapledLive />`, `@mapled/next` 0.8.0+) |
72
+ | `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). `capabilities` says whether open tabs follow Publish: `{ realtime: true, releaseRoute: "/api/mapled/release" }` for a Next.js site with `<MapledLive />` and `createReleaseHandler`, `{ realtime: true }` for a site rendered in the browser whose tabs ask Mapled directly (`live` on `MapledProvider`, `data-mapled-live` on the script tag), `{ realtime: false }` without live updates — only these two keys; MAPLED.md's Live updates line comes from it, so send it with every push |
73
+ | `configure_revalidation` | Point the publish webhook at the site (one with a server that caches what it reads), get the signing secret; the description also tells the agent how to add live updates for tabs that are already open (`createReleaseHandler` and `<MapledLive />`, `@mapled/next` 0.8.0+), declared then in the manifest's `capabilities` |
74
74
  | `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 |
75
75
  | `delete_collection` / `remove_field` / `clear_records` / `rename_field` / `convert_field` / `get_confirmation` | Destructive and breaking changes — each files a request a person confirms on a trusted Mapled screen (see above); `get_confirmation` reads its status |
76
76
  | `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 |
package/dist/tools.js CHANGED
@@ -41,10 +41,10 @@ export const FIELD_TYPES = [
41
41
  ];
42
42
  /** What add_field and propose_setup_plan say about formulas (§14.9). */
43
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, \", \"); or one link back — the records of another collection whose relation points at this record, written @collection.relation[.field], always a list, oldest first: count(@posts.author), sum(@order-items.order.total), max(@posts.author.published-on). " +
44
+ "Field keys as written (price, unit-cost — put spaces around a minus to subtract: price - cost); up to two links through relations: author.name, author.company.name, and lists over many-relations for aggregates: sum(items.price), count(tags), join(tags.name, \", \"), sum(items.product.price); or one link back — the records of another collection whose relation points at this record, written @collection.relation[.field], always a list, oldest first: count(@posts.author), sum(@order-items.order.total), max(@posts.author.published-on) — and one more link on from them: sum(@order-items.order.product.price). A path goes through at most one list (a many-relation, or the records that link back), so items.tags.name is refused. " +
45
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
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), created() — when the record was added (a datetime). 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.";
47
+ "Sensitive fields and relations, groups, JSON and location can't be read; there is no now(). The result type (number, text, boolean, date, datetime) follows from the formula.";
48
48
  export function createTools(api) {
49
49
  return [
50
50
  {
@@ -296,6 +296,13 @@ export function createTools(api) {
296
296
  "sveltekit…; react-spa and plain-html tell Mapled the site renders in the browser, so verification " +
297
297
  "expects no webhook and no preview route. A plain HTML page that shows one record keeps the slug in its " +
298
298
  "query — name it \"/post.html?slug=[slug]\", with a route_param binding on the slug field. " +
299
+ "`capabilities` says whether pages that are already open follow a publish (live updates): a Next.js site " +
300
+ "that renders <MapledLive /> (or calls watchRelease) and serves createReleaseHandler as GET at a route " +
301
+ "sends { realtime: true, releaseRoute: \"/api/mapled/release\" } — the path its tabs ask; a site " +
302
+ "rendered in the browser whose tabs ask Mapled directly (live on MapledProvider, data-mapled-live on the " +
303
+ "script tag) sends { realtime: true }; a site without live updates sends { realtime: false }. Only these two keys " +
304
+ "are accepted. Nothing is graded by them and they stay out of the integration hash, but MAPLED.md's " +
305
+ "Live updates line comes from them — send them with every push, as a push without them drops the line. " +
299
306
  "The answer's manifest.integrationHash is the hash of the schema and these " +
300
307
  "bindings — what the site is synced with from now on; check_integration reports inSync against it. " +
301
308
  "Needs the builder plan.",
@@ -328,6 +335,15 @@ export function createTools(api) {
328
335
  }))
329
336
  .max(500),
330
337
  notes: z.array(z.string().max(300)).max(20).optional(),
338
+ // the API's limits (lib/bindings.ts): strict, so an unknown capability is refused, never dropped
339
+ capabilities: z
340
+ .object({
341
+ realtime: z.boolean().optional(),
342
+ releaseRoute: z.string().min(1).max(200).startsWith("/").optional(),
343
+ })
344
+ .strict()
345
+ .optional()
346
+ .describe("Whether open tabs follow a publish: realtime, and releaseRoute — the path of the site's release route, e.g. /api/mapled/release."),
331
347
  },
332
348
  handler: async (args) => api.request("POST", "/v1/agent/manifest", args),
333
349
  },
@@ -542,7 +558,8 @@ export function createTools(api) {
542
558
  "Optional, when the owner wants pages that are already open to follow a publish without a reload " +
543
559
  "(@mapled/next 0.8.0+): also mount createReleaseHandler({ key: process.env.MAPLED_KEY! }) from " +
544
560
  "\"@mapled/next/server\" as GET at /api/mapled/release and render <MapledLive /> from " +
545
- "\"@mapled/next/live\" once in the root layout — tabs poll the site's own route, never Mapled.",
561
+ "\"@mapled/next/live\" once in the root layout — tabs poll the site's own route, never Mapled; then " +
562
+ "declare it in push_site_manifest's capabilities.",
546
563
  schema: {
547
564
  url: z.string().min(8).max(2048),
548
565
  },
@@ -551,7 +568,8 @@ export function createTools(api) {
551
568
  {
552
569
  name: "get_mapled_md",
553
570
  description: "Get MAPLED.md — the guide Mapled writes for the next agent and for people: the project and how the site " +
554
- "reads it, the content model, where the site renders each field, the last setup run, the working rules and " +
571
+ "reads it (and whether open tabs follow a publish, as the manifest's capabilities say), the content model, " +
572
+ "where the site renders each field, the last setup run, the working rules and " +
555
573
  "the verification commands, rendered from the project as it is now. Write `markdown` to MAPLED.md at the " +
556
574
  "repository root and commit it. If the file exists, replace everything above its `<!-- mapled:notes -->` " +
557
575
  "line and keep what is below — that part belongs to the repository. Its first line is a stamp with the " +
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mapled/mcp",
3
- "version": "0.15.0",
3
+ "version": "0.17.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",