@shipstatic/mcp 1.7.0 → 1.8.0
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/README.md +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/server.js +3 -3
- package/dist/tools.js +29 -29
- package/dist/vocabulary.d.ts +22 -0
- package/dist/vocabulary.js +21 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -64,7 +64,7 @@ Everything above works with no account at all. Connect one when your client offe
|
|
|
64
64
|
|
|
65
65
|
Install this package when your agent needs to deploy **a folder on your own machine** — the hosted endpoint takes files inline, so it has no path to read from — when you'd rather configure a token once than sign in, or when your MCP client doesn't speak OAuth yet.
|
|
66
66
|
|
|
67
|
-
The config asks for one thing: `SHIP_TOKEN`. **Its value is your API key** — one credential, two names. The console mints it as an *API key* (it starts with `ship-`), and the setting that carries it is called the *token*. Get yours free at [my.shipstatic.com/api-key](https://my.shipstatic.com/api-key), paste it where the snippets below show `ship-your-api-key`, and every site you publish lands in your account
|
|
67
|
+
The config asks for one thing: `SHIP_TOKEN`. **Its value is your API key** — one credential, two names. The console mints it as an *API key* (it starts with `ship-`), and the setting that carries it is called the *token*. Get yours free at [my.shipstatic.com/api-key](https://my.shipstatic.com/api-key), paste it where the snippets below show `ship-your-api-key`, and every site you publish lands in your account and never expires, with a rate limit of your own instead of the shared anonymous pools.
|
|
68
68
|
|
|
69
69
|
The key is optional: leave it out and the local server behaves exactly like the hosted endpoint with no account connected — public sites, claim links, live for 3 days.
|
|
70
70
|
|
package/dist/index.d.ts
CHANGED
|
@@ -63,4 +63,4 @@
|
|
|
63
63
|
export { type AuthFailure, type CallFn, type CallOptions, createCall, type ErrorHints, } from './call.js';
|
|
64
64
|
export { createServer } from './server.js';
|
|
65
65
|
export { ACCOUNT_TOOL_NAMES, registerAccountTools } from './tools.js';
|
|
66
|
-
export { ANNOTATIONS, DESCRIPTION_BLOCKS, INSTRUCTION_BLOCKS, PARAM_DESCRIPTIONS, PUBLIC_EXPIRY, SERVER_NAME, UPLOAD_TOOL_NAME, UPLOAD_TOOL_TITLE, } from './vocabulary.js';
|
|
66
|
+
export { ANNOTATIONS, DESCRIPTION_BLOCKS, INSTRUCTION_BLOCKS, PARAM_DESCRIPTIONS, PUBLIC_EXPIRY, SERVER_NAME, titled, UPLOAD_TOOL_NAME, UPLOAD_TOOL_TITLE, } from './vocabulary.js';
|
package/dist/index.js
CHANGED
|
@@ -63,4 +63,4 @@
|
|
|
63
63
|
export { createCall, } from './call.js';
|
|
64
64
|
export { createServer } from './server.js';
|
|
65
65
|
export { ACCOUNT_TOOL_NAMES, registerAccountTools } from './tools.js';
|
|
66
|
-
export { ANNOTATIONS, DESCRIPTION_BLOCKS, INSTRUCTION_BLOCKS, PARAM_DESCRIPTIONS, PUBLIC_EXPIRY, SERVER_NAME, UPLOAD_TOOL_NAME, UPLOAD_TOOL_TITLE, } from './vocabulary.js';
|
|
66
|
+
export { ANNOTATIONS, DESCRIPTION_BLOCKS, INSTRUCTION_BLOCKS, PARAM_DESCRIPTIONS, PUBLIC_EXPIRY, SERVER_NAME, titled, UPLOAD_TOOL_NAME, UPLOAD_TOOL_TITLE, } from './vocabulary.js';
|
package/dist/server.js
CHANGED
|
@@ -3,7 +3,7 @@ import { DeploymentVia, MY_API_KEY_URL } 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, UPLOAD_TOOL_TITLE, } from './vocabulary.js';
|
|
6
|
+
import { ANNOTATIONS, DESCRIPTION_BLOCKS, INSTRUCTION_BLOCKS, PARAM_DESCRIPTIONS, PUBLIC_EXPIRY, SERVER_NAME, titled, 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.
|
|
@@ -39,7 +39,7 @@ export function createServer(ship, options) {
|
|
|
39
39
|
instructions: INSTRUCTIONS,
|
|
40
40
|
});
|
|
41
41
|
// Deployments
|
|
42
|
-
server.registerTool(UPLOAD_TOOL_NAME, {
|
|
42
|
+
server.registerTool(UPLOAD_TOOL_NAME, titled({
|
|
43
43
|
title: UPLOAD_TOOL_TITLE,
|
|
44
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}`,
|
|
45
45
|
annotations: CREATE,
|
|
@@ -58,7 +58,7 @@ export function createServer(ship, options) {
|
|
|
58
58
|
// disagree with the first, silently; its absence fails loudly instead.
|
|
59
59
|
ttl: z.number().optional().describe(PARAM_DESCRIPTIONS.ttl),
|
|
60
60
|
},
|
|
61
|
-
}, ({ path, labels, password, idempotencyKey, ttl }) => call(() => ship.deployments.upload(path, { labels, password, idempotencyKey, ttl, via })));
|
|
61
|
+
}), ({ path, labels, password, idempotencyKey, ttl }) => call(() => ship.deployments.upload(path, { labels, password, idempotencyKey, ttl, via })));
|
|
62
62
|
// The other fourteen. Identical on every transport, so they live in the
|
|
63
63
|
// shared package rather than here — see tools.ts for why upload is not
|
|
64
64
|
// among them.
|
package/dist/tools.js
CHANGED
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
* every tool, so the next one cannot be added without one.
|
|
38
38
|
*/
|
|
39
39
|
import { z } from 'zod';
|
|
40
|
-
import { ANNOTATIONS } from './vocabulary.js';
|
|
40
|
+
import { ANNOTATIONS, titled } from './vocabulary.js';
|
|
41
41
|
const { READ, WRITE, DESTRUCTIVE } = ANNOTATIONS;
|
|
42
42
|
/**
|
|
43
43
|
* The fourteen, by name, in registration order.
|
|
@@ -103,13 +103,13 @@ const PAGING_NOTE = " The response's `cursor` is null on the last page; pass it
|
|
|
103
103
|
const DEPLOYMENT_EXAMPLE = 'happy-cat-abc1234.shipstatic.com';
|
|
104
104
|
export function registerAccountTools(server, ship, call) {
|
|
105
105
|
// Deployments
|
|
106
|
-
server.registerTool('deployments_list', {
|
|
106
|
+
server.registerTool('deployments_list', titled({
|
|
107
107
|
title: 'List Deployments',
|
|
108
108
|
description: `List all deployments with their URLs, status, labels, and password protection state.${PAGING_NOTE}`,
|
|
109
109
|
annotations: READ,
|
|
110
110
|
inputSchema: PAGINATION_INPUT,
|
|
111
|
-
}, ({ limit, cursor }) => call(() => ship.deployments.list({ limit, cursor })));
|
|
112
|
-
server.registerTool('deployments_get', {
|
|
111
|
+
}), ({ limit, cursor }) => call(() => ship.deployments.list({ limit, cursor })));
|
|
112
|
+
server.registerTool('deployments_get', titled({
|
|
113
113
|
title: 'Get Deployment',
|
|
114
114
|
description: 'Get deployment details including URL, status, file count, size, labels, and password protection state.',
|
|
115
115
|
annotations: READ,
|
|
@@ -118,8 +118,8 @@ export function registerAccountTools(server, ship, call) {
|
|
|
118
118
|
.string()
|
|
119
119
|
.describe(`Deployment hostname (e.g. "${DEPLOYMENT_EXAMPLE}"). Returned by deployments_upload or deployments_list.`),
|
|
120
120
|
},
|
|
121
|
-
}, ({ deployment }) => call(() => ship.deployments.get(deployment)));
|
|
122
|
-
server.registerTool('deployments_set', {
|
|
121
|
+
}), ({ deployment }) => call(() => ship.deployments.get(deployment)));
|
|
122
|
+
server.registerTool('deployments_set', titled({
|
|
123
123
|
title: 'Update Deployment Labels',
|
|
124
124
|
description: 'Update deployment labels. Replaces all existing labels.',
|
|
125
125
|
annotations: WRITE,
|
|
@@ -131,8 +131,8 @@ export function registerAccountTools(server, ship, call) {
|
|
|
131
131
|
.array(z.string())
|
|
132
132
|
.describe('Labels to set. Replaces all existing labels. Pass empty array to clear.'),
|
|
133
133
|
},
|
|
134
|
-
}, ({ deployment, labels }) => call(() => ship.deployments.set(deployment, { labels })));
|
|
135
|
-
server.registerTool('deployments_delete', {
|
|
134
|
+
}), ({ deployment, labels }) => call(() => ship.deployments.set(deployment, { labels })));
|
|
135
|
+
server.registerTool('deployments_delete', titled({
|
|
136
136
|
title: 'Delete Deployment',
|
|
137
137
|
description: 'Permanently delete a deployment and its files. You MUST confirm with the user before calling this tool, referencing the deployment.',
|
|
138
138
|
annotations: DESTRUCTIVE,
|
|
@@ -141,9 +141,9 @@ export function registerAccountTools(server, ship, call) {
|
|
|
141
141
|
.string()
|
|
142
142
|
.describe(`Deployment hostname to delete (e.g. "${DEPLOYMENT_EXAMPLE}")`),
|
|
143
143
|
},
|
|
144
|
-
}, ({ deployment }) => call(() => ship.deployments.delete(deployment)));
|
|
144
|
+
}), ({ deployment }) => call(() => ship.deployments.delete(deployment)));
|
|
145
145
|
// Domains
|
|
146
|
-
server.registerTool('domains_set', {
|
|
146
|
+
server.registerTool('domains_set', titled({
|
|
147
147
|
title: 'Connect Custom Domain',
|
|
148
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.',
|
|
149
149
|
annotations: WRITE,
|
|
@@ -158,14 +158,14 @@ export function registerAccountTools(server, ship, call) {
|
|
|
158
158
|
.optional()
|
|
159
159
|
.describe('Labels for organizing domains (e.g. ["production"]).'),
|
|
160
160
|
},
|
|
161
|
-
}, ({ domain, deployment, labels }) => call(() => ship.domains.set(domain, { deployment, labels })));
|
|
162
|
-
server.registerTool('domains_list', {
|
|
161
|
+
}), ({ domain, deployment, labels }) => call(() => ship.domains.set(domain, { deployment, labels })));
|
|
162
|
+
server.registerTool('domains_list', titled({
|
|
163
163
|
title: 'List Domains',
|
|
164
164
|
description: `List all domains with their URLs, linked deployment, and verification status.${PAGING_NOTE}`,
|
|
165
165
|
annotations: READ,
|
|
166
166
|
inputSchema: PAGINATION_INPUT,
|
|
167
|
-
}, ({ limit, cursor }) => call(() => ship.domains.list({ limit, cursor })));
|
|
168
|
-
server.registerTool('domains_get', {
|
|
167
|
+
}), ({ limit, cursor }) => call(() => ship.domains.list({ limit, cursor })));
|
|
168
|
+
server.registerTool('domains_get', titled({
|
|
169
169
|
title: 'Get Domain',
|
|
170
170
|
description: 'Get domain details including URL, linked deployment, verification status, and labels.',
|
|
171
171
|
annotations: READ,
|
|
@@ -174,8 +174,8 @@ export function registerAccountTools(server, ship, call) {
|
|
|
174
174
|
.string()
|
|
175
175
|
.describe('Domain name (e.g. "www.example.com"). Use domains_list to find names.'),
|
|
176
176
|
},
|
|
177
|
-
}, ({ domain }) => call(() => ship.domains.get(domain)));
|
|
178
|
-
server.registerTool('domains_records', {
|
|
177
|
+
}), ({ domain }) => call(() => ship.domains.get(domain)));
|
|
178
|
+
server.registerTool('domains_records', titled({
|
|
179
179
|
title: 'Get DNS Records',
|
|
180
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.',
|
|
181
181
|
annotations: READ,
|
|
@@ -184,8 +184,8 @@ export function registerAccountTools(server, ship, call) {
|
|
|
184
184
|
.string()
|
|
185
185
|
.describe('Domain name. Must be a domain previously created with domains_set.'),
|
|
186
186
|
},
|
|
187
|
-
}, ({ domain }) => call(() => ship.domains.records(domain)));
|
|
188
|
-
server.registerTool('domains_dns', {
|
|
187
|
+
}), ({ domain }) => call(() => ship.domains.records(domain)));
|
|
188
|
+
server.registerTool('domains_dns', titled({
|
|
189
189
|
title: 'Look Up DNS Provider',
|
|
190
190
|
description: 'Look up the DNS provider for a domain (e.g. Cloudflare, Namecheap). Helps the user know where to configure their DNS records.',
|
|
191
191
|
annotations: READ,
|
|
@@ -194,8 +194,8 @@ export function registerAccountTools(server, ship, call) {
|
|
|
194
194
|
.string()
|
|
195
195
|
.describe('Domain name to look up DNS provider for (e.g. "www.example.com")'),
|
|
196
196
|
},
|
|
197
|
-
}, ({ domain }) => call(() => ship.domains.dns(domain)));
|
|
198
|
-
server.registerTool('domains_share', {
|
|
197
|
+
}), ({ domain }) => call(() => ship.domains.dns(domain)));
|
|
198
|
+
server.registerTool('domains_share', titled({
|
|
199
199
|
title: 'Share DNS Setup',
|
|
200
200
|
description: 'Get a shareable DNS setup link for a domain. Share the link with the user so they, or whoever manages their DNS, can view the required records without needing an API key.',
|
|
201
201
|
annotations: READ,
|
|
@@ -204,8 +204,8 @@ export function registerAccountTools(server, ship, call) {
|
|
|
204
204
|
.string()
|
|
205
205
|
.describe('Domain name to generate a share link for. Must be a domain previously created with domains_set.'),
|
|
206
206
|
},
|
|
207
|
-
}, ({ domain }) => call(() => ship.domains.share(domain)));
|
|
208
|
-
server.registerTool('domains_validate', {
|
|
207
|
+
}), ({ domain }) => call(() => ship.domains.share(domain)));
|
|
208
|
+
server.registerTool('domains_validate', titled({
|
|
209
209
|
title: 'Check Domain Availability',
|
|
210
210
|
description: 'Check if a domain name is valid and available before creating it. Returns the normalized form and availability.',
|
|
211
211
|
annotations: READ,
|
|
@@ -214,8 +214,8 @@ export function registerAccountTools(server, ship, call) {
|
|
|
214
214
|
.string()
|
|
215
215
|
.describe('Domain name to check (e.g. "www.example.com"). Call before domains_set to check availability.'),
|
|
216
216
|
},
|
|
217
|
-
}, ({ domain }) => call(() => ship.domains.validate(domain)));
|
|
218
|
-
server.registerTool('domains_verify', {
|
|
217
|
+
}), ({ domain }) => call(() => ship.domains.validate(domain)));
|
|
218
|
+
server.registerTool('domains_verify', titled({
|
|
219
219
|
title: 'Verify Domain DNS',
|
|
220
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.',
|
|
221
221
|
annotations: WRITE,
|
|
@@ -224,19 +224,19 @@ export function registerAccountTools(server, ship, call) {
|
|
|
224
224
|
.string()
|
|
225
225
|
.describe('Domain name to verify DNS for. Must be a domain previously created with domains_set.'),
|
|
226
226
|
},
|
|
227
|
-
}, ({ domain }) => call(() => ship.domains.verify(domain)));
|
|
228
|
-
server.registerTool('domains_delete', {
|
|
227
|
+
}), ({ domain }) => call(() => ship.domains.verify(domain)));
|
|
228
|
+
server.registerTool('domains_delete', titled({
|
|
229
229
|
title: 'Delete Domain',
|
|
230
230
|
description: 'Permanently delete a domain. You MUST confirm with the user before calling this tool, referencing the domain name.',
|
|
231
231
|
annotations: DESTRUCTIVE,
|
|
232
232
|
inputSchema: {
|
|
233
233
|
domain: z.string().describe('Domain name to delete (e.g. "www.example.com")'),
|
|
234
234
|
},
|
|
235
|
-
}, ({ domain }) => call(() => ship.domains.delete(domain)));
|
|
235
|
+
}), ({ domain }) => call(() => ship.domains.delete(domain)));
|
|
236
236
|
// Account
|
|
237
|
-
server.registerTool('whoami', {
|
|
237
|
+
server.registerTool('whoami', titled({
|
|
238
238
|
title: 'Show Account',
|
|
239
239
|
description: 'Show authenticated account details including email, plan, and usage.',
|
|
240
240
|
annotations: READ,
|
|
241
|
-
}, () => call(() => ship.whoami()));
|
|
241
|
+
}), () => call(() => ship.whoami()));
|
|
242
242
|
}
|
package/dist/vocabulary.d.ts
CHANGED
|
@@ -141,6 +141,28 @@ export declare const ANNOTATIONS: {
|
|
|
141
141
|
readonly idempotentHint: true;
|
|
142
142
|
};
|
|
143
143
|
};
|
|
144
|
+
/**
|
|
145
|
+
* One title, two wire slots: project a tool config's top-level `title` into
|
|
146
|
+
* `annotations.title` at registration.
|
|
147
|
+
*
|
|
148
|
+
* The MCP spec carries a tool title in two places. The 2025-06-18 revision
|
|
149
|
+
* put it top-level on the Tool object (where every registration here states
|
|
150
|
+
* it), and `ToolAnnotations.title` is the older 2025-03-26 slot that some
|
|
151
|
+
* readers still key on. The Claude connectors portal is one of them, measured
|
|
152
|
+
* on submission day 2026-08-31: its Tools step rendered every top-level title
|
|
153
|
+
* as the heading and simultaneously flagged all fifteen tools with "Missing
|
|
154
|
+
* annotations: title". So both slots must be populated, and they must agree.
|
|
155
|
+
*
|
|
156
|
+
* The top-level `title` stays the single owner. This projection is the only
|
|
157
|
+
* writer of the annotations copy, applied at every registration on both
|
|
158
|
+
* transports, and the catalogue fences hold the two slots equal off a real
|
|
159
|
+
* `tools/list` so a registration that bypasses it goes red rather than
|
|
160
|
+
* shipping a bare slot back to the portal.
|
|
161
|
+
*/
|
|
162
|
+
export declare function titled<C extends {
|
|
163
|
+
title: string;
|
|
164
|
+
annotations?: object;
|
|
165
|
+
}>(config: C): C;
|
|
144
166
|
/**
|
|
145
167
|
* INSTRUCTIONS sentences both transports say.
|
|
146
168
|
*
|
package/dist/vocabulary.js
CHANGED
|
@@ -125,6 +125,27 @@ export const ANNOTATIONS = {
|
|
|
125
125
|
WRITE: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, ...OPEN_WORLD },
|
|
126
126
|
DESTRUCTIVE: { readOnlyHint: false, destructiveHint: true, idempotentHint: true, ...OPEN_WORLD },
|
|
127
127
|
};
|
|
128
|
+
/**
|
|
129
|
+
* One title, two wire slots: project a tool config's top-level `title` into
|
|
130
|
+
* `annotations.title` at registration.
|
|
131
|
+
*
|
|
132
|
+
* The MCP spec carries a tool title in two places. The 2025-06-18 revision
|
|
133
|
+
* put it top-level on the Tool object (where every registration here states
|
|
134
|
+
* it), and `ToolAnnotations.title` is the older 2025-03-26 slot that some
|
|
135
|
+
* readers still key on. The Claude connectors portal is one of them, measured
|
|
136
|
+
* on submission day 2026-08-31: its Tools step rendered every top-level title
|
|
137
|
+
* as the heading and simultaneously flagged all fifteen tools with "Missing
|
|
138
|
+
* annotations: title". So both slots must be populated, and they must agree.
|
|
139
|
+
*
|
|
140
|
+
* The top-level `title` stays the single owner. This projection is the only
|
|
141
|
+
* writer of the annotations copy, applied at every registration on both
|
|
142
|
+
* transports, and the catalogue fences hold the two slots equal off a real
|
|
143
|
+
* `tools/list` so a registration that bypasses it goes red rather than
|
|
144
|
+
* shipping a bare slot back to the portal.
|
|
145
|
+
*/
|
|
146
|
+
export function titled(config) {
|
|
147
|
+
return { ...config, annotations: { ...config.annotations, title: config.title } };
|
|
148
|
+
}
|
|
128
149
|
/**
|
|
129
150
|
* INSTRUCTIONS sentences both transports say.
|
|
130
151
|
*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shipstatic/mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.0",
|
|
4
4
|
"mcpName": "com.shipstatic/mcp",
|
|
5
5
|
"description": "Deploy static websites from AI agents. Start with the hosted endpoint at mcp.shipstatic.com \u2014 no install, no signup, no API key \u2014 or install this package to deploy folders from your own machine. The same fifteen tools either way.",
|
|
6
6
|
"type": "module",
|