@shipstatic/mcp 1.0.0-beta.11 → 1.0.0-beta.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -20,7 +20,9 @@
20
20
  * Every name below answers a question a consumer must otherwise answer for
21
21
  * itself, and each admission was a restatement deleted, not a convenience
22
22
  * added: `SERVER_NAME` and `UPLOAD_TOOL_NAME` were literals in two repos (the
23
- * first also correlates the Apps-SDK widget to the connector), `PUBLIC_EXPIRY`
23
+ * first also correlates the Apps-SDK widget to the connector; the third,
24
+ * `UPLOAD_TOOL_TITLE`, is the same shape — one operation, one English name for
25
+ * it, authored per transport only because upload itself is), `PUBLIC_EXPIRY`
24
26
  * was the same duration written out eight times, `DESCRIPTION_BLOCKS` the
25
27
  * fragments two tool descriptions genuinely share, `ACCOUNT_TOOL_NAMES` is
26
28
  * what lets the hosted catalogue fence name the fourteen without counting them
@@ -61,4 +63,4 @@
61
63
  export { type CallFn, type CallOptions, createCall, type ErrorHints } from './call.js';
62
64
  export { createServer } from './server.js';
63
65
  export { ACCOUNT_TOOL_NAMES, registerAccountTools } from './tools.js';
64
- export { ANNOTATIONS, DESCRIPTION_BLOCKS, INSTRUCTION_BLOCKS, PARAM_DESCRIPTIONS, PUBLIC_EXPIRY, SERVER_NAME, UPLOAD_TOOL_NAME, } from './vocabulary.js';
66
+ export { ANNOTATIONS, DESCRIPTION_BLOCKS, INSTRUCTION_BLOCKS, PARAM_DESCRIPTIONS, PUBLIC_EXPIRY, SERVER_NAME, UPLOAD_TOOL_NAME, UPLOAD_TOOL_TITLE, } from './vocabulary.js';
package/dist/index.js CHANGED
@@ -20,7 +20,9 @@
20
20
  * Every name below answers a question a consumer must otherwise answer for
21
21
  * itself, and each admission was a restatement deleted, not a convenience
22
22
  * added: `SERVER_NAME` and `UPLOAD_TOOL_NAME` were literals in two repos (the
23
- * first also correlates the Apps-SDK widget to the connector), `PUBLIC_EXPIRY`
23
+ * first also correlates the Apps-SDK widget to the connector; the third,
24
+ * `UPLOAD_TOOL_TITLE`, is the same shape — one operation, one English name for
25
+ * it, authored per transport only because upload itself is), `PUBLIC_EXPIRY`
24
26
  * was the same duration written out eight times, `DESCRIPTION_BLOCKS` the
25
27
  * fragments two tool descriptions genuinely share, `ACCOUNT_TOOL_NAMES` is
26
28
  * what lets the hosted catalogue fence name the fourteen without counting them
@@ -61,4 +63,4 @@
61
63
  export { createCall } from './call.js';
62
64
  export { createServer } from './server.js';
63
65
  export { ACCOUNT_TOOL_NAMES, registerAccountTools } from './tools.js';
64
- export { ANNOTATIONS, DESCRIPTION_BLOCKS, INSTRUCTION_BLOCKS, PARAM_DESCRIPTIONS, PUBLIC_EXPIRY, SERVER_NAME, UPLOAD_TOOL_NAME, } from './vocabulary.js';
66
+ export { ANNOTATIONS, DESCRIPTION_BLOCKS, INSTRUCTION_BLOCKS, PARAM_DESCRIPTIONS, PUBLIC_EXPIRY, SERVER_NAME, UPLOAD_TOOL_NAME, UPLOAD_TOOL_TITLE, } from './vocabulary.js';
package/dist/server.js CHANGED
@@ -3,7 +3,7 @@ import { DeploymentVia } from '@shipstatic/types';
3
3
  import { z } from 'zod';
4
4
  import { call } from './call.js';
5
5
  import { registerAccountTools } from './tools.js';
6
- import { ANNOTATIONS, DESCRIPTION_BLOCKS, INSTRUCTION_BLOCKS, PARAM_DESCRIPTIONS, PUBLIC_EXPIRY, SERVER_NAME, UPLOAD_TOOL_NAME, } from './vocabulary.js';
6
+ import { ANNOTATIONS, DESCRIPTION_BLOCKS, INSTRUCTION_BLOCKS, PARAM_DESCRIPTIONS, PUBLIC_EXPIRY, SERVER_NAME, UPLOAD_TOOL_NAME, UPLOAD_TOOL_TITLE, } from './vocabulary.js';
7
7
  // Destructured so the fifteen registrations below read as they always have.
