@areca-cms/skills 0.3.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.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,24 @@
2
2
 
3
3
  All notable changes to `@areca-cms/skills`.
4
4
 
5
+ ## 0.5.0 (2026-10-26)
6
+
7
+ ### Features
8
+
9
+ - **sdk:** manifest pull asks only when something would be removed (a265c3e)
10
+ - **skills:** add areca-quickstart skill and set_publishing_mode MCP tool (3c1bdbd)
11
+
12
+ ## 0.4.0 (2026-10-14)
13
+
14
+ ### Features
15
+
16
+ - add site content (globals) sections (b1c0aaf)
17
+ - implement full end-to-end types (86c76bb)
18
+
19
+ ### Bug fixes
20
+
21
+ - address review feedback on site content globals (46791c2)
22
+
5
23
  ## 0.3.0 (2026-10-11)
6
24
 
7
25
  No user-facing changes.
package/README.md CHANGED
@@ -6,6 +6,7 @@ Agent skills that teach AI coding agents and chat apps how to work with Areca CM
6
6
  | --- | --- |
7
7
  | `areca-sdk` | Connecting a website with `@areca-cms/site-sdk`: tokens and env vars, `areca.config.ts`, the `areca` CLI, reading content, rich text, SEO, preview routes, Go-live builds |
8
8
  | `areca-mcp` | Connecting an AI to a site's MCP server and using it: OAuth and personal keys, roles, the draft/ready/live workflow, field formats, SEO, images, every tool |
9
+ | `areca-quickstart` | Setting up Areca in a new website project: checks the project, interviews you about the content model, languages and build, wires the SDK, and makes a first release. Run it as `/areca-quickstart` |
9
10
 
