← Files Garchi CMSARCHIVED FILE
skills/garchi-manage-content/references/mcp-tools.md
16.5 KB · Oct 4, 2026 · 12:13 UTC
# Garchi MCP server reference
Server: `https://garchi.co.uk/mcp-oauth` (Streamable HTTP, OAuth 2.1 with PKCE
and dynamic client registration). A bearer-token variant is available at
`https://garchi.co.uk/mcp` for clients without OAuth support.
Argument names below match the tools' own schemas. Each tool still validates its
own input and returns a specific error naming the offending field — read that
error rather than guessing a different shape. Where no tool covers an operation,
the REST API may: <https://garchi.co.uk/docs/v2.openapi>.
`space_uid` is required by every space-scoped tool and comes from
`list-space-tool`.
## Safety annotations
Every tool declares MCP annotations, which your client may surface as approval
prompts. Summarised:
| Tool | Read-only | Idempotent | Destructive | Reaches the internet |
| --- | :-: | :-: | :-: | :-: |
| `get-garchi-cms-guide` | ✅ | ✅ | — | — |
| `list-space-tool` | ✅ | ✅ | — | — |
| `list-pages-tool` | ✅ | ✅ | — | — |
| `get-page-tool` | ✅ | ✅ | — | — |
| `list-section-template-tool` | ✅ | ✅ | — | — |
| `list-assets-tool` | ✅ | ✅ | — | — |
| `list-categories-tool` | ✅ | ✅ | — | — |
| `list-data-items-tool` | ✅ | ✅ | — | — |
| `get-data-item-tool` | ✅ | ✅ | — | — |
| `list-item-meta-tool` | ✅ | ✅ | — | — |
| `list-language-tool` | ✅ | ✅ | — | — |
| `create-page-tool` | — | — | — | — |
| `update-page-tool` | — | — | — | — |
| `create-section-tool` | — | — | — | — |
| `create-nested-section-tool` | — | — | — | — |
| `upsert-section-content-tool` | — | ✅ | — | — |
| `change-section-rank-tool` | — | ✅ | — | — |
| `change-nested-section-rank-tool` | — | ✅ | — | — |
| `create-section-template-tool` | — | — | — | — |
| **`update-prop-template-tool`** | — | ✅ | **✅** | — |
| **`delete-section-tool`** | — | ✅ | **✅** | — |
| `create-data-item-tool` | — | — | — | — |
| `update-data-item-tool` | — | — | — | — |
| `manage-category-tool` | — | — | — | — |
| `create-meta-for-item-tool` | — | — | — | — |
| `upload-asset-tool` | — | — | — | — |
| **`generate-image-tool`** | — | — | — | **✅** |
| `add-language-to-space-tool` | — | — | — | — |
| `list-social-channels-tool` | ✅ | ✅ | — | — |
| `list-social-posts-tool` | ✅ | ✅ | — | — |
| `get-social-post-tool` | ✅ | ✅ | — | — |
| `create-social-post-tool` | — | — | — | — |
| **`update-social-post-tool`** | — | ✅ | **✅** | — |
| `request-social-post-approval-tool` | — | ✅ | — | — |
The read-only tools are safe to call freely to orient yourself. The two
destructive content tools need explicit per-item confirmation.
`update-social-post-tool` is marked destructive because editing an approved post
withdraws its approval; say so before making that edit. `generate-image-tool`
reaches an external model and spends the account's image allowance.
## Orientation
**`get-garchi-cms-guide`** — no arguments. Returns the current content model,
field rules and tool ordering from the server. Call it first in any session that
will write content.
**`list-space-tool`** — no arguments. Returns every space the authenticated user
owns: `space_uid`, `name`, `agent_description`, `pages_count`, `items_count`,
`categories_count`, `section_templates_count`, `assets_count`, and
`front_end_url` when set. Start here. No tool creates a space — the user makes
one in the dashboard.
## Pages
**`list-pages-tool`** (`space_uid`) — every page in the space, with the
`page_id` that the section tools require, plus each page's `is_published`
state — false means it has unpublished changes waiting for the owner.
**`get-page-tool`** (`space_uid`, `slug`, `mode`, `lang?`) — one page with its
full section tree, section ids and current prop values. `slug` is the URL path
(`/`, `/about`), **not** an id. `mode` is required and is `draft` or `live`.
Unpublished changes only appear under `draft`; `live` returns the last published
version, or errors when the page has never been published. `lang` selects a
language variant.
**`create-page-tool`** (`space_uid`, `title`, `description`, `path`, `json_ld?`,
`agent_description?`) — creates the shell only, with no content. `title` and
`path` are unique within the space. `description` is the meta description;
`json_ld` is emitted as structured data. Counts against the plan's page limit.
**`update-page-tool`** (`id`, `space_uid`, plus any of `title`, `description`,
`path`, `json_ld`, `agent_description`) — page-level fields, including SEO. Only
the fields you send are written; sending one as `null` clears it, and `title`,
`description` and `path` cannot be emptied because the page requires them.
Changing `path` changes the page's URL, so check what links to it first.
## Sections
**`create-section-tool`** (`space_uid`, `page_id`, `section_template_id`) — adds
a top-level section instantiating a template. Returns the new section's `id`,
`order`, `page_id` and template details. Adds no content.
**`create-nested-section-tool`** — same, plus `parent_id`. Use this, not
`create-section-tool`, when placing a section inside another. Sections nest up
to 5 levels deep.
**`upsert-section-content-tool`** (`space_uid`, `page_id`, `section_id`,
`props[]`, `language_id?`) — sets prop values. Merges by prop template id:
props sent are written, props omitted are untouched. Each `props` entry takes
`id` (the prop template id) plus `value` or `asset_id` per the type contract in
the skill. Send every prop for a section in one call. An `asset_id` must belong
to the same space; one from another space is rejected.
Removing an image is an explicit `asset_id: null` on that prop, and blanking a
text prop is an explicit `value: ""` — omitting a prop leaves it in place,
because omitted props are untouched. A `select` prop can be blanked the same way,
and only a non-empty value is checked against `allowed_values`.
**This puts the page back into draft.** `mode=live` keeps serving the last
published version, so the live site stays intact — and the change is invisible
to visitors until the owner republishes. Say so when you finish.
**`change-section-rank-tool`** (`space_uid`, `page_id`, `section_id`,
`new_index`) — moves a top-level section to a new zero-based position.
**`change-nested-section-rank-tool`** — same, plus `parent_id`, for children.
**`delete-section-tool`** (`space_uid`, `section_id`, `page_id`) —
**destructive.** Removes the section, every nested section beneath it, and all
their prop values. On a published page it disappears from the live site. Section
ids come from `get-page-tool` with `mode=draft`. No MCP tool undoes this.
## Section templates and props
**`list-section-template-tool`** (`space_uid`) — every template with its props:
prop ids, keys, types and `allowed_values`. Read this before creating or filling
any section.
**`create-section-template-tool`** (`space_uid`, `name`, `description?`,
`agent_description?`, `props[]`) — a reusable blueprint. `name` should match the
component name in the codebase (`Hero`, `TeamCard`). `description` doubles as
the component import path used by the section renderer (`components/garchi/Hero`).
Each prop takes `key` (lowercase snake_case), `type`, and `allowed_values`
(comma-separated, required when `type` is `select`).
Prop types: `text`, `longtext`, `richtext`, `media`, `select`, `icon_lucid`,
`icon_hero`, `date`.
**`update-prop-template-tool`** (`space_uid`, `section_template_id`,
`prop_template_id`, plus any of `key`, `type`, `allowed_values`) —
**destructive.** A prop template belongs to a template that may be reused across
many pages, so changing `key` or `type` changes every section built from it and
can leave existing values invalid for the new type. Setting `type` to `select`
requires `allowed_values` in the same call. Renaming a key also breaks the
matching component prop until the code is updated.
## Data items
**`list-data-items-tool`** (`space_uid`) — items in the space.
**`get-data-item-tool`** (`space_uid`, `item_id`) — one item. `item_id` is
numeric.
**`create-data-item-tool`** (`space_uid`, `name`, `slug`, `categories[]`,
`detail_description`, plus optional `one_liner`, `agent_description`, `sku`,
`stock`, `price`, `images[]`, `scheduled_for_datetime`) — `slug` is unique in
the space. `detail_description` is the HTML body; `one_liner` is a one line
summary, max 1000 characters. `categories` needs at least one valid id.
`sku`/`stock`/`price` apply only to sellable items: `price` accepts decimals
(`19.99`) and `sku` is unique **within the space**, so the same sku may exist in
another space. `images` are base64 data URIs — `png`, `jpg`, `jpeg`, `webp` or
`svg+xml`, max 10 MB each — the first becoming the featured image; data items
never use space assets. Counts against the plan's item limit.
**The item is created as a draft** (`published: false`) and the content API
serves published items only, so it is not on the user's site yet. Pass
`scheduled_for_datetime` (`Y-m-d H:i`, in the future) to have Garchi publish it
automatically at that time; otherwise the user publishes it in the dashboard.
The result carries `published` and `scheduled_for` so you can confirm the state
and say so.
**`update-data-item-tool`** (`item_id`, `space_uid`, plus any creatable field) —
same fields, all optional. Only the fields you send are written, and they are
written as given: `stock: 0`, `price: 0` and an empty `one_liner` all land rather
than being ignored. An updated item stays a draft unless the user has already
published it; it does not publish itself.
**`list-categories-tool`** (`space_uid`) — categories in the space.
**`manage-category-tool`** (`space_uid`, `category`, `action`, `category_id?`) —
`action` is `create` or `update` only; `category_id` is required for `update`.
There is no category delete over MCP. Creating counts against the plan's
category limit.
**`list-item-meta-tool`** (`space_uid`) — the metadata keys and types already in
use across the space. Read this before adding metadata so similar items stay
consistent and the frontend can rely on the shape.
**`create-meta-for-item-tool`** (`item_id`, `key`, `type`, `value`) — one extra
field on an item. `key` is at most 50 characters. `value` is always stored as a
string; `type` says how to read it:
| Type | Value format |
| --- | --- |
| `string`, `url`, `email`, `color`, `icon_lucid`, `icon_hero` | plain string |
| `numeric` | numeric string, e.g. `"42"`, `"19.99"` |
| `date` | date string, e.g. `"2026-07-08"` |
| `array` | JSON-stringified array, e.g. `"[\"a\",\"b\"]"` |
| `object` | JSON-stringified object, e.g. `"{\"author\":\"Ada\"}"` |
## Assets
**`list-assets-tool`** (`space_uid`) — the complete asset list in one response,
so pick an id from it directly and never loop. Clients that support MCP UI also
show the user a gallery of the same assets; if the user picks some, their ids
arrive as a follow-up message.
Assets belong to the space that owns them: `upsert-section-content-tool` rejects
an `asset_id` from a different space.
**`upload-asset-tool`** (`space_uid`, `file_name`, `file_type`,
`file_raw_content?`, `agent_description?`) — `file_type` must be an allowed MIME
type (images, PDF, Office documents, plain text and CSV) and the `file_name`
extension has to match it. For text types pass raw text; for binary pass base64
or a data URI. Omit `file_raw_content` — or pass `UPLOAD_VIA_BROWSER` — to open
an upload window for the user and get a short-lived signed upload URL instead;
that is the right route for anything but small files. Rate-limited per user.
**`generate-image-tool`** (`prompt`, `space_uid`, `image_for`, `orientation`,
`data_item_id?`) — reaches an external model and **spends the account's monthly
AI image allowance, shared across all spaces**. Ask the user first.
`image_for: page` saves a reusable space asset and returns an `asset_id` for a
section's media prop. `image_for: data_item` requires `data_item_id` and sets
that item's main image. `orientation` is `landscape`, `portrait` or `square` —
match it to the slot. Prompt maximum 200 words; describe subject, style, colour
and composition, leave a clear area for any text overlay, and do not ask for
text inside the image.
## Languages
**`list-language-tool`** (`space_uid`) — languages configured on the space.
Every space starts with `en-US`.
**`add-language-to-space-tool`** (`space_uid`, `language_id`) — adds a language
by i18n code (`fr-FR`, `es-ES`). Prop values are then writable per language via
`upsert-section-content-tool`'s `language_id`.
## Social publishing
Drafting and approval requests only. No tool here approves, schedules, publishes,
retries, or edits or deletes a post that is live on a network — a person does
all of that in the dashboard. Full rules and examples:
[social-publishing.md](./social-publishing.md).
**`list-social-channels-tool`** (`space_uid`) — connected channels with
`channel_id`, `provider`, `account_name`, `status` and `usable`. Connecting a
channel is done in the dashboard.
**`create-social-post-tool`** (`space_uid`, `body`, `channel_ids[]?`, `media[]?`,
`source_type?`, `source_id?`) — creates a draft. `media` entries are
`{source: space_asset|data_item_image, id, alt_text?}` referencing existing
Garchi media; nothing is uploaded and URLs are not accepted. A post holds text
only, images, or one video.
**`update-social-post-tool`** (`space_uid`, `post_id`, plus any of `body`,
`channel_ids[]`, `media[]`) — `channel_ids` and `media` each replace the whole
list. Editing an approved or scheduled post withdraws its approval.
**`get-social-post-tool`** (`space_uid`, `post_id`) — the full post, per-channel
delivery status and recent activity.
**`list-social-posts-tool`** (`space_uid`, `status?`, `limit?`) — newest first,
optionally filtered by status.
**`request-social-post-approval-tool`** (`space_uid`, `post_id`) — checks the
post against each selected network's rules and hands it to a person. The last
step an agent can take.
Every social tool returns `publishing_allowance`. Credits are counted per space,
one per successful publish to one channel.
## Resources and prompt
The server also exposes MCP **resources**, useful when the task moves from
managing content to writing integration code. Load them on demand; they are not
needed for content operations:
| Resource | Contents |
| --- | --- |
| `garchi-cms-docs` | Garchi CMS features and content model |
| `garchi-api-docs` | The OpenAPI specification |
| `garchi-cms-node-sdk-resource` | Node SDK guide |
| `garchi-cms-php-sdk-resource` | PHP SDK guide |
| `garchi-cms-starter-kit-resource` | Starter-kit bootstrap commands |
There is also a `garchi-cms-assistant` prompt taking `tech_stack`
(`laravel`, `next`, `nuxt`, `node`, `php`, `other`) and an optional `goal`
(`continue`, `generate_code`, `troubleshoot`, `integrate`), which returns
guidance for that combination.
## What the server will not do
- Create a space.
- Publish anything. Page content writes put the page back into draft, and data
items are created and updated as drafts; both go live only when the owner
publishes them in the dashboard. Say what needs publishing when you finish.
- Delete a page, data item, category or section template.
- Restore anything. Garchi keeps automatic restore points for recent page,
section-template and data item changes, available from the content history in
the dashboard for a limited window, but no tool here rolls a change back.
- Approve, schedule, publish, cancel or retry a social post, edit or delete a
post that is live on a network, or connect a social channel.
- Upload video. `upload-asset-tool` accepts images, PDF, Office documents, plain
text and CSV; a video for a social post is uploaded in the dashboard.
## Safety model
- The server acts as the authenticated user. Their Garchi permissions bound
everything an agent can do; the plugin adds no privileges of its own, and a
space that is not theirs returns an authorization error.
- Read tools are free to call. Write tools change live content — read, write,
then verify.
- The two destructive tools need explicit per-item confirmation on top of
whatever approval your client asks for.
- Creating pages, items, categories and generated images is capped by the user's
plan. A limit error is a billing state, not a transient failure — stop and
report it instead of retrying.
- Tool calls are recorded against the user's account for their own audit and
troubleshooting, so retry loops are neither free nor invisible.
- No credentials belong in this repository, in a skill or in a manifest.
Authentication is the client's OAuth flow against Garchi.
SHA-256: 3ee2f42d0f482f1fd43b3ae42a0f44a5584a1a9373e8fa520cec67fc8ef26224