Skip to main content
Glama

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.com

ChatGPT

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.com

Cursor, 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

deployments_upload

Publish files and get a live URL instantly, optionally protected by a password

Deployments, with an account

Tool

Description

deployments_list

List all deployments with their URLs, status, labels, and password protection state. Pages with limit and cursor

deployments_get

Get deployment details including URL, status, file count, size, labels, and password protection state

deployments_set

Update the labels on a deployment for organization and filtering

deployments_delete

Permanently delete a deployment and all its files

Domains, with an account

Tool

Description

domains_set

Connect a custom domain to your site, switch deployments, or update labels

domains_list

List all domains with their linked deployment and verification status. Pages with limit and cursor

domains_get

Get domain details including linked deployment, verification status, and labels

domains_records

Get the DNS records you need to configure at your DNS provider

domains_dns

The DNS provider recorded for a domain, if known (e.g. Cloudflare, Namecheap)

domains_share

Get a shareable link so someone else can see the required DNS records

domains_validate

Check if a domain name is valid and available before connecting it

domains_verify

Check if DNS is configured correctly after you set up the records

domains_delete

Permanently disconnect and delete a custom domain

Account, with an account

Tool

Description

whoami

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/mcp

Any 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

CLI and SDK

npx @shipstatic/ship ./dist

VS Code

Search "ShipStatic" in the Marketplace

Plugin

Install it in Cursor, Claude Code, Codex or Gemini CLI

n8n

Search "ShipStatic" in n8n's node panel

GitHub Action

shipstatic/action@v3

Agent Skill

npx skills add shipstatic/plugin

License

MIT

Available Tools

15 tools
deployments_deleteDelete DeploymentB
DestructiveIdempotent
Inspect

Permanently deletes a deployment and its files.

NameRequiredDescriptionDefault
deploymentYesDeployment hostname to delete (e.g. "happy-cat-abc1234.shipstatic.com")

Output Schema

NameRequiredDescription
statusYesThe state the deployment is in while background cleanup runs. One of: pending, success, failed, deleting.
deploymentYesThe deployment hostname that was marked for removal.

TDQS

B3.4/5.0
Behavior3/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose4/5

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.

Usage Guidelines2/5

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 DeploymentA
Read-only
Inspect

Get deployment details including URL, status, file count, size, labels, and password protection state.

NameRequiredDescriptionDefault
deploymentYesDeployment hostname (e.g. "happy-cat-abc1234.shipstatic.com"). Returned by deployments_upload or deployments_list.

Output Schema

NameRequiredDescription
urlYesFull URL to the live deployment.
viaYesHow 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.
sizeYesTotal deployment size in bytes.
filesYesNumber of files in the deployment.
configYesTrue if the deployment includes a ship.json routing config.
labelsYesLabels attached to the deployment; empty when none.
statusYesDeployment lifecycle state; "success" means the site is live. One of: pending, success, failed, deleting.
createdYesUnix timestamp (seconds) when the deployment was created.
expiresYesUnix 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.
passwordYesTrue if the deployment is password-protected.
deploymentYesDeployment hostname, e.g. "happy-cat-abc1234.shipstatic.com".
screenshotYesFull 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

A4.3/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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 DeploymentsA
Read-only
Inspect

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.

NameRequiredDescriptionDefault
limitNoMaximum number of items to return in one page. Omit for the server default.
cursorNoOpaque position from the previous response's `cursor` field; omit for the first page.

Output Schema

NameRequiredDescription
cursorYesOpaque cursor for the next page; null on the last page. The whole has-more signal.
deploymentsYesThe deployments on this page.

TDQS

A4.1/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines3/5

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 LabelsA
Destructive
Inspect

Update deployment labels. Replaces all existing labels.

NameRequiredDescriptionDefault
labelsYesLabels to set. Replaces all existing labels. Pass empty array to clear.
deploymentYesDeployment hostname (e.g. "happy-cat-abc1234.shipstatic.com"). Use deployments_list to find deployments.

Output Schema

