Skip to content

The standard MCP workflow

What this is

The standard workflow for managing a ComStack site over MCP, written as the first-run loop — the path a fresh chat follows with zero prior context. Given only a page URL, an assistant should resolve the project and page, open the right editor, draft a change, get the user’s approval, and publish — without getting lost when the document id changes underneath it.

This page is the human-readable companion to two machine resources every client already loads: the server instructions (sent once per session) and the get-guide tool (full schema + Lighthouse rules). The canonical machine-readable agent guide is also the transformento://guide resource.

How it works

The loop has seven moves:

knowledgecustomPage URLget-project-stateResolve page by slug plus languagepage_typecreate-page / update-pageupload-custom-pageDraft plus approvalpublish dry-runpublish-confirmpublish-status to live URL
  1. Project. Call get-project-state first. It returns project_name (echo it back on destructive tools), site_url, available_doc_templates, the live and draft pages, a compact nav tree, and a workflow_hint that restates this loop inline.
  2. Page. Address a page by its slug + language — the durable handle. get-page-content and update-page accept either the Firestore doc id (path) or a (slug, language) pair; language defaults to the project’s default locale. A reference that matches nothing returns a clean Page not found, never a raw database error.
  3. Editor. Each page carries a page_type. A knowledge page is markdown — edit it with create-page / update-page. A custom page is vibe-coded body_source — edit it with upload-custom-page. Using the wrong tool is refused; see Page types.
  4. Draft. Editing a live page never changes it in place — it writes a draft and leaves the live URL up. Repeated edits to the same page collapse into one draft, and a no-op edit creates no draft at all.
  5. Approval. publish is a dry run: it returns a diff manifest and a single-use confirmation_token (5-minute TTL) and changes nothing. Show the manifest to the user and get explicit approval — every time.
  6. Publish. publish-confirm consumes the token, re-checks that nothing drifted since the dry run, and starts the deploy asynchronously, returning { publish_id, status: "running" }.
  7. Verify. Poll publish-status until succeeded. Its published_urls carry the resulting live path — the new doc id — so you read the post-publish identity back instead of guessing it.

When to use it

  • A fresh MCP session where the only input is a page URL or a vague request
  • Onboarding an assistant or a teammate to the publish flow end to end
  • Debugging “which step am I on?” when a tool response is unexpected

Tools in the loop

StepToolNotes
Project snapshotget-project-stateFirst call. Carries workflow_hint, nav, and page_type on every entry.
Read a pageget-page-contentBy path or (slug, language). Returns page_type + the resolved path.
Edit knowledgecreate-page / update-pageMarkdown. Editing live creates a draft.
Edit customupload-custom-pageOpaque body_source + translation markers.
Drop a draftdiscard-draftRemoves a pending draft; refuses live, hidden, or archived paths.
Dry runpublishManifest + confirmation_token. No writes.
Deploypublish-confirmAsync. Returns publish_id.
Pollpublish-statussucceededpublished_urls.

Example

“Change the headline on https://example.com/pricing/ to ‘Simple, honest pricing’.”

get-project-state(project_id)
-> project_name, site_url, the pricing page (slug 'pricing', page_type 'knowledge')
update-page(project_id, slug: 'pricing', language: 'en',
content: '## Simple, honest pricing ...')
-> { action: 'draft_created_from_live', draft_id, draft_url }
(present the draft_url and the change, get approval, then publish:)
publish(project_id, project_name)
-> manifest { drafts: [ { slug: 'pricing', change_type: 'replace', will_publish_to } ] },
confirmation_token (single-use, 5-min TTL)
publish-confirm(project_id, confirmation_token)
-> { publish_id, status: 'running' }
publish-status(project_id, publish_id)
-> { status: 'succeeded', published_urls: [ { slug: 'pricing', url } ] }

Common errors

  • Editing with the wrong tool. A markdown edit on a custom page (or upload-custom-page on a knowledge page) is refused with a redirect — check page_type first. See Page types.
  • Caching a doc id. The path rotates across an edit-publish cycle; address pages by (slug, language) and read the new path back from publish-status. See Publishing.
  • Publishing without approval. publish only returns a token; nothing deploys until publish-confirm. Always show the manifest first.
  • Expired token. The confirmation_token lasts 5 minutes and is single-use — call publish again for a fresh one.

Full recovery steps for every structured error are in the error reference.

Last updated: