@latellu/atlas-agent-skills 0.4.0 → 0.5.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.
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "atlas",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Work with Atlas CMS from Claude Code: bundles the Atlas MCP server (read/write content via tools) and the atlas-cms skill that teaches agents when and how to use the MCP tools, the @latellu/atlas-sdk delivery/management clients, and the @latellu/atlas-cli type generator.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Latellu",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@latellu/atlas-agent-skills",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Agent skill + MCP configuration for Atlas CMS. Works as a Claude Code plugin and as plain markdown guidance for any AI coding agent (Cursor, Codex, opencode, Gemini CLI, ...).",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Latellu (https://github.com/tenriajeng)",
|
|
@@ -82,8 +82,7 @@ types, then build the page"), route each sub-task to its own single reference.
|
|
|
82
82
|
|
|
83
83
|
Choosing between MCP and the management SDK for writes: MCP is for operating content
|
|
84
84
|
interactively in an agent session (one-off edits, content entry, audits); the SDK is for
|
|
85
|
-
code that outlives the session (migrations, sync jobs, backends) and for
|
|
86
|
-
lacks (bulk, scheduling, page unpublish/archive, block reorder, media alt-text edits).
|
|
85
|
+
code that outlives the session (migrations, sync jobs, backends) and for structured per-field error objects.
|
|
87
86
|
|
|
88
87
|
## Hard capability boundaries (don't go looking for these)
|
|
89
88
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# Atlas MCP tools
|
|
2
2
|
|
|
3
3
|
The `@latellu/atlas-mcp` server (stdio) exposes Atlas content operations as agent tools.
|
|
4
|
-
This file describes `@latellu/atlas-mcp` **≥ 1.
|
|
4
|
+
This file describes `@latellu/atlas-mcp` **≥ 1.2.0** (the bundled `.mcp.json` uses
|
|
5
5
|
`npx -y`, so it always runs the latest). Older servers lack `translations`,
|
|
6
|
-
`seo_translations`, per-field error detail,
|
|
6
|
+
`seo_translations`, per-field error detail, the schema `id`/`is_block` fields, page/entry lifecycle tools (unpublish/archive/duplicate/schedule), bulk operations, reorder tools, media alt-text editing, list meta+cursor pagination, automatic 429 retry, and pre-parsed block data in get_page.
|
|
7
7
|
|
|
8
8
|
**Environment** — read tools need `ATLAS_LIVE_API_KEY`, write tools need
|
|
9
9
|
`ATLAS_MGMT_API_KEY`; with only one set, the other half of the tools fails client-side
|
|
@@ -29,32 +29,42 @@ errors).
|
|
|
29
29
|
|
|
30
30
|
| Tool | Params | Notes |
|
|
31
31
|
|---|---|---|
|
|
32
|
-
| `list_entries` | `content_type`, `page?`=1, `limit?`=20, `status?` | `status` is
|
|
33
|
-
| `get_entry` | `content_type`, `slug` | resolves by `slug` alone — `content_type` is accepted but
|
|
32
|
+
| `list_entries` | `content_type`, `page?`=1, `limit?`=20, `status?`, `cursor?` | `status` is enum (draft \| published \| archived \| scheduled); live key **cannot** reveal drafts. Returns `{ data, meta }` where `meta` has `total_data`, `total_pages` (offset mode) or `next_cursor` (cursor mode). Use `cursor: meta.next_cursor` to page past the 1000-page limit. |
|
|
33
|
+
| `get_entry` | `content_type`, `slug` | resolves by `slug` alone — `content_type` is accepted but errors clearly if the slug belongs to a different content type |
|
|
34
34
|
| `create_entry` | `content_type`, `data`, `slug?`, `translations?` | creates a **draft**; slug auto-generated when omitted; `translations` = `{locale: {data: {...}}}` (required+localizable fields go HERE) |
|
|
35
35
|
| `update_entry` | `content_type`, `slug`, `data`, `translations?` | **full replace** of `data` (and per-locale `translations`), not a patch |
|
|
36
36
|
| `publish_entry` / `unpublish_entry` / `archive_entry` | `content_type`, `slug` | need the `content:publish` scope |
|
|
37
37
|
| `duplicate_entry` | `content_type`, `slug` | copies to a new draft |
|
|
38
|
-
| `
|
|
38
|
+
| `schedule_entry` | `content_type`, `slug`, `publish_at` | schedules publish for a future time (ISO 8601 UTC); needs `content:publish` scope |
|
|
39
|
+
| `bulk_entries` | `content_type`, `operations` | batch publish/archive/schedule/delete by entry UUIDs; each op in array: `{ op, id, publish_at? }` |
|
|
40
|
+
| `bulk_delete_entries` | `content_type`, `ids` | batch delete by entry UUIDs |
|
|
41
|
+
| `reorder_entries` | `content_type`, `ids` | reorder entries; pass the complete ordered list of entry UUIDs |
|
|
42
|
+
| `delete_entry` | `content_type`, `slug` | returns JSON `{ deleted: true, ... }` |
|
|
39
43
|
|
|
40
44
|
### Pages — read: live key · write: mgmt key
|
|
41
45
|
|
|
42
46
|
| Tool | Params | Notes |
|
|
43
47
|
|---|---|---|
|
|
44
|
-
| `list_pages` | `page?`=1, `limit?`=20 | summaries, no blocks |
|
|
45
|
-
| `get_page` | `slug` | block tree — each block's `data` is
|
|
48
|
+
| `list_pages` | `page?`=1, `limit?`=20, `cursor?` | summaries, no blocks. Returns `{ data, meta }` with cursor pagination option (same as `list_entries`). |
|
|
49
|
+
| `get_page` | `slug` | block tree — each block's `data` is already parsed to an object (no JSON.parse needed); nested children and translations included |
|
|
46
50
|
| `create_page` | `slug`, `title?`, `blocks?`, `seo?`, `seo_translations?` | draft; `title` is an alias for `seo.title`; `seo` accepts `title`/`description`/`keywords`/`og_image`/`canonical`; blocks = `[{block_type_id, parent_id?, position, data, translations?}]` |
|
|
47
51
|
| `update_page` | `slug`, `title?`, `blocks?`, `seo?`, `seo_translations?` | passing `blocks` replaces the whole list; `seo` replaces wholesale (title alone drops other seo fields) |
|
|
48
|
-
| `publish_page` | `slug` |
|
|
49
|
-
| `
|
|
52
|
+
| `publish_page` | `slug` | publish a page; fails on blockless pages |
|
|
53
|
+
| `unpublish_page` | `slug` | unpublish a page; needs `content:publish` scope |
|
|
54
|
+
| `archive_page` | `slug` | archive a page; needs `content:publish` scope |
|
|
55
|
+
| `duplicate_page` | `slug` | copy to a new draft |
|
|
56
|
+
| `schedule_page` | `slug`, `publish_at` | schedule publish for a future time (ISO 8601 UTC); needs `content:publish` scope |
|
|
57
|
+
| `reorder_page_blocks` | `slug`, `block_ids` | reorder blocks; pass the complete ordered list of block IDs |
|
|
58
|
+
| `delete_page` | `slug` | returns JSON `{ deleted: true, ... }` |
|
|
50
59
|
|
|
51
60
|
### Media
|
|
52
61
|
|
|
53
62
|
| Tool | Params | Notes |
|
|
54
63
|
|---|---|---|
|
|
55
64
|
| `get_media` | `id` | live key |
|
|
56
|
-
| `upload_media` | `file_path` (absolute), `folder?`="/", `alt_text?` | mgmt key; reads the local file, multipart upload |
|
|
57
|
-
| `
|
|
65
|
+
| `upload_media` | `file_path` (absolute), `folder?`="/", `alt_text?` | mgmt key; reads the local file, multipart upload. Pre-validates client-side: ≤10 MB, extension allowlist (.jpg .jpeg .png .gif .webp .mp4 .webm .mov .pdf). |
|
|
66
|
+
| `update_media` | `id`, `alt_text?`, `folder?` | mgmt key; edit metadata (alt text and/or folder). |
|
|
67
|
+
| `delete_media` | `id` | mgmt key; returns JSON `{ deleted: true, ... }` |
|
|
58
68
|
|
|
59
69
|
## Recommended write workflow
|
|
60
70
|
|
|
@@ -68,23 +78,20 @@ errors).
|
|
|
68
78
|
`get_entry` → merge your change into the full object → `update_entry` with everything.
|
|
69
79
|
3. **Create → verify → publish.** `create_entry` makes a draft; `publish_entry` needs
|
|
70
80
|
the `content:publish` scope (403 without it, with a clear message).
|
|
71
|
-
4. **Before `upload_media`**:
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
(so `.svg`, `.heic` fail). Allowed: `image/*`, `video/*`, `application/pdf` (i.e.
|
|
75
|
-
`.jpg .jpeg .png .gif .webp .mp4 .webm .mov .pdf`).
|
|
81
|
+
4. **Before `upload_media`**: the tool pre-validates client-side (≤ 10 MB, extension
|
|
82
|
+
allowlist), so failures are caught before upload. Allowed extensions:
|
|
83
|
+
`.jpg .jpeg .png .gif .webp .mp4 .webm .mov .pdf`.
|
|
76
84
|
|
|
77
85
|
## Capability gaps — route elsewhere instead of retrying
|
|
78
86
|
|
|
79
|
-
|
|
80
|
-
dashboard or the management SDK (`sdk-management.md`) rather than improvising:
|
|
87
|
+
The MCP manage plane is now fully covered. These gaps remain:
|
|
81
88
|
|
|
82
|
-
-
|
|
83
|
-
`
|
|
84
|
-
|
|
85
|
-
- **
|
|
86
|
-
|
|
87
|
-
|
|
89
|
+
- **No automatic merge on `update_entry`** — the tool replaces `data` wholesale, so you
|
|
90
|
+
must read-modify-write yourself: `get_entry` → merge your changes → `update_entry`.
|
|
91
|
+
The management SDK offers an `update` overload that accepts a patch, but MCP does not.
|
|
92
|
+
- **Schema is dashboard-only.** Creating content types, fields, or block types is not
|
|
93
|
+
exposed via MCP, SDK, or API. "Create a content type" = ask the user to do it in the
|
|
94
|
+
dashboard, then continue.
|
|
88
95
|
|
|
89
96
|
Before composing any `data` payload, read `authoring.md` — it defines the exact value
|
|
90
97
|
format per field type (richtext = Tiptap HTML, relation/image = UUIDs, etc.).
|
|
@@ -93,11 +100,8 @@ format per field type (richtext = Tiptap HTML, relation/image = UUIDs, etc.).
|
|
|
93
100
|
|
|
94
101
|
- **Drafts are invisible to live keys** — `list_entries(status="draft")` returning
|
|
95
102
|
empty means key scoping, not an empty workspace.
|
|
96
|
-
- **`
|
|
97
|
-
|
|
98
|
-
whatever the backend finds by slug.
|
|
99
|
-
- **No client-side 429 retry** — on `Atlas API error: 429`, back off exponentially and
|
|
100
|
-
retry the tool call yourself.
|
|
103
|
+
- **`get_entry` errors if the slug belongs to a different content type** — content types
|
|
104
|
+
used to share slug namespaces, now you get a clear error instead of silent mismatch.
|
|
101
105
|
- Every write sends a fresh auto-generated `Idempotency-Key` per call, so re-issuing a
|
|
102
106
|
failed create as a *new tool call* is a new operation — check whether the first call
|
|
103
107
|
actually landed (e.g. `get_entry`) before retrying creates.
|
|
@@ -69,7 +69,7 @@ await client.pages.create({ slug: "landing", seo: { title: "Landing" }, blocks:
|
|
|
69
69
|
await client.pages.update("landing", { seo: { title: "Landing v2" } });
|
|
70
70
|
await client.pages.publish("landing"); // fails unless the page has ≥1 block — see authoring.md
|
|
71
71
|
await client.pages.unpublish("landing"); // pages have the FULL lifecycle here
|
|
72
|
-
await client.pages.archive("landing"); //
|
|
72
|
+
await client.pages.archive("landing"); // (MCP also has parity since v1.2.0)
|
|
73
73
|
await client.pages.schedule("landing", "2026-08-01T09:00:00Z");
|
|
74
74
|
await client.pages.delete("landing");
|
|
75
75
|
await client.pages.blocksReorder("landing", ["block-id-2", "block-id-1", "block-id-3"]);
|