8
8
  // The definitions live in `vocabulary.ts` because the hosted transport speaks
9
9
  // the same ones — that file records what is shared, what is not, and why.
@@ -40,6 +40,7 @@ export function createServer(ship, options) {
40
40
  });
41
41
  // Deployments
42
42
  server.registerTool(UPLOAD_TOOL_NAME, {
43
+ title: UPLOAD_TOOL_TITLE,
43
44
  description: `Deploy a static site instantly — ${D.free}. Returns the live URL, file count, and size. Without SHIP_TOKEN, the response includes a claim URL (site expires in ${PUBLIC_EXPIRY}) — always show both the deployment URL and claim URL to the user. ${D.password}`,
44
45
  annotations: CREATE,
45
46
  inputSchema: {
package/dist/tools.d.ts CHANGED
@@ -26,6 +26,15 @@
26
26
  * on *this* transport (the hint is `createCall`'s one per-transport argument).
27
27
  * A tool list that changes shape under the caller would be a second, dynamic
28
28
  * contract for an agent to track, and MCP clients cache the catalogue.
29
+ *
30
+ * **Every tool carries a `title`, and it is a gate rather than a nicety.** The
31
+ * Claude connectors directory refuses submission for a tool that lacks one, so
32
+ * a titleless tool is not a shabby tool — it is an unlistable product. The
33
+ * style is short Title Case verb phrases naming what the USER gets ("List
34
+ * Deployments", "Connect Custom Domain"); the name obeys `resource_action` for
35
+ * the agent, the title reads as English for the human, and the description
36
+ * carries every precision neither can. Both catalogue pins assert a title on
37
+ * every tool, so the next one cannot be added without one.
29
38
  */
30
39
  import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
31
40
  import type Ship from '@shipstatic/ship';
package/dist/tools.js CHANGED
@@ -26,6 +26,15 @@
26
26
  * on *this* transport (the hint is `createCall`'s one per-transport argument).
27
27
  * A tool list that changes shape under the caller would be a second, dynamic
28
28
  * contract for an agent to track, and MCP clients cache the catalogue.
29
+ *
30
+ * **Every tool carries a `title`, and it is a gate rather than a nicety.** The
31
+ * Claude connectors directory refuses submission for a tool that lacks one, so
32
+ * a titleless tool is not a shabby tool — it is an unlistable product. The
33
+ * style is short Title Case verb phrases naming what the USER gets ("List
34
+ * Deployments", "Connect Custom Domain"); the name obeys `resource_action` for
35
+ * the agent, the title reads as English for the human, and the description
36
+ * carries every precision neither can. Both catalogue pins assert a title on
37
+ * every tool, so the next one cannot be added without one.
29
38
  */
30
39
  import { z } from 'zod';
31
40
  import { ANNOTATIONS } from './vocabulary.js';
@@ -95,11 +104,13 @@ const DEPLOYMENT_EXAMPLE = 'happy-cat-abc1234.shipstatic.com';
95
104
  export function registerAccountTools(server, ship, call) {
96
105
  // Deployments
97
106
  server.registerTool('deployments_list', {
107
+ title: 'List Deployments',
98
108
  description: `List all deployments with their URLs, status, labels, and password protection state.${PAGING_NOTE}`,
99
109
  annotations: READ,
100
110
  inputSchema: PAGINATION_INPUT,
101
111
  }, ({ limit, cursor }) => call(() => ship.deployments.list({ limit, cursor })));
102
112
  server.registerTool('deployments_get', {
113
+ title: 'Get Deployment',
103
114
  description: 'Get deployment details including URL, status, file count, size, labels, and password protection state.',
104
115
  annotations: READ,
105
116
  inputSchema: {
@@ -109,6 +120,7 @@ export function registerAccountTools(server, ship, call) {
109
120
  },
110
121
  }, ({ deployment }) => call(() => ship.deployments.get(deployment)));
111
122
  server.registerTool('deployments_set', {
123
+ title: 'Update Deployment Labels',
112
124
  description: 'Update deployment labels. Replaces all existing labels.',
113
125
  annotations: WRITE,
114
126
  inputSchema: {
@@ -121,6 +133,7 @@ export function registerAccountTools(server, ship, call) {
121
133
  },
122
134
  }, ({ deployment, labels }) => call(() => ship.deployments.set(deployment, { labels })));
123
135
  server.registerTool('deployments_delete', {
136
+ title: 'Delete Deployment',
124
137
  description: 'Permanently delete a deployment and its files. You MUST confirm with the user before calling this tool, referencing the deployment.',
125
138
  annotations: DESTRUCTIVE,
126
139
  inputSchema: {
@@ -131,6 +144,7 @@ export function registerAccountTools(server, ship, call) {
131
144
  }, ({ deployment }) => call(() => ship.deployments.delete(deployment)));
132
145
  // Domains
133
146
  server.registerTool('domains_set', {
147
+ title: 'Connect Custom Domain',
134
148
  description: 'Create or update a custom domain. Can reserve a name (omit deployment), link it to a deployment, switch deployments, or update labels. After creating, call domains_records and show the DNS records to the user.',
135
149
  annotations: WRITE,
136
150
  inputSchema: {
@@ -146,11 +160,13 @@ export function registerAccountTools(server, ship, call) {
146
160
  },
147
161
  }, ({ domain, deployment, labels }) => call(() => ship.domains.set(domain, { deployment, labels })));
148
162
  server.registerTool('domains_list', {
163
+ title: 'List Domains',
149
164
  description: `List all domains with their URLs, linked deployment, and verification status.${PAGING_NOTE}`,
150
165
  annotations: READ,
151
166
  inputSchema: PAGINATION_INPUT,
152
167
  }, ({ limit, cursor }) => call(() => ship.domains.list({ limit, cursor })));
153
168
  server.registerTool('domains_get', {
169
+ title: 'Get Domain',
154
170
  description: 'Get domain details including URL, linked deployment, verification status, and labels.',
155
171
  annotations: READ,
156
172
  inputSchema: {
@@ -160,6 +176,7 @@ export function registerAccountTools(server, ship, call) {
160
176
  },
161
177
  }, ({ domain }) => call(() => ship.domains.get(domain)));
162
178
  server.registerTool('domains_records', {
179
+ title: 'Get DNS Records',
163
180
  description: 'Get the DNS records the user needs to configure at their DNS provider. Call after domains_set. You MUST show the returned records to the user.',
164
181
  annotations: READ,
165
182
  inputSchema: {
@@ -169,6 +186,7 @@ export function registerAccountTools(server, ship, call) {
169
186
  },
170
187
  }, ({ domain }) => call(() => ship.domains.records(domain)));
171
188
  server.registerTool('domains_dns', {
189
+ title: 'Look Up DNS Provider',
172
190
  description: 'Look up the DNS provider for a domain (e.g. Cloudflare, Namecheap). Helps the user know where to configure their DNS records.',
173
191
  annotations: READ,
174
192
  inputSchema: {
@@ -178,6 +196,7 @@ export function registerAccountTools(server, ship, call) {
178
196
  },
179
197
  }, ({ domain }) => call(() => ship.domains.dns(domain)));
180
198
  server.registerTool('domains_share', {
199
+ title: 'Share DNS Setup',
181
200
  description: 'Get a shareable DNS setup hash for a domain. The hash can be shared with the user so they can view the required DNS records without needing an API key.',
182
201
  annotations: READ,
183
202
  inputSchema: {
@@ -187,6 +206,7 @@ export function registerAccountTools(server, ship, call) {
187
206
  },
188
207
  }, ({ domain }) => call(() => ship.domains.share(domain)));
189
208
  server.registerTool('domains_validate', {
209
+ title: 'Check Domain Availability',
190
210
  description: 'Check if a domain name is valid and available before creating it. Returns the normalized form and availability.',
191
211
  annotations: READ,
192
212
  inputSchema: {
@@ -196,6 +216,7 @@ export function registerAccountTools(server, ship, call) {
196
216
  },
197
217
  }, ({ domain }) => call(() => ship.domains.validate(domain)));
198
218
  server.registerTool('domains_verify', {
219
+ title: 'Verify Domain DNS',
199
220
  description: 'Trigger DNS verification for a custom domain. Call after the user has configured DNS records from domains_records. Verification is asynchronous — the domain status updates once DNS propagates.',
200
221
  annotations: WRITE,
201
222
  inputSchema: {
@@ -205,6 +226,7 @@ export function registerAccountTools(server, ship, call) {
205
226
  },
206
227
  }, ({ domain }) => call(() => ship.domains.verify(domain)));
207
228
  server.registerTool('domains_delete', {
229
+ title: 'Delete Domain',
208
230
  description: 'Permanently delete a domain. You MUST confirm with the user before calling this tool, referencing the domain name.',
209
231
  annotations: DESTRUCTIVE,
210
232
  inputSchema: {
@@ -213,6 +235,7 @@ export function registerAccountTools(server, ship, call) {
213
235
  }, ({ domain }) => call(() => ship.domains.delete(domain)));
214
236
  // Account
215
237
  server.registerTool('whoami', {
238
+ title: 'Show Account',
216
239
  description: 'Show authenticated account details including email, plan, and usage.',
217
240
  annotations: READ,
218
241
  }, () => call(() => ship.whoami()));
@@ -60,6 +60,26 @@ export declare const SERVER_NAME = "shipstatic";
60
60
  * `[UPLOAD_TOOL_NAME, ...ACCOUNT_TOOL_NAMES]` rather than counting to fifteen.
61
61
  */
62
62
  export declare const UPLOAD_TOOL_NAME = "deployments_upload";
63
+ /**
64
+ * The upload tool's human-readable `title`, shared for the same reason the
65
+ * name is — and NOT for the reason the description is not.
66
+ *
67
+ * A title names the OPERATION, and the operation is identical on both doors:
68
+ * a user reading "Deploy Static Site" in a client's tool list learns nothing
69
+ * about how the bytes got there. The description is the opposite — hosted
70
+ * spends a paragraph telling an Apps-SDK caller not to base64-encode text, a
71
+ * hazard a filesystem path cannot have — which is why one is exported whole
72
+ * and the other only in fragments.
73
+ *
74
+ * The other fourteen titles live inline in `tools.ts`: one definition, both
75
+ * transports, nothing to keep in agreement. This one is authored per transport
76
+ * (upload is the tool each door writes for itself), so without an owner it
77
+ * would be two literals in two repos with nothing comparing them.
78
+ *
79
+ * Titles are not decoration here: the Claude connectors directory refuses
80
+ * submission for a tool that lacks one.
81
+ */
82
+ export declare const UPLOAD_TOOL_TITLE = "Deploy Static Site";
63
83
  /**
64
84
  * How long an anonymous deployment lives, in the words an agent reads.
65
85
  *
@@ -62,6 +62,26 @@ export const SERVER_NAME = 'shipstatic';
62
62
  * `[UPLOAD_TOOL_NAME, ...ACCOUNT_TOOL_NAMES]` rather than counting to fifteen.
63
63
  */
64
64
  export const UPLOAD_TOOL_NAME = 'deployments_upload';
65
+ /**
66
+ * The upload tool's human-readable `title`, shared for the same reason the
67
+ * name is — and NOT for the reason the description is not.
68
+ *
69
+ * A title names the OPERATION, and the operation is identical on both doors:
70
+ * a user reading "Deploy Static Site" in a client's tool list learns nothing
71
+ * about how the bytes got there. The description is the opposite — hosted
72
+ * spends a paragraph telling an Apps-SDK caller not to base64-encode text, a
73
+ * hazard a filesystem path cannot have — which is why one is exported whole
74
+ * and the other only in fragments.
75
+ *
76
+ * The other fourteen titles live inline in `tools.ts`: one definition, both
77
+ * transports, nothing to keep in agreement. This one is authored per transport
78
+ * (upload is the tool each door writes for itself), so without an owner it
79
+ * would be two literals in two repos with nothing comparing them.
80
+ *
81
+ * Titles are not decoration here: the Claude connectors directory refuses
82
+ * submission for a tool that lacks one.
83
+ */
84
+ export const UPLOAD_TOOL_TITLE = 'Deploy Static Site';
65
85
  /**
66
86
  * How long an anonymous deployment lives, in the words an agent reads.
67
87
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shipstatic/mcp",
3
- "version": "1.0.0-beta.11",
3
+ "version": "1.0.0-beta.12",
4
4
  "mcpName": "com.shipstatic/mcp",
5
5
  "description": "ShipStatic MCP — deploy static websites from AI agents. Full toolset incl. custom domains. Free hosted endpoint at mcp.shipstatic.com — no install.",
6
6
  "type": "module",