Skip to main content
Glama

Server Configuration

Describes the environment variables required to run the server.

NameRequiredDescriptionDefault

No arguments

Instructions

Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.

Hostsmith MCP server: publish, share, and host files or static sites.

Context bootstrap:

  • On first use in a session, call get_account and list_domains once to learn the user's account (orgId, orgName), the user's home partition under user.homePartition, plan limits, and available domains. Cache and reuse these for the rest of the session; only re-call if the user asks for a refresh or you have reason to suspect the data changed (e.g. a domain was just claimed).

  • list_sites changes frequently (any create/delete mutates it). Always re-call before acting on a site reference rather than relying on a cached result.

Partition selection:

  • Pass partition: "eu" when the user signals EU residency or GDPR; otherwise omit partition and let it default to the user's home partition. Ask if unsure.

Plans and limits:

  • Every plan, Free included, can create sites in both the "us" and the "eu" partition. Pass partition: "eu" when the user asks for the EU or GDPR; otherwise omit it, and the site goes to the user's home partition.

  • When a plan's site limit is reached, creating a site returns the API error "Site limit reached for current plan". Surface it verbatim so the user knows they need to delete a site or upgrade.

Redirect hosts:

  • To forward a hostname with no content of its own, such as a retired domain or a campaign link, create a redirect host (create_site with kind: "redirect") and set its rules with set_redirects or add_redirect, rather than deploying a placeholder page.

Deploying content:

  • Two paths, pick by file size and type:

    • Use deploy_files for inline text/JSON/HTML you generated yourself, when total payload < ~1 MB. Bytes ship through the MCP server's JSON-RPC channel; subject to a ~6 MB hard ceiling.

    • Use deploy_create_upload + deploy_finalize for binaries (PDF, image, video, zip), files larger than ~1 MB, or any file you have available in your environment but not as inline text. The tools return per-part PUT URLs; bytes flow directly from your environment to the upload endpoint, never through the MCP server. The URL host is either a Hostsmith partition API host (us.api.hostsmith.net or eu.api.hostsmith.net) or a direct S3 endpoint - treat both identically (one HTTP PUT per URL, capture the ETag from each response).

  • If a deploy_create_upload PUT fails with a network/DNS/sandbox/proxy error, follow this escalation order. Do NOT improvise around it:

    1. Ask the user to enable egress for the URL's host (preferred). The sandbox blocking is an environment setting the user can change; surface deploy_create_upload's allowlist-recovery instructions and wait for confirmation.

    2. If the user declines or cannot change the sandbox, present the presigned URL(s) verbatim and ask them to upload the file themselves (curl, browser, etc.), then call deploy_finalize after they confirm.

    3. Never base64-embed, data-URI, or otherwise inline binary content into HTML/CSS/JSON/other deployed files to bypass the upload path. It bloats the page, breaks browser caching, reships on every deploy, and hides the real problem from the user. Do NOT fall back to deploy_files for the same reason (payload exceeds its cap and the workaround is itself the anti-pattern).

  • When you notice yourself reasoning "the sandbox blocks X, so I'll route around it," stop and escalate to the user instead. Sandbox constraints are signals to ask, not puzzles to solve silently.

  • Read or generate the content client-side (in your own environment) - the MCP server has no access to the user's local filesystem.

  • The site must exist first; call create_site if no siteId is available.

Naming:

  • Site subdomains are lowercase alphanumeric with hyphens; no dots, no uppercase, no underscores.

Resolving the user's site reference:

  • Infer the intended FQDN from how the user described the site:

    • A name that looks like an FQDN (e.g. blog.example.com) → split into subdomain + domain and validate against list_domains.

    • A bare string that doesn't look like an FQDN (e.g. "my-blog") → assume it's a subdomain on a shared domain in the user's home partition.

    • Phrases like "my company homepage" on a domain the user owns with enableApexDomain: true → apex/www site.

    • When genuinely ambiguous, ask the user.

  • After resolving, look up the FQDN in the latest list_sites result to determine whether this is a new or existing site, and validate the domain/subdomain against list_domains.

  • Before performing any create/deploy/delete action, show the user the resolved info - full FQDN, partition, and whether the site is new or existing - and ask for confirmation.

Destructive actions (require explicit user confirmation; never call speculatively):

  • delete_site is irreversible - the URL goes dark immediately and content cannot be recovered.

  • deploy_files (and deploy_create_upload + deploy_finalize) against an existing site overwrite its current content. If the resolved FQDN matches an existing site, confirm with the user that they want to overwrite it before deploying.

