# MCP tool reference _Category: AI agents and MCP_ Every tool of the HelpCenter.io MCP server at `https://mcp.helpcenter.io`: what it does, its arguments, the permission it needs, the REST API endpoint behind it and what it returns. To connect a client first, see [Connect an AI assistant to your help center](https://developers.helpcenter.io/content/connect-an-ai-assistant-to-your-help-center). For plans, sign-in and the security model, see [The HelpCenter.io MCP server](https://developers.helpcenter.io/content/the-mcp-connector-for-ai-agents). ## How to read this reference - **Permission** is the OAuth permission (scope) the tool needs. An API key covers the same ground: a **Read only** key holds `content.read` and `analytics.read`, a **Read & write** key adds `content.write`, and the team notes tools need a key created with team notes access (a **Read only** key can then read notes, a **Read & write** key can also reply and resolve). The design tools need a key created with design access, in the same way (a **Read only** key can then read the design, a **Read & write** key can also change and publish it). See [Scopes](https://developers.helpcenter.io/content/scopes). - **Kind** follows each tool's MCP annotations, which are in `tools/list`. **Read-only** tools change nothing (`readOnlyHint: true`). **Destructive** tools carry `destructiveHint: true`, so MCP clients can ask you before running them: they can change or remove something that already exists, or change what readers see. **Writes** marks the remaining tools, which only add something. - **Arguments are strict.** An argument a tool does not list is refused before any request is made, with `Input validation error` and `Unrecognized key(s) in object: ''`. The one argument the tables below do not repeat is `site_id`, which every tool except `helpcenter_list_sites` takes. See Choose the help center, below. - **Per-language fields** (`title`, `content` and `slug` of articles, `name` and `description` of categories) are objects keyed by language code, for example `{"en": "Getting started"}`. Keys must be two letters, optionally followed by a hyphen and two more letters, such as `en` or `de-AT`, so the tools refuse `zh-Hans`, `zh-Hant`, `fil` and `mul` today, although help centers can publish in those languages. A language your help center does not publish in is refused with `Unsupported language key "de" provided.` ### Choose the help center Every tool except `helpcenter_list_sites` takes this argument, in addition to the ones listed for it: | Argument | Type | Description | | --- | --- | --- | | `site_id` | integer | Optional. The id of the help center this call acts on, from `helpcenter_list_sites`. It applies to this call only: the server remembers nothing between calls. | - **One help center:** a connection that reaches one help center needs no `site_id`. - **Several help centers:** a call without `site_id` is refused, and nothing is changed. The text starts with `Error: This connection reaches more than one help center and this call did not say which` and lists the ids. - **An id the connection does not reach:** refused with `Error: This authorization does not cover help center 1234.` - **A pinned connection** (`?site=` on the server URL) acts on its help center without `site_id`, and refuses a different id before any request is made. - **An API key** acts on the help center it was created in, and refuses a different id before any request is made. See [Choose which help center a request acts on](https://developers.helpcenter.io/content/choosing-a-help-center). ### What tools return - Every successful call returns the API's response in `structuredContent`. Two design tools return a part of it instead: see `helpcenter_get_template_guide` and `helpcenter_get_template`. - Read tools take `response_format`: `markdown` (the default) puts a short readable summary in the text, without article bodies; `json` puts the full response in the text. `helpcenter_get_template_guide` is the exception: it always answers in markdown. - Write tools return the response as JSON text. The design write tools return a short summary as text instead: where the draft stands, the link to review it, and any results and warnings. - The six list tools (`helpcenter_search_articles`, `helpcenter_list_articles`, `helpcenter_list_categories`, `helpcenter_list_comments`, `helpcenter_list_change_sets`, `helpcenter_list_images`) wrap the API's list in `{total, count, page, per_page, total_pages, has_more, next, items}`. - A list page is cut to fit when it comes to more than 25,000 characters of text, or more than 5 MB in all. Article bodies become 300-character excerpts first (`content_truncated: true`); if that is not enough, the page keeps the longest prefix that fits, with `truncated: true` and a `truncation_reason` of `character_limit` or `response_size`. Every list page carries `next`, the `page` and `limit` that fetch the first item it did not return, or `null` when nothing is left. Follow `next` instead of asking for `page + 1`, which would skip the items that were cut. To go through a large help center, pass `include_content: false` to `helpcenter_list_articles` or `helpcenter_search_articles`: without bodies, far more articles fit in a page. - No reply is sent over 5.9 MB, the most one response can carry, whichever tool made it. A larger one is replaced by a tool error that starts `The reply to came to MB, over the 5.9 MB one HelpCenter.io connector response can carry, so it was not sent` and says to ask for less: a smaller `limit`, a filter, or one item at a time. Only the reply is withheld. A write whose answer was too large has already taken effect, so read before you repeat it. A list page whose first item alone is over 5 MB comes back as a tool error that names the item and gives the `page` and `limit` that continue past it. - A failed call returns `isError: true` and a text that says what went wrong and what to do, usually starting with `Error:`. The common ones are in the troubleshooting section of [Connect an AI assistant to your help center](https://developers.helpcenter.io/content/connect-an-ai-assistant-to-your-help-center). ## All tools | Tool | What it does | Permission | Kind | | --- | --- | --- | --- | | `helpcenter_search_articles` | Search published articles | `content.read` | Read-only | | `helpcenter_list_articles` | List every article, drafts included | `content.read` | Read-only | | `helpcenter_create_article` | Create an article, or update the one with the same `external_id` | `content.write` | Destructive | | `helpcenter_update_article` | Change an article, live | `content.write` | Destructive | | `helpcenter_get_article` | Read one article | `content.read` | Read-only | | `helpcenter_bulk_create_articles` | Create or update up to 50 articles | `content.write` | Destructive | | `helpcenter_delete_article` | Move an article to the Trash | content.write | Destructive | | `helpcenter_get_staged_changes` | Read the unpublished edits on an article | `content.read` | Read-only | | `helpcenter_stage_article_changes` | Stage an edit to a published article | `content.write` | Destructive | | `helpcenter_publish_staged_changes` | Publish staged edits | `content.write` | Destructive | | `helpcenter_discard_staged_changes` | Throw staged edits away | `content.write` | Destructive | | `helpcenter_list_article_versions` | List earlier published versions | `content.read` | Read-only | | `helpcenter_restore_article_version` | Put an earlier version back live | `content.write` | Destructive | | `helpcenter_list_change_sets` | List change sets, the releases being prepared | content.read | Read-only | | `helpcenter_get_change_set` | Read a change set: its items, schedule and readiness | content.read | Read-only | | `helpcenter_create_change_set` | Start an empty change set | content.write | Writes | | `helpcenter_update_change_set` | Rename a change set or change its description | content.write | Destructive | | `helpcenter_delete_change_set` | Delete a change set, not the work in it | content.write | Destructive | | `helpcenter_add_change_set_items` | Add articles and categories to a change set | content.write | Destructive | | `helpcenter_remove_change_set_item` | Take one item out of a change set | content.write | Destructive | | `helpcenter_publish_change_set` | Publish a change set now or at a set time | content.write | Destructive | | `helpcenter_unschedule_change_set` | Cancel a change set's scheduled publish | content.write | Destructive | | `helpcenter_get_change_set_status` | Follow a release until it is done | content.read | Read-only | | `helpcenter_list_images` | List the images uploaded through the API | content.read | Read-only | | `helpcenter_get_image` | Read one uploaded image | content.read | Read-only | | `helpcenter_upload_image` | Upload an image and get its URL | content.write | Writes | | `helpcenter_delete_image` | Delete an uploaded image | content.write | Destructive | | `helpcenter_list_categories` | List categories | `content.read` | Read-only | | `helpcenter_update_category` | Change a category or move it | `content.write` | Destructive | | `helpcenter_create_category` | Create a category | `content.write` | Writes | | `helpcenter_delete_category` | Delete a category and re-file what it holds | `content.write` | Destructive | | `helpcenter_reorder_categories` | Set the order of categories | `content.write` | Destructive | | `helpcenter_reorder_category_articles` | Set the order of articles in a category | `content.write` | Destructive | | `helpcenter_list_comments` | List reader comments, the moderation queue | `content.read` | Read-only | | `helpcenter_get_article_comments` | Read one article's comment threads | `content.read` | Read-only | | `helpcenter_moderate_comment` | Approve or unpublish a comment | `content.write` | Destructive | | `helpcenter_reply_to_comment` | Post a reply or a comment | `content.write` | Destructive | | `helpcenter_get_analytics_summary` | Traffic, ratings and activity for a period | `analytics.read` | Read-only | | `helpcenter_get_content_performance` | Views and ratings per article | `analytics.read` | Read-only | | `helpcenter_get_search_queries` | What readers searched for and did not find | `analytics.read` | Read-only | | `helpcenter_list_article_notes` | Read team notes on an article | `notes.read` | Read-only | | `helpcenter_reply_to_article_note` | Reply to a team note | `notes.write` | Writes | | `helpcenter_resolve_article_note` | Mark a team note resolved | `notes.write` | Destructive | | `helpcenter_get_template_guide` | Read what can be changed in the design, and how | `design.read` | Read-only | | `helpcenter_get_template` | Read the design draft: an outline, or one part in full | `design.read` | Read-only | | `helpcenter_list_template_themes` | List the themes, or describe one | `design.read` | Read-only | | `helpcenter_apply_template_theme` | Copy a theme onto the draft, whole or in part | `design.write` | Destructive | | `helpcenter_update_template_settings` | Change colours, fonts, brand, SEO and page settings | design.write | Destructive | | `helpcenter_add_template_components` | Add components to pages | design.write | Writes | | `helpcenter_update_template_components` | Change the settings of components | design.write | Destructive | | `helpcenter_move_template_components` | Move or reorder components | design.write | Destructive | | `helpcenter_remove_template_components` | Remove components | design.write | Destructive | | `helpcenter_update_template_region` | Style a page region: background, padding, border, alignment | design.write | Destructive | | `helpcenter_sync_template_region` | Share a region across pages, or let pages differ | design.write | Destructive | | `helpcenter_copy_template_region` | Copy a region to other pages | design.write | Destructive | | `helpcenter_add_template_css` | Add a block of custom CSS | design.write | Writes | | `helpcenter_update_template_css` | Change, move or switch off a block of custom CSS | design.write | Destructive | | `helpcenter_remove_template_css` | Delete a block of custom CSS | design.write | Destructive | | `helpcenter_add_template_script` | Add a script or snippet | design.write | Writes | | `helpcenter_update_template_script` | Change, move or switch off a script | design.write | Destructive | | `helpcenter_remove_template_script` | Delete a script | design.write | Destructive | | `helpcenter_set_template_navigation` | Replace the navigation menu | design.write | Destructive | | `helpcenter_publish_template` | Put the draft live | `design.write` | Destructive | | `helpcenter_discard_template_changes` | Reset the draft to the live design | `design.write` | Destructive | | `helpcenter_list_template_versions` | List the published versions of the design | `design.read` | Read-only | | `helpcenter_restore_template_version` | Load an earlier version into the draft | `design.write` | Destructive | | `helpcenter_list_sites` | List the help centers the connection can reach | `content.read` | Read-only | | **67 tools** | | | | ## Articles Article objects are the REST API's, with every language in per-language maps. See [Articles](https://developers.helpcenter.io/content/articles-api) for every field. ### `helpcenter_search_articles` Searches article titles and content by keyword. Calls `GET /v1/articles?search=`. Read-only. | Argument | Type | Description | | --- | --- | --- | | `query` | string | Required. The words to search for. | | `lang` | string | The language to search in: the help center's default language (the default) or one of its additional languages. Any other value is refused. | | `category_id` | integer | Only articles in this category. | | `include_content` | boolean | Default `true`. `false` returns each match without its body: see `helpcenter_list_articles`. | | `limit` | integer, 1-100 | Default `100`. Results per page. | | `page` | integer, 1 or more | Default `1`. | | `response_format` | `markdown` or `json` | Default `markdown`. | Returns the list envelope with full article objects in `items`, or, with `include_content: false`, the inventory entries described under `helpcenter_list_articles`. Search finds what an anonymous reader could find: published, public articles in public categories, in the language searched (in an additional language, only released translations). It returns every match, best first, up to the 1,000 best ranked: `total` counts them, and `limit` and `page`, or `next`, page through them. A `lang` the help center does not have is a tool error that says `lang: That language is not enabled on this help center.` To go through every article, drafts included, use `helpcenter_list_articles`. ### `helpcenter_list_articles` Lists every article that is not in the Trash: drafts, private and link-only articles included. Calls `GET /v1/articles`. Read-only. | Argument | Type | Description | | --- | --- | --- | | `category_id` | integer | Only articles in this category. | | `status` | `published` or `draft` | Only published articles, or only drafts. Both when omitted. | | `updated_since` | string | Only articles updated at or after this date or date-time, such as `2026-09-01` or `2026-09-01 14:30:00`. Send UTC: an offset such as `+02:00` is accepted, but not converted. A value that is not a date or a date-time is refused before any request is made. | | `order_by` | `views` | Most recently updated first when omitted. `views` orders by view count. | | `order_type` | `asc` or `desc` | Default `desc`. Direction for `order_by`. | | `lang` | string | Has no effect on a list: every article comes back with all its languages. | | `include_content` | boolean | Default `true`. `false` returns each article without its body: see below. | | `limit` | integer, 1-100 | Default `100`. | | `page` | integer, 1 or more | Default `1`. | | `response_format` | `markdown` or `json` | Default `markdown`. | With `include_content: false`, `items` holds an inventory instead of full articles, to decide what to read in full with `helpcenter_get_article`. Each entry has `id`, `external_id`, `title`, `slug`, `type`, `category_id`, `categories`, `published`, `visibility`, `views`, `has_staged_changes`, `staged_locales`, `staged_updated_at`, `updated_at` and `content_length`: the length of each language's body in characters, for example `{"en": 5231}`. For an incremental sync, pass the newest `updated_at` of your last pass as `updated_since`. The bound is inclusive, so that article comes back again: skip it by `id`. With `status: "draft"` the same call lists the drafts changed since then. ### `helpcenter_get_article` Reads one article, including whether staged edits are waiting on it (`has_staged_changes`, `staged_locales`, `staged_updated_at`). Calls `GET /v1/articles/{id}`. Read-only. | Argument | Type | Description | | --- | --- | --- | | `article_id` | integer | Required. | | `response_format` | `markdown` or `json` | Default `markdown`, a summary without the body. Use `json`, or `structuredContent`, for the content. | Returns `{status, article}`. The API counts this read against the 120-a-minute write limit. ### `helpcenter_create_article` Creates an article. With an `external_id` it is an upsert: the same key again updates the article it created. Calls `POST /v1/articles`. | Argument | Type | Description | | --- | --- | --- | | `title` | per-language object | Required. For example `{"en": "Close your account"}`. | | `content` | per-language object | The body, in HTML or Markdown (see `content_format`). | | `slug` | per-language object | Made from the title when omitted. | | `category_id` | integer, 0 or more | The primary category. `0` leaves the article uncategorized. | | `categories` | array of integers | Leave it out: a new article sent with `categories` is not saved. Create it with `category_id`, then put it in several categories with `helpcenter_update_article`. | | `type` | `article` or `faq` | Default `article`. | | `visibility` | `public`, `private` or `link_only` | Default `public`. `link_only` is not kept on create: see below. | | `published` | boolean | Default `false`: the article is saved as a draft. | | `external_id` | string, up to 191 characters | A stable key you own, such as a file path or a CMS id. | | `content_format` | `html` or `markdown` | Default `html`. Send `markdown` with Markdown content and it is converted to HTML; without it, the Markdown is stored as it is. | | `rehost_images` | boolean | Default `true` through the MCP server (the REST API's default is `false`). `false` keeps the original image addresses and leaves out the `images` report. | Returns `{status, action, article}`, plus `images` when you send `content` and leave `rehost_images` on. `action` is `created`, or `updated` when the `external_id` matched an article. This is the `images` report of an article with one embedded image and one image on a private address: ``` { "rehosted": 1, "reused": 0, "failed": [ { "src": "http://127.0.0.1:9/nothing.png", "reason": "the host resolves to a private or reserved address" } ], "failed_count": 1 } ``` - **Images are copied in.** Images in `content` that point to other websites, or are embedded as `data:` URLs, are copied into your help center's storage, up to 25 per article, and `images` reports what happened. An image that cannot be copied keeps its original address and is listed in `failed` with a reason. Send `rehost_images: false` to keep every original address. - **`link_only` is lost on create.** The article is saved `public`, with a share token. For a link-only article, create it as a draft (leave out `published`), then send `visibility: "link_only"` and `published: true` together in one `helpcenter_update_article` call, so readers never see it without the link. - **Use `external_id` for anything that may run twice.** Without it, every retry creates another article. ### `helpcenter_update_article` Changes an article. Calls `PATCH /v1/articles/{id}`. On a published article, readers see the change at once: stage it instead to review it first. | Argument | Type | Description | | --- | --- | --- | | `article_id` | integer | Required. | | `title`, `content`, `slug`, `category_id`, `categories`, `type`, `visibility`, `published`, `external_id`, `content_format`, `rehost_images` | as in `helpcenter_create_article` | All optional. Only what you send changes. `published: false` unpublishes the article. `categories` puts the article in exactly the categories you list, and it then reports `"category_id": -1`. | Returns `{status, article}`, plus `images` when you send `content` and leave `rehost_images` on. An `external_id` that already belongs to another article is refused with `That external_id already belongs to another article.` ### `helpcenter_bulk_create_articles` Creates or updates several articles in one request, for imports and migrations. Calls `POST /v1/articles/bulk`. | Argument | Type | Description | | --- | --- | --- | | `articles` | array of article objects | Required. Each item takes the arguments of `helpcenter_create_article`, `rehost_images` included. Send at most 50: see below. | Returns `{status, results, meta}`, where `meta` counts `total`, `created`, `updated` and `failed`. Each result is `{index, status, article, images}` with `status` `created` or `updated`, or `{index, status: "error", external_id, error}` for an item that failed (`external_id` when the item had one), with `error.code` one of `invalid_item`, `validation_error`, `invalid_argument`, `external_id_busy` and `persist_failed` (for example a new article sent with `categories`). One failed item does not stop the others. `rehost_images` is set per item, and `images` is left out of a result whose item has no `content` or sends `rehost_images: false`. All items of one call share a single time budget for downloading images. An article is saved even when some of its images could not be copied, so check `failed_count` in each result. A call with more than 50 items is refused before any request is made, with `Input validation error` and `Send at most 50 articles per batch; split a larger import into several batches`, and nothing is written. Send a larger import in batches of 50 or fewer, each item with an `external_id`. ### `helpcenter_delete_article` Moves an article to the help center's Trash. Calls `DELETE /v1/articles/{id}`. Destructive: readers can no longer reach the article, its URL stops resolving, and links to it from other articles break. Only a person can bring it back, from the dashboard's Trash: no tool restores it. A change set that holds the article refuses to publish until that item is removed. To take an article off the help center and keep it editable, send `helpcenter_update_article` with `published: false` instead. | Argument | Type | Description | | --- | --- | --- | | `article_id` | integer | Required. | Returns `{status, message, article}`, where `article` is `{id, deleted_at}`. An article that is not in this help center, or is already in the Trash, answers as not found. ## Staged changes and versions Staging lets an agent prepare an edit to a published article without readers seeing it. Staging an edit needs staged changes on the help center, part of the Catalyst plan; otherwise `helpcenter_stage_article_changes` is refused with `STAGING_UNAVAILABLE`. Staged edits are kept per language. See [Staged changes and versions](https://developers.helpcenter.io/content/staged-changes-api) for the objects and errors. ### `helpcenter_get_staged_changes` Reads the unpublished edits waiting on an article, with the `etag` to pass when you stage again. Calls `GET /v1/articles/{id}/staged`. Read-only. | Argument | Type | Description | | --- | --- | --- | | `article_id` | integer | Required. | | `locale` | string | One language. Every staged language when omitted. | | `response_format` | `markdown` or `json` | Default `markdown`. | Returns `{status, staged}`: one object when you name a `locale`, otherwise an array. Each has `article_id`, `locale`, `fields`, `shared`, `release_translation`, `etag`, `shared_etag`, `base_signature`, `updated_at` and `_links`. The API counts this read against the write limit. ### `helpcenter_stage_article_changes` Saves an edit to a published article without readers seeing it. Calls `PATCH /v1/articles/{id}/staged`. | Argument | Type | Description | | --- | --- | --- | | `article_id` | integer | Required. A published article. | | `locale` | string | Required. The language of this edit, one of your help center's language codes, for example `en` or `de`. | | `title`, `content`, `slug` | string | Plain strings for this language, not per-language objects. `content` is HTML. A new title does not change the URL: send `slug` to do that. | | `category_id`, `categories`, `visibility` | as in `helpcenter_create_article` | Shared by every language of the article. | | `release_translation` | boolean | `true` releases this language to readers when the edit is published. | | `etag` | string | The `etag` from your last read. When someone else changed the staged copy since, the call is refused with `STALE_ETAG` instead of overwriting their edit. | Returns `{status, staged}`. On an article that isn't published, the call is refused with `NOT_PUBLISHED`, and the agent is told to use `helpcenter_update_article`. ### `helpcenter_publish_staged_changes` Publishes staged edits, so readers see them. Calls `POST /v1/articles/{id}/staged/publish`. | Argument | Type | Description | | --- | --- | --- | | `article_id` | integer | Required. | | `locale` | string | One language. Every staged language when omitted. | | `force` | boolean | Publish even when the live article changed after the edit was staged, which is otherwise refused with `BASE_CHANGED`. The live change is lost. | Returns `{status, published_locales, article}`. If the article was unpublished in the meantime, the staged edit is still applied and the article stays unpublished. ### `helpcenter_discard_staged_changes` Throws staged edits away. The live article does not change. Calls `DELETE /v1/articles/{id}/staged`. Destructive: a discarded edit cannot be recovered. | Argument | Type | Description | | --- | --- | --- | | `article_id` | integer | Required. | | `locale` | string | One language. Every staged language when omitted. | Returns `{status, discarded, article}`, where `discarded` counts the staged languages removed. On an article with nothing staged, the tool answers not found: `This article has no staged changes to discard.` ### `helpcenter_list_article_versions` Lists an article's earlier published versions, newest first. Calls `GET /v1/articles/{id}/versions`. Read-only. | Argument | Type | Description | | --- | --- | --- | | `article_id` | integer | Required. | | `response_format` | `markdown` or `json` | Default `markdown`. The markdown summary shows every date as `archived unknown`; use `json` for `published_at`. | Returns `{status, versions}`, each `{id, locale, title, published_at, _links}`, at most 20 across all languages. HelpCenter.io keeps 20 versions per language. A version is recorded when staged changes are published or a version is restored, so an article that was never staged has none. This tool and the next need no Catalyst plan. The API counts this read against the write limit. ### `helpcenter_restore_article_version` Puts an earlier version back live. Calls `POST /v1/articles/{id}/versions/{versionId}/restore`. Destructive: readers see the restored version at once. | Argument | Type | Description | | --- | --- | --- | | `article_id` | integer | Required. | | `version_id` | integer | Required. An `id` from `helpcenter_list_article_versions`. | Returns `{status, article}`. The version it replaced is kept in the history, so you can restore it back. ## Change sets A change set is a named release. It groups staged edits to published articles, drafts that have never been published and category visibility changes, and publishes all of them together, now or at a scheduled time. It owns no content, so removing an item or deleting the change set never deletes the work in it. Change sets are part of the Catalyst plan, in early preview, and a help center can have at most 25 open ones. The plan, the early preview and every error are in [Change sets](https://developers.helpcenter.io/content/change-sets-api). The flow: stage edits with `helpcenter_stage_article_changes`, or write drafts with `helpcenter_create_article` and `published: false`; create the change set; add the items; check that it is ready with `helpcenter_get_change_set`; publish it; then poll `helpcenter_get_change_set_status` until `done` is true. ### `helpcenter_list_change_sets` Lists the help center's change sets, most recently changed first. Calls `GET /v1/change-sets`. Read-only. Check it before creating one: the release may already exist. | Argument | Type | Description | | --- | --- | --- | | `status` | `open`, `publishing`, `published`, `partially_published`, `failed` or `cancelled` | Only change sets in this state. `open` is what can still be edited and published; `partially_published` and `failed` can be fixed and published again. | | `limit` | integer | Items per page, 1 to 100. Default 100. | | `page` | integer | Default 1. | | `response_format` | `markdown` or `json` | Default `markdown`. | Returns `{total, count, page, per_page, total_pages, has_more, next, items}`. Each item is `{id, name, description, status, is_scheduled, scheduled_for, published_at, release_note, items_count, processed_items, total_items, created_at, updated_at}`. ### `helpcenter_get_change_set` Reads one change set: its items, its schedule and whether it is ready to publish. Calls `GET /v1/change-sets/{id}`. Read-only. Call it before publishing. | Argument | Type | Description | | --- | --- | --- | | `change_set_id` | integer | Required. | | `response_format` | `markdown` or `json` | Default `markdown`. | Returns `{status, change_set}`. The `change_set` has the fields of a list item plus `readiness`, `{counts, locales, articles, blockers, warnings, publishable}`, and `items`, each `{id, type, article_id, category_id, locale, variant, payload, applied, error}`. - **Item types.** `staged_version` is one staged language of a published article, `article_publish` is a draft the change set will publish, and `category_visibility` is a category's visibility change, with a `payload` of `{from, to}`. The `id` of an item is what `helpcenter_remove_change_set_item` takes. - **Blockers and warnings.** A blocker stops a publish: the article was deleted, or the live article changed after its edits were staged. A warning never does: an update in one language with no counterpart in another may be deliberate, so the agent is told to pass warnings on rather than decide. ### `helpcenter_create_change_set` Starts a new, empty change set. Calls `POST /v1/change-sets`. It is not idempotent: calling it twice makes two change sets with the same name, so the agent lists the open ones first. | Argument | Type | Description | | --- | --- | --- | | `name` | string | Required. Up to 120 characters, for example `October billing launch`. | | `description` | string | Up to 2,000 characters, for your team. Readers never see it. | Returns `{status, change_set}` with the new `id`. A help center that already has 25 open change sets is refused with `TOO_MANY_OPEN_CHANGE_SETS`. ### `helpcenter_update_change_set` Renames a change set or changes its description, also after it was published: the name is how a release is found in history. Calls `PATCH /v1/change-sets/{id}`. Destructive: it changes a change set that exists. The items are not touched. | Argument | Type | Description | | --- | --- | --- | | `change_set_id` | integer | Required. | | `name` | string | Up to 120 characters. | | `description` | string or `null` | Up to 2,000 characters. `null` clears it. | Returns `{status, change_set}`. ### `helpcenter_delete_change_set` Deletes a change set. Calls `DELETE /v1/change-sets/{id}`. Destructive: the grouping, the release note and any schedule, which is cancelled, are gone, and the API cannot bring them back. The staged edits, drafts and categories in it are not touched: they stay unreleased. To stop a scheduled release but keep it, the agent is told to use `helpcenter_unschedule_change_set` instead. | Argument | Type | Description | | --- | --- | --- | | `change_set_id` | integer | Required. | Returns `{status}`. A change set that is publishing is refused with `CHANGE_SET_NOT_OPEN`. ### `helpcenter_add_change_set_items` Adds articles and categories to an open change set, many in one call. Calls `POST /v1/change-sets/{id}/items`. Destructive: it changes a change set that exists. Adding something that is already in the change set is harmless. | Argument | Type | Description | | --- | --- | --- | | `change_set_id` | integer | Required. | | `article_ids` | array of integers, up to 500 | Articles to release. A published article is added with every language it has staged changes in, one item each, and must have some. A draft is added to be published by the change set. | | `category_ids` | array of integers, up to 500 | Categories whose visibility the change set changes when it publishes. | | `category_visibility` | `public`, `unlisted`, `private` or `team_private` | The visibility the categories get when it publishes. Default `public`: the usual case is a category built `unlisted` and revealed by the release. | Returns `{status, added, rejected, change_set}`. At least one of `article_ids` and `category_ids` must have an entry. - **A partly rejected batch is a normal result.** It answers `status: "partial"` (HTTP 207) and lists each refused id in `rejected`, as `{article_id or category_id, reason}`. One bad id never discards the others, so the agent reads `rejected` instead of assuming everything landed. A `reason` of `not_found` means the id is not in this help center. - **What `added` counts.** Items, so an article staged in two languages adds 2. To ship only some languages, remove the other items afterwards. - **Limits.** The change set must be open (`CHANGE_SET_NOT_OPEN` once it is publishing or published) and holds at most 500 items (`CHANGE_SET_FULL`). ### `helpcenter_remove_change_set_item` Takes one item out of an open change set. Calls `DELETE /v1/change-sets/{id}/items/{itemId}`. Destructive: it changes a change set that exists. The staged edit, draft or category the item pointed at is untouched and stops being part of this release. This is how to ship a release without one of its parts. | Argument | Type | Description | | --- | --- | --- | | `change_set_id` | integer | Required. | | `item_id` | integer | Required. The id of the item, from `helpcenter_get_change_set`, not an article or category id. | Returns `{status, change_set}` with the remaining items. A change set that is publishing or published is refused with `CHANGE_SET_NOT_OPEN`. ### `helpcenter_publish_change_set` Publishes every item of a change set together, now or at a scheduled time. Calls `POST /v1/change-sets/{id}/publish`. Destructive: readers see everything in the change set at once. Each staged edit archives the live version it replaces, so one article can be rolled back afterwards with `helpcenter_restore_article_version`. | Argument | Type | Description | | --- | --- | --- | | `change_set_id` | integer | Required. | | `scheduled_for` | string | A future time, in ISO 8601 with a time zone, for example `2026-10-01T09:00:00Z`. Omit to publish now. Calling the tool again with another time moves the schedule. | | `release_note` | string | Up to 500 characters, recorded with the release. | Returns `{status: "queued", change_set, status_url}`, or `{status: "scheduled", change_set}` when `scheduled_for` was given. - **Accepted is not done.** The API answers 202 either way. `queued` means publishing has started in the background and the articles are not necessarily live yet: the agent polls `helpcenter_get_change_set_status` until `done` is true, then reads each item's outcome. `scheduled` means the release is armed and nothing is live yet. - **Readiness is checked first.** A change set that is empty, has blockers, or has a `scheduled_for` in the past is refused with 422, and nothing is published. A change set that is already publishing or published is refused with `CHANGE_SET_NOT_OPEN`. ### `helpcenter_unschedule_change_set` Cancels a change set's scheduled publish. Calls `DELETE /v1/change-sets/{id}/schedule`. Destructive: it changes a change set that exists. The change set stays open with all its items, and nothing is published or lost. Calling it on a change set that is not scheduled is harmless. | Argument | Type | Description | | --- | --- | --- | | `change_set_id` | integer | Required. | Returns `{status, change_set}` with `is_scheduled` false. A change set that has already started publishing, or has published, is refused with `CHANGE_SET_NOT_OPEN`: it is too late to cancel. ### `helpcenter_get_change_set_status` Checks on a change set's release: the poll after `helpcenter_publish_change_set`. Calls `GET /v1/change-sets/{id}/status`. Read-only. | Argument | Type | Description | | --- | --- | --- | | `change_set_id` | integer | Required. | | `response_format` | `markdown` or `json` | Default `markdown`. | Returns `{status, change_set_status, done, processed_items, total_items, published_at, items}`, where each item is `{id, type, article_id, locale, variant, applied, error}`. - **Loop on `done`, not on the status name.** `done` is true once nothing more will happen without the agent (published, partially published, failed, or open and unscheduled), and false while the change set is publishing or waiting for its scheduled time. The agent waits a few seconds between polls. - **A partial or failed release.** When it finishes as `partially_published` or `failed`, each item's `error` says what went wrong. Fix that, then publish the change set again. ## Images These tools work on the images uploaded through the API, and so through the connector. Pictures added by hand in the article editor are a separate library: they are not listed, read or deleted here. Uploading is step one. Step two is writing the returned URL into an article's content as an `` with `helpcenter_create_article`, `helpcenter_update_article` or `helpcenter_stage_article_changes`. An `` that points at another host, written with one of the article tools, is copied into the help center's own storage when the article is saved, so an image that already has a public URL needs no upload. See [Images](https://developers.helpcenter.io/content/images-api). ### `helpcenter_list_images` Lists the images uploaded through the API, newest first. Calls `GET /v1/images`. Read-only. Use it to find an image uploaded earlier instead of uploading it again, or to check after an interrupted run. | Argument | Type | Description | | --- | --- | --- | | `limit` | integer | Items per page, 1 to 100. Default 100. | | `page` | integer | Default 1. | | `checksum` | string | The SHA-256 of a file's bytes, as hex. Finds that exact file. | | `response_format` | `markdown` or `json` | Default `markdown`. | Returns `{total, count, page, per_page, total_pages, has_more, next, items}`. Each item is `{id, url, filename, mime_type, size, checksum, alt_text, snippets, created_at}`. `alt_text` is always empty on a read: alt text belongs to the `` in the article, not to the image. ### `helpcenter_get_image` Reads one uploaded image: its public URL, type, size and checksum. Calls `GET /v1/images/{id}`. Read-only. | Argument | Type | Description | | --- | --- | --- | | `image_id` | integer | Required. | | `response_format` | `markdown` or `json` | Default `markdown`. | Returns `{status, image}`. An id that is unknown, belongs to another help center, or is a picture from the editor's own library answers as not found. ### `helpcenter_upload_image` Uploads an image, a screenshot, a diagram or an animated GIF, and returns a stable public URL. Calls `POST /v1/images`, as multipart form data. It only adds something. With `dedupe` on, the same bytes uploaded twice resolve to the one image, so a retry is safe. | Argument | Type | Description | | --- | --- | --- | | `data_base64` | string | Required. The file's bytes, base64-encoded. A `data:` URL is accepted too. | | `filename` | string | Required. For example `billing-settings.png`. It is stored and shown, and never used as a path. | | `mime_type` | `image/jpeg`, `image/png`, `image/gif` or `image/webp` | Optional: defaults to the `data:` URL's type, else the file name's extension. The API checks the bytes either way. | | `alt_text` | string, up to 255 characters | What the image shows, for readers who cannot see it. The agent is told to always send it. It goes into the returned snippet only: it is not stored with the image. | | `dedupe` | boolean | Default `true`. `false` makes a new copy even when the same bytes were uploaded before. | Returns `{status, reused, image}`, where `image.snippets` holds a ready `` tag (`html`) and its Markdown form (`markdown`), and `reused` is true when an identical image already existed. - **Formats and size.** JPEG, PNG, GIF (animated too) and WebP. SVG is refused, and the API checks the file's bytes, not its name. The hosted server takes at most 4 MiB decoded, because that is the size of one request it can receive; the API itself takes up to 10 MB. A larger file is refused before anything is sent, with advice to shrink it. Uploads are limited to 60 a minute. ### `helpcenter_delete_image` Deletes an uploaded image. Calls `DELETE /v1/images/{id}`. Destructive and irreversible: the file is removed from storage, there is no trash for images, and its URL stops working everywhere it is used. | Argument | Type | Description | | --- | --- | --- | | `image_id` | integer | Required. | | `force` | boolean | Delete even though articles still embed the image. Those articles then show a broken image, so the agent is told to decide that on purpose, not by default. | Returns `{status, deleted}`, where `deleted` is `{id, url}`. - **Refused while an article embeds it.** The API answers 409 and names up to 20 of those articles; the agent removes or replaces the image in them first, or repeats the call with `force`. The check reads article content as it is now: it does not see an edit that is staged but not yet published. ## Categories Category objects are `{id, parent, name, description, icon, position, privacy, created_at, updated_at}`. See [Categories](https://developers.helpcenter.io/content/categories-api). ### `helpcenter_list_categories` Lists every category of the help center. Calls `GET /v1/categories`. Read-only. | Argument | Type | Description | | --- | --- | --- | | `limit` | integer, 1-100 | Default `100`. | | `page` | integer, 1 or more | Default `1`. | | `response_format` | `markdown` or `json` | Default `markdown`. | ### `helpcenter_create_category` Creates a category, at the top level or inside another one. Calls `POST /v1/categories`. | Argument | Type | Description | | --- | --- | --- | | `name` | per-language object | Required. For example `{"en": "Billing"}`. Up to 190 characters per language. | | `description` | per-language object | Optional. | | `parent_id` | integer | A category of this help center. `0` or omitted makes a top-level category. | | `icon` | string, up to 190 characters | An icon identifier. | | `position` | integer, 0 or more | Order among its siblings, ascending. When omitted, the category goes after the ones you have ordered. | Returns `{status, category}`. When you leave out `position`, the response shows `"position": 0` although the category is stored after the others: list the categories to see the stored order. New categories are always public. To make one private, use the dashboard. ### `helpcenter_update_category` Renames a category, changes its description, icon or position, or moves it. Calls `PATCH /v1/categories/{id}`. | Argument | Type | Description | | --- | --- | --- | | `category_id` | integer | Required. | | `name`, `description` | per-language object | Optional. | | `parent_id` | integer | The new parent: a category of this help center, but not the category itself or one beneath it. `0` moves it to the top level. | | `icon` | string, up to 190 characters | Optional. | | `position` | integer, 0 or more | Order among its siblings. `0` puts it first. | Returns `{status, category}`. The tool cannot change a category's privacy. ### `helpcenter_delete_category` Deletes a category. Calls `DELETE /v1/categories/{id}`. Destructive. It never deletes articles: it re-files them. | Argument | Type | Description | | --- | --- | --- | | `category_id` | integer | Required. | | `on_orphan` | `refuse`, `uncategorize` or `reparent` | Default `refuse`: a category that still holds articles or subcategories is not deleted. `uncategorize` moves its articles to Uncategorized and its subcategories to the top level. `reparent` moves both up to the category's own parent. | Returns `{status, message, on_orphan, articles_moved, children_moved, trashed_articles_refiled, trashed_children_refiled, moved_to}`. A refused delete tells the agent what the category holds, for example `It holds 1 article.`, and asks it to choose `uncategorize` or `reparent`. ### `helpcenter_reorder_categories` Sets the order of many categories in one call. Calls `PUT /v1/categories/order`. | Argument | Type | Description | | --- | --- | --- | | `categories` | array of `{id, position}`, 1 to 500 items | Required. The categories in the order you want. Leave out `position` to use each entry's place in the list. | Returns `{status, message, updated_count, categories}`. ### `helpcenter_reorder_category_articles` Sets the order of the articles in one category. Calls `PUT /v1/categories/{id}/articles/order`. | Argument | Type | Description | | --- | --- | --- | | `category_id` | integer | Required. | | `articles` | array of `{id, position}`, 1 to 1,000 items | Required. Leave out `position` to use each entry's place in the list. Ids that are not in the category are skipped. | Returns `{status, message, updated_count, skipped_article_ids, order_visible, article_sort, article_sort_source, hint}`. Readers see this order only when the help center's category pages sort articles by Custom: check `order_visible`, and read `hint` when it is `false`. ## Comments Comment objects leave out the commenter's email address and IP address, and team notes never appear in these tools. See [Comments](https://developers.helpcenter.io/content/comments-api) for the fields. ### `helpcenter_list_comments` Lists reader comments across the help center, for example the ones waiting for approval. Calls `GET /v1/comments`. Read-only. | Argument | Type | Description | | --- | --- | --- | | `status` | `pending`, `published`, `unpublished`, `deleted` or `all` | Everything except deleted comments when omitted. `pending` is the moderation queue. | | `article_id` | integer | Only this article's comments. | | `lang` | string | A language the help center publishes in. | | `search` | string, up to 190 characters | Text the comment contains. | | `order` | `asc` or `desc` | Default `desc`, newest first. | | `limit` | integer, 1-100 | Default `25`. | | `page` | integer, 1 or more | Default `1`. | | `include_email` | boolean | Does not work today: leave it out. See below. | | `response_format` | `markdown` or `json` | Default `markdown`. | Returns the list envelope plus `status_counts`, the number of comments in each state. A call with `include_email: true` fails today, whatever the credential, so the tools cannot return email addresses. ### `helpcenter_get_article_comments` Reads one article's comments as threads, with each reply under the comment it answers. Calls `GET /v1/articles/{id}/comments`. Read-only. | Argument | Type | Description | | --- | --- | --- | | `article_id` | integer | Required. | | `status` | as in `helpcenter_list_comments` | Everything except deleted comments when omitted. | | `lang` | string | Only comments in this language. | | `order` | `asc` or `desc` | Default `asc`, oldest first. | | `include_email` | boolean | Does not work today, as in `helpcenter_list_comments`. | | `response_format` | `markdown` or `json` | Default `markdown`. | Returns `{status, article, comments, meta}`, with `meta.threads_count` and `meta.comments_count`. The whole conversation comes back in one call, without paging. ### `helpcenter_moderate_comment` Approves a comment, or unpublishes it to take it off the article. Calls `PATCH /v1/comments/{id}`. It cannot delete a comment. | Argument | Type | Description | | --- | --- | --- | | `comment_id` | integer | Required. | | `status` | `published` or `unpublished` | Required. `published` shows it to readers. | Returns `{status, message, comment}`. Approving a reply emails the author of the comment it answers, once, as approving it in the dashboard does. ### `helpcenter_reply_to_comment` Posts a reply to a comment, or a new comment on an article, in the name of the person behind the connection. Calls `POST /v1/articles/{id}/comments`. The comment is published at once. | Argument | Type | Description | | --- | --- | --- | | `article_id` | integer | Required. | | `comment` | string, 1 to 5,000 characters | Required. Plain text: HTML is shown as text, not as formatting. | | `parent_id` | integer | The comment to answer, on the same article. A new top-level comment when omitted. | | `lang` | string | The parent comment's language, else the help center's default, when omitted. | Returns `{status, message, comment}`. Calling it twice posts two comments: read the thread before retrying. ## Analytics The three analytics tools share a limit of 6 requests a minute per credential, on top of the API's other limits. Traffic, view and search figures are computed once a day, so asking again for the same period returns the same numbers; ratings, activity and totals are current. Over the limit, the agent is told not to retry. Without `from` and `to`, a report covers the last 7 days; a range can be at most 92 days. The fields are in [Analytics](https://developers.helpcenter.io/content/analytics-api). ### `helpcenter_get_analytics_summary` Visitors, searches, article views, ratings and your team's activity for a period, compared with the period before. Calls `GET /v1/analytics/summary`. Read-only. | Argument | Type | Description | | --- | --- | --- | | `from`, `to` | string, `YYYY-MM-DD` | The period, both days included. The last 7 days when omitted; `to` defaults to today. | | `lang` | string | Only this language. | | `response_format` | `markdown` or `json` | Default `markdown`. | Returns `{status, range, summary}`, with `summary.traffic`, `summary.ratings`, `summary.activity` and `summary.totals`. ### `helpcenter_get_content_performance` Views and ratings for each article that was viewed in the period. Calls `GET /v1/analytics/content`. Read-only. | Argument | Type | Description | | --- | --- | --- | | `from`, `to`, `lang` | as in `helpcenter_get_analytics_summary` | Optional. | | `sort` | `views_desc`, `views_asc` or `rating_asc` | Default `views_desc`. `rating_asc` puts the worst-rated first. | | `category_id` | integer | Only articles in this category. | | `limit` | integer, 1-100 | Has no effect today: every page holds 25 articles. | | `page` | integer, 1 or more | Default `1`. | | `response_format` | `markdown` or `json` | Default `markdown`. | Returns `{status, range, excludes_never_viewed, articles, meta}`. Articles nobody viewed in the period are not listed. ### `helpcenter_get_search_queries` What readers searched for, and which searches found nothing: a list of articles you have not written yet. Calls `GET /v1/analytics/searches`. Read-only. | Argument | Type | Description | | --- | --- | --- | | `from`, `to`, `lang` | as in `helpcenter_get_analytics_summary` | Optional. | | `limit` | integer, 1-50 | Default `20`. Rows per list. | | `response_format` | `markdown` or `json` | Default `markdown`. | Returns `{status, range, content_gaps, frequent_queries, common_terms, meta}`. The lists are the top entries only. ## Team notes Team notes are the private notes your team leaves on articles; readers never see them. Every call also checks that the person behind the credential still has access to team notes on the help center, and answers `notes_forbidden` when they do not. See [Team notes](https://developers.helpcenter.io/content/team-notes-api). ### `helpcenter_list_article_notes` Reads the open notes on an article, each tied to the passage it is about. Calls `GET /v1/articles/{id}/notes`. Read-only. | Argument | Type | Description | | --- | --- | --- | | `article_id` | integer | Required. | | `include_resolved` | boolean | Does not work today: `true` fails with `The request could not be accepted.` Leave it out. | | `lang` | string | Only notes in this language. | | `response_format` | `markdown` or `json` | Default `markdown`. | Returns `{status, article, notes, meta}`. Each note has `id`, `note`, `anchor` (`mark_id` and `quote`, the highlighted passage), `author`, `resolved`, `replies` and `_links`. `meta` has `threads_count`, `open_count` and `includes_resolved`. ### `helpcenter_reply_to_article_note` Replies to a note. The reply stays internal. Calls `POST /v1/articles/{id}/notes/{noteId}/replies`. | Argument | Type | Description | | --- | --- | --- | | `article_id` | integer | Required. | | `note_id` | integer | Required. The note thread to answer. | | `note` | string, 1 to 5,000 characters | Required. Plain text. | Returns `{status, message, note}`, the thread with the new reply in `replies`. Calling it twice posts two replies. ### `helpcenter_resolve_article_note` Marks a note as done. Calls `POST /v1/articles/{id}/notes/{noteId}/resolve`. | Argument | Type | Description | | --- | --- | --- | | `article_id` | integer | Required. | | `note_id` | integer | Required. | Returns `{status, message, id}`. ## Design The design tools work on the draft that the template editor opens. An agent edits the draft, a person reviews it in the template editor with a live preview, and visitors see nothing until `helpcenter_publish_template`. The tools call the design endpoints of the REST API: the design document, every operation and every error are in [Design API](https://developers.helpcenter.io/content/design-api). - **Two checks on every call.** The connection needs `design.read` or `design.write`, which `content.read` and `content.write` don't include, and the person behind the credential must be able to edit the design in the dashboard: an Owner, Admin or Editor. Without that access, the call is refused with `design_forbidden`. - **Help centers that use the template editor.** On a help center that hasn't switched to the template editor yet, every design tool is refused with `template_migration_required` and the link to its template editor. The agent is told not to retry and to pass the link on: switching is the owner's decision, made in the dashboard. - **One tool for each kind of edit.** Each tool that edits the draft applies one operation of `PATCH /v1/template/draft`, so an MCP client can ask you about the change it is about to make. The settings tool and the four component tools take a list of up to 50 entries, applied in order, all or nothing: when one is refused, nothing is saved, and the refusal names the entry by position, counting from 0. The other tools take one item. A field a tool does not list is refused before any request is made. The fields of every operation are under Operations in [Design API](https://developers.helpcenter.io/content/design-api). - **The `etag`.** The tools that need `design.write` take an optional `etag`: the draft's `etag` from the agent's last read or write. If the draft changed since, because someone saved in the template editor or another agent wrote to it, the call is refused with `stale_draft` and nothing changes. Without `etag`, the call applies to the draft as it is at that moment. - **Text is in the default language.** The tools set design texts in the help center's default language. Translations of design texts are made in the dashboard, and they stay with their components when an agent moves or copies them. ### `helpcenter_get_template_guide` Reads the customization guide: what can be changed in the design and how, built from the components and settings the API accepts. Calls `GET /v1/template/schema`. Read-only. | Argument | Type | Description | | --- | --- | --- | | `topic` | `overview`, `components`, `settings`, `theme`, `css`, `scripts` or `navigation` | Default `overview`: the model of pages, regions and components, every operation with an example, and an index of the components. | | `component_types` | array of strings, up to 8 | With the `components` topic: the component types to describe in full, for example `["Hero", "SearchBar"]`. The index of components when omitted. | Returns the guide as markdown, with the `guide` object of the API's response in `structuredContent`. It takes no `response_format`. What each topic holds is under Read the customization guide in [Design API](https://developers.helpcenter.io/content/design-api). The tool's description tells the agent to read the overview before its first design edit, and a component's settings before it adds or configures that component: a setting takes only the values the template editor offers. ### `helpcenter_get_template` Reads the design draft: where it stands, the link to review it in the template editor, and an outline of every page, or one part of the draft in full. Calls `GET /v1/template` for the outline and `GET /v1/template/draft` for a part. Read-only. | Argument | Type | Description | | --- | --- | --- | | `section` | `outline`, `document`, `brand`, `theme`, `meta`, `navigation`, `scripts`, `custom_css`, `page`, `region`, `component` or `translations` | Default `outline`. `document` is the whole draft, which can be large: read the part you need. | | `page` | `home`, `category`, `article`, `search`, `contact` or `notFound` | Required for the `page` and `region` sections. With `component`, it names the page when the id is on several pages. | | `region` | `header`, `hero`, `sidebar`, `main`, `footer` or `utility` | Required for the `region` section. | | `id` | string, up to 64 characters | Required for the `component` section: the component's id. With `scripts` or `custom_css`, one script or CSS block instead of all of them. | | `response_format` | `markdown` or `json` | Default `markdown`. | The outline returns `{status, template, outline}`. `template` says where the design stands, with the draft's `etag` in `template.draft.etag` and the link to review the draft in `template.urls.customizer`. `outline` lists every component with its `id`, its `type` and the settings that differ from its defaults. A part returns `{section, etag, data}`. A part that is too large for one answer, over 25,000 characters, comes back as a text that names the smaller parts to read, without `structuredContent`. If the help center has no draft yet, reading starts one from the live design. ### `helpcenter_list_template_themes` Lists the themes a help center can start from, or describes one of them. Calls `GET /v1/template/themes`, or `GET /v1/template/themes/{themeKey}` when you name a theme. Read-only. | Argument | Type | Description | | --- | --- | --- | | `theme` | string | A theme key, to describe that theme in full. Every theme when omitted. | | `response_format` | `markdown` or `json` | Default `markdown`. | Returns `{status, themes}`, each theme with its `key`, `name`, `tagline`, `summary`, `best_for`, palettes, fonts, density and `preview_image`. `current` is `true` for the theme the draft came from. With `theme`, it returns `{status, theme}`, which adds the theme's `description`, `screenshots`, `anatomy` (what each page is built from), `changed_sections` (the sections of the draft that applying the theme would change) and `sections` (every section you can apply). An unknown key is refused with `unknown_theme`, and the message lists the keys. ### `helpcenter_apply_template_theme` Copies a theme onto the draft: all of it, or only the sections you name. Calls `POST /v1/template/themes/{themeKey}/apply`. Destructive: each section it applies replaces that part of the draft. The live design does not change. | Argument | Type | Description | | --- | --- | --- | | `theme` | string | Required. A theme key from `helpcenter_list_template_themes`. | | `sections` | array of strings, 1 or more | The parts of the theme to take: any of `brand`, `theme.colors`, `theme.darkColors`, `theme.fonts`, `theme.radius`, `theme.density`, `pages.home`, `pages.category`, `pages.article`, `pages.search`, `pages.contact`, `pages.notFound`, `globals.navigation`, `globals.scripts`, `meta` and `customCss`. Every section when omitted, `brand` and `meta` included. | | `etag` | string | The draft's `etag` from the last read or write. | Returns `{status, applied, warnings, template}`. `applied` names the `theme` and the `sections` that were applied, and `template` carries the draft's new `etag`. - **Component ids change.** Applying a page replaces its components, with new ids, so the agent reads the draft again before it edits them. Applying `customCss` replaces your custom CSS blocks. - **Without `sections`, the draft also takes the theme's `brand` and `meta`:** the theme's placeholder name and tagline instead of yours, no logo or favicon, and the theme's SEO title and description. To give the current design a theme's look and keep its layout, apply only `theme.colors`, `theme.darkColors`, `theme.fonts`, `theme.radius` and `theme.density`. See Apply a theme in [Design API](https://developers.helpcenter.io/content/design-api). ### `helpcenter_update_template_settings` Changes document-level settings in the draft: theme colours (light and dark), fonts, corner radius and density; the brand (name, logo, favicon); meta and SEO; and per-page settings such as a page's layout or how a category page lists its articles. Calls `PATCH /v1/template/draft` with the `set` operation. Destructive: it overwrites settings that exist. The live design does not change. | Argument | Type | Description | | --- | --- | --- | | `settings` | array of objects, 1 to 50 items | Required. Each has a `path` and its new `value`: `theme.colors.primary` and `"#635bff"`, or a whole group such as `theme.colors` and an object. `null` clears a nullable setting. The paths and the values each accepts are in the `settings` topic of the guide, and anything else is refused with the list of what is accepted. | | `etag` | string | The draft's `etag` from the last read or write. | Returns `{status, results, warnings, template}`: `results` says what each entry did, with the `id` of anything new, and `template` carries the draft's new `etag`. - **Colours.** They take hex, `rgb()` or `hsl()`, stored as hex. The agent is told to set `theme.darkColors` alongside `theme.colors` so dark mode stays readable. - **Images.** `brand.logoAssetId` and `brand.faviconAssetId` take `{"source_url": "https://…"}`: the image is copied onto the help center. - **Regions.** A region's own styling has its own tool, `helpcenter_update_template_region`. ### `helpcenter_add_template_components` Adds components to pages of the draft: a `Hero`, a `CategoryGrid`, `FeaturedArticles`, `Faqs`, `RichText`, a `CustomHtml` block, a `Container`. Calls `PATCH /v1/template/draft` with the `add_component` operation, once per entry. It only adds. The live design does not change. | Argument | Type | Description | | --- | --- | --- | | `components` | array of objects, 1 to 50 items | Required. Each has a `type` and where it goes: a `page` and `region` (`header`, `hero`, `sidebar`, `main`, `footer` or `utility`), or a `parent_id` to put it inside a Hero or Container. It may also have `config` (settings by name), `index` (a 0-based position; omit to append) and `id` (an id of your choosing). | | `etag` | string | The draft's `etag` from the last read or write. | Returns `{status, results, warnings, template}`: `results` says what each entry did, with the `id` of anything new, and `template` carries the draft's new `etag`. - **All or nothing.** The entries are applied in order. When one is refused, nothing is saved, and the refusal names the entry by position, counting from 0. - **Settings first.** The agent reads a component's settings in the `components` topic of the guide before setting them. Omitted settings keep their defaults, and a value outside the editor's options is refused. - **Containers in one call.** Give a container an `id` of your own and name it as `parent_id` in the later entries. A new Hero comes with a SearchBar inside it. ### `helpcenter_update_template_components` Changes the settings of components that are already in the draft: a heading, a variant, a column count, a `CustomHtml` block's markup. Calls `PATCH /v1/template/draft` with the `update_component` operation, once per entry. Destructive: it overwrites settings that exist. The live design does not change. | Argument | Type | Description | | --- | --- | --- | | `components` | array of objects, 1 to 50 items | Required. Each has the `id` of a component, as the draft reports it, and a `config` of the settings to change. Settings are merged: name only the ones to change, and `null` resets one to its default. Add a `page` when the id exists on several pages of an unsynced region. | | `etag` | string | The draft's `etag` from the last read or write. | Returns `{status, results, warnings, template}`: `results` says what each entry did, with the `id` of anything new, and `template` carries the draft's new `etag`. - **Synced regions.** In a region every page shares (the header and footer usually are), the change reaches every page. One whose pages differ is refused until the agent chooses with `helpcenter_sync_template_region`. - **All or nothing.** When one entry is refused, nothing is saved, and the refusal names the entry by position, counting from 0. ### `helpcenter_move_template_components` Reorders or moves components within their page: to another position among their siblings, to another region, into a Hero or Container, or out to the region's top level. Calls `PATCH /v1/template/draft` with the `move_component` operation, once per entry. Destructive: it changes the draft. The live design does not change. | Argument | Type | Description | | --- | --- | --- | | `components` | array of objects, 1 to 50 items | Required. Each has the `id` of a component and, optionally, a `region` on the same page, a `parent_id` (a container's id, or `null` for the region's top level) and an `index` (0-based; counted after the component is lifted out). Anything omitted keeps the component where it is, so `{id, index}` alone reorders it among its siblings. Add a `page` when the id exists on several pages of an unsynced region. | | `etag` | string | The draft's `etag` from the last read or write. | Returns `{status, results, warnings, template}`: `results` says what each entry did, with the `id` of anything new, and `template` carries the draft's new `etag`. - **Synced regions.** Moved into a synced region, a component reaches every page, so the move is refused while another page still holds its own copy; the error says how to proceed. To put a component on another page, add it there with `helpcenter_add_template_components`. ### `helpcenter_remove_template_components` Removes components from the draft, with everything nested inside them. Calls `PATCH /v1/template/draft` with the `remove_component` operation, once per entry. Destructive. Visitors keep seeing a removed component until the draft is published; to undo a removal, add the component again, or discard every unpublished change with `helpcenter_discard_template_changes`. | Argument | Type | Description | | --- | --- | --- | | `components` | array of objects, 1 to 50 items | Required. Each has the `id` of a component, and a `page` when an unsynced region holds the id on several pages. | | `etag` | string | The draft's `etag` from the last read or write. | Returns `{status, results, warnings, template}`: `results` says what each entry did, with the `id` of anything new, and `template` carries the draft's new `etag`. In a synced region the component goes from every page. ### `helpcenter_update_template_region` Styles one region's wrapper on one page: its background, padding, bottom border and alignment. Calls `PATCH /v1/template/draft` with the `update_region` operation. Destructive: it overwrites styling that exists. The live design does not change. | Argument | Type | Description | | --- | --- | --- | | `page` | `home`, `category`, `article`, `search`, `contact` or `notFound` | Required. | | `region` | `header`, `hero`, `sidebar`, `main`, `footer` or `utility` | Required. | | `config` | object | Required. `background` (hex, or `var(--hc-color-primary)` to follow the theme), `padding` (`compact`, `standard` or `tall`), `borderBottom` (boolean) and `align` (`left` or `center`). `null` resets one, and keys left out keep their value. | | `etag` | string | The draft's `etag` from the last read or write. | Returns `{status, results, warnings, template}`: `results` says what each entry did, with the `id` of anything new, and `template` carries the draft's new `etag`. - **Themes can outrank it.** Some themes ship custom CSS that paints a region itself, and that CSS wins over this setting. When the draft's outline marks the region as laid out by custom CSS, the agent is told to restyle it with `helpcenter_add_template_css` instead. ### `helpcenter_sync_template_region` Makes a region one shared copy on every page, or lets each page keep its own. Calls `PATCH /v1/template/draft` with the `sync_region` operation. Destructive: enabling replaces the other pages' copies. The live design does not change. | Argument | Type | Description | | --- | --- | --- | | `region` | `header`, `hero`, `sidebar`, `footer` or `utility` | Required. Every region but `main` can be shared. | | `enabled` | boolean | Required. `true` makes one region shared by every page. `false` lets pages differ. | | `source_page` | `home`, `category`, `article`, `search`, `contact` or `notFound` | When enabling, the page whose version every page takes. Default `home`. | | `etag` | string | The draft's `etag` from the last read or write. | Returns `{status, results, warnings, template}`: `results` says what each entry did, with the `id` of anything new, and `template` carries the draft's new `etag`. - **Defaults.** The header and footer are synced by default: one region mirrored to all six pages under the same component ids. `enabled: false` unsyncs it, and each page keeps its own copy under the same ids, so later edits name the page. - **Enabling.** Every page takes `source_page`'s version, translations included, replacing the other pages' copies wherever they differ. An edit to a synced region whose pages differ is refused until the agent runs this, either way. ### `helpcenter_copy_template_region` Copies one page's version of an unsynced region onto other pages, once, translations included. Calls `PATCH /v1/template/draft` with the `copy_region` operation. Destructive: each target page's region is replaced. The pages stay independent afterwards; to keep them identical, sync the region with `helpcenter_sync_template_region` instead. The live design does not change. | Argument | Type | Description | | --- | --- | --- | | `region` | `header`, `hero`, `sidebar`, `footer` or `utility` | Required. | | `from_page` | `home`, `category`, `article`, `search`, `contact` or `notFound` | Required. The page to copy from. | | `to_pages` | array of pages | Required. The pages that receive the copy. | | `etag` | string | The draft's `etag` from the last read or write. | Returns `{status, results, warnings, template}`: `results` says what each entry did, with the `id` of anything new, and `template` carries the draft's new `etag`. ### `helpcenter_add_template_css` Adds a labelled block of custom CSS, to restyle components, regions or the whole help center beyond what the settings offer. Calls `PATCH /v1/template/draft` with the `add_css` operation. It only adds. The live design does not change. | Argument | Type | Description | | --- | --- | --- | | `css` | string | Required. The CSS. | | `label` | string | A name for the block, for example `Cards · hover lift`. | | `enabled` | boolean | Default `true`. `false` keeps the block without applying it. | | `index` | integer | Position among the blocks, which apply in order and the later one wins. Omit to append. | | `id` | string | An id of your choosing. Omit and one is generated, and returned. | | `etag` | string | The draft's `etag` from the last read or write. | Returns `{status, results, warnings, template}`: `results` says what each entry did, with the `id` of anything new, and `template` carries the draft's new `etag`. - **Scoped for you.** The CSS is scoped to the help center automatically. A component is targeted with `[data-hc-instance-id=""]` and every component of a type with `[data-hc-component-type="Hero"]`; the `css` topic of the guide lists the other hooks. `@import` and `javascript:` URLs are stripped. - **Dark mode and contrast.** The agent is told to use `var(--hc-color-*)` instead of literal colours so dark mode keeps working, and to keep text at 4.5:1 contrast. ### `helpcenter_update_template_css` Changes one custom CSS block: replaces its CSS, renames it, switches it on or off, or moves it in the order. Fields left out keep their value. Calls `PATCH /v1/template/draft` with the `update_css` operation. Destructive: it overwrites a block that exists. The live design does not change. | Argument | Type | Description | | --- | --- | --- | | `id` | string | Required. The block, as the draft reports it. | | `css` | string | The new CSS, replacing the block's. | | `label` | string | A name for the block. | | `enabled` | boolean | `false` shows the design without the block and keeps it to switch back on. | | `index` | integer | Move the block to this 0-based position. | | `etag` | string | The draft's `etag` from the last read or write. | Returns `{status, results, warnings, template}`: `results` says what each entry did, with the `id` of anything new, and `template` carries the draft's new `etag`. - **A theme's blocks are yours too.** They are edited in the dashboard, under Advanced, Custom CSS. To change how a theme looks, the agent is told to prefer a block of its own with `helpcenter_add_template_css`, which comes later and wins. ### `helpcenter_remove_template_css` Deletes one custom CSS block from the draft. Calls `PATCH /v1/template/draft` with the `remove_css` operation. Destructive. To see the design without the block first, switch it off with `helpcenter_update_template_css` and `enabled: false` instead. The live design does not change. | Argument | Type | Description | | --- | --- | --- | | `id` | string | Required. The block, as the draft reports it. | | `etag` | string | The draft's `etag` from the last read or write. | Returns `{status, results, warnings, template}`: `results` says what each entry did, with the `id` of anything new, and `template` carries the draft's new `etag`. ### `helpcenter_add_template_script` Adds a script or snippet to the help center's pages: an external script (`src`), inline JavaScript (`inlineBody`), or raw HTML such as a vendor snippet or a `` verification tag (`htmlBody`), at the start or end of `` or ``. Calls `PATCH /v1/template/draft` with the `add_script` operation. It only adds. The live design does not change. | Argument | Type | Description | | --- | --- | --- | | `position` | `headStart`, `headEnd`, `bodyStart` or `bodyEnd` | Required. Where it is emitted. | | `src` | string | An external script URL, https only. Exactly one of `src`, `inlineBody` and `htmlBody`. | | `inlineBody` | string | JavaScript source, without `