@mapled/mcp 0.11.0 → 0.13.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 +4 -2
- package/dist/tools.d.ts +1 -1
- package/dist/tools.js +64 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -48,9 +48,11 @@ For the first integration, propose one plan and let the owner approve it on a tr
|
|
|
48
48
|
5. Wire the site: `get_connection`, `configure_revalidation`, deploy, then close with `report_setup` (files changed, `buildPassed`, `secretsCommitted: false`). Mapled runs its own checks — the site reads content, the webhook delivered, the preview route responds, fields have help texts — and the run is completed only when they pass. Fix what failed and call `verify_setup`.
|
|
49
49
|
6. Leave a guide: `get_mapled_md` renders `MAPLED.md` from the project — what the site reads and where, the content model, the working rules, the commands that verify the integration. Write it to the repository root and commit it; the next agent (or person) starts from it. When the file exists, replace everything above its `<!-- mapled:notes -->` line and keep the notes below.
|
|
50
50
|
|
|
51
|
-
## Destructive changes
|
|
51
|
+
## Destructive and breaking changes
|
|
52
52
|
|
|
53
|
-
`delete_collection`, `remove_field` and `clear_records` never act on their own. Each one files a request and returns a `reviewUrl`: send it to the user, who confirms on a trusted Mapled screen by typing the name. Poll `get_confirmation` until the status is `applied` (the result says what changed), `denied` or `expired` (after an hour). Nothing
|
|
53
|
+
`delete_collection`, `remove_field` and `clear_records` never act on their own, and neither do the two breaking schema changes — `rename_field` (a field's key, what the site's code reads) and `convert_field` (its type, converting the stored values). Each one files a request and returns a `reviewUrl`: send it to the user, who confirms on a trusted Mapled screen by typing the name. Poll `get_confirmation` until the status is `applied` (the result says what changed), `denied` or `expired` (after an hour). Nothing changes until then.
|
|
54
|
+
|
|
55
|
+
A rename or a conversion Mapled wouldn't take is refused at once with the reason: a key that is taken or malformed, a type the field can't become, a formula that reads the field, values that can't be converted (with their count and examples — fix the content, or ask again with `clearFailed: true`; the person confirming sees how many will be cleared). After a rename the old key keeps working as an alias until a person removes it, so move the site's code to the new key first. Both can be undone from Field settings.
|
|
54
56
|
|
|
55
57
|
## Tools
|
|
56
58
|
|
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, \", \"); 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). " +
|
|
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), 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.";
|
|
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
|
|
@@ -204,9 +215,55 @@ export function createTools(api) {
|
|
|
204
215
|
fieldKey: args.fieldKey,
|
|
205
216
|
}),
|
|
206
217
|
},
|
|
218
|
+
{
|
|
219
|
+
name: "rename_field",
|
|
220
|
+
description: "Breaking change, a person's decision: rename a field's key (what the site's code reads). The values follow, formulas and the " +
|
|
221
|
+
"schema are updated, and the old key keeps working as an alias — delivery serves the value under both keys, and get_schema lists " +
|
|
222
|
+
"it under `aliases` — until a person removes it in Field settings, so the site never breaks mid-change. Nothing changes until a " +
|
|
223
|
+
"person confirms it on a trusted Mapled screen by typing the field's name (returns a reviewUrl to send to the user); poll " +
|
|
224
|
+
"get_confirmation. After it is applied: update the code to read the new key, regenerate the types, push the manifest. A refusal " +
|
|
225
|
+
"(key taken, malformed key) comes back at once. It can be undone from Field settings.",
|
|
226
|
+
schema: {
|
|
227
|
+
collectionKey: z.string().min(1).max(120),
|
|
228
|
+
fieldKey: z.string().min(1).max(120).describe("The field's current key."),
|
|
229
|
+
newKey: z.string().min(1).max(50).describe("Lowercase letters, digits and hyphens, up to 50 characters."),
|
|
230
|
+
},
|
|
231
|
+
handler: async (args) => api.request("POST", "/v1/agent/confirmations", {
|
|
232
|
+
action: "rename_field",
|
|
233
|
+
collectionKey: args.collectionKey,
|
|
234
|
+
fieldKey: args.fieldKey,
|
|
235
|
+
newKey: args.newKey,
|
|
236
|
+
}),
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
name: "convert_field",
|
|
240
|
+
description: "Breaking change, a person's decision: change a field's type, converting the stored values (get_schema lists the types a field " +
|
|
241
|
+
"can become under `convertibleTo`). Mapled works the conversion out over every record first: if some values can't be converted " +
|
|
242
|
+
"the request is refused with their count and a few examples — fix the content, or ask again with clearFailed: true to clear " +
|
|
243
|
+
"those values (the person confirming sees how many). A conversion that would break a formula reading the field is refused too. " +
|
|
244
|
+
"Nothing changes until a person confirms it on a trusted Mapled screen by typing the field's name (returns a reviewUrl to send " +
|
|
245
|
+
"to the user); poll get_confirmation. It can be undone from Field settings, with the previous values.",
|
|
246
|
+
schema: {
|
|
247
|
+
collectionKey: z.string().min(1).max(120),
|
|
248
|
+
fieldKey: z.string().min(1).max(120),
|
|
249
|
+
type: z.string().min(1).max(40).describe("The type to convert to — one of the field's convertibleTo."),
|
|
250
|
+
cardinality: z.enum(["one", "many"]).optional().describe("For a relation: one ↔ many."),
|
|
251
|
+
options: z.array(z.string().min(1).max(60)).max(60).optional().describe("For enum: the choices; derived from the values when omitted."),
|
|
252
|
+
clearFailed: z.boolean().optional().describe("Clear the values that can't be converted instead of refusing."),
|
|
253
|
+
},
|
|
254
|
+
handler: async (args) => api.request("POST", "/v1/agent/confirmations", {
|
|
255
|
+
action: "convert_field",
|
|
256
|
+
collectionKey: args.collectionKey,
|
|
257
|
+
fieldKey: args.fieldKey,
|
|
258
|
+
type: args.type,
|
|
259
|
+
...(args.cardinality !== undefined ? { cardinality: args.cardinality } : {}),
|
|
260
|
+
...(args.options !== undefined ? { options: args.options } : {}),
|
|
261
|
+
...(args.clearFailed !== undefined ? { clearFailed: args.clearFailed } : {}),
|
|
262
|
+
}),
|
|
263
|
+
},
|
|
207
264
|
{
|
|
208
265
|
name: "clear_records",
|
|
209
|
-
description: "Destructive: move every record of a collection to Trash (kept 7 days), e.g. before re-importing content. " +
|
|
266
|
+
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
267
|
"Needs a person's confirmation on a trusted Mapled screen (returns a reviewUrl to send to the user); poll " +
|
|
211
268
|
"get_confirmation.",
|
|
212
269
|
schema: { collectionKey: z.string().min(1).max(120) },
|
|
@@ -217,8 +274,8 @@ export function createTools(api) {
|
|
|
217
274
|
},
|
|
218
275
|
{
|
|
219
276
|
name: "get_confirmation",
|
|
220
|
-
description: "Check a destructive
|
|
221
|
-
"says what changed), denied, expired (after an hour; request again if still needed) or failed.",
|
|
277
|
+
description: "Check a request that waits for a person (a destructive change, a rename, a conversion): status is pending (waiting for the " +
|
|
278
|
+
"person), applied (done — result says what changed), denied, expired (after an hour; request again if still needed) or failed.",
|
|
222
279
|
schema: { confirmationId: z.string().uuid() },
|
|
223
280
|
handler: async (args) => api.request("GET", `/v1/agent/confirmations/${encodeURIComponent(args.confirmationId)}`),
|
|
224
281
|
},
|
|
@@ -296,7 +353,7 @@ export function createTools(api) {
|
|
|
296
353
|
},
|
|
297
354
|
{
|
|
298
355
|
name: "add_field",
|
|
299
|
-
description: "Add a field to a collection. Types: short_text, long_text, rich_text (Markdown: headings, lists, links, bold/italic, images as ), 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).",
|
|
356
|
+
description: "Add a field to a collection. Types: short_text, long_text, rich_text (Markdown: headings, lists, links, bold/italic, images as ), 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).",
|
|
300
357
|
schema: {
|
|
301
358
|
collectionKey: z.string().min(1).max(120),
|
|
302
359
|
displayName: z.string().min(1).max(120),
|
|
@@ -360,6 +417,7 @@ export function createTools(api) {
|
|
|
360
417
|
})
|
|
361
418
|
.optional()
|
|
362
419
|
.describe("For type group only. Sub-field keys are the lowercase, hyphenated names."),
|
|
420
|
+
computed: z.object({ expression: z.string().min(1).max(500) }).optional().describe(COMPUTED_HELP),
|
|
363
421
|
},
|
|
364
422
|
handler: async (args) => api.request("POST", `/v1/agent/collections/${encodeURIComponent(args.collectionKey)}/fields`, {
|
|
365
423
|
displayName: args.displayName,
|
|
@@ -372,6 +430,7 @@ export function createTools(api) {
|
|
|
372
430
|
...(args.options ? { options: args.options } : {}),
|
|
373
431
|
...(args.sensitive !== undefined ? { sensitive: args.sensitive } : {}),
|
|
374
432
|
...(args.group ? { group: args.group } : {}),
|
|
433
|
+
...(args.computed ? { computed: args.computed } : {}),
|
|
375
434
|
}),
|
|
376
435
|
},
|
|
377
436
|
{
|