Capabilities

Features and capabilities supported by this server

Protocol revision2025-11-25

CapabilityDetails
tools
{
  "listChanged": true
}

Tools

Functions exposed to the LLM to take actions

NameDescription
list_sitesA

List Hostsmith sites in the user's account. Returns each site's siteId, subdomain, domain, kind ("redirect" for a redirect host, which takes no deploys) and current status - feed siteId into get_site, deploy_files, deploy_create_upload, or delete_site. This is the source of truth for "does the user already have a site at FQDN X" - call it before any create/deploy/delete to resolve the user's site reference. By default queries all data partitions and merges the results; pass partition: "us" or "eu" to limit the query.

list_domainsA

List domains the user can host sites under. Returns shared hosting domains (e.g. hostsmith.link, available to everyone) and custom domains owned by the user's organization. Use this to pick a domain value before calling create_site. By default queries all partitions and merges; pass partition or shared to narrow.

get_accountA

Get the user's account: organization details (orgId, orgName), the calling user's home partition under user.homePartition, current subscription plan with its limits (max sites, max domains, storage, bandwidth), and current usage counts. Use to check how much headroom the user has before creating new sites or to confirm plan-tier features. Usage covers every partition: the site and storage counts are the organization's, and custom domains are added up from each partition.

get_siteA