NameRequiredDescription
urlYesFull URL to the live deployment.
viaYesHow 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.
sizeYesTotal deployment size in bytes.
filesYesNumber of files in the deployment.
configYesTrue if the deployment includes a ship.json routing config.
labelsYesLabels attached to the deployment; empty when none.
statusYesDeployment lifecycle state; "success" means the site is live. One of: pending, success, failed, deleting.
createdYesUnix timestamp (seconds) when the deployment was created.
expiresYesUnix 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.
passwordYesTrue if the deployment is password-protected.
deploymentYesDeployment hostname, e.g. "happy-cat-abc1234.shipstatic.com".
screenshotYesFull 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

A3.6/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose4/5

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.

Usage Guidelines2/5

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.

NameRequiredDescriptionDefault
ttlNoSeconds 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.
pathYesAbsolute path to the build output directory to deploy (e.g. "/Users/me/project/dist")
labelsNoLabels 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.
passwordNoOptional 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.
idempotencyKeyNoMakes 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

NameRequiredDescription
urlYesFull URL to the live deployment.
viaYesHow 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.
sizeYesTotal deployment size in bytes.
claimNoOne-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.
filesYesNumber of files in the deployment.
configYesTrue if the deployment includes a ship.json routing config.
labelsYesLabels attached to the deployment; empty when none.
statusYesDeployment lifecycle state; "success" means the site is live. One of: pending, success, failed, deleting.
createdYesUnix timestamp (seconds) when the deployment was created.
expiresYesUnix 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.
passwordYesTrue if the deployment is password-protected.
deploymentYesDeployment hostname, e.g. "happy-cat-abc1234.shipstatic.com".
screenshotYesFull 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

A4/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines3/5

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 DomainA
DestructiveIdempotent
Inspect

Permanently deletes a domain.

NameRequiredDescriptionDefault
domainYesDomain name to delete (e.g. "www.example.com")

Output Schema

NameRequiredDescription
domainYesThe domain name that was removed, normalized.

TDQS

A3.5/5.0
Behavior2/5

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.

Conciseness5/5

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.

Completeness3/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines2/5

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 ProviderA
Read-only
Inspect

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.

NameRequiredDescriptionDefault
domainYesDomain name (e.g. "www.example.com"). Must be a domain previously created with domains_set.

Output Schema

NameRequiredDescription
dnsYesWhat the platform recorded about the domain's DNS provider when the domain was created; null if nothing was recorded.
domainYesThe domain name.

TDQS

A3.9/5.0
Behavior4/5

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.

Conciseness4/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose4/5

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.

Usage Guidelines4/5

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 DomainA
Read-only
Inspect

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).

NameRequiredDescriptionDefault
domainYesDomain name (e.g. "www.example.com"). Use domains_list to find names.

Output Schema

NameRequiredDescription
urlYesFull URL to the domain.
linksYesHow many times a deployment has been linked to this domain.
domainYesThe domain name, e.g. "www.example.com".
labelsYesLabels attached to the domain; empty when none.
linkedYesUnix timestamp (seconds) when a deployment was last linked; null if never linked.
pausedYesUnix timestamp (seconds) when plan enforcement paused serving; null while the plan has room for it.
statusYesWhat 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.
createdYesUnix timestamp (seconds) when the domain was created.
verifiedYesWhen 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.
deploymentYesThe deployment hostname this domain points to; null when reserved but not yet linked.
verificationYesHow 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.
verificationsYesHow many DNS verification attempts this domain has had.

TDQS

A3.5/5.0
Behavior4/5

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.

Conciseness4/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose4/5

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.

Usage Guidelines2/5

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 DomainsA
Read-only
Inspect

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.

NameRequiredDescriptionDefault
limitNoMaximum number of items to return in one page. Omit for the server default.
cursorNoOpaque position from the previous response's `cursor` field; omit for the first page.

Output Schema

NameRequiredDescription
cursorYesOpaque cursor for the next page; null on the last page. The whole has-more signal.
domainsYesThe domains on this page.

TDQS

A3.8/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose4/5

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.

Usage Guidelines3/5

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 RecordsA
Read-only
Inspect

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.

