{"mcp_version":"2025-11-25","name":"WebsitePublisher.ai","version":"2.1.1","description":"The AI web platform. Describe a website, app or store to any AI assistant \u2014 it goes live on a real URL with auth, payments, forms, integrations and memory built in.","transport":["streamable-http"],"endpoints":{"streamable_http":"https:\/\/mcp.websitepublisher.ai\/mcp\/"},"authentication":{"type":"oauth2","metadata":"https:\/\/mcp.websitepublisher.ai\/mcp\/.well-known\/oauth-protected-resource"},"tools":[{"name":"get_started","title":"Get Started","description":"Call this first, before anything else, with no arguments. Returns the user's projects with their live URLs, which project to build in, and the exact next call that makes a page live on the web. Cheap and read-only.","annotations":{"title":"Get Started","readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false}},{"name":"list_projects","title":"List Projects","description":"List all projects the authenticated user has access to. Returns the id, name and subdomain of each project. At the start of a conversation prefer get_started: it includes this list plus the project to build in and the next call.","annotations":{"title":"List Projects","readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false}},{"name":"get_project_status","title":"Get Project Status","description":"Get detailed status of a specific project including page, asset, and entity counts","annotations":{"title":"Get Project Status","readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false}},{"name":"get_skill","title":"Get Agent Skill","description":"Returns agent skill documents for building WebsitePublisher sites: page-structure patterns, code snippets and guidelines. \"main\" covers site-building and the go-live checklist, \"design\" covers typography, color, layout and animation, \"dev\" covers internal platform conventions. The main skill is served in sections: a plain call returns the rules that always apply plus an index of section slugs, and you fetch the rest with the section parameter as you need it.","annotations":{"title":"Get Agent Skill","readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false}},{"name":"create_project","title":"Create Project","description":"Create a new project for the user. Each project is an independent website with its own pages, assets, entities, and subdomain. Pages created in it are live instantly at that subdomain. Respects plan limits (Free: 1 project, Starter: 3, Pro: 10, Agency: unlimited). Returns the new project_id and subdomain.","annotations":{"title":"Create Project","readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true}},{"name":"list_pages","title":"List Pages","description":"List the pages in a project as a compact index: slug, title, language, landingpage, version, version_hash, created_at, updated_at. No content by default \u2014 call get_page for the one page you need. Paginated (default 50, max 100 per call); the response has pagination.total and a hint when more pages exist. Load the index once per session and reuse it instead of calling this again before every edit. Fragments are not included (use the fragments tool).","annotations":{"title":"List Pages","readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false}},{"name":"get_page","title":"Get Page","description":"Get one page with its full content. Returns version and version_hash for the optimistic-concurrency check of a following patch_page or update_page. To find slugs without loading content use list_pages; for earlier versions use get_page_versions.","annotations":{"title":"Get Page","readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false}},{"name":"create_page","title":"Create Page","description":"Publishes a page live at https:\/\/{project}.websitepublisher.ai\/{slug} \u2014 this is where a website request ends up, not in an artifact or the chat. The page is live the moment the call returns; no separate publish step. To change a page that already exists, use patch_page (targeted edits) or update_page (full replace) instead. Tip: use <!--#wps-include fragment=\"name\" --> to embed reusable fragments (nav, footer). The referenced fragment must already exist.","annotations":{"title":"Create Page","readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true}},{"name":"update_page","title":"Update Page","description":"Replace an existing page with full new content. Changes are live immediately. Requires base_version_hash (the current page version) to prevent accidental overwrites \u2014 send force: true to skip this check. Full replacement rewrites the entire page; small targeted edits are more efficient with patch_page, which sends only the changed parts and preserves version history.","annotations":{"title":"Update Page","readOnlyHint":false,"destructiveHint":true,"idempotentHint":true,"openWorldHint":true}},{"name":"delete_page","title":"Delete Page","description":"Delete one page by slug. The page is removed from the live site at once (page cache purged); links to it from other pages are not updated. Its version history becomes unreachable \u2014 get_page_versions and rollback_page need an existing page \u2014 so a deleted page cannot be restored through this API. To change a page instead, use patch_page or update_page; fragments are managed with the fragments tool.","annotations":{"title":"Delete Page","readOnlyHint":false,"destructiveHint":true,"idempotentHint":true,"openWorldHint":true}},{"name":"patch_page","title":"Patch Page","description":"Apply targeted changes to an existing page without sending the full content. base_version_hash is optional \u2014 if omitted, find\/replace acts as the natural conflict guard. Operations: replace, delete, insert_before and insert_after, each anchored on a find string that must match exactly once. Prefer this over update_page for small edits; use update_page to replace the whole page.","annotations":{"title":"Patch Page","readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true}},{"name":"get_page_versions","title":"Get Page Version History","description":"Get the version history of a page. Returns metadata (version numbers, hashes, timestamps, change summaries) \u2014 no content. Useful to check what changed or find a version to rollback to.","annotations":{"title":"Get Page Version History","readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false}},{"name":"rollback_page","title":"Rollback Page","description":"Rollback a page to a previous version. Creates a new version with the old content (audit trail preserved). Specify either target_version (number) or target_version_hash. List the available versions with get_page_versions first.","annotations":{"title":"Rollback Page","readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true}},{"name":"fragments","title":"Fragments","description":"Manage reusable HTML fragments (shared nav, footer, banners) embedded via <!--#wps-include fragment=\"name\" -->. Single entry point \u2014 pick an operation. list = all fragments + versions. create = name+content. update = name+content, full replace (supports base_version_hash optimistic lock + force). patch = name+patches, targeted find\/replace, efficient for small edits, preserves version history. delete = name. versions = name \u2192 version history. rollback = name + target_version|target_version_hash. All changes invalidate cache automatically.","annotations":{"title":"Fragments","readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true}},{"name":"list_assets","title":"List Assets","description":"List all assets (images, CSS, JS, etc.) in a project, without file content. Private assets are included with is_private: true and url: null. Use get_asset to read one file, upload_asset or patch_asset to change one.","annotations":{"title":"List Assets","readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false}},{"name":"get_asset","title":"Get Asset","description":"Read the full content of an existing asset. Text assets (js, css, json, svg, txt, html) are returned as UTF-8 strings in `content` with `encoding: \"utf-8\"`. Binary assets (images, fonts, pdf) are returned as base64 in `content` with `encoding: \"base64\"`, but only if size \u2264 1MB; above that the content is omitted and the `url` field can be used to download directly. Always returns `version_hash` (first 8 hex chars of the SHA-256 of the content) for optimistic concurrency on subsequent updates.","annotations":{"title":"Get Asset","readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false}},{"name":"upload_asset","title":"Upload Asset","description":"Upload an asset (image, font, PDF, etc). Provide exactly one of: content (base64), content_text (plain text for JS\/CSS\/JSON\/SVG \u2014 preferred, saves tokens), or source_url (public HTTPS URL for images). Set overwrite: true to replace an existing asset.","annotations":{"title":"Upload Asset","readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true}},{"name":"delete_asset","title":"Delete Asset","description":"Delete one asset by path: the file is removed from storage and purged from the CDN, so its URL stops working. Pages, fragments and CSS that still reference it are not updated and will show a broken link or image \u2014 check before deleting. A private asset is deleted together with its share links. To replace a file, keep the path and use upload_asset with overwrite: true (or patch_asset for text files); list_assets shows the existing paths.","annotations":{"title":"Delete Asset","readOnlyHint":false,"destructiveHint":true,"idempotentHint":true,"openWorldHint":true}},{"name":"patch_asset","title":"Patch Asset","description":"Apply targeted text changes to an existing asset (js, css, json, svg) without re-uploading the full file. Uses find\/replace on the file content. Binary assets (images, fonts) are updated by re-uploading with overwrite: true instead.","annotations":{"title":"Patch Asset","readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true}},{"name":"entities","title":"Entities","description":"Manage MAPI entities (schema level \u2014 like database tables). Single entry point \u2014 pick an operation. list = all entities in the project. create = entity_name(+properties[], description?, plural?, public_read?). update = entity_name + any of description\/plural\/public_read\/policy_json. delete = entity_name \u2014 irreversible, drops all data. schema = entity_name \u2192 full property list + current policy. add_property = entity_name+property_name+type(+length?,required?,default?,in_listing?) \u2014 add a column to an existing entity. delete_property = entity_name+property_name+confirm:true \u2014 irreversible, drops the column and its data.","annotations":{"title":"Entities","readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true}},{"name":"records","title":"Records","description":"Manage MAPI records (data level \u2014 rows within an entity). Single entry point \u2014 pick an operation. list = entity_name(+page?,per_page?,sort_by?,sort_order?). get = entity_name+record_id. create = entity_name+data. update = entity_name+record_id+data, partial \u2014 only provided fields change. delete = entity_name+record_id \u2014 irreversible.","annotations":{"title":"Records","readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true}},{"name":"vault_list_secrets","title":"List Vault Secrets","description":"List all secrets stored in a project's vault. Returns metadata only (key names, prefixes, service types, status) \u2014 never the actual secret values. Use this to check what credentials are stored before setting up integrations.","annotations":{"title":"List Vault Secrets","readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false}},{"name":"vault_store_secret","title":"Store Vault Secret","description":"Store or update a secret in the project vault. The value is encrypted with AES-256-GCM and can never be read back. Use this to save API keys for integrations. If the key_name already exists, the value is replaced. For production API keys, the Dashboard Vault tab (dashboard.websitepublisher.ai\/vault) is the recommended secure alternative \u2014 keys go directly to encrypted storage without passing through the AI conversation.","annotations":{"title":"Store Vault Secret","readOnlyHint":false,"destructiveHint":true,"idempotentHint":true,"openWorldHint":false}},{"name":"vault_delete_secret","title":"Delete Vault Secret","description":"Permanently delete a secret from the project vault. This cannot be undone. The encrypted value is destroyed.","annotations":{"title":"Delete Vault Secret","readOnlyHint":false,"destructiveHint":true,"idempotentHint":true,"openWorldHint":false}},{"name":"list_integrations","title":"List Integrations","description":"List every integration for a project and whether it is configured (vault secrets present, ready to call) or still needs setup. Compact by default: id, name, category and endpoint names. For the input fields of one integration call get_integration_schema \u2014 that also returns its usage guidance. Use detail:true only when you really need every endpoint description of every integration (large response). Full catalog of every platform building block, no auth needed: https:\/\/www.websitepublisher.ai\/integrations.txt.","annotations":{"title":"List Integrations","readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false}},{"name":"search_integrations","title":"Search Integrations","description":"Search every capability the platform has, across ALL projects this user can reach, in plain language \u2014 \"email archive\", \"search my inbox\", \"send invoices\", \"book a table\". Returns real, live capabilities from the integration manifests, including the project_id to call them on, so you never need to know the project up front. ALWAYS call this before telling the user something is not possible, and before reaching for an external tool, web search or a third-party connector: the platform ships 100+ integrations and the one you need is usually already there. Returns the exact service and endpoint names to pass to execute_integration. Full public catalog as one plain-text file, no auth or MCP needed: https:\/\/www.websitepublisher.ai\/integrations.txt (one line per integration: slug, category, endpoint names).","annotations":{"title":"Search Integrations","readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false}},{"name":"get_integration_schema","title":"Get Integration Schema","description":"Get the full schema of a specific integration: all available endpoints, required fields, and input parameters \u2014 plus its usage guidance (how to apply, pages to build, anti-patterns) when available. Full catalog of every platform building block, no auth needed: https:\/\/www.websitepublisher.ai\/integrations.txt.","annotations":{"title":"Get Integration Schema","readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false}},{"name":"setup_integration","title":"Set Up Integration","description":"Configure an integration by storing its required API keys in the vault. Validates key format against the integration manifest. After setup, the integration endpoints become available for use. Required secrets are defined by the integration manifest. For production API keys, consider using the Dashboard Vault tab (dashboard.websitepublisher.ai\/vault) instead \u2014 keys are stored directly without passing through the AI conversation. Full catalog of every platform building block, no auth needed: https:\/\/www.websitepublisher.ai\/integrations.txt.","annotations":{"title":"Set Up Integration","readOnlyHint":false,"destructiveHint":true,"idempotentHint":true,"openWorldHint":true}},{"name":"execute_integration","title":"Run Integration Action","description":"Execute an integration action \u2014 e.g., send an email via Resend, create a payment via Mollie. Vault credentials are resolved server-side, so API keys are never handled directly. Non-built-in integrations must be configured before use. The exact endpoint name and required input fields are available from the integration schema. Payment endpoints only create checkout sessions hosted by the payment provider (e.g. Mollie); card data is entered on the provider-hosted checkout page and never passes through or is stored by WebsitePublisher. Full catalog of every platform building block, no auth needed: https:\/\/www.websitepublisher.ai\/integrations.txt.","annotations":{"title":"Run Integration Action","readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true}},{"name":"remove_integration","title":"Remove Integration","description":"Remove an integration by permanently deleting all its vault secrets. After removal, the integration endpoints will no longer work until it is reconfigured. Full catalog of every platform building block, no auth needed: https:\/\/www.websitepublisher.ai\/integrations.txt.","annotations":{"title":"Remove Integration","readOnlyHint":false,"destructiveHint":true,"idempotentHint":true,"openWorldHint":true}},{"name":"configure_form","title":"Configure Form","description":"Define or update a form for a published website. Sets required fields and what actions execute on submit. Use action for a single action, or actions (array, max 3) for multiple in sequence. Built-in action (no setup needed): {\\\"type\\\": \\\"leads\\\"} \u2014 stores submissions in platform-native lead capture, retrievable via the platform lead-capture API. External actions: {\\\"type\\\": \\\"iapi\\\", \\\"service\\\": \\\"resend\\\", ...} for email, or {\\\"type\\\": \\\"webhook\\\", \\\"url\\\": \\\"...\\\"}. The visitor only sends field values \u2014 actions are locked server-side. External service availability depends on the configured integrations. On custom domains (e.g. www.site.com) Safari blocks third-party cookies, so the page form JavaScript carries the session via sessionStorage and an X-Session-Id header on both the session GET and the form-submit fetch (the Safari ITP-proof pattern). Form submissions are stored on behalf of the site owner. Forms must not be used to collect restricted-category data such as payment card numbers, government ID numbers, health or biometric data.","annotations":{"title":"Configure Form","readOnlyHint":false,"destructiveHint":true,"idempotentHint":true,"openWorldHint":true}},{"name":"list_forms","title":"List Forms","description":"List the forms of a project as a compact summary: required fields, actions (type, service, endpoint, size), submit limits and bot drops of the last 7 days. Pass form_name to get one form in full - needed before configure_form, which replaces the whole config.","annotations":{"title":"List Forms","readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false}},{"name":"remove_form","title":"Remove Form","description":"Remove a form configuration from a project. Visitors will no longer be able to submit this form.","annotations":{"title":"Remove Form","readOnlyHint":false,"destructiveHint":true,"idempotentHint":true,"openWorldHint":true}},{"name":"set_tracking_scripts","title":"Set Tracking Scripts","description":"Set Google Analytics, Google Tag Manager, Meta Pixel, or other tracking\/conversion scripts for a project. Scripts are automatically injected into every page: head_scripts before <\/head> (for analytics\/GTM), body_scripts before <\/body> (for conversion pixels). Set a field to null or omit it to clear.","annotations":{"title":"Set Tracking Scripts","readOnlyHint":false,"destructiveHint":true,"idempotentHint":true,"openWorldHint":true}},{"name":"get_tracking_scripts","title":"Get Tracking Scripts","description":"Get the current tracking scripts configured for a project. Returns head_scripts and body_scripts, or null if none configured.","annotations":{"title":"Get Tracking Scripts","readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false}},{"name":"remove_tracking_scripts","title":"Remove Tracking Scripts","description":"Remove all tracking scripts from a project. Pages will no longer have tracking code injected.","annotations":{"title":"Remove Tracking Scripts","readOnlyHint":false,"destructiveHint":true,"idempotentHint":true,"openWorldHint":true}},{"name":"create_edit_session","title":"Create Visual Edit Session","description":"Creates a visual edit session so the user can upload and manage images on their published page using a browser-based editor. Returns an edit URL to share with the user. When creating pages with images, use data-wpe-slot placeholder images instead of base64 \u2014 then create an edit session so the user can upload real images.","annotations":{"title":"Create Visual Edit Session","readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true}},{"name":"get_edit_session_changes","title":"Get Edit Session Changes","description":"Reads back what the user changed during a visual edit session. Returns a structured changelog with uploaded images, dimensions, style changes, etc. Use this after sharing the edit URL with the user to see what they did.","annotations":{"title":"Get Edit Session Changes","readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false}},{"name":"create_scheduled_task","title":"Create Scheduled Task","description":"Create a scheduled task that runs automatically at specified times. Supports cron expressions for flexible scheduling. Use run_once=true for one-time scheduled actions (e.g., set a blog post record to published at a specific date\/time). Common cron patterns: \"0 9 * * *\" (daily 9am), \"0 9 * * 1\" (Monday 9am), \"0 *\/6 * * *\" (every 6h), \"0 0 1 1 *\" (Jan 1st midnight).","annotations":{"title":"Create Scheduled Task","readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true}},{"name":"list_scheduled_tasks","title":"List Scheduled Tasks","description":"List all scheduled tasks for a project, showing their status, next run time, and last execution. A task with disabled_by_system=true was switched off by the platform after repeated failures: disabled_reason says why. Fix the cause named there, then ask the user to switch the task back on in the WebsitePublisher dashboard (dashboard.websitepublisher.ai\/schedule) \u2014 do not create a second task alongside it.","annotations":{"title":"List Scheduled Tasks","readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false}},{"name":"delete_scheduled_task","title":"Delete Scheduled Task","description":"Delete a scheduled task and all its run history.","annotations":{"title":"Delete Scheduled Task","readOnlyHint":false,"destructiveHint":true,"idempotentHint":true,"openWorldHint":true}},{"name":"configure_visitor_auth","title":"Configure Visitor Authentication","description":"Configure visitor authentication for a published website. Enables email-based login (magic link or 6-digit code) for website visitors. Required before visitors can authenticate. Use method \"link\" for one-click email login, \"code\" for a 6-digit verification code. Visitor email addresses are used solely to authenticate visitors of the published website and are processed on behalf of the site owner.","annotations":{"title":"Configure Visitor Authentication","readOnlyHint":false,"destructiveHint":true,"idempotentHint":true,"openWorldHint":true}},{"name":"get_visitor_auth_config","title":"Get Visitor Authentication Config","description":"Get the current visitor auth configuration for a project. Shows whether auth is enabled, which methods are allowed, and the success redirect URL.","annotations":{"title":"Get Visitor Authentication Config","readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false}},{"name":"get_analytics","title":"Get Visitor Analytics","description":"Get visitor analytics for a project. Returns pageview counts, unique visitors, top pages, referrers, device breakdown, UTM data, or daily trend. Use period \"today\", \"7d\", \"30d\", or \"90d\".","annotations":{"title":"Get Visitor Analytics","readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false}},{"name":"tasks","title":"Tasks","description":"Shared task tracker (TAPI) with append-only history. Single entry point \u2014 pick an operation. list = the working overview \u2014 compact by default: active tasks (open\/in_progress\/blocked), roots only, most recently updated first, max 50 rows, no descriptions; verbose:true for the full payload. get = slug|id \u2192 single task + architecture versions. history = slug|id \u2192 newest 50 records (shown oldest first; limit max 200), with_content=true adds MD from S3 for max 20 records within ~200 KB. create = slug+title(+description, parent_id, related_to, tags, scope). add_history = slug|id+type+summary \u2014 the primary way to report progress, notes, snippets, blockers and architecture docs; supports snoozed_until. update = slug|id + any of title\/description\/parent_id\/related_to\/tags \u2014 metadata only, logs an audit note; status and completion stay history-driven via add_history. delete = slug|id+confirm:true \u2014 soft delete, refused while the task has children. search = AND-match on distinctive words across title\/description\/slug + history summaries. export = full Markdown archive of all tasks, returned as a short-lived download link \u2014 not for getting an overview; use list for that.","annotations":{"title":"Tasks","readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":false}}],"tool_count":45,"prompts":[],"resources":[],"links":{"documentation":"https:\/\/websitepublisher.ai\/docs\/mcp","dashboard":"https:\/\/dashboard.websitepublisher.ai"}}