# SiteForge — Agent Guide

You are talking to a **SiteForge** MCP server. SiteForge builds and hosts
static websites ("subsites"). Using the MCP tools below you can create a new
site, apply a template, add pages, and build/publish it.

## Connect

- **MCP endpoint (JSON-RPC over HTTP):** `https://fedcanvas.be/mcp/rpc`
- **Machine-readable manifest:** `https://fedcanvas.be/.well-known/mcp.json`
- **Auth:** send a bearer token in the `Authorization: Bearer <token>` header (ask a SiteForge operator to issue one).

## Generate a new site (recommended workflow)

1. `list_site_templates` — see the available starting points.
2. `create_site` — create a draft subsite (you supply a `sitekey`).
3. `apply_site_template` — apply a chosen template to the new subsite.
4. `build_site` — build & publish it; the result includes the live URL.

Use `get_subsite` / `get_subsite_inventory` to inspect state along the way.

> **No account yet?** `create_site` also works anonymously: pass a
> `captcha_token` to mint a ghost-owned DRAFT and get back a single-use
> claim credential (`claim_method` `cookie_token` returns it inline,
> `email_link` emails it to `claim_email`). The draft is publish-locked
> until a registered user redeems the credential to adopt it — or is
> auto-claimed on first registration. Unclaimed drafts are
> garbage-collected after their retention deadline.

## Reuse this later (so the user can just say "siteforge")

Persist this server in your MCP client under the name **`SiteForge`** (endpoint
`https://fedcanvas.be/mcp/rpc`). Because auth is OAuth with token storage, you only connect + authorize
once. After that the user does not need to give the domain again — when they say
something like _"generate a new site on siteforge"_, resolve
"SiteForge" to this already-connected server and call its tools directly.

## All available tools

