thinhost-mcp
Officialthinhost-mcp lets you publish and manage static sites, provision custom domains, and send transactional email from an MCP client.
Publish static sites from a local HTML file, folder, ZIP, or static build (Docusaurus, Astro, Vite, Next export), with automatic batching for large builds.
Update existing sites by pushing upserts, optionally syncing to prune files no longer in the new build.
Publish or update sites from a public
.zipor.htmlURL.List hosted websites with their live URLs.
Provision custom domains, returning DNS instructions and a claim URL for payment/setup.
Check domain provisioning status, update the origin URL, release domains, and list domains.
Send single transactional emails, subject to account approval and verified sending domains.
Allows publishing Astro static builds as live sites, including updating existing sites and pruning removed files with sync.
Allows publishing Docusaurus static sites as live sites, with update/sync support and a dedicated Docusaurus recipe and skill.
Allows publishing Vite static builds as live sites, with automatic batching for large builds and update/sync support.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@thinhost-mcp publish my ./build folder as a live website"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
thinhost-mcp
The thin.host MCP server: publish static sites (Docusaurus, Astro, Vite, Next export, hand-written HTML), provision custom domains, and send transactional email — from Claude Code, Claude Desktop, or any MCP client.
Prefer nothing to install? The same tools are hosted at https://thin.host/mcp (OAuth or a
bearer API key): claude mcp add --transport http thin-host https://thin.host/mcp.
Claude Code plugin
This repo is also a Claude Code plugin marketplace. The thin-host plugin connects the hosted
server (OAuth sign-in) and adds the skills in skills/:
/plugin marketplace add thinhost/thinhost-mcp
/plugin install thin-host@thinhostSetup for Cursor, VS Code, Windsurf, Codex and ChatGPT: https://thin.host/docs/quickstart-mcp
Related MCP server: seite
Install (local server, reads your build folder directly)
Create an API key in the thin.host dashboard (Settings → Create API key), then:
claude mcp add thin-host \
-e THINHOST_API_URL=https://thin.host/v1 \
-e THIN_HOST_API_KEY=th_live_your_key \
-- uvx thinhost-mcpClaude Desktop (claude_desktop_config.json):
{{ "mcpServers": {{ "thin-host": {{ "command": "uvx", "args": ["thinhost-mcp"],
"env": {{ "THINHOST_API_URL": "https://thin.host/v1", "THIN_HOST_API_KEY": "th_live_your_key" }} }} }} }}Tools
Tool | What it does |
| Publish an HTML file, folder, ZIP or static build folder as a live site (big builds batched automatically) |
| Push changes; |
| Same, from a public .zip/.html URL |
| List the account's hosted sites |
| Custom domains with a hosted claim + DNS flow |
| Transactional email (allowlist + verified sending domain required) |
Docusaurus users: see the recipe and the drop-in Claude
skill in skills/thin-host-docusaurus.
Development
This repo is exported from the thin.host application repo (scripts/export_mcp_package.py
there) so the package can never drift from the deployed server; edit it there, re-export, and
push. Releases are built by GitHub Actions and published to PyPI with trusted publishing when a
v* tag is pushed.
Available Tools
11 toolscheck_domain_statusA
Check the current provisioning status of a domain.
Call this to poll whether a domain is ready. Typical flow:
provision_domain → returns pending_payment
User visits claim_url and pays → status becomes pending_dns
User configures DNS → status becomes pending_ssl
SSL auto-provisions → status becomes active, ready=true
Args: provision_id: The provision_id returned by provision_domain
Returns: status: Current status enum (pending_payment, pending_dns, pending_ssl, active, failed, released) dns_status: Whether DNS is resolving (resolved, unresolved) ssl_status: SSL certificate state (pending, active, failed) payment_status: Whether the user has paid (paid, unpaid, unknown) ready: Boolean — true only when domain is fully active with SSL failure_reason: Present only if status is "failed", explains what went wrong
Inputs: provision_id (required).
list_domainsA
List all domains provisioned through your platform account.
Use this to build dashboards or check the state of all domains.
Args: status_filter: Optional filter by status (pending_payment, pending_dns, pending_ssl, active, failed, released) limit: Maximum number of domains to return (default 50, max 100)
Returns: domains: Array of domain objects with id, hostname, status, ready fields total: Total number of matching domains has_more: Whether more results exist beyond this page
Inputs: limit, status_filter.
list_websitesB
List the account's hosted websites with their live URLs, newest first.
Args: limit: Max sites to return (default 50, max 100).
Inputs: limit.
provision_domainA
Provision a new custom domain for an AI-generated site or app.
Call this when a user wants their deployed site accessible at a custom domain. This creates the domain mapping and returns a claim_url where the user completes payment ($8/mo) and DNS setup. The domain is NOT immediately active — the user must visit the claim_url first.
Args: domain: The custom domain to provision (e.g., "mysite.com", "portfolio.dev") origin_url: The current URL where the site is hosted (e.g., "https://myapp.vercel.app") user_email: The end user's email address for billing and notifications idempotency_key: Optional key to prevent duplicate provisions on retry
Returns: provision_id: Unique ID to track this domain (use with check_domain_status) status: Current provisioning status enum (pending_payment, pending_dns, pending_ssl, active, failed, released) dns_instructions: Structured DNS record the user needs to create, plus a human_readable summary claim_url: URL to send the user to for payment and DNS setup walkthrough expected_completion_seconds: Estimated time for full provisioning after payment
Inputs: domain (required), origin_url (required), user_email (required), idempotency_key.
publish_websiteA
Publish a local HTML file, directory, ZIP, or static build folder as a live site on thin.host.
Use this right after generating a site so the user gets a live, shareable URL
instead of loose files they would have to upload somewhere themselves. Works for
hand-written sites and for generator output — point it at a Docusaurus build/,
an Astro dist/, a Vite dist/, or a Next out/ folder. HTML files become
pages (index.html -> /, about.html -> /about, docs/intro/index.html -> /docs/intro,
404.html -> the site's own not-found page); css/js/images/fonts become assets
served relative to the site root. Large builds are uploaded in several requests
automatically.
Docusaurus: the response reports the build's base_url. A build made with
baseUrl '/' only renders correctly once a custom domain is mapped to the site;
to preview at the returned thin.host URL, build with baseUrl '/s//' (pass
that slug here). Any mismatch comes back as a warning — surface it to the user.
The account's API key must be created from the thin.host dashboard (Settings → Create API key) so it is linked to a user account — error_code "account_not_linked" means it isn't; surface that guidance rather than retrying.
Args: source_path: Absolute path to an .html file, a site/build directory, or a .zip. title: Human-readable site title (shown in the dashboard and emails). slug: Optional URL slug (site lives at /s//). Auto-generated if omitted. "slug_taken" means it's in use — pick another or omit.
Returns: url: The live site URL — share this with the user. id, slug, title, page_count, asset_count, pages, assets: What was published. framework, base_url: Detected generator (e.g. "docusaurus") and its baseUrl. warning: Present when the build's baseUrl won't resolve at the returned url. skipped_files: Local files ignored because their type isn't supported.
Inputs: title (required), source_path (required), slug.
publish_website_from_urlA
Publish a site from a URL — a .zip of the site/build folder, or a single HTML page.
The hosted thin.host MCP endpoint cannot read your disk, so this is its publish
path: zip the build folder (cd build && zip -r ../site.zip .), put the zip
somewhere publicly reachable (a release asset, object storage, a slim.to link),
and pass that URL. Everything else — page/asset mapping, batching, Docusaurus
baseUrl detection and the warning it may produce — matches publish_website.
Private, loopback and cloud-metadata addresses are refused.
Args: source_url: Public http(s) URL of a .zip archive or an .html file (≤150MB). title: Human-readable site title. slug: Optional URL slug (site lives at /s//).
Returns: Same shape as publish_website.
Inputs: title (required), source_url (required), slug.
release_domainA
Release a provisioned domain, removing it from thin.host.
This tears down the domain mapping, SSL certificate, and cancels billing. The domain becomes available for re-provisioning. This action is not reversible.
Args: provision_id: The provision_id of the domain to release
Returns: status: "released" released_at: Timestamp of the release
Inputs: provision_id (required).
send_emailA
Send a single transactional notification email (e.g. a sign-in link, receipt, or alert).
PRECONDITION — this only works for accounts thin.host has approved for email AND when the 'from' address uses a verified sending domain. There is no self-serve:
Unapproved accounts get error_code "email_not_enabled".
A 'from' address on an unverified/unapproved domain gets "invalid_from_domain". In both cases the returned suggested_next_tool_call explains how to get approved or which sending domain to use. Do NOT retry blindly — surface that guidance to the user.
Omit 'from_address' to send from the account's default verified sender (recommended). Provide at least one of 'text' or 'html'. This is transactional only — do not use it for marketing or bulk sends.
Args: to: Recipient email address subject: Email subject line text: Plain-text body (provide this and/or html) html: HTML body (provide this and/or text) from_address: Optional sender; must be on a verified sending domain. Omit for the default. reply_to: Optional Reply-To address
Returns: id: The provider message ID for the accepted send status: "sent" when the message was accepted for delivery to: The recipient the message was sent to from_address: The sender the message was sent from
On failure returns the standard agent error shape (error_code, error_message, agent_should_retry, suggested_next_tool_call). Common error_codes: email_not_enabled, invalid_from_domain, recipient_suppressed (prior bounce/complaint — do not retry), rate_limited (retryable after the window resets), invalid_to, missing_subject, empty_body.
Inputs: to (required), subject (required), html, text, +2 more.
update_originA
Change the origin/target URL for an existing domain.
Use this when the user redeploys their site to a new URL and wants the custom domain to point to the new location.
Args: provision_id: The provision_id of the domain to update new_origin_url: The new URL to route traffic to (e.g., "https://new-deploy.vercel.app")
Returns: status: Current domain status updated_at: Timestamp of the update
Inputs: provision_id (required), new_origin_url (required).
update_websiteA
Push updated pages/assets to an existing hosted website (upsert by path).
Files present locally replace the same paths on the site. With sync=false (default) site files not in this upload are left untouched — right for editing a few pages by hand. With sync=true the upload is treated as the complete site: after it lands, every page and asset the site has that this upload does not is deleted. Always use sync=true when redeploying a generator build folder (Docusaurus, Astro, Vite, Next export) — each build renames its hashed chunks, and without sync the old ones pile up forever. Dashboard-authored redirect pages are kept regardless and listed in kept_redirects.
Use publish_website for a brand-new site.
Args: website: The site's id, slug, or live URL (e.g. "https://thin.host/s/my-site/"). source_path: Absolute path to an .html file, a site/build directory, or a .zip. title: Optional new site title. sync: Treat the upload as the whole site and remove everything else.
Returns: url plus updated counts, and with sync=true the removed_pages / removed_assets. framework, base_url, warning as in publish_website.
Inputs: website (required), source_path (required), sync, title.
update_website_from_urlA
Redeploy an existing site from a URL (.zip of the site, or a single HTML page).
The URL form of update_website, for the hosted endpoint or any agent that has the build as a downloadable archive. sync defaults to true here because a zipped build is the whole site: after upload, files the archive does not contain are deleted (dashboard-authored redirect pages are kept). Pass sync=false to upsert only.
Args: website: The site's id, slug, or live URL. source_url: Public http(s) URL of a .zip archive or an .html file (≤150MB). title: Optional new site title. sync: Treat the archive as the whole site (default true).
Returns: Same shape as update_website.
Inputs: website (required), source_url (required), sync, title.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 11 tools
Tools target mostly distinct resources and actions: website publishing/listing/updating, domain provisioning/status/update/release/listing, and email. The only real overlap is between publish_website/update_website and their _from_url variants; descriptions clarify the source-path vs URL distinction, but an agent could still hesitate between them.
All tool names use consistent snake_case and follow a predictable verb_noun or verb_noun_suffix pattern. The _from_url variants also use a consistent suffix convention.
11 tools is well-scoped for a hosting, domain, and transactional email platform. Each tool covers a distinct operation without excessive surface area.
Domain lifecycle is complete: provision, check status, update origin, release, and list. Website lifecycle covers publish, update, and list, but lacks an obvious delete/unpublish or get-detail operation, which is a notable gap for a hosting service.
Maintenance
Related MCP Connectors
Deploy static sites and connect custom domains from Claude, Cursor, or any MCP agent.
Publish websites with a small backend (KV, SQLite, files). MCP for AI agents.
Deploy AI-generated HTML/CSS/JS to instant public HTTPS URLs from any MCP-compatible agent.
Hosted MCP for creating, checking, deploying, and hosting static sites for AI agents.
Related MCP Servers
- AlicenseAqualityBmaintenanceDeploy static websites, landing pages, and prototypes instantly. Free, no account needed.4151,002 npm6MIT
- AlicenseNot gradedqualityBmaintenanceAI-native static site generator with built-in MCP server and Claude Code integration29MIT
- AlicenseNot gradedqualityDmaintenancePublishes HTML pages straight from your AI assistant to a shareable URL, then lets you manage them - update, list, search, fetch, and delete pages in a public or private workspace. Turns "share what I just made" into a single tool call from Claude, Cursor, or any MCP client.MIT
- FlicenseNot gradedqualityDmaintenanceEnables AI agents to edit and serve a static website via natural language, providing file management tools over MCP and HTTP hosting.-