NameRequiredDescriptionDefault
domainYesDomain name. Must be a domain previously created with domains_set.

Output Schema

NameRequiredDescription
apexYesThe apex (registered) domain where DNS records are managed.
domainYesThe domain the records are for.
recordsYesThe records to configure at the DNS provider, in the order to add them.

TDQS

A3.8/5.0
Behavior3/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose4/5

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.

Usage Guidelines4/5

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 DomainA
Destructive
Inspect

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.

NameRequiredDescriptionDefault
domainYesDomain name: a ShipStatic domain (e.g. "yourname.shipstatic.com") or a custom domain (e.g. "www.example.com")
labelsNoLabels for organizing domains (e.g. ["production"]).
deploymentNoDeployment to serve on this domain (e.g. "happy-cat-abc1234.shipstatic.com"). Omit to reserve the domain without linking.

Output Schema

NameRequiredDescription
urlYesFull URL to the domain.
linksYesHow many times a deployment has been linked to this domain.
domainYesThe domain name, e.g. "www.example.com".
labelsYesLabels attached to the domain; empty when none.
linkedYesUnix timestamp (seconds) when a deployment was last linked; null if never linked.
pausedYesUnix timestamp (seconds) when plan enforcement paused serving; null while the plan has room for it.
statusYesWhat 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.
createdYesUnix timestamp (seconds) when the domain was created.
isCreateYesTrue when this call created the domain; false when it updated an existing one.
verifiedYesWhen 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.
deploymentYesThe deployment hostname this domain points to; null when reserved but not yet linked.
verificationYesHow 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.
verificationsYesHow many DNS verification attempts this domain has had.

TDQS

A4.2/5.0
Behavior4/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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_shareShare DNS SetupA
Read-only
Inspect

Returns a shareable DNS setup URL that needs no API key, for whoever manages the domain's DNS. Custom domains only, and only while the domain is unverified; a verified domain has no setup left to share.

NameRequiredDescriptionDefault
domainYesDomain name to generate a share link for. Must be a domain previously created with domains_set.

Output Schema

