@ampless/mcp-server 0.2.0-alpha.7 → 0.2.0-alpha.8
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.
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/tools/post-mapping.ts
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
decodeAwsJson
|
|
6
|
+
} from "ampless";
|
|
5
7
|
var POST_FIELDS = (
|
|
6
8
|
/* GraphQL */
|
|
7
9
|
`
|
|
@@ -16,10 +18,12 @@ var POST_FIELDS = (
|
|
|
16
18
|
status
|
|
17
19
|
publishedAt
|
|
18
20
|
tags
|
|
21
|
+
metadata
|
|
19
22
|
}
|
|
20
23
|
`
|
|
21
24
|
);
|
|
22
25
|
function toCorePost(p) {
|
|
26
|
+
const metadata = decodeAwsJson(p.metadata);
|
|
23
27
|
return {
|
|
24
28
|
siteId: p.siteId,
|
|
25
29
|
postId: p.postId,
|
|
@@ -30,7 +34,8 @@ function toCorePost(p) {
|
|
|
30
34
|
body: decodeAwsJson(p.body),
|
|
31
35
|
status: p.status ?? "draft",
|
|
32
36
|
publishedAt: p.publishedAt ?? void 0,
|
|
33
|
-
tags: (p.tags ?? []).filter((t) => typeof t === "string")
|
|
37
|
+
tags: (p.tags ?? []).filter((t) => typeof t === "string"),
|
|
38
|
+
metadata: metadata && typeof metadata === "object" && !Array.isArray(metadata) ? metadata : void 0
|
|
34
39
|
};
|
|
35
40
|
}
|
|
36
41
|
|
|
@@ -124,7 +129,11 @@ async function getPost(client, defaultSiteId, args) {
|
|
|
124
129
|
}
|
|
125
130
|
|
|
126
131
|
// src/tools/create-post.ts
|
|
127
|
-
import {
|
|
132
|
+
import {
|
|
133
|
+
composeSiteIdStatus,
|
|
134
|
+
composeSiteIdSlug,
|
|
135
|
+
encodeAwsJson
|
|
136
|
+
} from "ampless";
|
|
128
137
|
|
|
129
138
|
// src/posttag.ts
|
|
130
139
|
function entries(post) {
|
|
@@ -236,14 +245,29 @@ var createPostSchema = {
|
|
|
236
245
|
postId: { type: "string", description: "Optional explicit id; auto-generated if omitted" },
|
|
237
246
|
slug: { type: "string" },
|
|
238
247
|
title: { type: "string" },
|
|
239
|
-
format: {
|
|
248
|
+
format: {
|
|
249
|
+
type: "string",
|
|
250
|
+
enum: ["tiptap", "markdown", "html"],
|
|
251
|
+
description: "tiptap = rich text JSON tree; markdown = source string (GFM extensions enabled); html = raw HTML string (rendered verbatim, no sanitization)."
|
|
252
|
+
},
|
|
240
253
|
body: {
|
|
241
|
-
description: "tiptap JSON (when format=tiptap), markdown source string, or raw HTML string"
|
|
254
|
+
description: "tiptap JSON (when format=tiptap), markdown source string (format=markdown), or raw HTML string (format=html)."
|
|
242
255
|
},
|
|
243
256
|
status: { type: "string", enum: ["draft", "published"], default: "draft" },
|
|
244
257
|
excerpt: { type: "string" },
|
|
245
258
|
publishedAt: { type: "string", description: "ISO 8601 timestamp; required when status=published" },
|
|
246
|
-
tags: { type: "array", items: { type: "string" } }
|
|
259
|
+
tags: { type: "array", items: { type: "string" } },
|
|
260
|
+
metadata: {
|
|
261
|
+
type: "object",
|
|
262
|
+
description: "Free-form per-post metadata. Reserved well-known keys: `no_layout` (boolean) \u2014 when true, the public page is served as bare HTML with no theme chrome (the route redirects to /raw/<slug>); meaningful only with format=html. Other keys pass through unchanged for themes/plugins.",
|
|
263
|
+
properties: {
|
|
264
|
+
no_layout: {
|
|
265
|
+
type: "boolean",
|
|
266
|
+
description: "Serve the post as bare HTML with no theme chrome. Only meaningful when format=html; ignored otherwise."
|
|
267
|
+
}
|
|
268
|
+
},
|
|
269
|
+
additionalProperties: true
|
|
270
|
+
}
|
|
247
271
|
}
|
|
248
272
|
};
|
|
249
273
|
async function createPost(client, defaultSiteId, args) {
|
|
@@ -263,6 +287,7 @@ async function createPost(client, defaultSiteId, args) {
|
|
|
263
287
|
status,
|
|
264
288
|
publishedAt,
|
|
265
289
|
tags: args.tags,
|
|
290
|
+
metadata: args.metadata !== void 0 ? encodeAwsJson(args.metadata) : void 0,
|
|
266
291
|
// Denormalized GSI keys.
|
|
267
292
|
siteIdStatus: composeSiteIdStatus(siteId, status),
|
|
268
293
|
siteIdSlug: composeSiteIdSlug(siteId, args.slug)
|
|
@@ -274,7 +299,11 @@ async function createPost(client, defaultSiteId, args) {
|
|
|
274
299
|
}
|
|
275
300
|
|
|
276
301
|
// src/tools/update-post.ts
|
|
277
|
-
import {
|
|
302
|
+
import {
|
|
303
|
+
composeSiteIdStatus as composeSiteIdStatus2,
|
|
304
|
+
composeSiteIdSlug as composeSiteIdSlug2,
|
|
305
|
+
encodeAwsJson as encodeAwsJson2
|
|
306
|
+
} from "ampless";
|
|
278
307
|
var MUTATION2 = (
|
|
279
308
|
/* GraphQL */
|
|
280
309
|
`
|
|
@@ -295,11 +324,26 @@ var updatePostSchema = {
|
|
|
295
324
|
slug: { type: "string" },
|
|
296
325
|
title: { type: "string" },
|
|
297
326
|
excerpt: { type: "string" },
|
|
298
|
-
format: {
|
|
299
|
-
|
|
327
|
+
format: {
|
|
328
|
+
type: "string",
|
|
329
|
+
enum: ["tiptap", "markdown", "html"],
|
|
330
|
+
description: "tiptap = rich text JSON tree; markdown = source string; html = raw HTML string (no sanitization)."
|
|
331
|
+
},
|
|
332
|
+
body: { description: "tiptap JSON, markdown source, or raw HTML string" },
|
|
300
333
|
status: { type: "string", enum: ["draft", "published"] },
|
|
301
334
|
publishedAt: { type: "string", description: "ISO 8601 timestamp" },
|
|
302
|
-
tags: { type: "array", items: { type: "string" } }
|
|
335
|
+
tags: { type: "array", items: { type: "string" } },
|
|
336
|
+
metadata: {
|
|
337
|
+
type: "object",
|
|
338
|
+
description: "Free-form per-post metadata. Reserved well-known keys: `no_layout` (boolean) \u2014 when true, the public page is served as bare HTML with no theme chrome (the route redirects to /raw/<slug>); meaningful only with format=html. Passing metadata replaces the existing metadata object \u2014 read the current post first if you only want to add a key.",
|
|
339
|
+
properties: {
|
|
340
|
+
no_layout: {
|
|
341
|
+
type: "boolean",
|
|
342
|
+
description: "Serve the post as bare HTML with no theme chrome. Only meaningful when format=html; ignored otherwise."
|
|
343
|
+
}
|
|
344
|
+
},
|
|
345
|
+
additionalProperties: true
|
|
346
|
+
}
|
|
303
347
|
}
|
|
304
348
|
};
|
|
305
349
|
async function updatePost(client, defaultSiteId, args) {
|
|
@@ -314,6 +358,7 @@ async function updatePost(client, defaultSiteId, args) {
|
|
|
314
358
|
if (args.status !== void 0) input.status = args.status;
|
|
315
359
|
if (args.publishedAt !== void 0) input.publishedAt = args.publishedAt;
|
|
316
360
|
if (args.tags !== void 0) input.tags = args.tags;
|
|
361
|
+
if (args.metadata !== void 0) input.metadata = encodeAwsJson2(args.metadata);
|
|
317
362
|
if (args.status !== void 0) {
|
|
318
363
|
input.siteIdStatus = composeSiteIdStatus2(siteId, args.status);
|
|
319
364
|
}
|
|
@@ -442,7 +487,11 @@ function getSchema() {
|
|
|
442
487
|
},
|
|
443
488
|
status: { type: "enum", values: ["draft", "published"], default: "draft" },
|
|
444
489
|
publishedAt: { type: "datetime", description: "ISO 8601" },
|
|
445
|
-
tags: { type: "string[]" }
|
|
490
|
+
tags: { type: "string[]" },
|
|
491
|
+
metadata: {
|
|
492
|
+
type: "json",
|
|
493
|
+
description: "Free-form per-post key/value bag. Reserved well-known keys (owned by ampless): `no_layout` (boolean). Other keys pass through unchanged for themes/plugins."
|
|
494
|
+
}
|
|
446
495
|
}
|
|
447
496
|
},
|
|
448
497
|
{
|
|
@@ -475,7 +524,9 @@ function getSchema() {
|
|
|
475
524
|
formats: ["tiptap", "markdown", "html"],
|
|
476
525
|
notes: {
|
|
477
526
|
editorTrust: 'editor stores arbitrary HTML/JS verbatim \u2014 same trust shape as WordPress unfiltered_html capability. See docs/architecture/04-access-layer-mcp.md \xA7"editor \u306E\u4FE1\u983C\u30E2\u30C7\u30EB".',
|
|
478
|
-
tiptapBody: 'When format=tiptap, body is the tiptap document JSON: { type: "doc", content: [...] }. The renderer expects this shape.'
|
|
527
|
+
tiptapBody: 'When format=tiptap, body is the tiptap document JSON: { type: "doc", content: [...] }. The renderer expects this shape.',
|
|
528
|
+
noLayout: "metadata.no_layout=true serves the post as bare HTML with no theme chrome \u2014 the public route at /<slug> 302-redirects to /raw/<slug>, and that route renders the body verbatim with no wrapping <html>/<head>/layout. Use this for landing pages, embeds, or any post whose body is a full HTML document. Only meaningful with format=html (the other formats need the theme renderer).",
|
|
529
|
+
staticFormat: "A fourth format value `static` exists on the underlying data model for posts whose body is a JSON manifest pointing to a pre-uploaded HTML/CSS/JS bundle in S3 at public/static/<siteId>/<slug>/. Static uploads currently only flow through the admin UI; the MCP `upload_media` tool writes to public/media/ and does not handle static bundles. Use the admin StaticUploader for now."
|
|
479
530
|
}
|
|
480
531
|
};
|
|
481
532
|
}
|
|
@@ -496,13 +547,13 @@ var tools = [
|
|
|
496
547
|
},
|
|
497
548
|
{
|
|
498
549
|
name: "create_post",
|
|
499
|
-
description: "Create a new post. Title and slug are required. Body shape depends on format: tiptap=JSON node tree, markdown=source string, html=raw HTML string. Defaults to status=draft.",
|
|
550
|
+
description: "Create a new post. Title and slug are required. Body shape depends on format: tiptap=JSON node tree, markdown=source string, html=raw HTML string. Defaults to status=draft. Pass `metadata: { no_layout: true }` alongside format=html to publish the body as a bare HTML page with no theme chrome (the public route redirects to /raw/<slug>).",
|
|
500
551
|
inputSchema: createPostSchema,
|
|
501
552
|
handler: (args, ctx) => createPost(ctx.graphql, ctx.defaultSiteId, args)
|
|
502
553
|
},
|
|
503
554
|
{
|
|
504
555
|
name: "update_post",
|
|
505
|
-
description: "Update an existing post by postId. Only the fields you pass are changed. Tag list / publishedAt changes also update the PostTag denormalized index.",
|
|
556
|
+
description: "Update an existing post by postId. Only the fields you pass are changed. Tag list / publishedAt changes also update the PostTag denormalized index. Passing `metadata` REPLACES the existing object \u2014 call get_post first if you only want to add or change one key.",
|
|
506
557
|
inputSchema: updatePostSchema,
|
|
507
558
|
handler: (args, ctx) => updatePost(ctx.graphql, ctx.defaultSiteId, args)
|
|
508
559
|
},
|
package/dist/index.js
CHANGED
package/dist/tools/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ampless/mcp-server",
|
|
3
|
-
"version": "0.2.0-alpha.
|
|
3
|
+
"version": "0.2.0-alpha.8",
|
|
4
4
|
"description": "MCP server for ampless — lets AI agents (Claude Desktop, Cursor, Claude Code) read and write posts and media via AppSync",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|