- **`read_datagroup`** — Reads SiteForge data items by id, or filters a datagroup by a field value.
- **`test_ping`** — Test fixture for plugin discovery - returns pong.
- **`generate_theme_design_from_prompt`** — Synthesizes a complete, WCAG-harmonized design token set from a natural language brand description and compiles tokens.css.
- **`report_environment`** — Declare the client execution environment; the server acknowledges and confirms the floor tier is always available.
- **`set_design_context`** — Stores a subsite's PRODUCT.md or DESIGN.md design context markdown, and/or its WCAG conformance target (wcag_target: '2.1 AA' | '2.2 AA' | '2.2 AAA' — an OWNER decision: ask your user, never pick silently).
- **`get_theme_design_tokens`** — Returns active visual design tokens, matched preset, and WCAG contrast metrics for a subsite.
- **`get_design_context`** — Returns a subsite's stored PRODUCT.md or DESIGN.md design context markdown for a subsite the caller is a member of.
- **`set_theme_design_tokens`** — Updates visual design tokens for a subsite and recompiles tokens.css.
- **`design_guidance`** — Returns a design discipline instruction block with the subsite's stored brand brief injected; your agent does the reasoning. Commands: palette (CHOOSE SITE COLORS from the brand brief — use this before ever touching theme colors), accessible (WCAG AA audit — alt text, names, labels, contrast), typeset (typography), harmonize (unify to the design tokens), polish (final quality pass), critique (scored design review), distill (simplify).
- **`import_theme_design_dtcg`** — Imports W3C DTCG or Figma Token Studio JSON payload into subsite design tokens.
- **`ingest_local_findings`** — Normalise a client-side detector run JSON into the canonical design verdict.
- **`apply_theme_design_preset`** — Applies a curated visual design preset to a subsite and recompiles tokens.css.
- **`check_design_quality`** — Run the deterministic design-quality detector over supplied HTML or a subsite built output.
- **`get_focal_point_session`** — Polls a focal-point picker session (from create_focal_point_session). status 'pending' means your user has not confirmed yet — keep conversing and poll again in a few seconds; 'selected' carries the user-chosen x/y percentages: RELAY them VERBATIM as focal_x/focal_y on upload_media/import_media_from_url or via set_media_focal_point, then tell your user the point was stored. You only pass coordinates through — never crop, resize or edit the image yourself; the platform regenerates all crops around the stored point automatically. An expired or foreign selection_id is not found — mint a fresh session.
- **`suggest_alt_text`** — Proposes alt text for a base64-encoded image (JPEG/PNG/GIF/WebP), in the requested language, using the platform's configured AI vision provider. Returns available: false with a reason when no provider is configured — this is a suggestion service, never a substitute for a human checking the description.
- **`get_subsite_inventory`** — Returns a module-gated census of what already exists on a SiteForge subsite across authoring domains.
- **`create_focal_point_session`** — Creates a focal-point picker session for YOUR USER and returns a picker_url: an anonymous, login-free page showing the image with a click-to-select crosshair. USE THIS WHEN YOU ARE UNCERTAIN where an image's focal point belongs — instead of guessing, send picker_url to your user ('click the most important part of the image and press Confirm'), then poll get_focal_point_session (every few seconds, up to ~1 hour) until it returns the selection, and RELAY the returned x/y VERBATIM as focal_x/focal_y on upload_media/import_media_from_url or via set_media_focal_point. YOU NEVER CROP, RESIZE OR EDIT THE IMAGE YOURSELF and never adjust the user's coordinates — storing the point is your entire job; the platform's image styles regenerate every crop around it automatically. Works BEFORE uploading when you have the image's URL (your user's browser loads it directly); for base64 payloads, upload first and run the picker on the stored image's url.
- **`set_subsite_setting`** — Sets a single allowlisted third-party setting on a subsite the caller is a member of.
- **`set_media_focal_point`** — Sets the focal point (x/y as 0-100 percentages from the top-left) of a subsite media image. WHY THIS MATTERS: page images are served through focal-point scale-and-crop styles (styled_urls) — every placement crops the image to its own aspect ratio AROUND this point, so an unset or wrong focal point cuts faces and subjects out of cards, banners and thumbnails. Set it on every image you place: the subject's most important detail (a face's eyes, a product, the text on a sign). IF YOU ARE UNCERTAIN where the focal point should be — you have not inspected the image, or the subject is ambiguous — let your user pick it visually: create_focal_point_session gives you a login-free picker page to send them, and get_focal_point_session returns their choice; otherwise state the point you chose so they can correct it. Storing the point is ALL you do — never crop, resize or edit the image yourself; the platform regenerates every styled derivative around the stored point automatically (re-setting flushes them).
- **`translate_canvas_page`** — Creates or updates a language translation of a Canvas page. langcode must be one of the subsite's configured languages. A NEW translation inherits a copy of the source component tree (then translate props via the components argument — same shape and validation as set_canvas_page_components); title is required when creating. The translation inherits the source page's published state on create. Builds render the translation at the language-prefixed path once it exists.
- **`list_skills`** — Lists the authoring skills enabled for a SiteForge subsite (metadata only; use get_skill for the body).
- **`get_platform_changelog`** — Returns what changed on this MCP server since a catalog fingerprint you logged earlier (pass the 12-char hash from tools/list _meta.siteforge.catalog_fingerprint as since_fingerprint). Entries cover tools added/removed, description and argument-schema changes, and operator platform notes, newest first. Omit since_fingerprint for the full history.
- **`list_available_components`** — Lists the components a SiteForge subsite may place on a Canvas page.
- **`list_subsites`** — Lists the SiteForge subsites the current user can view.
- **`set_subsite_homepage`** — Points a subsite's homepage at one of its own Canvas pages (or an existing operator node).
- **`get_skill`** — Returns one authoring skill (its raw markdown body included) for a subsite, if that skill is enabled for the subsite.
- **`list_webform_submissions`** — Reads a subsite webform's submissions, newest first (capped at 50 per call; paginate with offset). Submissions contain PERSONAL DATA visitors entered — handle accordingly and only relay to your user what they asked for.
- **`list_menus`** — Lists a subsite's navigation menus (e.g. main_nav, footer) with their nested link trees ({title, url, weight, enabled, children}). Read this before set_menu_links: that write REPLACES a menu's whole tree, so start from the current one.
- **`list_automations`** — READ-ONLY: lists the subsite's automations — trigger, condition tree, action chain, environments, categories, and enabled state — so you can explain what happens automatically on this site (e.g. on form submissions or publishes). There is NO automation write surface over MCP by design; changes go through the operator UI.
- **`list_redirects`** — Lists the URL redirects owned by a subsite the caller is a member of.
- **`list_canvas_pages`** — Lists the Drupal Canvas pages attached to a SiteForge subsite (deprecated; use list_subsite_pages).
- **`create_redirect`** — Creates a URL redirect confined to a subsite the caller is a member of (source path, destination, HTTP status code).
- **`clone_component`** — Clones a catalog component into a member subsite so it becomes placeable there: pass the catalog id from list_available_components' catalog section (the not-yet-cloned set). The clone ships in the site's active framework variant and appears under its sdc.<theme>.<clone> id on the next list. Re-cloning with force: true overwrites a customized clone — use only deliberately.
- **`read_canvas_page`** — Reads a single Drupal Canvas page belonging to a SiteForge subsite, including its component tree (mirroring the shape set_canvas_page_components accepts).
- **`list_library_proposals`** — Lists agent-submitted library proposals with their FSM status — the poll surface for "was my proposal approved?". mine:true returns only the calling token's proposals.
- **`get_subsite_urls`** — Returns the browser URLs where a subsite can be viewed: the published site (primary domain or local host), per-language variants, and the operator dashboard.
- **`list_subsite_pages`** — Lists a SiteForge subsite's Canvas pages with their draft/published state and path.
- **`delete_canvas_page`** — Deletes a Canvas page in a subsite the caller is a member of.
- **`create_canvas_page`** — Creates a draft Canvas page in a subsite the caller is a member of. DESIGN QUALITY: call design_guidance BEFORE laying out the page — it returns the site's on-brand rules (Impeccable provider); check_design_quality validates the finished page.
- **`build_site`** — Runs a static build of the subsite and returns a browsable preview URL; publish: true additionally promotes the build to the live published site. Requires a one-line memo (why this build is being made) — it is stored on the build record and shown to operators in the build history.
- **`update_canvas_page`** — Updates the metadata of a Canvas page in a subsite the caller is a member of.
- **`list_media`** — Lists a subsite's image media with browser-reachable URLs, alt text, focal point and focal-crop styled_urls. Use styled_urls.card/wide in component image_url props (they crop around the focal point so the subject stays visible); when focal_point is null, set one with set_media_focal_point — ask your user if uncertain.
- **`list_site_templates`** — Lists the published site templates — versioned, captured site slices (pages, menus, components, theme) that apply_site_template can instantiate into a subsite. Richer than create_site's blank/starter seeds: a template ships a complete starter site. Each row lists the parts its current version captured.
- **`import_media_from_url`** — Server-fetches a public, direct image URL (JPEG/PNG/GIF/WebP, max 5 MB, no redirects) and stores it as subsite media, returning its browser URL for component image_url props.
- **`get_subsite`** — Returns a SiteForge subsite's configuration snapshot (label, theme, languages, build paths, status).
- **`set_canvas_page_components`** — Sets a Canvas page's component tree, validating each component's prop inputs before save; an invalid tree is rejected with structured violations and no write. DESIGN QUALITY: before composing or restyling a page, call design_guidance for the site's on-brand rules (spacing, hierarchy, color usage), and run check_design_quality on the result — plain default-styled stacks read as unfinished.
- **`create_webform`** — Creates a webform on a member subsite: title + fields[] ({key, type: text|email|textarea|tel|number|date|select|checkbox, label, required?, options? for select}) with an optional confirmation_message and notification_email. The static-embed snippet is enabled automatically; place the returned embed_markup on a page (HTML-capable prop) and builds bake it into a working form. Submissions are read via list_webform_submissions.
- **`delete_redirect`** — Deletes a URL redirect owned by a subsite the caller is a member of. Refuses redirects owned by any other subsite.
- **`update_subsite_config`** — Updates a member subsite configuration (label, theme, languages, output/include/exclude paths). Partial update: only supplied fields change.
- **`upload_file`** — Uploads a base64-encoded NON-IMAGE file (PDF, Word, Excel, PowerPoint, OpenDocument, plain text, CSV; max 5 MB decoded) as subsite media and returns its browser URL. A title is REQUIRED and is never derived from the filename — ask your user for one rather than inventing it. Use upload_media for images (JPEG/PNG/GIF/WebP); this tool refuses them. The file type is decided by sniffing the bytes, so a mislabelled extension changes nothing. Re-uploading identical bytes returns the existing media instead of storing a duplicate.
- **`list_available_libraries`** — Lists the offered frontend libraries an agent may attach to a subsite via create_site (dynamic — the offered set changes as operators approve proposals).
- **`list_subsite_setting_keys`** — Lists the (module, key) third-party setting pairs the set_subsite_setting write tool is allowed to write.
- **`capture_site_template`** — Captures a member subsite AS a reusable site template: the selected parts (default: everything capturable) snapshot into version 1.0.0. The template stays DRAFT awaiting operator review — it appears in list_site_templates only after the operator publishes it; tell your user to expect that review step. Optional parts[] narrows the capture; changelog describes what this template is.
- **`apply_site_template`** — Instantiates a published site template (see list_site_templates) into a member subsite: pages, menus, components, theme and settings from the template's current version land in the subsite, and an instantiation link is recorded for future template updates. Optional parts[] selects which captured parts apply (default: all). Best applied to a FRESH subsite right after create_site — parts overwrite same-named resources. Missing/unavailable parts are skipped with warnings, never fatal. Changes appear on the next build_site.
- **`set_theme_library`** — Sets a subsite's active theme library (the CSS framework builds render with — see get_theme_library for the available set) and/or its per-library options (e.g. {colors: {primary, accent}}). Supply library, options, or both; options are validated against the library's schema and an invalid payload changes nothing. Switching the library also re-ships cloned component variants to match the new framework. Changes appear on the next build_site. COLORS: never hand-pick or keep framework defaults — FIRST call design_guidance command "palette" (derives a brand-true, WCAG-checked palette from the site's stored brief), store its result here, and re-run check_design_quality after restyling. Typography: design_guidance command "typeset".
- **`get_theme_library`** — Returns the subsite's active theme library (the CSS framework its builds render with — e.g. tailwind, bootstrap), its per-library options (colors, typography), and the available libraries. A null active_library means builds render frameworkless — set one with set_theme_library.
- **`propose_library`** — Proposes an npm package NOT currently offered for operator review. The proposal is screened and queued; it is never auto-forged (an operator must approve).
- **`create_site`** — Creates a new DRAFT subsite from a caller-supplied DNS-label sitekey and human label, and makes the caller its owner. Idempotent by sitekey, collision-safe, quota-limited; never publishes. ANONYMOUS callers (no sfmcp_ token) may also create: pass a valid captcha_token to mint a ghost-owned, publish-locked draft and receive a single-use claim credential — choose claim_method cookie_token (credential returned inline, default) or email_link (credential emailed to claim_email). A registered user later redeems the credential to adopt the site (or is auto-claimed on first registration); unclaimed drafts are garbage-collected after the retention deadline. THE DESIGN FLOW IS REQUIRED: the response carries design_flow — an interview you must relay VERBATIM to your user (never answer it yourself); store the answers via set_design_context and consult design_guidance before composing any page.
- **`upload_media`** — Uploads a base64-encoded image (JPEG/PNG/GIF/WebP, max 5 MB) as subsite media and returns its browser URL for use in component image_url props.
- **`list_webforms`** — Lists the subsite's webforms: element definitions, open/closed status, snippet-embed state, and the ready-to-place embed markup (<siteforge-webform …> — put it in a page's HTML-capable prop; static builds bake it into a working form that submits back to the platform). Pair with create_webform and list_webform_submissions.
- **`set_menu_links`** — REPLACES a subsite menu's entire link tree with the supplied list (nested children supported) — read list_menus first and send the complete intended tree, not a diff. Links: {title, url (site-relative /path, full http(s), or '/' for home), weight?, enabled?, children?}. Changes appear on the next build_site.

---

This document is generated live: the endpoint, auth and tool list above always
reflect this running SiteForge instance and the domain it is served on.
