$ integrations

MCP tool reference

The hostdocs MCP server lets Claude or ChatGPT create, update, and publish pages — and build data-driven pages — without leaving the chat.

Connect

The server runs over stdio via npx. Add it to your assistant’s MCP config with an API token from your dashboard:

mcp.json
1{
2 "mcpServers": {
3 "hostdocs": {
4 "command": "npx",
5 "args": ["-y", "@hostdocs/mcp"],
6 "env": {
7 "HOSTDOCS_API_URL": "https://app.hostdocs.io",
8 "HOSTDOCS_API_TOKEN": "<your-token>"
9 }
10 }
11 }
12}
  • HOSTDOCS_API_URL — the control-plane URL (the dashboard app).
  • HOSTDOCS_API_TOKEN — your personal token, sent as a bearer token on every request.

Workspaces and sites

Most tools accept an optional accountId — omit it to act on your personal workspace, or pass an id from list_workspaces to act on an organization. The site-scoped tools (pages, collections, records) also accept an optional siteId: omit it to use the account’s default site, or pass an id from list_sites to target a specific site (each site is its own subdomain).

Page tools

list_workspaces

List the workspaces you can publish to — your personal account and any organizations you belong to. Use a returned id as accountId on other tools.

  • (none)
list_sites

List a workspace's sites — each is its own subdomain and owns its pages, layouts, collections, and domains. Use a returned id as siteId on the site-scoped tools.

  • accountId?
list_pages

List a site's hosted pages (path, status, last updated).

  • accountId? — workspace id; omit for personal
  • siteId? — omit for the account's default site
get_page

Get a page including its current published HTML — load an existing page to re-render as an editable preview before update_page.

  • id — the page id
  • accountId?
create_page

Publish a NEW page live at a path on a site's subdomain. Returns the live URL.

  • path — e.g. "/landing"
  • html — full self-contained document
  • title?
  • accountId?
  • siteId? — omit for the account's default site
update_page

Replace an existing page's HTML, publishing a new live version (prior version kept for rollback).

  • id — the page id
  • html — new full document
  • accountId?
delete_page

Delete a hosted page (takes it offline).

  • id — the page id
  • accountId?

Collection & record tools

Forms and collections share one typed-record engine; create_collection’s type picks the primary concept — form (public submissions) or collection (authored content, the default). Define a type, populate it with records, then bind a page to render them.

list_collections

List a site's collections and forms with their fields, slug field, and record counts. Pass type to list only one.

  • type? — 'form' or 'collection'; omit to list both
  • accountId?
  • siteId? — omit for the account's default site
create_collection

Create a collection or form (a user-defined data type, like a table) on a site. type 'form' makes it submittable; 'collection' (default) is authored content. Returns its id.

  • name — e.g. "Products" or "Contact"
  • type? — 'collection' (default) or 'form'
  • slug? — derived from name when omitted
  • accountId?
  • siteId? — omit for the account's default site
set_collection_fields

Define (or replace) a collection's field schema. Replaces the entire schema, so include every field each time.

  • id — the collection id
  • fields — the full field list
  • accountId?
set_collection_slug_field

Set which field's value becomes each record's URL slug. Required before binding a detail page. Pass null to clear.

  • id — the collection id
  • slugField — a field key, or null
  • accountId?
create_record

Add one record (object) to a collection. data is keyed by field key and must satisfy the schema.

  • collectionId
  • data — field values, e.g. { "name": "Widget", "price": 9 }
  • accountId?
  • siteId?
list_records

List a collection's records (cursor-paginated). Optional search over searchable fields.

  • collectionId
  • search?
  • limit? (max 200)
  • cursor?
  • accountId?
  • siteId?
search_records

Search a collection's records by a required full-text query over its searchable fields.

  • collectionId
  • search — the query
  • limit? (max 200)
  • cursor?
  • accountId?
  • siteId?
bind_page_to_collection

Publish a data-driven page bound to a collection. routeMode 'list' renders all records at basePath; 'detail' renders one record per slug.

  • collectionId
  • routeMode — 'list' or 'detail'
  • basePath — e.g. "/products"
  • html? — template with {{ token }} / {{#each}} placeholders
  • templateId? — use a saved template instead of inline html
  • title?
  • accountId?
  • siteId? — omit for the account's default site

Recommended workflow

The server instructs the assistant to preview before it publishes: build the full HTML as an artifact (Claude Artifacts / ChatGPT Canvas), iterate with you there, and only call create_page / update_page once you confirm. Nothing goes live without your go-ahead.

Walkthrough: a data-driven page, end to end

  1. create_collection — define the type, e.g. “Create a Products collection.”
  2. set_collection_fields — declare the shape (e.g. name (text, searchable), price (number), features (list of text)).
  3. set_collection_slug_field — pick the field whose value becomes each record’s URL (e.g. name), needed for a per-record detail page.
  4. create_record — add each product (one call per object).
  5. bind_page_to_collection — publish the page. Provide template HTML that uses {{ name }}, {{ price }}, and {{#each features}}…{{/each}}, then choose list (all products at /products) or detail (each product at /products/<slug>).
<!-- detail template bound to /products -->
<h1>{{ name }}</h1>
<p class="price">{{ price }}</p>
<ul>{{#each features}}<li>{{ this }}</li>{{/each}}</ul>
Prefer to do it by hand? Everything here maps to the REST API and the dashboard — see Data-driven pages.