Skip to main content
Docs Limits and errors

Limits and errors

Plan-driven limits

Per-account limits are set by your subscription plan. Read them at runtime:

Call get_account and tell me my plan limits.

The response includes plan.limits (max sites, max domains, storage, bandwidth) and usage (current counts and bytes). Hitting a plan limit returns a clear error from create_site or a deploy tool - the agent should surface the limit and either free space (delete_site) or suggest an upgrade.

Deploy payload limits

ConstraintValueWhy
deploy_files total payload≤ ~1 MB practical, hard cap ~6 MBJSON-RPC + Lambda payload caps. For anything larger, use deploy_create_upload.
deploy_create_upload part size~5 MB per partS3 multipart minimum. The server returns one presigned PUT URL per part.
Presigned PUT URL TTLA few hours (expiresAt returned in the envelope)Use the URLs promptly; if they expire, call deploy_create_upload again.
Recommended bundlingZip when > 3 files OR any file > ~1 MBThe fileWorker auto-extracts a single-zip upload, preserving subdirectories.

OAuth TTLs

TokenLifetimeNotes
Access token1 hourRefreshed silently by your MCP client.
Refresh token90 daysRotates on each refresh; old refresh token is invalidated.

After 90 days of inactivity, the next tool call returns 401 and your client opens the consent flow again. See Authentication for the full flow.

Rate limits

The Hostsmith API enforces per-account rate limits to protect partition capacity. The MCP server passes API responses through, so a rate-limit hit surfaces as a tool error with retry guidance. Treat any 429-style error as backoff-and-retry; do not loop without a delay.

Error categories

MCP tools return errors as { isError: true, content: [{ type: "text", text: "<message>" }] }. The text is human-readable and intended for the agent to surface to the user.

CategoryTypical triggerWhat the agent should do
Auth (401)Access token expired or revoked.Reconnect the client; the next call re-auths.
Forbidden (403)Token scopes don't cover the call (rare - the server requests the full set).Reconnect to refresh scopes.
Validation (400)Bad input - subdomain pattern, partition mismatch, missing required field.Surface the message; do not retry the same call unchanged.
Conflict (409)Subdomain already taken; site name in use.Pick a different subdomain; for shared domains, omit subdomain to auto-generate.
Not found (404)siteId doesn't exist or is in another partition.Re-resolve via list_sites; pass partition explicitly if needed.
Plan limitcreate_site would exceed plan.limits.maxSites.Surface the limit; delete_site to free space or suggest upgrade.
Domain not activecreate_site called against a domain still validating or failed.Surface state; do not retry - the user fixes it in the app.
Rate limit (429)Too many requests in a short window.Wait and retry once; if it recurs, surface to the user.
Server (5xx)Transient backend issue.Retry once after a short delay; otherwise surface.
Confirmation requireddelete_site called without confirm: true.Confirm with the user, then call again with confirm: true.

Retry guidance

Safe to retry automatically (with a short delay):

  • 5xx server errors.
  • 429 rate-limit errors (back off, then retry once).
  • Transient network failures during a presigned S3 PUT (the URLs stay valid until expiresAt).

Do not retry without changes:

  • 4xx validation, conflict, or auth errors. Surface the message; the agent or user must change something.
  • deploy_create_upload envelopes after expiresAt - call deploy_create_upload again to get fresh URLs.

Diagnosing failed deploys

If deploy_files returns success but get_site shows a non-active status, the deploy was accepted but post-processing (zip extraction, content scan) is still running or failed. Wait a few seconds and call get_site again. If it stays in a failed state, surface the status to the user and inspect the site in the app for details.