Get full details of a specific Hostsmith site by ID, including its public URL (https://<subdomain>.<domain>), current deployment status, and configuration. Use after list_sites to inspect a single site, or after deploy_files / deploy_finalize to confirm the site is live and grab the URL to share with the user. Defaults to the user's home partition; pass partition explicitly when the site lives in a different one (visible in list_sites output).

create_siteA

Create a new Hostsmith site and return its siteId, full URL, and configuration. Use when the user wants to publish or host new content and no suitable site already exists. After creation, deploy content with deploy_files (small inline text) or deploy_create_upload + deploy_finalize (binaries / files > ~1 MB, uploaded directly to S3). The site-resolution and confirmation flow is described in the global server instructions; the rules below are specific to this tool's parameters.

domain MUST be one of the domains returned by list_domains for this user - never invent or assume one. The selected domain must be in active status; if it isn't, surface the problem to the user instead of attempting creation. partition passed to this tool MUST match the partition of the selected domain.

Subdomain selection must respect the domain's capabilities from list_domains. To serve the bare apex, pass subdomain: "www" - only valid when the domain has enableApexDomain: true (typically custom domains the user owns). For any other subdomain, the domain must have enableSubdomains: true; shared hosting domains (e.g. *.hostsmith.link) and most custom domains have enableApexDomain: false, so a non-apex subdomain is required there. If the chosen domain doesn't support the kind of site the user asked for (apex vs subdomain), surface the conflict rather than silently picking something else.

Pass kind: "redirect" to create a redirect host instead of a site: it serves only redirect rules, set afterwards with set_redirects or add_redirect, and takes no deploys. Its domain must be a custom domain the organization owns (shared: false in list_domains). On a domain with enableApexDomain: true, a redirect host at subdomain: "www" also forwards the bare apex, which first redirects to www and then follows the host's rules.

delete_siteA

Permanently delete a Hostsmith site and all of its deployed files. Destructive - only call after explicit user confirmation. The site URL becomes unreachable immediately and the content cannot be recovered. The user must pass confirm: true for the deletion to proceed; otherwise the call returns an error explaining the safeguard.

deploy_filesA

Publish in-memory file contents to a Hostsmith site without writing to disk. Use when you have just generated content (an HTML page, a report, JSON data) and the user wants it live. Returns the deployment version and status; call get_site afterwards if you need the public URL to share. The site must already exist - call create_site first if you do not have a siteId. Deploying to a site that already has content overwrites it - confirm overwrite with the user first. A redirect host (kind: "redirect") takes no files and answers RedirectHostHasNoFiles: change its rules with the redirect tools instead.

Anti-pattern: do not use this tool to ship binaries (images, PDFs, video, fonts, zips) by base64-embedding or data-URI inlining them into HTML/CSS/JSON. Binaries belong on deploy_create_upload. If that path is blocked by sandbox/network, escalate to the user (ask them to enable egress, or offer manual upload of the presigned URL) - never reach for this tool as a workaround. Inlining bloats pages, breaks browser caching, and reships the bytes on every deploy.

deploy_create_uploadA

Start a direct-to-S3 upload for binary or large files. Use this instead of deploy_files for binaries (PDF, image, video, zip) or any file > ~1 MB. The MCP server has no access to the user's filesystem and deploy_files ships content inline through Lambda (capped at ~6 MB JSON-RPC payloads); this tool returns presigned S3 PUT URLs so the file bytes flow directly from your environment to S3, never through the MCP server. A redirect host (kind: "redirect") takes no files and answers RedirectHostHasNoFiles.

Bundle into a zip first when: the upload contains more than 3 files OR any file is larger than ~1 MB. The fileWorker auto-extracts a single-zip upload after promotion, so subdirectories are preserved end-to-end and you avoid one PUT round-trip per file. Skip zipping only for the trivial single-small-file case (e.g. one HTML).

Bash bundle-and-deploy template (the agent should adapt fileNames and the cleanup prompt): TMP=$(mktemp -d) zip -r "$TMP/site.zip" index.html styles.css img/ # add every file/dir to deploy SIZE=$(stat -c%s "$TMP/site.zip" 2>/dev/null || stat -f%z "$TMP/site.zip") # 1. call deploy_create_upload with { siteId, files: [{ fileName: "site.zip", fileSize: $SIZE }] } # 2. PUT $TMP/site.zip to the returned URL(s) per the protocol below, capturing ETag # 3. call deploy_finalize with { siteId, versionId, completions: [...] } # 4. ASK THE USER: "Deploy succeeded. Remove temp folder $TMP? [y/N]" # Only run rm -rf "$TMP" after explicit confirmation; otherwise leave it for them to inspect.

Three-step protocol:

  1. Call this tool with { siteId, files: [{ fileName, fileSize }] }. Receive { versionId, files: { [fileName]: { uploadId, key, partUploadUrls: [{ part, url }], partSize, expiresAt } } }.

  2. For each file, slice the bytes into chunks of partSize and PUT each chunk to its partUploadUrls[i].url. Capture the ETag response header from every PUT - you will need it for finalize.

    Single-part (small file, one URL): curl -D - -X PUT --data-binary @file.pdf "$URL", then grep the response headers for ETag.

    Multi-part with dd (no temp files; reads each chunk in place): count=$(jq ".files["large.zip"].partUploadUrls | length" envelope.json) for i in $(seq 0 $((count-1))); do url=$(jq -r ".files["large.zip"].partUploadUrls[$i].url" envelope.json) etag=$(dd if=large.zip bs=5M skip=$i count=1 status=none
    | curl -sS -D - -X PUT --data-binary @- "$url"
    | awk -F': ' 'tolower($1)=="etag"{print $2}' | tr -d '\r') echo "{ "PartNumber": $((i+1)), "ETag": $etag }" >> parts.json done

    Multi-part in Python - prefer this over dd for files > ~50 MB (parallel PUTs, no temp files, cleaner error handling): import json, requests from concurrent.futures import ThreadPoolExecutor env = json.load(open("envelope.json")) info = env["files"]["large.zip"] part_size = info["partSize"] def upload_part(p): with open("large.zip", "rb") as f: # own handle per thread f.seek((p["part"] - 1) * part_size) r = requests.put(p["url"], data=f.read(part_size)) r.raise_for_status() return {"PartNumber": p["part"], "ETag": r.headers["ETag"]} with ThreadPoolExecutor(max_workers=5) as ex: # cap concurrency at 5 parts = list(ex.map(upload_part, info["partUploadUrls"]))

  3. Call deploy_finalize with { siteId, versionId, completions: [{ uploadId, key, parts: [{ ETag, PartNumber }] }] } for every multi-part file. Single-part uploads (uploadId is empty in the start response) need no completion entry.

The site must already exist - call create_site first if you do not have a siteId. Deploying overwrites existing content; confirm overwrite with the user first.

Anti-patterns - never do these to bypass a blocked or unavailable upload path:

  • Do NOT base64-embed, data-URI, or otherwise inline binary content (images, PDFs, video, fonts, zips) into HTML/CSS/JSON or any other deployed file. Inlining bloats the page, breaks browser caching, reships the bytes on every redeploy, and hides the real environment problem from the user.

  • Do NOT fall back to deploy_files for a binary that was meant for deploy_create_upload - the payload exceeds deploy_files' cap and the workaround is itself an anti-pattern.

  • Do NOT silently downscale, recompress, or otherwise mutate the user's file to fit a smaller path - ask first. When the upload path is unavailable, surface it to the user using the escalation order below.

Recovery escalation order when a PUT fails with a network/DNS error (connection refused, name resolution failure, timeout, sandbox-denied, proxy 403/407) OR your host environment has no HTTP-PUT capability at all (no bash/curl, no Python requests, no fetch). Do NOT retry blindly - a sandbox denial does not resolve on its own.

  1. Ask the user to enable egress (preferred fix). This is the cheapest option and unblocks all future uploads. Surface the exact sandbox configuration below and wait for the user to confirm before retrying. Most users can flip this setting in seconds; do not skip to step 2 without asking.

  2. If the user declines, cannot change the sandbox, or has no HTTP-PUT capability in-environment, present the failing presigned URL(s) verbatim and ask them to upload the file themselves (curl one-liner, browser, or any HTTP client they have). Provide a copy-pasteable command. Call deploy_finalize only after the user confirms each PUT returned 200 with an ETag (they will need to share the ETags back for multi-part uploads).

  3. Never route around the failure by base64-inlining the file into another deploy, recompressing, or falling back to deploy_files. See anti-patterns above.

Egress allowlist instructions for step 1:

  1. Read the failing URL's hostname. It will be either us.api.hostsmith.net, eu.api.hostsmith.net, or an S3 endpoint (copy verbatim from the failing URL).

  2. Infer the sandbox and give the user the exact configuration snippet:

    • Cursor (signal: cwd contains .cursor/, or CURSOR_* env vars) - edit ~/.cursor/sandbox.json (user scope) or <repo>/.cursor/sandbox.json (repo scope):

      { "networkPolicy": { "allow": ["us.api.hostsmith.net", "eu.api.hostsmith.net"] } }

      Reload Cursor.

    • Claude Code (signal: CLAUDE_CODE_* env vars, or ~/.claude/ settings present) - edit ~/.claude/settings.json:

      { "sandbox": { "enabled": true, "network": { "allowedDomains": ["us.api.hostsmith.net", "eu.api.hostsmith.net"] } } }

      If deniedDomains lists a matching host, remove it first - deny takes precedence.

    • Codex CLI (signal: ~/.codex/ settings, CODEX_* env vars) - edit ~/.codex/config.toml:

      [sandbox_workspace_write]
      network_access = true

      Codex has no per-host allowlist at this layer - this enables network for workspace-write mode globally. Risk is bounded by the upload token in the URL.

    • Unknown sandbox - tell the user: allow outbound HTTPS (port 443) to us.api.hostsmith.net and eu.api.hostsmith.net (and the failing S3 host if the URL points at S3) in whatever firewall/proxy they control. If a corporate HTTP proxy is in play, ensure CONNECT to those hostnames is permitted, or set NO_PROXY for direct routing.

  3. After the user confirms the change, retry the failed PUT. Tokens in the URL (ut=... for partition-host URLs, X-Amz-Signature for S3 URLs) remain valid for 1 hour from issuance, so re-running the same URL within that window works without re-calling deploy_create_upload.

deploy_finalizeA

Commit a deploy started with deploy_create_upload. Pass the versionId from the start response and a completions array containing the agent-collected ETags for each multi-part file (single-part uploads - those whose start response had an empty uploadId - do not need a completion entry). Returns the live site URL on success. The site must belong to the authenticated user; bearer-token auth is re-validated server-side, so holding presigned URLs alone does not let an unrelated caller finalize.

list_redirectsA

List a site's redirect rules in the order they are checked; the first match answers. User rules come first: managedBy: "user", each with an id, kept on the hostname and changed with the redirect tools. Then the live deploy's _redirects rules: managedBy: "file", each with its line, changed only by deploying a new _redirects. A file rule with shadowedBy never answers, because a user rule for the same path comes first. Returns version, which set_redirects and edit_redirects take to refuse a change if the rules changed since; total and a page of at most 1,000 rules from offset; the file's report, with the lines it skipped and why, and whether it is enabled; and the limits. Redirects apply only on the organization's own custom domains: on a shared domain the report says notApplied: "CUSTOM_DOMAIN_REQUIRED".

set_redirectsA

Replace all of a site's user redirect rules in one call, all or nothing: pass either rules or text in the _redirects format, one from to [status] per line. Use this, or edit_redirects, for bulk work, such as moving a list of redirects from another host, rather than many add_redirect calls. Rules are checked in the order given, before the live deploy's file rules, and the status defaults to 301. A rule sent with the id of an existing rule keeps it. Pass the version from list_redirects to refuse the change if the rules changed since: the error is StaleVersion, with the latest version, so read the rules again and reapply the change. One invalid rule refuses the call with InvalidRules, listing each error by the rule's index or the text's line. The file rules don't change. Redirects apply only on the organization's own custom domains (CustomDomainRequired otherwise). Visitors get the change within about 5 minutes. Rules left out are deleted, and an empty list deletes them all: confirm with the user before dropping rules.

edit_redirectsA

Apply a batch of adds, updates and deletes to a site's user redirect rules, in order, as one change: all of them or none. Use this, or set_redirects, for bulk work rather than many single calls. Rule ids come from list_redirects and start with r_. File rules can't be changed here: an operation naming a file rule's line answers FileRule, with the line and the operation's index. Pass the version from list_redirects to refuse the batch if the rules changed since (StaleVersion, with the latest version). One invalid rule refuses the batch with InvalidRules, listing each error by the operation's index. Redirects apply only on the organization's own custom domains (CustomDomainRequired otherwise). Visitors get the change within about 5 minutes.

add_redirectA

Add one user redirect rule to a site, such as forwarding a moved page to its new path. User rules are checked before the live deploy's _redirects, in list order: the rule goes at the end of the user rules, or at position. The status defaults to 301, a permanent move. It is added to the latest list, without a version. Returns the rule with its id, and the new version. Visitors get it within about 5 minutes; check it with test_redirect. Each call is a separate save, so for more than a few rules use set_redirects or edit_redirects. Redirects apply only on the organization's own custom domains (CustomDomainRequired otherwise).

delete_redirectA

Delete one user redirect rule by its id, from list_redirects. File rules can't be deleted this way: naming a file rule's line answers FileRule with the line. Change the deploy's _redirects instead, or switch the file rules off with switch_file_redirects. To delete several rules, use edit_redirects or set_redirects. Visitors stop being redirected within about 5 minutes.

switch_file_redirectsA

Switch the live deploy's _redirects rules off, or back on, without a deploy, for example when a deployed file sends visitors to the wrong place. User rules keep applying either way. The switch lasts until it is turned back on or the next deploy goes live. Visitors get the change within about 5 minutes. Answers NoFileRules when the live deploy has no _redirects. Confirm with the user before switching the file rules off.

test_redirectA

Test a path against a site's redirect rules, as the site would answer it: the rule that matches, with its status and the location visitors are sent to, or match: null when the path is served as is. Tests the live rules by default. To check a change before saving or deploying it, pass draftRules to test in place of the saved user rules, or draftText to test in place of the live deploy's _redirects. A draft's errors are listed by index or line, and its valid rules are still tested. Nothing is saved.

Prompts

Interactive templates invoked by user choice

NameDescription

No prompts

Resources

Contextual data attached and managed by the client

NameDescription

No resources

TDQS

A4.2/5.0

Scored across 16 tools

Disambiguation4/5

Most tools target a distinct resource+action: sites (list/get/create/delete), deploys (files/upload/finalize), and redirects are clearly separated. The only real overlap is among set_redirects, edit_redirects, and add_redirect, which all mutate the same rule list, but the descriptions explicitly differentiate bulk replace, batch edit, and single add.

Naming Consistency5/5

Every tool is snake_case with a leading verb (list_sites, get_site, create_site, delete_site, add_redirect, test_redirect, etc.), grouped by resource noun. The only slight irregularity is the compound deploy_create_upload, which is still readable and fits the pattern.

Tool Count4/5

16 tools is at the upper edge of the comfortable range but each earns its place across three coherent sub-areas: site lifecycle, deploy pipeline, and redirect management. Slightly heavy on redirect tooling (six tools) relative to the rest.

Completeness4/5

Site lifecycle (create/list/get/delete), a full two-path deploy pipeline, and complete redirect CRUD plus testing are covered. Gaps exist around site configuration updates (no update_site) and deploy history/rollback, so recovery from a bad deploy means overwriting rather than reverting.

Maintenance

ActivityMaintained
ResponsivenessOutdated data