10
11
  The skills are plain `SKILL.md` folders in the open [Agent Skills](https://agentskills.io) format. They have no scripts and no dependencies, so they work in any project.
11
12
 
@@ -45,7 +46,7 @@ MCP config is written to the project file for Claude Code (`.mcp.json`), Cursor,
45
46
  ## Other ways to install
46
47
 
47
48
  - **Claude Code plugin:** `/plugin marketplace add ekozf/areca-cms`, then `/plugin install areca@areca-cms`.
48
- - **skills CLI:** `npx skills add ekozf/areca-cms --skill areca-sdk --skill areca-mcp`.
49
+ - **skills CLI:** `npx skills add ekozf/areca-cms --skill areca-sdk --skill areca-mcp --skill areca-quickstart`.
49
50
  - **Manually:** copy `skills/areca-*` from the repository into your agent's skills folder.
50
51
 
51
52
  ## Development
package/dist/cli.js CHANGED
@@ -19,7 +19,7 @@ Commands:
19
19
 
20
20
  Options:
21
21
  -a, --agent <id> Agent id, repeatable or comma separated (see list)
22
- -s, --skill <name> Only this skill (areca-sdk, areca-mcp); default all
22
+ -s, --skill <name> Only this skill (areca-sdk, areca-mcp, areca-quickstart); default all
23
23
  -g, --global Install into user-level folders instead of the project
24
24
  --mcp-url <url> Connector URL (<cms>/api/mcp/<site-slug>) to register
25
25
  --out <dir> Zip folder for chat apps and export (default: areca-skills)
@@ -245,6 +245,8 @@ function hintFor(name) {
245
245
  return 'website code: setup, config, CLI, content, preview, deploy';
246
246
  if (name === 'areca-mcp')
247
247
  return 'AI content editing: connect, tools, workflow';
248
+ if (name === 'areca-quickstart')
249
+ return 'Set up Areca in a new site project (interview + wiring)';
248
250
  return '';
249
251
  }
250
252
  async function chooseMcpUrl(options, cwd, interactive, required = false) {
package/dist/skills.d.ts CHANGED
@@ -5,10 +5,15 @@ export type Skill = {
5
5
  dir: string;
6
6
  };
7
7
  /**
8
- * Skills ship in the package's `skills/` folder (copied from the repo root at
9
- * build). From source inside the monorepo, fall back to the repo root copy.
8
+ * Where the bundled skills live. Inside the monorepo the root `skills/` folder is
9
+ * the source of truth, so it wins over the `skills/` copy that `build` makes inside
10
+ * the package (that copy can go stale). An npm install has no repo root, so the
11
+ * packaged copy is used.
12
+ *
13
+ * `moduleDir` is the folder of this module (`src/` from source, `dist/` when built).
14
+ * It is a parameter so tests can point it at a temp layout.
10
15
  */
11
- export declare function skillsRoot(): string;
16
+ export declare function skillsRoot(moduleDir?: string): string;
12
17
  export declare function loadSkills(root?: string): Skill[];
13
18
  /** Top-level `key: value` pairs of a SKILL.md frontmatter block. */
14
19
  export declare function parseFrontmatter(source: string): Record<string, string>;
package/dist/skills.js CHANGED
@@ -1,19 +1,26 @@
1
1
  import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';
2
- import { join, relative } from 'node:path';
2
+ import { dirname, join, relative, resolve } from 'node:path';
3
3
  import { fileURLToPath } from 'node:url';
4
+ const MARKER = 'areca-sdk/SKILL.md';
4
5
  /**
5
- * Skills ship in the package's `skills/` folder (copied from the repo root at
6
- * build). From source inside the monorepo, fall back to the repo root copy.
6
+ * Where the bundled skills live. Inside the monorepo the root `skills/` folder is
7
+ * the source of truth, so it wins over the `skills/` copy that `build` makes inside
8
+ * the package (that copy can go stale). An npm install has no repo root, so the
9
+ * packaged copy is used.
10
+ *
11
+ * `moduleDir` is the folder of this module (`src/` from source, `dist/` when built).
12
+ * It is a parameter so tests can point it at a temp layout.
7
13
  */
8
- export function skillsRoot() {
9
- const candidates = [
10
- fileURLToPath(new URL('../skills', import.meta.url)),
11
- fileURLToPath(new URL('../../../skills', import.meta.url)),
12
- ];
13
- const found = candidates.find((dir) => existsSync(join(dir, 'areca-sdk', 'SKILL.md')));
14
- if (!found)
15
- throw new Error(`Bundled skills not found (looked in ${candidates.join(', ')})`);
16
- return found;
14
+ export function skillsRoot(moduleDir = dirname(fileURLToPath(import.meta.url))) {
15
+ const repoRoot = resolve(moduleDir, '../../..');
16
+ const repoSkills = join(repoRoot, 'skills');
17
+ const packaged = resolve(moduleDir, '../skills');
18
+ const inRepo = existsSync(join(repoRoot, 'pnpm-workspace.yaml')) && existsSync(join(repoSkills, MARKER));
19
+ if (inRepo)
20
+ return repoSkills;
21
+ if (existsSync(join(packaged, MARKER)))
22
+ return packaged;
23
+ throw new Error(`Bundled skills not found (looked in ${repoSkills}, ${packaged})`);
17
24
  }
18
25
  export function loadSkills(root = skillsRoot()) {
19
26
  return readdirSync(root, { withFileTypes: true })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@areca-cms/skills",
3
- "version": "0.3.0",
3
+ "version": "0.5.0",
4
4
  "description": "Agent skills for Areca CMS: the site SDK and the MCP server. Installs into Claude Code, Codex, Cursor, Copilot, OpenCode, Gemini CLI and 20+ other agents.",
5
5
  "keywords": [
6
6
  "areca",
@@ -3,12 +3,12 @@ name: areca-mcp
3
3
  description: Connects an AI client to an Areca CMS site through its MCP server and uses its tools to write, edit, review and publish content. Covers the per-site connector URL, OAuth sign-in or personal keys, roles and go-live permission, the draft/ready/live workflow, field and Markdown formats, SEO, images, and every tool. Use when the user wants to connect Areca to an AI app or coding agent, or to create, update, approve, schedule or publish Areca CMS entries, upload images, or check what is live.
4
4
  license: MIT
5
5
  metadata:
6
- version: "0.3.0"
6
+ version: "0.5.0"
7
7
  ---
8
8
 
9
9
  # Areca MCP
10
10
 
11
- Every Areca site has its own remote MCP server. Through it an AI can read and write that site's content: entries, the media Library, releases and, for agency admins, content types. It edits CMS content and is separate from the `@areca-cms/site-sdk` website code (see the `areca-sdk` skill).
11
+ Every Areca site has its own remote MCP server. Through it an AI can read and write that site's content: entries, site content (single sections such as company info), the media Library, releases and, for agency admins, content types and site content structure. It edits CMS content and is separate from the `@areca-cms/site-sdk` website code (see the `areca-sdk` skill).
12
12
 
13
13
  ## Connect
14
14
 
@@ -20,8 +20,8 @@ Every Areca site has its own remote MCP server. Through it an AI can read and wr
20
20
 
21
21
  ## First calls (always)
22
22
 
23
- 1. `get_site_info`: returns your role, what you **cannot** do, the collections and the site's publishing mode.
24
- 2. `get_collection_schema({ collection })`: returns exact field formats, an example payload and SEO guidance. Call it before every first write to a collection.
23
+ 1. `get_site_info`: returns your role, what you **cannot** do, the collections, the site content sections (`globals`), the site's publishing mode, whether a deployment target is configured (`deploymentConfigured`) and, on a multilingual site, its `languages`.
24
+ 2. `get_collection_schema({ collection })`: returns exact field formats, an example payload and SEO guidance. Call it before every first write to a collection. For a site content section, `get_global({ global })` gives the same information.
25
25
 
26
26
  Tools your role can't use are not listed at all. If the user asks for one of those actions, explain who can do it and don't look for workarounds.
27
27
 
@@ -36,8 +36,9 @@ schedule_entry -> scheduled goes live at a set time (also publishes o
36
36
 
37
37
  - `status`: `draft` | `ready` | `scheduled` | `archived`. To answer "what is live" use the flags: `live` (on the production site now), `pendingRelease` (approved changes waiting for the next go live) and `editedSinceReady`.
38
38
  - Drafts are safe. Nothing changes the live site until an entry is marked ready **and** a go live happens.
39
+ - Publishing mode: `production` (go live deploys to the live site) or `demo` (go live builds a release that `areca pull` fetches; demo releases never reach visitors). Agency admins switch it with `set_publishing_mode`. A site that has ever gone live cannot switch to demo, and production needs a deployment target set in Settings › Deployment.
39
40
  - Only call `mark_ready`, `go_live`, `schedule_entry`, `rollback`, `delete_*` or `archive_entry` when the user explicitly asks.
40
- - Writes return a `version`. Pass it as `expectedVersion` on the next `update_entry`. On a version conflict, call `get_entry`, reapply the change and retry.
41
+ - Writes return a `version`. Pass it as `expectedVersion` on the next `update_entry` or `update_global`. On a version conflict, call `get_entry` (or `get_global`), reapply the change and retry.
41
42
  - Show the user the `previewUrl` that create and update return (it's signed and valid for about 1 hour). If the site has no production URL, preview isn't available.
42
43
 
43
44
  ## Roles
@@ -47,7 +48,7 @@ schedule_entry -> scheduled goes live at a set time (also publishes o
47
48
  | editor | read everything, create and edit drafts, upload images, edit alt text, preview |
48
49
  | owner | everything an editor can, plus `mark_ready`, `unpublish_entry`, `archive_entry`, `cancel_schedule`, `delete_entry`, `restore_revision`, `delete_asset` |
49
50
  | + go-live permission | `go_live`, `schedule_entry`, `rollback`, `cancel_build`. Granted per connection or key with "Allow going live" (owners and agency admins only). |
50
- | agency admin | everything above, plus `upsert_collection` and `delete_collection` (needs 2FA) |
51
+ | agency admin | everything above, plus `upsert_collection`, `delete_collection`, `upsert_global`, `delete_global`, `set_site_languages` and `set_publishing_mode` (needs 2FA) |
51
52
 
52
53
  ## Writing content
53
54
 
@@ -56,9 +57,21 @@ schedule_entry -> scheduled goes live at a set time (also publishes o
56
57
  - **Field values:** `image` and `reference` take ids, `date` is `YYYY-MM-DD`, `datetime` is ISO 8601 with an offset, `select` must match an option exactly, and `slug` is lowercase with dashes and unique. Date fields are content only and never schedule an entry.
57
58
  - **Clearing:** use `""` for a field or SEO text, `[]` for SEO lists and `false` for `noindex`/`nofollow`. Avoid `null` (`seo` rejects it). A key you leave out keeps its value.
58
59
  - **SEO on every new entry:** `seo.title` (50-60 chars), `seo.description` (140-160), `focusKeyphrase`, `summary` (2-3 sentences) and 3-5 `keyTakeaways`. Add `faq` only when the body really answers those questions.
59
- - **Schema:** if the site project has `areca.config.ts`, change the schema there and push it with the SDK rather than calling `upsert_collection`. `upsert_collection` replaces the whole field list.
60
+ - **Site content (globals):** single sections such as company info or the home page. Read one with `get_global({ global })` and change it with `update_global({ global, fields?, seo?, expectedVersion? })`. It is not a collection, so `create_entry` and `list_entries` do not apply. Its `id` (from `get_global`) works with `mark_ready`, `schedule_entry`, `cancel_schedule`, `list_revisions`, `restore_revision` and `get_preview_url`. Use `discard_global_draft` to go back to the ready values. `seo` is only accepted when the section has SEO on.
61
+ - **Schema:** check the first line of the site's `areca.config.ts`. If it is `// Generated by \`areca manifest pull\`.`, the schema is managed in the CMS: change it with `upsert_collection` or `upsert_global`, then run `areca manifest pull`. If the config is hand-written, the schema is in code: change `areca.config.ts` and push it with `areca manifest push`. Both ways replace the whole field list, so send every field.
60
62
 
61
- Full formats, the SEO object, limits and errors are in [references/content.md](references/content.md). Every tool with its inputs is in [references/tools.md](references/tools.md).
63
+ Full formats, the SEO object, limits and errors are in [references/content.md](references/content.md). Every tool with its inputs is in [references/tools.md](references/tools.md). Multilingual details are in [references/languages.md](references/languages.md).
64
+
65
+ ## Multilingual sites
66
+
67
+ Only when `get_site_info` returns `languages`. The main language is the fallback; each other language is written on its own.
68
+
69
+ 1. `get_site_info`: note `languages.main`, `languages.all` and each collection's `requiredLanguages`.
70
+ 2. `create_entry` or `update_entry` (or `update_global`) for the main language, with no `locale`.
71
+ 3. One `update_entry({ id, locale, fields, seo, slug, expectedVersion })` call per other language. Check `sharedFieldsUpdated` in each response: those fields changed in every language.
72
+ 4. `get_entry({ id })` and read `translations`. Fill any missing required fields until each language is `complete`.
73
+
74
+ `mark_ready` refuses an entry until every required language is complete. Only mark ready when the user asks. Details, the `translatable` rules and the errors are in [references/languages.md](references/languages.md).
62
75
 
63
76
  ## Errors
64
77
 
@@ -67,6 +80,8 @@ Tool errors come back as normal results with `isError: true` and a message that
67
80
  - `Validation failed`: call `get_collection_schema`.
68
81
  - `changed since you last read it`: call `get_entry` and retry.
69
82
  - `Only site owners…` or `Going live…`: tell the user who can do it.
83
+ - `is not one of this site's languages`: use a code from `get_site_info`. `This site has one language`: drop `locale`.
84
+ - A refusal from `mark_ready` or `schedule_entry` that names languages: fill in those languages with `update_entry` and `locale`.
70
85
  - `Something went wrong on the Areca server (ref …)`: nothing is confirmed saved. Retry once, then report the ref.
71
86
 
72
87
  Over HTTP, `401` means sign in again or reconnect. `403 mfa_required` means the agency admin must turn on 2FA. `429` means wait for `Retry-After` (120 requests/min per credential).
@@ -19,6 +19,10 @@ Unknown field keys are refused, and the error lists the valid ones. Entry data i
19
19
 
20
20
  **Clearing on update:** use `""` for fields and SEO text, `false` for `noindex`/`nofollow`, `[]` for `keyTakeaways`/`faq`/`about`, and an empty `name` for `author`. Don't use `null`: fields accept it, but `seo` rejects it. A key you leave out keeps its value.
21
21
 
22
+ ## Site content (globals)
23
+
24
+ A section has the same field types as a collection, except `slug`. Its fields can set `group`, a heading shown above the field in the CMS editor (not in the data). Collection fields cannot set `group`. A section stores one set of values, so there is no create and no list: read it with `get_global` and change it with `update_global`. `seo` is only accepted on a section that has SEO turned on; `get_global` shows whether it does. `get_global` returns `previewAvailable: true` only when the section has a `previewPath` and the site has a production URL.
25
+
22
26
  ## Rich text Markdown
23
27
 
24
28
  - Use `##` for sections and `###` or `####` for subsections. Other heading levels are clamped.
@@ -63,7 +67,10 @@ Unknown SEO keys are refused. There is no SEO-generation tool, so you write thes
63
67
  | `Could not import the file:` | Ask the user for a direct, public file link |
64
68
  | `Only site owners…` / `Going live…` / `Only agency admins…` | Tell the user who can do it, e.g. an owner presses Go live in the CMS |
65
69
  | `No entry with id…` (or asset/job/publication) | Use the list tools to find valid ids |
66
- | `No collection "…" on this site` | Use one of the listed keys (see `get_site_info`) |
70
+ | `No collection "…" on this site` | Use one of the listed keys (see `get_site_info`). Site content keys are not collections: use `get_global`. |
71
+ | `No site content "…" on this site` | Use one of the `globals` keys from `get_site_info`. Disabled sections are not listed to editors and owners. |
72
+ | `… has no SEO` | The section has SEO off, so drop `seo`. Ask an agency admin to turn SEO on if it is needed. |
73
+ | `… has no preview page` | Preview needs a `previewPath` on the section. An agency admin sets it. |
67
74
  | `Something went wrong on the Areca server (ref …)` | Nothing is confirmed saved. Retry once, then report the ref. |
68
75
 
69
76
  HTTP: `401` = token or key invalid, expired, revoked or for another site, so reconnect. `403 mfa_required` = the agency admin must enable 2FA. `429` = wait `Retry-After` seconds (120/min per credential, plus 600/min per client IP when the CMS trusts its proxy).
@@ -0,0 +1,86 @@
1
+ # Multilingual sites
2
+
3
+ A site can publish in several languages. A site with one language behaves as described in the rest of the skill, and none of the `locale`, `translations`, `missingLanguage` or `translatable` parameters appear. Use this file only when `get_site_info` returns `languages`.
4
+
5
+ ## Languages and the main language
6
+
7
+ `get_site_info` returns `languages`:
8
+
9
+ ```json
10
+ { "main": "nl", "all": ["nl", "en"], "names": { "nl": "Dutch", "en": "English" } }
11
+ ```
12
+
13
+ - `main` is the fallback. Visitors get it when a translation is missing, and it holds the shared base values.
14
+ - `all` is the display order and always includes `main`.
15
+ - Codes are BCP 47 (`nl`, `en`, `nl-BE`). Use the exact code from `all` in `locale`.
16
+
17
+ `set_site_languages({ main, all })` changes them. Agency admins only.
18
+
19
+ | Parameter | Behaviour |
20
+ | --- | --- |
21
+ | `main` | Required. Must be one of `all`. |
22
+ | `all` | Required. Every language, in display order, including `main`. At least one, at most the site limit. |
23
+
24
+ - Removing a language hides it: it stops shipping and leaves the editor, but its text stays in the entries and comes back if you add the language again.
25
+ - A site cannot go back to having no languages. To go back to one language, set `all` to the single code (the rest are hidden as above).
26
+ - Changing `main` deletes nothing. Entries and sections that are not complete in the new main language cannot be marked ready until they are. The result's `gaps` counts them, and the message says how many.
27
+
28
+ ## Writing one language per call
29
+
30
+ `create_entry`, `update_entry`, `update_global` and `update_asset_alt` take `locale`. Leave it out for the main language.
31
+
32
+ - `fields`, `seo` and `slug` apply to the language you name. A translation's `slug` is that language's own URL. Send `""` to fall back to the main slug.
33
+ - Fields that are not translatable are shared. Changing one in any language changes it in every language, and the response lists them in `sharedFieldsUpdated`. Check that list before you assume a write stayed in one language.
34
+ - By default `text`, `textarea`, `richtext` and `url` fields are per language. Other types (number, date, image, reference, select and so on) are shared. `get_collection_schema` shows `translatable` for each field, and `get_site_info` lists `translatableFields` per collection and section.
35
+
36
+ `update_entry` only changes the keys you send. Pass `expectedVersion` from `get_entry` as usual.
37
+
38
+ ## Checking translations
39
+
40
+ `get_entry` without `locale` returns the main language's values plus `translations`:
41
+
42
+ ```json
43
+ "translations": {
44
+ "en": { "complete": false, "missing": ["fields.summary"] }
45
+ }
46
+ ```
47
+
48
+ - `complete` is true when every required field has a value in that language.
49
+ - `missing` lists the required fields that are empty there.
50
+ - With `locale`, `get_entry` returns that language's values (slug and seo included) instead, and no `translations`.
51
+
52
+ `list_entries({ collection, missingLanguage: "en" })` returns only entries whose draft is not complete in that language.
53
+
54
+ `get_global({ global, locale })` and `get_preview_url({ id, locale })` work the same way. A preview link with `locale` opens that language's page.
55
+
56
+ ## Required languages
57
+
58
+ Each collection and section can require languages to be complete before it is marked ready. Set them with `requiredLanguages` (for example `["en"]`) on `upsert_collection` or `upsert_global`, or in `areca.config.ts`. `get_site_info` shows the current list per collection.
59
+
60
+ `mark_ready` and `schedule_entry` refuse an entry until every required language is complete. The error names the languages and the fields that are missing. Fill them in with `update_entry` and `locale`, then mark ready again. Only when the user asks.
61
+
62
+ ## Per-language routes
63
+
64
+ `upsert_collection` also takes `routes`, a route pattern per language, each with `$slug`. For example `{"nl": "/vacatures/$slug"}`. Languages that are not listed use `routePattern`. Patterns do not contain the language prefix, because the site adds it. Send `{}` to remove them all.
65
+
66
+ `routes` and `requiredLanguages` are ignored on a site without languages. For a site that syncs its schema from code, put these in `areca.config.ts` and push with `areca manifest push` rather than calling `upsert_collection`.
67
+
68
+ ## Translating with AI
69
+
70
+ There is no MCP tool for AI translation. The CMS editor's language bar offers "translate with AI", which fills empty fields from the main language. An agent that is asked to translate writes each language itself with `update_entry` and `locale`.
71
+
72
+ ## Multilingual workflow
73
+
74
+ 1. `get_site_info`: read `languages` (main and `all`), and each collection's `requiredLanguages` and `translatableFields`.
75
+ 2. `get_collection_schema({ collection })`: check which fields are `translatable`, and use the `translation` example if the response has one.
76
+ 3. `create_entry` or `update_entry` for the main language, with no `locale`.
77
+ 4. For each other language, one `update_entry({ id, locale, fields, seo, slug, expectedVersion })` call. Read `sharedFieldsUpdated` in each response.
78
+ 5. `get_entry({ id })` and check `translations`. Fill any missing required field, then repeat until every language is `complete`.
79
+ 6. Show the user the `previewUrl`, or call `get_preview_url({ id, locale })` to check one language. Mark ready only when the user asks.
80
+
81
+ ## Errors
82
+
83
+ - `This site has one language, so locale does not apply. Leave it out.`: remove `locale` from the call.
84
+ - `"xx" is not one of this site's languages (...)`: the error lists the codes the site has. Use one of them, or call `get_site_info`.
85
+ - `Only agency admins can change the site languages.`: tell the user an agency admin must change them.
86
+ - A mark-ready refusal for incomplete languages: fill in the named languages and fields, then retry.
@@ -6,19 +6,29 @@
6
6
 
7
7
  | Tool | Access | Inputs | Returns |
8
8
  | --- | --- | --- | --- |
9
- | `get_site_info` | all | none | `site` (name, slug, productionUrl, publishingMode), `you` (role, capabilities), `cannotDo[]`, `collections[]`, `guide`. **Call first.** |
10
- | `get_collection_schema` | all | `collection*` | Per-field key, type, required, format, options; example `fields` and `seo` payloads; SEO guide |
9
+ | `get_site_info` | all | none | `site` (name, slug, productionUrl, publishingMode, deploymentConfigured), `you` (role, capabilities), `cannotDo[]`, `collections[]`, `globals[]` (site content: key, label, enabled, fieldCount, seo, previewPath), `guide`. On a site with languages also `languages` (`main`, `all`, `names`) and, per collection and section, `requiredLanguages`, `translatableFields` and `routes`. **Call first.** |
10
+ | `get_collection_schema` | all | `collection*` | Per-field key, type, required, format, options (and `translatable` on sites with languages); example `fields` and `seo` payloads; SEO guide; `translation` example on sites with languages |
11
11
 
12
12
  ## Entries
13
13
 
14
14
  | Tool | Access | Inputs | Returns |
15
15
  | --- | --- | --- | --- |
16
- | `list_entries` | all | `collection*`, `status?` (draft, ready, scheduled, archived), `search?`, `limit?` (1-100, default 20), `offset?` | `items[]` (id, slug, status, live, pendingRelease, title, version), `total`, `nextOffset` |
17
- | `get_entry` | all | `id*`, `includePublished?` | `fields`, `seo`, `status`, `live`, `pendingRelease`, `editedSinceReady`, `version`. With `includePublished`, also `liveFields` and `approvedFields`. |
18
- | `create_entry` | all | `collection*`, `fields?`, `seo?` | New draft + `previewUrl` |
19
- | `update_entry` | all | `id*`, `fields?`, `seo?` (at least one), `expectedVersion?` | Updated draft + `previewUrl`. Keys you leave out keep their values. |
16
+ | `list_entries` | all | `collection*`, `status?` (draft, ready, scheduled, archived), `search?`, `limit?` (1-100, default 20), `offset?`, `missingLanguage?` (languages sites: only entries whose draft is not complete in that language) | `items[]` (id, slug, status, live, pendingRelease, title, version), `total`, `nextOffset` |
17
+ | `get_entry` | all | `id*`, `includePublished?`, `locale?` (languages sites) | `fields`, `seo`, `status`, `live`, `pendingRelease`, `editedSinceReady`, `version`. With `includePublished`, also `liveFields` and `approvedFields`. With `locale`, that language's values (slug and seo included) and `locale`. Without it on a languages site: the main language plus `translations` (`complete` and `missing` for each other language). |
18
+ | `create_entry` | all | `collection*`, `fields?`, `seo?`, `slug?`, `locale?` (languages sites) | New draft + `previewUrl`. `fields`, `seo` and `slug` apply to `locale` (default main). |
19
+ | `update_entry` | all | `id*`, `fields?`, `seo?`, `slug?` (at least one), `locale?` (languages sites), `expectedVersion?` | Updated draft + `previewUrl`. Keys you leave out keep their values. Languages sites: one language per call; `sharedFieldsUpdated` lists the non-translatable fields that changed in every language. |
20
20
  | `list_revisions` | all | `id*` | Revision id, note, createdAt, createdBy |
21
- | `get_preview_url` | all | `id*` | `{ url }`, signed, about 1 hour. Fails without a site production URL. |
21
+ | `get_preview_url` | all | `id*`, `locale?` (languages sites) | `{ url }`, signed, about 1 hour. Fails without a site production URL. |
22
+
23
+ ## Site content (globals)
24
+
25
+ Single sections such as company info or the home page. Editors and owners see enabled sections only; agency admins see all of them. The `id` returned here is the entry id for the workflow tools below.
26
+
27
+ | Tool | Access | Inputs | Returns |
28
+ | --- | --- | --- | --- |
29
+ | `get_global` | all | `global*` (key from `get_site_info`), `locale?` (languages sites) | `id`, `key`, `label`, `status`, `live`, `pendingRelease`, `version`, `editedSinceReady`, `previewAvailable`, `values` (rich text as Markdown, images as `{assetId,url,alt}`, references as `{entryId}`), `seo` (only with SEO on), `fields` (format of each field), `example` |
30
+ | `update_global` | all | `global*`, `fields?`, `seo?` (at least one; refused without SEO on the section), `locale?` (languages sites), `expectedVersion?` | Updated draft + `previewUrl`. Keys you leave out keep their values. |
31
+ | `discard_global_draft` | all | `global*` | Draft reset to the ready values, kept in history. Refused when the section was never ready. |
22
32
 
23
33
  ## Workflow
24
34
 
@@ -32,6 +42,8 @@
32
42
  | `restore_revision` | owner | `id*`, `revisionId*`, `expectedVersion?` | Copies a revision into the draft and returns `skippedFields`. Doesn't mark it ready. |
33
43
  | `schedule_entry` | go-live | `id*`, `publishAt*` (future ISO 8601 with offset), `timezone*` (IANA, e.g. `Europe/Amsterdam`) | Goes live at that time, together with the site's other ready changes |
34
44
 
45
+ `mark_ready`, `schedule_entry`, `cancel_schedule`, `list_revisions`, `restore_revision` and `get_preview_url` also take a site content section's `id`. `unpublish_entry`, `archive_entry` and `delete_entry` refuse it: change the section instead.
46
+
35
47
  ## Library (assets)
36
48
 
37
49
  | Tool | Access | Inputs | Returns |
@@ -39,7 +51,7 @@
39
51
  | `list_assets` | all | `search?`, `limit?` (1-100), `offset?` | assetId, filename, mimeType, width, height, alt, url |
40
52
  | `get_asset` | all | `id*` | Asset + `usageCount` |
41
53
  | `upload_asset_from_url` | all | `url*` (direct http(s) file link), `altText?`, `filename?` | Asset with `assetId` + `howToUse` |
42
- | `update_asset_alt` | all | `id*`, `altText*` (`""` clears) | Asset |
54
+ | `update_asset_alt` | all | `id*`, `altText*` (`""` clears), `locale?` (languages sites: alt text for that language) | Asset |
43
55
  | `delete_asset` | owner | `id*` | Refused while the asset is in use |
44
56
 
45
57
  ## Publishing
@@ -47,6 +59,7 @@
47
59
  | Tool | Access | Inputs | Returns |
48
60
  | --- | --- | --- | --- |
49
61
  | `get_release_status` | all | none | `publishingMode`, `live`, `demo`, `activeJob`, `pendingCount`, `pendingChanges[]` |
62
+ | `set_publishing_mode` | agency | `mode*` (`demo` or `production`) | `publishingMode`, `deploymentConfigured`. `demo`: `go_live` builds a release that `areca pull` can fetch without a deployment; demo releases never reach visitors. `production`: `go_live` deploys to the live site and needs a deployment target (application ID and health check URL, set in Settings › Deployment). Refused with a conflict when switching to `demo` after the site has ever gone live, or to `production` without a deployment target. The same mode changes nothing and writes no audit entry. Each change is audited with the MCP caller. |
50
63
  | `list_publications` | all | `limit?` (1-50, default 10) | Publications, newest first |
51
64
  | `get_build_job` | all | `jobId*` | Status, attempts, timing, error |
52
65
  | `go_live` | go-live | `note?` | Queues a build that publishes **all** ready changes and returns `publicationId` and `jobId`. Poll `get_build_job`. |
@@ -57,8 +70,18 @@
57
70
 
58
71
  | Tool | Access | Inputs | Effect |
59
72
  | --- | --- | --- | --- |
60
- | `upsert_collection` | agency | `key*`, `label*`, `routePattern*`, `fields*` (up to 100: `key*`, `label*`, `type*`, `required?`, `options?`, `collection?`, `description?`, `after?`), `enabled?` | Creates the collection or **replaces** its field list. Prefer `areca.config.ts` + `areca manifest push` when the site syncs its schema from code. |
73
+ | `upsert_collection` | agency | `key*`, `label*`, `routePattern*`, `fields*` (up to 100: `key*`, `label*`, `type*`, `required?`, `options?`, `collection?`, `description?`, `after?`, `translatable?` on languages sites), `enabled?`, `requiredLanguages?`, `routes?` (languages sites) | Creates the collection or **replaces** its field list. Prefer `areca.config.ts` + `areca manifest push` when the site syncs its schema from code. |
61
74
  | `delete_collection` | agency | `key*` | Deletes the collection and its entries. Destructive. |
75
+ | `upsert_global` | agency | `key*`, `label*`, `fields*` (as `upsert_collection`, plus `group?` heading; no `slug` type), `seo?`, `previewPath?` (e.g. `/about`, `""` removes it), `enabled?`, `requiredLanguages?` (languages sites) | Creates the site content section or **replaces** its fields, SEO setting, preview path and enabled flag. Keeps its content. |
76
+ | `delete_global` | agency | `key*` | Deletes the section. Its content is kept in the deleted-content archive. Destructive. |
77
+
78
+ ## Languages (agency)
79
+
80
+ | Tool | Access | Inputs | Returns |
81
+ | --- | --- | --- | --- |
82
+ | `set_site_languages` | agency | `main*` (must be in `all`), `all*` (every language in display order, including `main`) | `languages` (main, all, names) and `gaps`: entries and sections not complete in the new main language. Removing a language hides it and keeps its text. Languages cannot be turned off once set. |
83
+
84
+ On a site without languages none of the `locale`, `translations`, `missingLanguage`, `translatable` or `requiredLanguages` parameters appear, and their results are unchanged. See [languages.md](languages.md) for the workflow.
62
85
 
63
86
  ## Prompt
64
87