NameRequiredDescription
urlYesThe shareable DNS setup URL; whoever opens it sees the records to configure, with no API key.
domainYesThe domain the setup link is for.

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already mark this read-only and non-destructive, and the description adds meaningful behavioral context beyond them: the resulting URL requires no API key, and the operation is a no-op for verified domains. It does not disclose link lifetime or revocation, which keeps it 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.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single dense sentence, front-loaded with the return value, followed by the two constraining clauses. Every clause carries information; nothing is padding.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

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 need not explain the return shape, and it covers auth, scope, and eligibility adequately. Minor gaps remain around what happens on an ineligible domain (error vs empty), but an agent has enough to call it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the single parameter is fully documented there, so baseline 3 applies. The description adds the 'custom domains only' constraint, which narrows what values are valid, but adds no syntax or format detail beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and artifact ('Returns a shareable DNS setup URL') and immediately names the audience ('for whoever manages the domain's DNS'). It is clearly distinguishable from siblings like domains_dns/domains_records, which return actual DNS data rather than a share link.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit applicability conditions: custom domains only, and only while the domain is unverified, with a stated reason ('a verified domain has no setup left to share'). It does not name an alternative sibling, but the when/when-not boundary is unambiguous.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

domains_validateCheck Domain AvailabilityA
Read-only
Inspect

Check if a domain name is valid and available before creating it. Returns the normalized form and availability.

NameRequiredDescriptionDefault
domainYesDomain name to check (e.g. "yourname.shipstatic.com" or "www.example.com"). Call before domains_set to check availability.

Output Schema

NameRequiredDescription
validYesWhether the domain's shape is usable.
reasonYesWhy the name is unusable, for display; null when it is usable.
availableYesWhether 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.
normalizedYesThe normalized domain name; null when invalid.

TDQS

A3.5/5.0
Behavior3/5

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.

Conciseness4/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose4/5

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.

Usage Guidelines3/5

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.

NameRequiredDescriptionDefault
domainYesDomain name to verify DNS for. Must be a domain previously created with domains_set.

Output Schema

NameRequiredDescription
domainYesThe 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

A4.7/5.0
Behavior5/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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 AccountA
Read-only
Inspect

Returns your email and name, and the account's plan, usage and caps.

NameRequiredDescriptionDefault

No parameters

Output Schema

NameRequiredDescription
capsYesWhat 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.
nameYesDisplay name; null if not set.
planYesThe plan the account is on. One of: free, pro, team, scale, sponsored.
emailYesThe account email address.
usageYesWhat the account currently holds: every cap, and the pending invitations beside them.

TDQS

A4/5.0
Behavior3/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines3/5

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.

  1. 17 tool updatesv0.4.6
    • Addeddeployments_delete
    • Changeddeployments_get1 field changed
      • changedOutput 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"
        +}
    • Changeddeployments_list4 fields changed
      • addedInput schema / $schema
        Added value: +"http://json-schema.org/draft-07/schema#"
      • addedInput schema / properties / cursor
        Added value: +{
        +  "description": "Opaque position from the previous response's `cursor` field; omit for the first page.",
        +  "type": "string"
        +}
      • addedInput schema / properties / limit
        Added value: +{
        +  "description": "Maximum number of items to return in one page. Omit for the server default.",
        +  "maximum": 9007199254740991,
        +  "minimum": 1,
        +  "type": "integer"
        +}
      • changedOutput 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"
        +}
    • Removeddeployments_remove
    • Changeddeployments_set1 field changed
      • changedOutput 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"
        +}
    • Changeddeployments_upload5 fields changed
      • addedInput schema / properties / idempotencyKey
        Added 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"
        +}
      • changedInput schema / properties / labels / description
        Previous 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."
      • addedInput schema / properties / password
        Added 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"
        +}
      • addedInput schema / properties / ttl
        Added 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"
        +}
      • changedOutput 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"
        +}
    • Addeddomains_delete
    • Changeddomains_dns2 fields changed
      • changedInput schema / properties / domain / description
        Previous 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."
      • changedOutput 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"
        +}
    • Changeddomains_get1 field changed
      • changedOutput 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"
        +}
    • Changeddomains_list4 fields changed
      • addedInput schema / $schema
        Added value: +"http://json-schema.org/draft-07/schema#"
      • addedInput schema / properties / cursor
        Added value: +{
        +  "description": "Opaque position from the previous response's `cursor` field; omit for the first page.",
        +  "type": "string"
        +}
      • addedInput schema / properties / limit
        Added value: +{
        +  "description": "Maximum number of items to return in one page. Omit for the server default.",
        +  "maximum": 9007199254740991,
        +  "minimum": 1,
        +  "type": "integer"
        +}
      • changedOutput 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"
        +}
    • Changeddomains_records1 field changed
      • changedOutput 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"
        +}
    • Removeddomains_remove
    • Changeddomains_set2 fields changed
      • changedInput schema / properties / domain / description
        Previous 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\")"
      • changedOutput 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"
        +}
    • Changeddomains_share1 field changed
      • changedOutput 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"
        +}
    • Changeddomains_validate2 fields changed
      • changedInput schema / properties / domain / description
        Previous 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."
      • changedOutput 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"
        +}
    • Changeddomains_verify1 field changed
      • changedOutput 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"
        +}
    • Changedwhoami1 field changed
      • changedOutput 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"
        +}
  2. 15 tool updatesv0.4.5
    • First observeddeployments_get
    • First observeddeployments_list
    • First observeddeployments_remove
    • First observeddeployments_set
    • First observeddeployments_upload
    • First observeddomains_dns
    • First observeddomains_get
    • First observeddomains_list
    • First observeddomains_records
    • First observeddomains_remove
    • First observeddomains_set
    • First observeddomains_share
    • First observeddomains_validate
    • First observeddomains_verify
    • First observedwhoami

TDQS

A3.9/5.0

Scored across 15 tools

Disambiguation4/5

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.

Naming Consistency5/5

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.

Tool Count5/5

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.

Completeness4/5

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

ActivityActive
ResponsivenessUnresponsive

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    MCP 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.
    4
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    MCP 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 npm
    2
    MIT