# Dotsy Muse connector

From musedirectory.ai, the independent directory of Meta Muse connectors. Not affiliated with Meta.

## Dotsy

Build and publish static sites with draft-first workflows, content management, and analytics.

- Record: https://musedirectory.ai/connector/dotsy
- Category: Productivity
- Developer: Dotsy (https://dotsy.ai)
- Muse status: Extra setup. Not in Muse's Connectors list yet. Muse can still use it: its page gives you a request to paste into Muse.
- Health: Working, 691ms, checked 2026-10-29T11:45:47Z
- Endpoint: https://mcp.dotsy.ai/mcp
- Auth: No account needed; Pricing: unknown
- Screening: Screened, no issues found (2026-10-28T22:06:51Z)
- Source: Found in the official MCP Registry (ai.dotsy/mcp) https://registry.modelcontextprotocol.io/v0/servers?search=ai.dotsy%2Fmcp

Dotsy is a static site builder that lets you create, edit, and publish websites with draft-first workflows. Manage content, collections, and analytics through MCP tools. Supports importing from URLs, structuring pages into layouts, and publishing with SEO checks.

Example request: "Create a new website, import content from an existing site, and publish it with draft reviews."

How to connect: Not in Muse's Connectors list yet, but Muse can still use it. Paste this into Muse: "Use Dotsy to help me. It is a free service with an MCP server at https://mcp.dotsy.ai/mcp. It does not need an API key. Ask me before you share anything with it." Muse asks before it shares anything with the app's site. Meta does not review apps used this way, so only use ones you trust. We tested this in the Muse app on September 24, 2026: Muse used an app's link directly this way and returned a live answer.

Tools:
- create_site: Create empty site; seeds brief. Globally taken slugs auto-suffix to `{slug}-{adjective}-{noun}` (default); pass onSlugTaken:"fail" to get a 409 instead of a renamed site.
- get_site: Site detail, stats, publicUrl, brief head (default-on), and readiness flags. pages[] is a ~25-entry head by default (stats.pages has the true count) — pass pages: true for the full array (capped at 1000), or enumerate everything with list_content/get_site_manifest. Large sites (2
- update_brief: Update `_intent/site.md` (site brief) or a page brief when `page` is set. See field descriptions for rules, notes, and head enums.
- get_plan: Read-only workspace plan and pooled usage; pass slug for this site's add-ons. Call before a large build.
- get_analytics: Read-only traffic overview (default) or full breakdowns via include[]; optional bot id for crawler page drill-down.
- set_analytics_provider: Connect a third-party analytics provider (GA4, Plausible, Fathom, Umami) or remove it (provider 'none'). Dotsy adds the provider's script to the <head> of every live page — live immediately, no publish needed. Replaces any earlier provider (one per site). Use this instead of past
- get_custom_code: Read the site-wide custom code: `draft` (what the next publish puts live) and `published` (what visitors get now) for both boxes — head (before </head>) and body (before </body>) — plus `pending`, `runOn` and `maxChars`.
- set_custom_code: Set site-wide custom code: `head` goes before </head> and `body` before </body> on every page, on every layout. It is saved as a draft and goes live with the next publish_site (on a live-mode site the dashboard publishes only the code). It never runs in the editor. Up to 20,000 c
- update_site: Update site settings: title, keyConvention, or editingMode ('live' = each editor save publishes immediately; 'staged' = saves stay drafts until publish_site). Slug is the hostname — change it with rename_site, not this tool. Set 'staged' before handing the editor to a person via 
- rename_site: Rename the site slug (public hostname {slug}.dotsy.site). Owner-only. After success: use the returned slug in every later tool. Published site: the old slug redirects on the API (301 for reads, 308 for writes) while it stays reserved; the old host 301s and stays reserved until de
- publish_site: Publish draft to live. feedback and handoff required (use dummy feedback + one-line handoff if clean).
- get_draft_status: Pending draft changes: content keys and routes with status. May include requiredDecision (publish_confirm) before publish_site.
- review_changes: Review queue: what changed and isn't live yet. list (counts first) → get one item (hidden changes, optional diff, bodyChanged: false means only title/meta/route fields changed — review hidden, not the visible page) → mark_ready / unmark (≤50 ids). Then publish_site onlyReady:true
- discard_drafts: Discard unpublished drafts: all (omit key/keys/routes/menus), one content key (key), menu draft only (menus:true), or a selection (keys, routes). Destructive — check get_draft_status first.
- delete_site: Permanently delete site; confirmSlug must equal slug.
- bulk_put_content: Stage many content keys (pages, layouts, fragments). Content only — not routes or assets. Each body ≤60KB and the whole call ≤80KB; larger pages use stage_content_chunk, dotsy push, or PUT content-raw. May queue above the inline threshold.
- get_site_manifest: Content keys + hashes only (optional routes=true) — static files live in list_assets, not manifest. Diff keys+hashes before apply_changeset; stage only changed bodies.
- find_replace: Case-insensitive find→replace across pages in one staged commit. Batch all replacements into ONE call — never parallelize find_replace on the same key (concurrent edits surface as per-key conflict). find/replace ≤60KB.
- search_content: Find pages containing a phrase (grep without reading bodies). Requires do-sqlite — graduate_site first if search_unavailable.
- graduate_site: Enable site search & collections (kv → do-sqlite), one-way. Unlocks search_content, collection indexes, visitor /__paige/search, and moves any R2 form-submission ledger into SiteDb. 409 blocked covers three unrelated gates: an unsupported source backend (no override, ever); stric
- apply_changeset: Stage writes[] + deletes[] in one call; attach routes via writes[].route. writes[].ifMatch (hash from get_site_manifest; "" = must not exist) guards each key (a delete takes { key, ifMatch } too); atomic:true makes one stale key write nothing (409 changeset_conflict). At most 10 
- import_site_from_url: Import URL to draft. On complete, response may include requiredDecision — preview then ask mirror vs editable before structure_*.
- get_structure_status: Flat vs structured page counts; informs user — do not auto-run analyze/apply while requiredDecision pending.
- structure_site_analyze: Propose shared layout + fragments; persist:false first. Wait for mirror-vs-editable answer if requiredDecision pending.
- decompose_analyze: Deprecated — use structure_site_analyze.
- structure_site_apply: Rewrite flat pages to layout + fragments (draft). Do not call while requiredDecision pending — user must pick editable first. It extracts header/footer only: afterwards share_section with no arguments lists the other repeated blocks (banner, CTA).
- get_structure_result: Last structure apply job result (structuredKeys, conflicts, partial).
- adapt_site_analyze: Propose nav wiring + blog collectionization for an imported mirror (draft, opt-in). Read-only; returns per-adapter reports + proposalEtag. Nav decline may include nextStep (e.g. mega-menu → edit fragments/header.html). Wait for mirror-vs-editable answer if requiredDecision pendin
- adapt_site_apply: Apply the adapt proposal (draft): wire nav into the menu store and/or rewrite the blog index to a live <dotsy-collection>. One undo covers the whole apply; a second apply is refused until adapt_site_revert (or force). Queued applies are polled to completion.
- adapt_site_revert: Atomically restore everything the last adapt_site_apply wrote (fragments, the menu doc when the op touched it, index, member configs, routes).
- get_adapt_status: Read adapt state: proposal summary + proposalEtag (+ applied/consumed flag), undo-record presence, active or queued job progress. Use to resume in a fresh session.
- list_content: List content keys (HTML/md); not assets — use list_assets. Defaults to 50 keys per page — raise limit (max 1000) or pass cursor (from nextCursor) to page through the rest. Per-row `size`/`missing` are measured automatically only on pages of ≤100 rows; past that they're ABSENT (no
- get_content: Read one content key; optional selector (region) or published=true (live body). Bodies over 40KB without a selector return a truncated summary — use selector, batch_patch_content, or dotsy pull.
- put_content: Stage one content key. Body ≤60KB. Larger pages: stage_content_chunk + apply_changeset bodyStaging, dotsy push, or PUT content-raw. Edits to an existing large page: batch_patch_content.
- stage_content_chunk: Append one ≤60KB chunk of a large new page. Omit stagingId on seq 0; pass the returned stagingId on later seq. Set finalize:true on the last chunk, then apply_changeset with writes[].bodyStaging.
- patch_content: Edit one content key via ops[] (selector ops or replace-string; wrap/unwrap/move restructure siblings). Stages draft; op shapes in schema.
- batch_patch_content: patch_content on multiple keys; all-or-nothing validation. Preferred edit path for pages over 60KB. replace-string value/replace ≤60KB; whole call ≤80KB.
- delete_content: Delete content key (tombstone if published). A fragments/* section that pages still place is refused with section_in_use (lists the pages) — detach it or remove it first.
- rename_content: Re-key a page by slug (draft or published static). Server-side hash copy — no body round-trip. Default deletes static routes (obscure-URL); movePath:true repoints the route, rewrites menu refs and other redirects aimed at the old path, rewrites root-relative and https://{slug}.do
- put_post: Stage a blog post via structured meta+body (?format=post). Key e.g. blog/my-post.html. Declared membership: meta.collections; schedule: meta.visibleAt; SEO title override: meta.seoTitle (card always shows meta.title); custom fields: meta.custom (typed per collection by get_collec

Screening checks:
- MCP handshake: pass (Answered in 492ms)
- Domain against threat feeds (Cloudflare security DNS): pass (mcp.dotsy.ai, dotsy.ai not flagged)
- Published packages against the OSV malicious-package database: n/a (No npm or PyPI package published)
- Hidden instructions or invisible characters in tool text: pass (89 tools read, nothing found)
- Inputs asking for passwords, card numbers or seed phrases: pass (None found)
- Domain and redirects: pass (Domain registered 120 days ago)
- AI review of purpose and tool behavior: pass (No concerns)
