ShipStatic
ShipStatic MCP lets an agent publish static sites instantly and, with an account, manage deployments, custom domains, and account info.
Publish a static site from a local path with
deployments_upload; no account needed, returns a live URL, file count, size, and a claim URL (site expires in 3 days unless claimed).Manage deployments with an account: list, get details, update labels, and permanently delete (
deployments_list,deployments_get,deployments_set,deployments_remove).Manage custom domains: create/update/reserve/link, list, get details, fetch DNS records, look up DNS provider, share DNS setup, validate availability, verify DNS, and delete (
domains_*tools).View authenticated account details via
whoami(email, name, plan, usage, caps).Use it hosted at
https://mcp.shipstatic.comwith no install/signup/API key, or run locally vianpx @shipstatic/mcpwithSHIP_TOKENfor account tools.Extra README features include paging long lists with limit/cursor, safe deploy retries with idempotency keys, self-cleaning deployments with TTL, and built-in password protection.
Provides the ability to identify if a domain's DNS is managed by Cloudflare, helping users know where to configure DNS records.
Provides the ability to identify if a domain's DNS is managed by Namecheap, helping users know where to configure DNS records.
ShipStatic MCP
One URL. Your agent ships.
Deploy static websites, landing pages, and prototypes instantly. Free, no account needed.
Ask your agent to put your site online, and get back a real link you can share in seconds.
Try it in seconds, no account needed
Drop https://mcp.shipstatic.com into any MCP client. No install, no signup, no API key: your agent can publish a website in its next message.
https://mcp.shipstatic.comChatGPT
Add the ShipStatic plugin from its page in ChatGPT. There is nothing to paste.
Claude Desktop and claude.ai
Settings → Connectors → Add custom connector, paste https://mcp.shipstatic.com, save.
Claude Code
claude mcp add --transport http shipstatic https://mcp.shipstatic.comCursor, Antigravity, Windsurf, n8n, Zed, and anywhere with mcp.json
{
"mcpServers": {
"shipstatic": {
"url": "https://mcp.shipstatic.com"
}
}
}VS Code
Install ShipStatic for VS Code. The server is built in, with no config at all.
Then just ask
"Publish this with ShipStatic."
Your agent publishes it, and you get back a link you can share right away, and a claim link. The site stays up for 3 days, and opening the claim link keeps it for good.
Want the site private? Say "publish this with ShipStatic's built-in password protection". Visitors have to type the password before they see anything, and saying "built-in" keeps your agent from writing a password page of its own.
Related MCP server: deloc-mcp
Keep your sites with a free account
Everything above works with no account. A free account keeps your sites for good, lets you use your own domain, and shows you everything you've published in one place.
Connect one when your client offers to sign you in, and the same URL answers with the rest. There's nothing to install and no key to paste: your client starts the sign-in itself.
Tools
All fifteen tools are on both doors. What changes is not which tools exist, but which ones answer: deployments_upload is the one that needs no account, and the other fourteen answer once you have connected one (hosted) or set SHIP_TOKEN (local).
Publishing, with no account
Tool | Description |
| Publish files and get a live URL instantly, optionally protected by a password |
Deployments, with an account
Tool | Description |
| List all deployments with their URLs, status, labels, and password protection state. Pages with |
| Get deployment details including URL, status, file count, size, labels, and password protection state |
| Update the labels on a deployment for organization and filtering |
| Permanently delete a deployment and all its files |
Domains, with an account
Tool | Description |
| Connect a custom domain to your site, switch deployments, or update labels |
| List all domains with their linked deployment and verification status. Pages with |
| Get domain details including linked deployment, verification status, and labels |
| Get the DNS records you need to configure at your DNS provider |
| The DNS provider recorded for a domain, if known (e.g. Cloudflare, Namecheap) |
| Get a shareable link so someone else can see the required DNS records |
| Check if a domain name is valid and available before connecting it |
| Check if DNS is configured correctly after you set up the records |
| Permanently disconnect and delete a custom domain |
Account, with an account
Tool | Description |
| Your email and name, and the account's plan, usage and caps |
Paging long lists
deployments_list and domains_list accept limit and cursor. Each response carries a cursor: pass it back to fetch the next page. A null cursor means you're on the last one.
Retrying a deploy safely
deployments_upload accepts an idempotencyKey. If a deploy times out you cannot tell "it never landed" from "it landed and the response was lost", and retrying without a key creates a second site. Send the same key on the retry and you get back the site the first try made, once it went live. A key works only within your account: an anonymous deploy ignores it, and a retry makes a new site.
Key the attempt, not the try: a run id, a commit sha, or a uuid generated before the first call. A key that changes on every retry does nothing.
Deployments that clean themselves up
deployments_upload accepts a ttl in seconds. The deployment expires when the time is up and the platform removes it. That's useful for previews and quick experiments you'd otherwise have to remember to delete.
{ "path": "/path/to/dist", "ttl": 3600 }It needs an account (a connected account on the hosted endpoint, or SHIP_TOKEN locally): a deploy with no account already expires on the platform's schedule, so a ttl on one is refused rather than ignored. A deployment carrying a ttl cannot be linked to any domain: deploy without one when the site needs a domain.
Run it on your own machine
This package runs the same fifteen tools, reached the other way: as a local process instead of the hosted URL. Use it when your MCP client doesn't speak OAuth yet, or when you'd rather set a key once than sign in. To publish a folder from your own machine, use the ShipStatic CLI instead: it reads the files straight from disk.
It needs Node.js 20.19 or newer, and takes one setting, SHIP_TOKEN, whose value is your API key from my.shipstatic.com/api-key. Without it, the local server works like the hosted URL with no account connected.
claude mcp add shipstatic -e SHIP_TOKEN=ship-your-api-key -- npx -y @shipstatic/mcpAny other client takes the same command and setting in its mcp.json:
{
"mcpServers": {
"shipstatic": {
"command": "npx",
"args": ["-y", "@shipstatic/mcp"],
"env": { "SHIP_TOKEN": "ship-your-api-key" }
}
}
}The MCP Registry lists ShipStatic as com.shipstatic/mcp, with the hosted URL.
Also available
Surface | Reach it |
| |
Search "ShipStatic" in the Marketplace | |
Install it in Cursor, Claude Code, Codex or Gemini CLI | |
Search "ShipStatic" in n8n's node panel | |
| |
|
License
MIT
Available Tools
15 toolsdeployments_deleteDelete DeploymentBDestructiveIdempotentInspect
Permanently deletes a deployment and its files.
| Name | Required | Description | Default |
|---|---|---|---|
| deployment | Yes | Deployment hostname to delete (e.g. "happy-cat-abc1234.shipstatic.com") |
Output Schema
| Name | Required | Description |
|---|---|---|
| status | Yes | The state the deployment is in while background cleanup runs. One of: pending, success, failed, deleting. |
| deployment | Yes | The deployment hostname that was marked for removal. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true, idempotentHint=true, readOnlyHint=false and openWorldHint=true, so safety is largely covered. The description adds one genuinely useful behavioral fact beyond the annotations: deletion cascades to the deployment's files. It does not address auth requirements, confirmation, or what happens to a repeated call despite the idempotent hint.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single front-loaded sentence with no filler; every word ('Permanently', 'and its files') carries weight. Nothing could be trimmed without losing information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With a fully documented schema, an output schema, and annotations covering the safety profile, the description supplies the one extra fact that matters (cascade to files). It is close to complete, though it omits any note on irreversibility/confirmation context an agent might want before a destructive call.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the single parameter ('deployment' hostname) is fully documented with an example in the schema. The description adds no parameter-level detail, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb ('deletes') and resource ('a deployment'), so an agent can distinguish it from deployments_get/list/set/upload at a glance. It does not, however, explicitly name the sibling tools or the condition that selects deletion over them, which a 5 would require.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no when-to-use or when-not-to-use guidance and no mention of alternatives such as deployments_set or deployments_list. Usage is only implied by the verb 'delete'.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
deployments_getGet DeploymentARead-onlyInspect
Get deployment details including URL, status, file count, size, labels, and password protection state.
| Name | Required | Description | Default |
|---|---|---|---|
| deployment | Yes | Deployment hostname (e.g. "happy-cat-abc1234.shipstatic.com"). Returned by deployments_upload or deployments_list. |
Output Schema
| Name | Required | Description |
|---|---|---|
| url | Yes | Full URL to the live deployment. |
| via | Yes | How the deployment was created, as shown in deployment history (today one of: web, sdk, cli, mcp, git, n8n, gpt, vsc, cld, crs, gmn, api). Null on deployments older than the tag. |
| size | Yes | Total deployment size in bytes. |
| files | Yes | Number of files in the deployment. |
| config | Yes | True if the deployment includes a ship.json routing config. |
| labels | Yes | Labels attached to the deployment; empty when none. |
| status | Yes | Deployment lifecycle state; "success" means the site is live. One of: pending, success, failed, deleting. |
| created | Yes | Unix timestamp (seconds) when the deployment was created. |
| expires | Yes | Unix timestamp (seconds) when the deployment expires; null when permanent. Anonymous deployments expire 3 days after creation unless claimed; an authenticated deployment carries one only when it requested a ttl. |
| password | Yes | True if the deployment is password-protected. |
| deployment | Yes | Deployment hostname, e.g. "happy-cat-abc1234.shipstatic.com". |
| screenshot | Yes | Full URL to the deployment screenshot. Rendered on the first request for it, so the URL is returned immediately and the first request takes a few seconds; every request after that is served immediately. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already establish that this is read-only and non-destructive, lowering the behavioral burden. The description adds value by specifying exactly what details are returned, which helps the agent understand the tool's output scope without needing to inspect the output schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single sentence that front-loads the action and immediately lists the valuable result fields. There is no filler, repetition, or unnecessary context.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter, read-only lookup with full input schema coverage, explicit read-only annotations, and an output schema, the description plus structured metadata gives an agent everything needed to select and invoke the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The only parameter, deployment, is fully documented in the schema with a type, example hostname, and a note that it comes from deployments_upload or deployments_list. With 100% schema description coverage, the description adds little extra meaning beyond what the schema already provides.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a strong, specific verb and resource ('Get deployment details') and enumerates the concrete data fields returned: URL, status, file count, size, labels, and password protection state. This clearly distinguishes it from sibling operations like deployments_delete, deployments_list, or deployments_upload.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description makes it clear this is a single-deployment lookup, and the parameter schema adds helpful provenance guidance: deployment hostnames are returned by deployments_upload or deployments_list. It does not explicitly state when not to use it, but the get-versus-list distinction is strongly implied by the tool name and description.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
deployments_listList DeploymentsARead-onlyInspect
List all deployments with their URLs, status, labels, and password protection state. The response's cursor is null on the last page; pass it back as cursor to fetch the next.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum number of items to return in one page. Omit for the server default. | |
| cursor | No | Opaque position from the previous response's `cursor` field; omit for the first page. |
Output Schema
| Name | Required | Description |
|---|---|---|
| cursor | Yes | Opaque cursor for the next page; null on the last page. The whole has-more signal. |
| deployments | Yes | The deployments on this page. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false, so the safety profile is known. The description adds the pagination contract (cursor null on last page, pass it back to fetch next), which is behavioral detail beyond the annotations. It does not contradict any annotation, and the read-only nature is consistent with the described operation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences with no filler. The first sentence states exactly what the tool returns, and the second covers the essential pagination detail. Every word earns its place, and the most important information is front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given that an output schema exists (signaling the response structure is documented separately), the description is complete for a list tool. It covers the action, the returned fields, and the pagination mechanics. Annotations cover safety, and the parameter schema is fully documented, so nothing an agent needs to call this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema fully documents both parameters (limit and cursor). The description adds no additional meaning to the parameters beyond what the schema already provides; it only ties the cursor to the pagination flow, which is implicit in the schema's description. The baseline of 3 applies because the schema carries the heavy lifting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb ('List') and resource ('all deployments') and enumerates the fields returned (URLs, status, labels, password protection state). It clearly distinguishes itself from sibling tools like deployments_get (which retrieves a single item) and deployments_delete (which removes one). The name and title reinforce the purpose.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explains how to handle pagination (passing cursor back), which is clear usage guidance for iterating pages. However, it does not explicitly contrast with alternatives (e.g., when to use deployments_get vs this list), though the sibling names are self-explanatory. It provides context but no exclusions or explicit when-not-to-use scenarios.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
deployments_setUpdate Deployment LabelsADestructiveInspect
Update deployment labels. Replaces all existing labels.
| Name | Required | Description | Default |
|---|---|---|---|
| labels | Yes | Labels to set. Replaces all existing labels. Pass empty array to clear. | |
| deployment | Yes | Deployment hostname (e.g. "happy-cat-abc1234.shipstatic.com"). Use deployments_list to find deployments. |
Output Schema
| Name | Required | Description |
|---|---|---|
| url | Yes | Full URL to the live deployment. |
| via | Yes | How the deployment was created, as shown in deployment history (today one of: web, sdk, cli, mcp, git, n8n, gpt, vsc, cld, crs, gmn, api). Null on deployments older than the tag. |
| size | Yes | Total deployment size in bytes. |
| files | Yes | Number of files in the deployment. |
| config | Yes | True if the deployment includes a ship.json routing config. |
| labels | Yes | Labels attached to the deployment; empty when none. |
| status | Yes | Deployment lifecycle state; "success" means the site is live. One of: pending, success, failed, deleting. |
| created | Yes | Unix timestamp (seconds) when the deployment was created. |
| expires | Yes | Unix timestamp (seconds) when the deployment expires; null when permanent. Anonymous deployments expire 3 days after creation unless claimed; an authenticated deployment carries one only when it requested a ttl. |
| password | Yes | True if the deployment is password-protected. |
| deployment | Yes | Deployment hostname, e.g. "happy-cat-abc1234.shipstatic.com". |
| screenshot | Yes | Full URL to the deployment screenshot. Rendered on the first request for it, so the URL is returned immediately and the first request takes a few seconds; every request after that is served immediately. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description explicitly discloses the destructive behavior: 'Replaces all existing labels.' This goes beyond the generic destructiveHint annotation by telling the agent exactly what is affected and that labels not included in the request will be removed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two short sentences with no filler. The primary action is front-loaded and the essential replacement behavior is stated immediately after, making it easy for an agent to parse quickly.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a two-parameter tool with a fully documented input schema and an existing output schema, the description provides the key operational context, particularly the label replacement semantics. It lacks explicit usage guidance and alternative routing, but the core information needed to call the tool correctly is present.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, and the schema already documents each parameter thoroughly, including the empty-array-to-clear behavior for labels. The description adds no parameter-specific meaning beyond what the schema provides, so the baseline score of 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the action ('Update') and the resource ('deployment labels'), and the second sentence clarifies the full replacement semantics. It does not explicitly differentiate from sibling tools like deployments_get or deployments_list, but the resource and verb are specific enough to avoid major ambiguity.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives no guidance on when to prefer this tool over alternatives, nor does it state prerequisites or exclusions. The schema mentions 'Use deployments_list to find deployments,' but the tool description itself does not provide usage context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
deployments_uploadDeploy Static SiteAInspect
Deploy a static site instantly: free, no account or API key required. Returns the live URL, file count, and size. Without SHIP_TOKEN, the response also includes a one-time claim URL, and the site expires in 3 days unless claimed. Pass password to make the site private.
| Name | Required | Description | Default |
|---|---|---|---|
| ttl | No | Seconds until this deployment expires and the platform reclaims it; omit for one that never does. Only for authenticated deploys — an anonymous deployment already expires on the platform's schedule, and a requested ttl on one is refused. A deployment carrying a ttl cannot be linked to any domain: deploy without one if the site needs a domain. | |
| path | Yes | Absolute path to the build output directory to deploy (e.g. "/Users/me/project/dist") | |
| labels | No | Labels for organizing deployments (e.g. ["env:production", "v1.2"]). Each is a word, or a key and a value split by one ":". Lowercase, 3-63 chars, allows . _ - inside a word. Up to 10. | |
| password | No | Optional password to gate the deployment behind an unlock prompt (6–128 characters; whitespace significant). Visitors must enter this password before viewing the site, including on any custom domains pointing at it. | |
| idempotencyKey | No | Makes this deploy replayable instead of repeatable. A deploy is not naturally idempotent: if a call times out you cannot tell "it never landed" from "it landed and the response was lost", and retrying creates a second deployment. Send the same key on the retry and you get back the deployment the first try made, if it went live in the last 24 hours. A key works only within the account that sent it: without an account it is ignored, and a retry deploys again. Key the ATTEMPT (a run id, a commit sha, a uuid minted before the first try), never one minted fresh on each retry, which would defeat the point. |
Output Schema
| Name | Required | Description |
|---|---|---|
| url | Yes | Full URL to the live deployment. |
| via | Yes | How the deployment was created, as shown in deployment history (today one of: web, sdk, cli, mcp, git, n8n, gpt, vsc, cld, crs, gmn, api). Null on deployments older than the tag. |
| size | Yes | Total deployment size in bytes. |
| claim | No | One-time URL that claims this anonymous deployment to a free account, making it permanent. Only present on anonymous deploys; absent when the deploy was made with a connected account. |
| files | Yes | Number of files in the deployment. |
| config | Yes | True if the deployment includes a ship.json routing config. |
| labels | Yes | Labels attached to the deployment; empty when none. |
| status | Yes | Deployment lifecycle state; "success" means the site is live. One of: pending, success, failed, deleting. |
| created | Yes | Unix timestamp (seconds) when the deployment was created. |
| expires | Yes | Unix timestamp (seconds) when the deployment expires; null when permanent. Anonymous deployments expire 3 days after creation unless claimed; an authenticated deployment carries one only when it requested a ttl. |
| password | Yes | True if the deployment is password-protected. |
| deployment | Yes | Deployment hostname, e.g. "happy-cat-abc1234.shipstatic.com". |
| screenshot | Yes | Full URL to the deployment screenshot. Rendered on the first request for it, so the URL is returned immediately and the first request takes a few seconds; every request after that is served immediately. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=false and openWorldHint=true; the description adds real behavioral context beyond them — no auth needed, anonymous sites expire in 3 days unless claimed via a one-time URL, and the password gate applies to custom domains too. It omits operational traits such as rate limits, payload/size limits, and what happens to existing deployments, so it stops short of a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight sentences, front-loaded with the core action and followed by the two facts an agent most needs (returns and expiry/claim behavior). No filler or repetition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With a full output schema, complete parameter documentation, and annotation-covered safety, the description covers the essentials: what it does, what it returns, and the anonymous-expiry caveat. Minor gaps remain around auth token sourcing (SHIP_TOKEN is referenced but never explained) and deployment limits.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so all five parameters (including the rich ttl and idempotencyKey semantics) are already fully documented in the schema. The description restates only the password behavior ("make the site private"), adding little beyond what the schema says; baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
"Deploy a static site instantly" is a specific verb+resource, and it is unambiguously distinct from the sibling read/manage tools (deployments_list, deployments_get, deployments_set, deployments_delete). The added notes about return values and anonymous vs. token-based deploys further pin down what this tool is.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives useful context for choosing the anonymous path (free, no account/API key, 3-day expiry unless claimed) but never explicitly states when to use this over siblings or when to prefer an authenticated deploy. Usage is implied rather than spelled out, and no alternatives are named.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
domains_deleteDelete DomainADestructiveIdempotentInspect
Permanently deletes a domain.
| Name | Required | Description | Default |
|---|---|---|---|
| domain | Yes | Domain name to delete (e.g. "www.example.com") |
Output Schema
| Name | Required | Description |
|---|---|---|
| domain | Yes | The domain name that was removed, normalized. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotation destructiveHint=true already signals the destructive nature, so the description adds little beyond repeating 'Permanently deletes'. It does not clarify whether the action is reversible, requires authentication, affects DNS records, or has rate limits. With annotations providing basic safety hints, the description fails to add meaningful behavioral context for a destructive operation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Extremely concise single sentence that front-loads the key verb. No waste, no redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive tool with an output schema and full parameter description, the minimal description is adequate but misses important context such as whether deletion cascades to related domains or DNS records, whether it can be undone, and any required permissions. The annotations cover some safety aspects, but the overall guidance for a high-risk operation is thin.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Only one parameter, and the schema fully describes it with an example. The description correctly implies a domain name is needed but adds no extra meaning since the schema already covers it well. Since there is a single parameter, baseline 4 applies when the schema is rich.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (deletes) and resource (domain) precisely matching the tool name and title. It is clearly distinguishable from siblings like domains_get or domains_set, making the agent's selection easy.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides no guidance on when to use this tool versus alternatives such as domains_set or domains_verify, nor any prerequisites or warnings beyond the word 'Permanently'. The agent must infer appropriate contexts.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
domains_dnsGet DNS ProviderARead-onlyInspect
Returns the DNS provider recorded for the domain, if known (e.g. Cloudflare, Namecheap): where its DNS records are configured. Custom domains only, and only while the domain is unverified; once its DNS is right there is nothing left to locate.
| Name | Required | Description | Default |
|---|---|---|---|
| domain | Yes | Domain name (e.g. "www.example.com"). Must be a domain previously created with domains_set. |
Output Schema
| Name | Required | Description |
|---|---|---|
| dns | Yes | What the platform recorded about the domain's DNS provider when the domain was created; null if nothing was recorded. |
| domain | Yes | The domain name. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already establish readOnlyHint=true, destructiveHint=false, openWorldHint=false, so safety is covered. The description earns credit by adding non-obvious behavior beyond them: the result is best-effort ('if known'), and the tool is only meaningful while the domain is unverified — a real applicability constraint an agent cannot get from the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
One compact passage with the resource stated first and the scoping constraint immediately after. The closing clause ('once its DNS is right there is nothing left to locate') is slightly colloquial but does real work by explaining the unverified-only rule.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, return-shape detail is not required, and the description covers purpose, scope, and the unverified-only precondition adequately. The only meaningful omission is routing to sibling tools when the precondition fails.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and there is a single required 'domain' parameter fully documented in the schema, including its prerequisite ('previously created with domains_set'). The description adds no syntax or format detail, so the baseline 3 for schema-covered params applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description gives a specific verb and resource — 'Returns the DNS provider recorded for the domain' — with concrete examples (Cloudflare, Namecheap). It does not name the nearest siblings (domains_records, domains_get, domains_verify), so differentiation is implied by scope rather than stated.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It states a clear when-condition and two when-not conditions: 'Custom domains only, and only while the domain is unverified; once its DNS is right there is nothing left to locate.' That is strong applicability guidance, though it never points to the alternative tool an agent should use instead (e.g. domains_records for record inspection).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
domains_getGet DomainARead-onlyInspect
Get domain details including URL, linked deployment, labels, and status: the one word saying what the domain needs from its owner (unverified, unlinked, live, paused).
| Name | Required | Description | Default |
|---|---|---|---|
| domain | Yes | Domain name (e.g. "www.example.com"). Use domains_list to find names. |
Output Schema
| Name | Required | Description |
|---|---|---|
| url | Yes | Full URL to the domain. |
| links | Yes | How many times a deployment has been linked to this domain. |
| domain | Yes | The domain name, e.g. "www.example.com". |
| labels | Yes | Labels attached to the domain; empty when none. |
| linked | Yes | Unix timestamp (seconds) when a deployment was last linked; null if never linked. |
| paused | Yes | Unix timestamp (seconds) when plan enforcement paused serving; null while the plan has room for it. |
| status | Yes | What this domain needs from its owner, derived: "live" serves the linked deployment and needs nothing; "unlinked" is verified with nothing published there, so link a deployment; "unverified" needs its DNS records configured; "paused" means the plan no longer has room for it. Read this word rather than recomputing it. One of: live, unlinked, unverified, paused. |
| created | Yes | Unix timestamp (seconds) when the domain was created. |
| verified | Yes | When DNS last became verified; null if it never has, and never cleared, so a domain whose records moved away keeps it. Read `verification` for whether DNS is right now. |
| deployment | Yes | The deployment hostname this domain points to; null when reserved but not yet linked. |
| verification | Yes | How far DNS verification has got: "pending" is the site's CNAME not pointing here, "partial" is a www domain's CNAME pointing here without its apex A record (the redirect), "verified" is every required record. The diagnostic under "unverified"; ShipStatic domains are born verified. One of: pending, partial, verified. |
| verifications | Yes | How many DNS verification attempts this domain has had. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, openWorldHint=false, and destructiveHint=false, so safety is covered. The description adds genuinely non-structured context by decoding the `status` values (unverified, unlinked, live, paused) and what they mean to the owner, which an agent cannot infer from the schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single sentence that leads with the core action and then lists the payload. The trailing status parenthetical is somewhat long but it carries real information, so it earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, the description needn't document return values, and it still sketches them usefully. Combined with annotations covering the read-only profile and a fully documented single parameter, an agent has what it needs to call this correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
There is only one parameter and schema description coverage is 100%, including an example format and a pointer to domains_list. The description adds nothing about the `domain` argument, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description gives a specific verb ('Get') and resource ('domain details') and enumerates the returned fields (URL, linked deployment, labels, status), which is enough to separate it from domains_list and domains_delete. It does not explicitly name a sibling to contrast against, so it falls short of the top score.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no when-to-use guidance in the description itself — no mention of when to call this versus domains_list, domains_records, or domains_dns. The only routing hint ('Use domains_list to find names') lives in the schema's parameter description, not here.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
domains_listList DomainsARead-onlyInspect
List all domains with their URLs, linked deployment, and status. The response's cursor is null on the last page; pass it back as cursor to fetch the next.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum number of items to return in one page. Omit for the server default. | |
| cursor | No | Opaque position from the previous response's `cursor` field; omit for the first page. |
Output Schema
| Name | Required | Description |
|---|---|---|
| cursor | Yes | Opaque cursor for the next page; null on the last page. The whole has-more signal. |
| domains | Yes | The domains on this page. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, destructiveHint=false, and openWorldHint=false, so the safety profile is covered. The description adds useful behavioral detail beyond the annotations: the response includes URLs, linked deployment, and status, and pagination terminates when cursor is null. It does not mention auth or rate limits, but this is a safe read operation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences with zero waste. The core listing behavior is front-loaded, and pagination guidance follows naturally without repetition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the presence of an output schema and read-only annotations, the description covers what is listed, what fields are returned, and how pagination works. It omits sibling alternatives and any filtering context, but no filter parameters exist, so it is nearly complete for a simple list tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so both parameters are already documented. The description restates cursor usage and adds that it is null on the last page, but adds no syntax or format detail for limit, so the baseline 3 is appropriate when the schema carries parameter semantics.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource ('List all domains') and names the returned fields (URLs, linked deployment, status), so the tool's purpose is immediately clear. It does not explicitly distinguish itself from the sibling domains_get, but the list scope is implied.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The tool's usage is implied by 'List all domains' and the description explicitly explains how to continue pagination. It gives no guidance on when to prefer this over siblings like domains_get or domains_records, and no exclusions or prerequisites are stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
domains_recordsGet DNS RecordsARead-onlyInspect
Returns the DNS records to configure at the domain's DNS provider. Call after domains_set. Custom domains only: a ShipStatic domain has no records to configure.
| Name | Required | Description | Default |
|---|---|---|---|
| domain | Yes | Domain name. Must be a domain previously created with domains_set. |
Output Schema
| Name | Required | Description |
|---|---|---|
| apex | Yes | The apex (registered) domain where DNS records are managed. |
| domain | Yes | The domain the records are for. |
| records | Yes | The records to configure at the DNS provider, in the order to add them. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, destructiveHint=false and openWorldHint=false, so the safety profile is covered. The description usefully adds the sequencing dependency and the custom-domain restriction, but says nothing about authentication, rate limits, or how records are sourced, which is acceptable given the annotation coverage.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight sentences with zero waste; the purpose is front-loaded and the constraint follows. Nothing could be removed without losing information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be explained, and the description covers the prerequisite and scope. For a single-parameter read tool this is close to complete, with only the sibling distinction left implicit.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Only one parameter exists and schema coverage is 100%, with the schema itself stating the domain must have been created via domains_set. The description adds no syntax, format, or example beyond what the schema already provides, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Returns the DNS records to configure at the domain's DNS provider') and scopes it to custom domains, which is clear enough to act on. It stops short of explicitly differentiating itself from the nearby domains_dns sibling, so an agent could still hesitate between the two.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit prerequisite ('Call after domains_set') and an explicit exclusion ('a ShipStatic domain has no records to configure'), which is strong when/when-not guidance. It does not name an alternative tool for the excluded case, which is the only thing keeping it from a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
domains_setSet DomainADestructiveInspect
Create or update a domain: a ShipStatic domain (e.g. "yourname.shipstatic.com"), live as soon as a deployment is linked, or a custom domain (e.g. "www.example.com"), which needs DNS records first. Can reserve a name (omit deployment), link it to a deployment, switch deployments, or update labels. For a custom domain, domains_records then returns the DNS records to configure.
| Name | Required | Description | Default |
|---|---|---|---|
| domain | Yes | Domain name: a ShipStatic domain (e.g. "yourname.shipstatic.com") or a custom domain (e.g. "www.example.com") | |
| labels | No | Labels for organizing domains (e.g. ["production"]). | |
| deployment | No | Deployment to serve on this domain (e.g. "happy-cat-abc1234.shipstatic.com"). Omit to reserve the domain without linking. |
Output Schema
| Name | Required | Description |
|---|---|---|
| url | Yes | Full URL to the domain. |
| links | Yes | How many times a deployment has been linked to this domain. |
| domain | Yes | The domain name, e.g. "www.example.com". |
| labels | Yes | Labels attached to the domain; empty when none. |
| linked | Yes | Unix timestamp (seconds) when a deployment was last linked; null if never linked. |
| paused | Yes | Unix timestamp (seconds) when plan enforcement paused serving; null while the plan has room for it. |
| status | Yes | What this domain needs from its owner, derived: "live" serves the linked deployment and needs nothing; "unlinked" is verified with nothing published there, so link a deployment; "unverified" needs its DNS records configured; "paused" means the plan no longer has room for it. Read this word rather than recomputing it. One of: live, unlinked, unverified, paused. |
| created | Yes | Unix timestamp (seconds) when the domain was created. |
| isCreate | Yes | True when this call created the domain; false when it updated an existing one. |
| verified | Yes | When DNS last became verified; null if it never has, and never cleared, so a domain whose records moved away keeps it. Read `verification` for whether DNS is right now. |
| deployment | Yes | The deployment hostname this domain points to; null when reserved but not yet linked. |
| verification | Yes | How far DNS verification has got: "pending" is the site's CNAME not pointing here, "partial" is a www domain's CNAME pointing here without its apex A record (the redirect), "verified" is every required record. The diagnostic under "unverified"; ShipStatic domains are born verified. One of: pending, partial, verified. |
| verifications | Yes | How many DNS verification attempts this domain has had. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=false, destructiveHint=true and openWorldHint=true, so the safety profile is covered. The description adds real behavioral context beyond them: a ShipStatic domain goes live as soon as a deployment is linked, while a custom domain requires DNS records first. It does not spell out that an update overwrites existing linkage/labels, which would have earned a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three dense sentences, front-loaded with the core action and its two branches before the operational modes. The repeated inline examples overlap with the schema's own examples, a small redundancy, but no sentence is filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, return values need no explanation, and the annotations carry the safety profile. The description covers the domain variants, the DNS prerequisite, and every mutation mode the tool supports, so nothing an agent needs to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents all three parameters including the omit-to-reserve semantics. The description restates the domain-type distinction and the reserve case but adds no format or behavioral detail the schema lacks, making the baseline 3 appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ("Create or update a domain") and immediately splits the resource into its two meaningful variants, ShipStatic vs custom, with examples. It also distinguishes itself from the sibling domains_records, so an agent can place it without opening another schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Enumerates the four usage modes clearly: reserve (omit deployment), link to a deployment, switch deployments, update labels, and points to domains_records as the follow-up for custom DNS. It lacks an explicit when-not/alternative (e.g. domains_delete for removal, domains_get for reads), so it falls just short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
domains_validateCheck Domain AvailabilityARead-onlyInspect
Check if a domain name is valid and available before creating it. Returns the normalized form and availability.
| Name | Required | Description | Default |
|---|---|---|---|
| domain | Yes | Domain name to check (e.g. "yourname.shipstatic.com" or "www.example.com"). Call before domains_set to check availability. |
Output Schema
| Name | Required | Description |
|---|---|---|
| valid | Yes | Whether the domain's shape is usable. |
| reason | Yes | Why the name is unusable, for display; null when it is usable. |
| available | Yes | Whether nobody has registered the name yet; null when invalid. Creating it would be new; re-pointing your own domain is a write, not a create. |
| normalized | Yes | The normalized domain name; null when invalid. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, destructiveHint=false, and openWorldHint=false, so the safety profile is covered. The description adds that the call returns a normalized form and availability, which hints at behavior, but nothing about rate limits or what makes a domain 'valid'. With annotations carrying the main burden, a 3 is right.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight sentences with the purpose front-loaded and zero filler. No structural problems, though it stops short of the routing information that would let it earn a 5.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be expanded, and the description still summarizes the return payload (normalized form, availability). For a one-parameter read-only tool this is adequate, with the only real gap being disambiguation from domains_verify.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Only one parameter at 100% schema description coverage, so the schema already documents the argument and even the pre-call guidance. The description adds no format or normalization detail beyond what the schema provides; baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: validates and checks availability of a domain name, with the temporal context 'before creating it'. However, it does not distinguish itself from the sibling domains_verify, which an agent may reasonably confuse with this tool.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The phrase 'before creating it' implies this is a pre-flight check, and the schema param description names domains_set directly. But the description itself never names the alternative tools (domains_set, domains_verify) or states when NOT to use it, so routing between validate and verify is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
domains_verifyVerify Domain DNSAInspect
Trigger DNS verification for a custom domain. Call after the user has configured DNS records from domains_records. Custom domains only, and refused once the domain is verified: read domains_get instead. Verification is asynchronous: read the domain again with domains_get to learn the verdict, since its status has not moved yet when this returns. A verified domain serves nothing until a deployment is linked with domains_set.
| Name | Required | Description | Default |
|---|---|---|---|
| domain | Yes | Domain name to verify DNS for. Must be a domain previously created with domains_set. |
Output Schema
| Name | Required | Description |
|---|---|---|
| domain | Yes | The domain whose DNS verification was queued, normalized. The check runs asynchronously; the domain's `verification` and `status` update once DNS propagates, so read the domain again rather than trusting this acknowledgement for a verdict. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations (readOnlyHint=false, destructiveHint=false, openWorldHint=true), the description discloses key traits: the call is asynchronous, the returned status is stale, results must be polled via domains_get, and the operation is refused once verified. It also notes a verified domain serves nothing until a deployment is linked. This is rich behavioral context an agent cannot get from the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Tight, front-loaded prose: the core action leads, followed by prerequisite, exclusions, async caveat, and follow-up. Every clause carries actionable signal with no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return-value explanation is unnecessary, and the description instead covers the async lifecycle and the follow-up reads/writes needed. For a single-parameter verification trigger, nothing an agent needs is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Only one parameter with 100% schema description coverage; the schema already states it must be a domain previously created with domains_set. The description's prerequisite wording amplifies but does not add format or syntax detail beyond the schema. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (trigger verification) and resource (DNS for a custom domain) in the first sentence. It is immediately distinguishable from siblings like domains_get (read status) and domains_set (link deployment), which it names explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit precondition (call after configuring DNS records from domains_records), an exclusion (custom domains only), a negative condition (refused once verified, use domains_get instead), and a follow-up routing (link with domains_set). Nothing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
whoamiShow AccountARead-onlyInspect
Returns your email and name, and the account's plan, usage and caps.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| caps | Yes | What the account is allowed to hold, under usage's cap keys, so the pair divides. A pending invitation takes a member place, so it counts against members. |
| name | Yes | Display name; null if not set. |
| plan | Yes | The plan the account is on. One of: free, pro, team, scale, sponsored. |
| Yes | The account email address. | |
| usage | Yes | What the account currently holds: every cap, and the pending invitations beside them. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare the full safety profile (readOnlyHint=true, destructiveHint=false, openWorldHint=false), so the description carries a light burden. It adds a summary of what is retrieved, but since an output schema exists that already documents the return values, this is largely restatement rather than new behavioral context.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single front-loaded sentence with no filler — verb first, then the exact fields returned. Every clause earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter read tool with a full annotation set and an output schema, the description is essentially complete. The only omission is any mention of authentication or state assumptions, which is minor given openWorldHint=false and the self-referential 'your' framing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so there is no parameter semantics for the description to explain; the baseline for a no-arg tool applies. Nothing about argument form or filtering options is missing.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Specific verb ('Returns') plus precisely enumerated resources: the caller's email and name, and the account's plan, usage and caps. The sibling set is entirely deployment/domain CRUD operations, so there is no overlapping purpose to disambiguate against — the agent can identify this tool's job immediately.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is only implied: an agent infers it should call this when it needs to know which account it is acting as. There is no explicit when-to-use statement, no prerequisites (e.g. auth required), and no named alternative — though none of the siblings compete here.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
17 tool updates
v0.4.6- Added
deployments_delete - Changed
deployments_get1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "properties": { + "config": { + "description": "True if the deployment includes a ship.json routing config.", + "type": "boolean" + }, + "created": { + "description": "Unix timestamp (seconds) when the deployment was created.", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "deployment": { + "description": "Deployment hostname, e.g. \"happy-cat-abc1234.shipstatic.com\".", + "type": "string" + }, + "expires": { + "anyOf": [ + { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "Unix timestamp (seconds) when the deployment expires; null when permanent. Anonymous deployments expire 3 days after creation unless claimed; an authenticated deployment carries one only when it requested a ttl." + }, + "files": { + "description": "Number of files in the deployment.", + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" + }, + "labels": { + "description": "Labels attached to the deployment; empty when none.", + "items": { + "type": "string" + }, + "type": "array" + }, + "password": { + "description": "True if the deployment is password-protected.", + "type": "boolean" + }, + "screenshot": { + "description": "Full URL to the deployment screenshot. Rendered on the first request for it, so the URL is returned immediately and the first request takes a few seconds; every request after that is served immediately.", + "format": "uri", + "type": "string" + }, + "size": { + "description": "Total deployment size in bytes.", + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" + }, + "status": { + "description": "Deployment lifecycle state; \"success\" means the site is live. One of: pending, success, failed, deleting.", + "type": "string" + }, + "url": { + "description": "Full URL to the live deployment.", + "format": "uri", + "type": "string" + }, + "via": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "How the deployment was created, as shown in deployment history (today one of: web, sdk, cli, mcp, git, n8n, gpt, vsc, cld, crs, gmn, api). Null on deployments older than the tag." + } + }, + "required": [ + "deployment", + "url", + "files", + "size", + "status", + "config", + "password", + "labels", + "via", + "created", + "expires", + "screenshot" + ], + "type": "object" +}
- Changed
deployments_list4 fields changed- added
Input schema / $schemaAdded value: +"http://json-schema.org/draft-07/schema#" - added
Input schema / properties / cursorAdded value: +{ + "description": "Opaque position from the previous response's `cursor` field; omit for the first page.", + "type": "string" +} - added
Input schema / properties / limitAdded value: +{ + "description": "Maximum number of items to return in one page. Omit for the server default.", + "maximum": 9007199254740991, + "minimum": 1, + "type": "integer" +} - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "properties": { + "cursor": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Opaque cursor for the next page; null on the last page. The whole has-more signal." + }, + "deployments": { + "description": "The deployments on this page.", + "items": { + "additionalProperties": false, + "properties": { + "config": { + "description": "True if the deployment includes a ship.json routing config.", + "type": "boolean" + }, + "created": { + "description": "Unix timestamp (seconds) when the deployment was created.", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "deployment": { + "description": "Deployment hostname, e.g. \"happy-cat-abc1234.shipstatic.com\".", + "type": "string" + }, + "expires": { + "anyOf": [ + { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "Unix timestamp (seconds) when the deployment expires; null when permanent. Anonymous deployments expire 3 days after creation unless claimed; an authenticated deployment carries one only when it requested a ttl." + }, + "files": { + "description": "Number of files in the deployment.", + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" + }, + "labels": { + "description": "Labels attached to the deployment; empty when none.", + "items": { + "type": "string" + }, + "type": "array" + }, + "password": { + "description": "True if the deployment is password-protected.", + "type": "boolean" + }, + "screenshot": { + "description": "Full URL to the deployment screenshot. Rendered on the first request for it, so the URL is returned immediately and the first request takes a few seconds; every request after that is served immediately.", + "format": "uri", + "type": "string" + }, + "size": { + "description": "Total deployment size in bytes.", + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" + }, + "status": { + "description": "Deployment lifecycle state; \"success\" means the site is live. One of: pending, success, failed, deleting.", + "type": "string" + }, + "url": { + "description": "Full URL to the live deployment.", + "format": "uri", + "type": "string" + }, + "via": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "How the deployment was created, as shown in deployment history (today one of: web, sdk, cli, mcp, git, n8n, gpt, vsc, cld, crs, gmn, api). Null on deployments older than the tag." + } + }, + "required": [ + "deployment", + "url", + "files", + "size", + "status", + "config", + "password", + "labels", + "via", + "created", + "expires", + "screenshot" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "cursor", + "deployments" + ], + "type": "object" +}
- Removed
deployments_remove - Changed
deployments_set1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "properties": { + "config": { + "description": "True if the deployment includes a ship.json routing config.", + "type": "boolean" + }, + "created": { + "description": "Unix timestamp (seconds) when the deployment was created.", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "deployment": { + "description": "Deployment hostname, e.g. \"happy-cat-abc1234.shipstatic.com\".", + "type": "string" + }, + "expires": { + "anyOf": [ + { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "Unix timestamp (seconds) when the deployment expires; null when permanent. Anonymous deployments expire 3 days after creation unless claimed; an authenticated deployment carries one only when it requested a ttl." + }, + "files": { + "description": "Number of files in the deployment.", + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" + }, + "labels": { + "description": "Labels attached to the deployment; empty when none.", + "items": { + "type": "string" + }, + "type": "array" + }, + "password": { + "description": "True if the deployment is password-protected.", + "type": "boolean" + }, + "screenshot": { + "description": "Full URL to the deployment screenshot. Rendered on the first request for it, so the URL is returned immediately and the first request takes a few seconds; every request after that is served immediately.", + "format": "uri", + "type": "string" + }, + "size": { + "description": "Total deployment size in bytes.", + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" + }, + "status": { + "description": "Deployment lifecycle state; \"success\" means the site is live. One of: pending, success, failed, deleting.", + "type": "string" + }, + "url": { + "description": "Full URL to the live deployment.", + "format": "uri", + "type": "string" + }, + "via": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "How the deployment was created, as shown in deployment history (today one of: web, sdk, cli, mcp, git, n8n, gpt, vsc, cld, crs, gmn, api). Null on deployments older than the tag." + } + }, + "required": [ + "deployment", + "url", + "files", + "size", + "status", + "config", + "password", + "labels", + "via", + "created", + "expires", + "screenshot" + ], + "type": "object" +}
- Changed
deployments_upload5 fields changed- added
Input schema / properties / idempotencyKeyAdded value: +{ + "description": "Makes this deploy replayable instead of repeatable. A deploy is not naturally idempotent: if a call times out you cannot tell \"it never landed\" from \"it landed and the response was lost\", and retrying creates a second deployment. Send the same key on the retry and you get back the deployment the first try made, if it went live in the last 24 hours. A key works only within the account that sent it: without an account it is ignored, and a retry deploys again. Key the ATTEMPT (a run id, a commit sha, a uuid minted before the first try), never one minted fresh on each retry, which would defeat the point.", + "type": "string" +} - changed
Input schema / properties / labels / descriptionPrevious value: -"Labels for organizing deployments (e.g. [\"production\", \"v1.2\"]). Lowercase, 3-25 chars, allows . _ - separators."New value: +"Labels for organizing deployments (e.g. [\"env:production\", \"v1.2\"]). Each is a word, or a key and a value split by one \":\". Lowercase, 3-63 chars, allows . _ - inside a word. Up to 10." - added
Input schema / properties / passwordAdded value: +{ + "description": "Optional password to gate the deployment behind an unlock prompt (6–128 characters; whitespace significant). Visitors must enter this password before viewing the site, including on any custom domains pointing at it.", + "type": "string" +} - added
Input schema / properties / ttlAdded value: +{ + "description": "Seconds until this deployment expires and the platform reclaims it; omit for one that never does. Only for authenticated deploys — an anonymous deployment already expires on the platform's schedule, and a requested ttl on one is refused. A deployment carrying a ttl cannot be linked to any domain: deploy without one if the site needs a domain.", + "type": "number" +} - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "properties": { + "claim": { + "description": "One-time URL that claims this anonymous deployment to a free account, making it permanent. Only present on anonymous deploys; absent when the deploy was made with a connected account.", + "format": "uri", + "type": "string" + }, + "config": { + "description": "True if the deployment includes a ship.json routing config.", + "type": "boolean" + }, + "created": { + "description": "Unix timestamp (seconds) when the deployment was created.", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "deployment": { + "description": "Deployment hostname, e.g. \"happy-cat-abc1234.shipstatic.com\".", + "type": "string" + }, + "expires": { + "anyOf": [ + { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "Unix timestamp (seconds) when the deployment expires; null when permanent. Anonymous deployments expire 3 days after creation unless claimed; an authenticated deployment carries one only when it requested a ttl." + }, + "files": { + "description": "Number of files in the deployment.", + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" + }, + "labels": { + "description": "Labels attached to the deployment; empty when none.", + "items": { + "type": "string" + }, + "type": "array" + }, + "password": { + "description": "True if the deployment is password-protected.", + "type": "boolean" + }, + "screenshot": { + "description": "Full URL to the deployment screenshot. Rendered on the first request for it, so the URL is returned immediately and the first request takes a few seconds; every request after that is served immediately.", + "format": "uri", + "type": "string" + }, + "size": { + "description": "Total deployment size in bytes.", + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" + }, + "status": { + "description": "Deployment lifecycle state; \"success\" means the site is live. One of: pending, success, failed, deleting.", + "type": "string" + }, + "url": { + "description": "Full URL to the live deployment.", + "format": "uri", + "type": "string" + }, + "via": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "How the deployment was created, as shown in deployment history (today one of: web, sdk, cli, mcp, git, n8n, gpt, vsc, cld, crs, gmn, api). Null on deployments older than the tag." + } + }, + "required": [ + "deployment", + "url", + "files", + "size", + "status", + "config", + "password", + "labels", + "via", + "created", + "expires", + "screenshot" + ], + "type": "object" +}
- Added
domains_delete - Changed
domains_dns2 fields changed- changed
Input schema / properties / domain / descriptionPrevious value: -"Domain name to look up DNS provider for (e.g. \"www.example.com\")"New value: +"Domain name (e.g. \"www.example.com\"). Must be a domain previously created with domains_set." - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "properties": { + "dns": { + "anyOf": [ + { + "additionalProperties": false, + "properties": { + "provider": { + "additionalProperties": false, + "description": "The provider serving this domain's DNS; absent when unidentified.", + "properties": { + "name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Provider name, e.g. \"Cloudflare\"; null if unknown." + }, + "url": { + "anyOf": [ + { + "format": "uri", + "type": "string" + }, + { + "type": "null" + } + ], + "description": "The provider's DNS dashboard, where the records get added; null or absent when unknown." + } + }, + "required": [ + "name" + ], + "type": "object" + } + }, + "type": "object" + }, + { + "type": "null" + } + ], + "description": "What the platform recorded about the domain's DNS provider when the domain was created; null if nothing was recorded." + }, + "domain": { + "description": "The domain name.", + "type": "string" + } + }, + "required": [ + "domain", + "dns" + ], + "type": "object" +}
- Changed
domains_get1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "properties": { + "created": { + "description": "Unix timestamp (seconds) when the domain was created.", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "deployment": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "The deployment hostname this domain points to; null when reserved but not yet linked." + }, + "domain": { + "description": "The domain name, e.g. \"www.example.com\".", + "type": "string" + }, + "labels": { + "description": "Labels attached to the domain; empty when none.", + "items": { + "type": "string" + }, + "type": "array" + }, + "linked": { + "anyOf": [ + { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "Unix timestamp (seconds) when a deployment was last linked; null if never linked." + }, + "links": { + "description": "How many times a deployment has been linked to this domain.", + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" + }, + "paused": { + "anyOf": [ + { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "Unix timestamp (seconds) when plan enforcement paused serving; null while the plan has room for it." + }, + "status": { + "description": "What this domain needs from its owner, derived: \"live\" serves the linked deployment and needs nothing; \"unlinked\" is verified with nothing published there, so link a deployment; \"unverified\" needs its DNS records configured; \"paused\" means the plan no longer has room for it. Read this word rather than recomputing it. One of: live, unlinked, unverified, paused.", + "type": "string" + }, + "url": { + "description": "Full URL to the domain.", + "format": "uri", + "type": "string" + }, + "verification": { + "description": "How far DNS verification has got: \"pending\" is the site's CNAME not pointing here, \"partial\" is a www domain's CNAME pointing here without its apex A record (the redirect), \"verified\" is every required record. The diagnostic under \"unverified\"; ShipStatic domains are born verified. One of: pending, partial, verified.", + "type": "string" + }, + "verifications": { + "description": "How many DNS verification attempts this domain has had.", + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" + }, + "verified": { + "anyOf": [ + { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "When DNS last became verified; null if it never has, and never cleared, so a domain whose records moved away keeps it. Read `verification` for whether DNS is right now." + } + }, + "required": [ + "domain", + "url", + "status", + "deployment", + "linked", + "links", + "verification", + "verified", + "verifications", + "paused", + "labels", + "created" + ], + "type": "object" +}
- Changed
domains_list4 fields changed- added
Input schema / $schemaAdded value: +"http://json-schema.org/draft-07/schema#" - added
Input schema / properties / cursorAdded value: +{ + "description": "Opaque position from the previous response's `cursor` field; omit for the first page.", + "type": "string" +} - added
Input schema / properties / limitAdded value: +{ + "description": "Maximum number of items to return in one page. Omit for the server default.", + "maximum": 9007199254740991, + "minimum": 1, + "type": "integer" +} - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "properties": { + "cursor": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Opaque cursor for the next page; null on the last page. The whole has-more signal." + }, + "domains": { + "description": "The domains on this page.", + "items": { + "additionalProperties": false, + "properties": { + "created": { + "description": "Unix timestamp (seconds) when the domain was created.", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "deployment": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "The deployment hostname this domain points to; null when reserved but not yet linked." + }, + "domain": { + "description": "The domain name, e.g. \"www.example.com\".", + "type": "string" + }, + "labels": { + "description": "Labels attached to the domain; empty when none.", + "items": { + "type": "string" + }, + "type": "array" + }, + "linked": { + "anyOf": [ + { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "Unix timestamp (seconds) when a deployment was last linked; null if never linked." + }, + "links": { + "description": "How many times a deployment has been linked to this domain.", + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" + }, + "paused": { + "anyOf": [ + { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "Unix timestamp (seconds) when plan enforcement paused serving; null while the plan has room for it." + }, + "status": { + "description": "What this domain needs from its owner, derived: \"live\" serves the linked deployment and needs nothing; \"unlinked\" is verified with nothing published there, so link a deployment; \"unverified\" needs its DNS records configured; \"paused\" means the plan no longer has room for it. Read this word rather than recomputing it. One of: live, unlinked, unverified, paused.", + "type": "string" + }, + "url": { + "description": "Full URL to the domain.", + "format": "uri", + "type": "string" + }, + "verification": { + "description": "How far DNS verification has got: \"pending\" is the site's CNAME not pointing here, \"partial\" is a www domain's CNAME pointing here without its apex A record (the redirect), \"verified\" is every required record. The diagnostic under \"unverified\"; ShipStatic domains are born verified. One of: pending, partial, verified.", + "type": "string" + }, + "verifications": { + "description": "How many DNS verification attempts this domain has had.", + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" + }, + "verified": { + "anyOf": [ + { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "When DNS last became verified; null if it never has, and never cleared, so a domain whose records moved away keeps it. Read `verification` for whether DNS is right now." + } + }, + "required": [ + "domain", + "url", + "status", + "deployment", + "linked", + "links", + "verification", + "verified", + "verifications", + "paused", + "labels", + "created" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "cursor", + "domains" + ], + "type": "object" +}
- Changed
domains_records1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "properties": { + "apex": { + "description": "The apex (registered) domain where DNS records are managed.", + "type": "string" + }, + "domain": { + "description": "The domain the records are for.", + "type": "string" + }, + "records": { + "description": "The records to configure at the DNS provider, in the order to add them.", + "items": { + "additionalProperties": false, + "properties": { + "name": { + "description": "The DNS name to configure.", + "type": "string" + }, + "type": { + "description": "Record type: A for the apex redirect, CNAME for the hosted subdomain.", + "enum": [ + "A", + "CNAME" + ], + "type": "string" + }, + "value": { + "description": "The value to set: an IP for A, a hostname for CNAME.", + "type": "string" + } + }, + "required": [ + "type", + "name", + "value" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "domain", + "apex", + "records" + ], + "type": "object" +}
- Removed
domains_remove - Changed
domains_set2 fields changed- changed
Input schema / properties / domain / descriptionPrevious value: -"Domain name (e.g. \"www.example.com\" or \"blog.example.com\")"New value: +"Domain name: a ShipStatic domain (e.g. \"yourname.shipstatic.com\") or a custom domain (e.g. \"www.example.com\")" - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "properties": { + "created": { + "description": "Unix timestamp (seconds) when the domain was created.", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "deployment": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "The deployment hostname this domain points to; null when reserved but not yet linked." + }, + "domain": { + "description": "The domain name, e.g. \"www.example.com\".", + "type": "string" + }, + "isCreate": { + "description": "True when this call created the domain; false when it updated an existing one.", + "type": "boolean" + }, + "labels": { + "description": "Labels attached to the domain; empty when none.", + "items": { + "type": "string" + }, + "type": "array" + }, + "linked": { + "anyOf": [ + { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "Unix timestamp (seconds) when a deployment was last linked; null if never linked." + }, + "links": { + "description": "How many times a deployment has been linked to this domain.", + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" + }, + "paused": { + "anyOf": [ + { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "Unix timestamp (seconds) when plan enforcement paused serving; null while the plan has room for it." + }, + "status": { + "description": "What this domain needs from its owner, derived: \"live\" serves the linked deployment and needs nothing; \"unlinked\" is verified with nothing published there, so link a deployment; \"unverified\" needs its DNS records configured; \"paused\" means the plan no longer has room for it. Read this word rather than recomputing it. One of: live, unlinked, unverified, paused.", + "type": "string" + }, + "url": { + "description": "Full URL to the domain.", + "format": "uri", + "type": "string" + }, + "verification": { + "description": "How far DNS verification has got: \"pending\" is the site's CNAME not pointing here, \"partial\" is a www domain's CNAME pointing here without its apex A record (the redirect), \"verified\" is every required record. The diagnostic under \"unverified\"; ShipStatic domains are born verified. One of: pending, partial, verified.", + "type": "string" + }, + "verifications": { + "description": "How many DNS verification attempts this domain has had.", + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" + }, + "verified": { + "anyOf": [ + { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "When DNS last became verified; null if it never has, and never cleared, so a domain whose records moved away keeps it. Read `verification` for whether DNS is right now." + } + }, + "required": [ + "domain", + "url", + "status", + "deployment", + "linked", + "links", + "verification", + "verified", + "verifications", + "paused", + "labels", + "created", + "isCreate" + ], + "type": "object" +}
- Changed
domains_share1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "properties": { + "domain": { + "description": "The domain the setup link is for.", + "type": "string" + }, + "url": { + "description": "The shareable DNS setup URL; whoever opens it sees the records to configure, with no API key.", + "format": "uri", + "type": "string" + } + }, + "required": [ + "domain", + "url" + ], + "type": "object" +}
- Changed
domains_validate2 fields changed- changed
Input schema / properties / domain / descriptionPrevious value: -"Domain name to check (e.g. \"www.example.com\"). Call before domains_set to check availability."New value: +"Domain name to check (e.g. \"yourname.shipstatic.com\" or \"www.example.com\"). Call before domains_set to check availability." - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "properties": { + "available": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "description": "Whether nobody has registered the name yet; null when invalid. Creating it would be new; re-pointing your own domain is a write, not a create." + }, + "normalized": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "The normalized domain name; null when invalid." + }, + "reason": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Why the name is unusable, for display; null when it is usable." + }, + "valid": { + "description": "Whether the domain's shape is usable.", + "type": "boolean" + } + }, + "required": [ + "valid", + "normalized", + "available", + "reason" + ], + "type": "object" +}
- Changed
domains_verify1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "properties": { + "domain": { + "description": "The domain whose DNS verification was queued, normalized. The check runs asynchronously; the domain's `verification` and `status` update once DNS propagates, so read the domain again rather than trusting this acknowledgement for a verdict.", + "type": "string" + } + }, + "required": [ + "domain" + ], + "type": "object" +}
- Changed
whoami1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "properties": { + "caps": { + "additionalProperties": false, + "description": "What the account is allowed to hold, under usage's cap keys, so the pair divides. A pending invitation takes a member place, so it counts against members.", + "properties": { + "customDomains": { + "description": "Hostnames the customer owns, paused ones included.", + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" + }, + "deployments": { + "description": "Deployments, every row whatever its status.", + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" + }, + "members": { + "description": "Member places: as caps, how many people the plan allows, the owner included; as usage, the members the account has.", + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" + }, + "platformDomains": { + "description": "Names chosen under the platform's own suffix, e.g. \"my-app.shipstatic.com\".", + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "deployments", + "platformDomains", + "customDomains", + "members" + ], + "type": "object" + }, + "email": { + "description": "The account email address.", + "type": "string" + }, + "name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Display name; null if not set." + }, + "plan": { + "description": "The plan the account is on. One of: free, pro, team, scale, sponsored.", + "type": "string" + }, + "usage": { + "additionalProperties": false, + "description": "What the account currently holds: every cap, and the pending invitations beside them.", + "properties": { + "customDomains": { + "description": "Hostnames the customer owns, paused ones included.", + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" + }, + "deployments": { + "description": "Deployments, every row whatever its status.", + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" + }, + "invitations": { + "description": "Invitations still open: pending and not yet expired. Each takes a member place beside the members, against the members cap.", + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" + }, + "members": { + "description": "Member places: as caps, how many people the plan allows, the owner included; as usage, the members the account has.", + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" + }, + "platformDomains": { + "description": "Names chosen under the platform's own suffix, e.g. \"my-app.shipstatic.com\".", + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "deployments", + "platformDomains", + "customDomains", + "members", + "invitations" + ], + "type": "object" + } + }, + "required": [ + "email", + "name", + "plan", + "usage", + "caps" + ], + "type": "object" +}
15 tool updates
v0.4.5- First observed
deployments_get - First observed
deployments_list - First observed
deployments_remove - First observed
deployments_set - First observed
deployments_upload - First observed
domains_dns - First observed
domains_get - First observed
domains_list - First observed
domains_records - First observed
domains_remove - First observed
domains_set - First observed
domains_share - First observed
domains_validate - First observed
domains_verify - First observed
whoami
TDQS
Scored across 15 tools
Deployment tools map cleanly to distinct actions, and the domains_* helpers each have a documented purpose. The main soft spot is the DNS-setup cluster (domains_records, domains_dns, domains_share, domains_verify) plus a kitchen-sink domains_set that handles create/reserve/link/switch/labels, which could occasionally be confused with a label-update operation.
Uniform resource_verb snake_case pattern across deployments_* and domains_*, with whoami as the only (acceptable) exception. Verb choices are consistent (list/get/set/delete/validate/verify) throughout.
15 tools sit right at the top of the well-scoped range and each earns its place across two coherent resources plus an account tool. No redundant or filler tools are apparent.
Deployments cover create/list/get/label-update/delete, and domains cover validate/set/records/dns/share/verify/get/list/delete, giving full lifecycle coverage. Minor gaps exist (no redeploy/rollback or file-level listing for a deployment), but core workflows are covered with no dead ends.
Maintenance
Related MCP Connectors
Hosted MCP for creating, checking, deploying, and hosting static sites for AI agents.
Publish and manage HTML pages and multi-file static websites directly from Claude, ChatGPT, Cursor, Codex, and other AI agents via MCP. Streamable HTTP with OAuth 2.1 browser sign-in — no API key to copy.
MCP server for AI agents to plan, verify, and deploy Cloudflare-native apps.
Publish websites with a small backend (KV, SQLite, files). MCP for AI agents.
Related MCP Servers
- AlicenseNot gradedqualityAmaintenanceAI-native static site generator with built-in MCP server and Claude Code integration26MIT
- AlicenseNot gradedqualityDmaintenanceMCP server for Deloc — deploy static sites from AI coding agents. Say "deploy this to Deloc" in Claude Code or Cursor and get a live URL back without leaving your editor.4MIT
- AlicenseNot gradedqualityFmaintenanceHosted MCP server for Novence, a static site hosting platform for AI agents. It enables users to deploy and manage static sites through natural language using a streamable HTTP endpoint.MIT
- AlicenseNot gradedqualityDmaintenanceMCP server for self-hosted static site publishing on Cloudflare Workers. Enables AI coding agents to deploy pages with a single 'publish' tool and get live URLs, with support for atomic updates, versioning, and per-site passwords.2 npm2MIT