@shipstatic/mcp 1.1.1 → 1.2.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 +45 -24
- package/dist/call.js +11 -2
- package/dist/server.js +10 -3
- package/dist/vocabulary.d.ts +16 -0
- package/dist/vocabulary.js +16 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
ShipStatic MCP — deploy static websites, landing pages, and prototypes from AI agents.
|
|
1
|
+
# ShipStatic MCP
|
|
4
2
|
|
|
5
3
|
**One URL. Your agent ships.**
|
|
6
4
|
|
|
5
|
+
Give your AI a publish button for the internet: ask it to put your site online, and get back a real, shareable link in seconds. Landing pages, prototypes, portfolios — any static site.
|
|
6
|
+
|
|
7
7
|
[](https://smithery.ai/servers/shipstatic/ship)
|
|
8
8
|
[](https://glama.ai/mcp/servers/shipstatic/mcp)
|
|
9
9
|
|
|
10
|
-
## Hosted —
|
|
10
|
+
## Hosted — nothing to install
|
|
11
11
|
|
|
12
|
-
Drop
|
|
12
|
+
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.
|
|
13
13
|
|
|
14
14
|
```
|
|
15
15
|
https://mcp.shipstatic.com
|
|
@@ -21,6 +21,10 @@ https://mcp.shipstatic.com
|
|
|
21
21
|
claude mcp add --transport http shipstatic https://mcp.shipstatic.com
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
+
### Claude Desktop and claude.ai
|
|
25
|
+
|
|
26
|
+
**Settings → Connectors → Add custom connector**, paste `https://mcp.shipstatic.com`, save.
|
|
27
|
+
|
|
24
28
|
### Cursor, Antigravity, Windsurf, Zed — anywhere with `mcp.json`
|
|
25
29
|
|
|
26
30
|
```json
|
|
@@ -33,20 +37,31 @@ claude mcp add --transport http shipstatic https://mcp.shipstatic.com
|
|
|
33
37
|
}
|
|
34
38
|
```
|
|
35
39
|
|
|
36
|
-
###
|
|
40
|
+
### Then just ask
|
|
41
|
+
|
|
42
|
+
> "Put my site online."
|
|
37
43
|
|
|
38
|
-
|
|
44
|
+
Your agent publishes the files and answers with two links:
|
|
39
45
|
|
|
40
|
-
The
|
|
46
|
+
- **The live site** — a real URL you can share right away.
|
|
47
|
+
- **A claim link** — the site stays live for 3 days; open the claim link to keep it forever. A free account is all it takes.
|
|
41
48
|
|
|
42
|
-
|
|
49
|
+
Want the site private? Ask for a password — visitors must enter it before they can see anything.
|
|
43
50
|
|
|
44
|
-
|
|
51
|
+
## Local — the full toolset
|
|
52
|
+
|
|
53
|
+
The hosted URL does one thing: publish. Install this package for the full toolset (custom domains, listing, account-tied ops) — see everything you've shipped, connect your own domain, and publish sites that stay up permanently.
|
|
54
|
+
|
|
55
|
+
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 looks like `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-...`, and every site you publish lands in your account, never expires, and gets bigger limits.
|
|
56
|
+
|
|
57
|
+
The key is optional: leave it out and the local server behaves exactly like the hosted one (public sites, claim links, live for 3 days).
|
|
58
|
+
|
|
59
|
+
The server runs with `npx`, which ships with [Node.js](https://nodejs.org) (20.19 or newer).
|
|
45
60
|
|
|
46
61
|
### Claude Code
|
|
47
62
|
|
|
48
63
|
```bash
|
|
49
|
-
claude mcp add shipstatic -- npx @shipstatic/mcp
|
|
64
|
+
claude mcp add shipstatic -e SHIP_TOKEN=ship-... -- npx -y @shipstatic/mcp
|
|
50
65
|
```
|
|
51
66
|
|
|
52
67
|
### Cursor
|
|
@@ -58,7 +73,8 @@ Add to `~/.cursor/mcp.json`:
|
|
|
58
73
|
"mcpServers": {
|
|
59
74
|
"shipstatic": {
|
|
60
75
|
"command": "npx",
|
|
61
|
-
"args": ["@shipstatic/mcp"]
|
|
76
|
+
"args": ["-y", "@shipstatic/mcp"],
|
|
77
|
+
"env": { "SHIP_TOKEN": "ship-..." }
|
|
62
78
|
}
|
|
63
79
|
}
|
|
64
80
|
}
|
|
@@ -73,7 +89,8 @@ Add to `~/.gemini/antigravity/mcp_config.json`:
|
|
|
73
89
|
"mcpServers": {
|
|
74
90
|
"shipstatic": {
|
|
75
91
|
"command": "npx",
|
|
76
|
-
"args": ["@shipstatic/mcp"]
|
|
92
|
+
"args": ["-y", "@shipstatic/mcp"],
|
|
93
|
+
"env": { "SHIP_TOKEN": "ship-..." }
|
|
77
94
|
}
|
|
78
95
|
}
|
|
79
96
|
}
|
|
@@ -81,17 +98,11 @@ Add to `~/.gemini/antigravity/mcp_config.json`:
|
|
|
81
98
|
|
|
82
99
|
### Windsurf, Zed, and other MCP clients
|
|
83
100
|
|
|
84
|
-
Same config
|
|
85
|
-
|
|
86
|
-
## Free API key — permanent deployments
|
|
101
|
+
Same config shape — `npx -y @shipstatic/mcp`, with `SHIP_TOKEN` in `env`. Works with any MCP-compatible client.
|
|
87
102
|
|
|
88
|
-
|
|
103
|
+
### VS Code
|
|
89
104
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
```bash
|
|
93
|
-
claude mcp add shipstatic -e SHIP_TOKEN=ship-... -- npx @shipstatic/mcp
|
|
94
|
-
```
|
|
105
|
+
Prefer an editor extension? [ShipStatic for VS Code](https://marketplace.visualstudio.com/items?itemName=shipstatic.shipstatic) has this server built in — no config at all.
|
|
95
106
|
|
|
96
107
|
## Tools
|
|
97
108
|
|
|
@@ -127,7 +138,7 @@ The hosted endpoint exposes `deployments_upload` only. The local install exposes
|
|
|
127
138
|
|------|-------------|
|
|
128
139
|
| `whoami` | Get your account details including email, plan, and usage |
|
|
129
140
|
|
|
130
|
-
### Paging
|
|
141
|
+
### Paging long lists
|
|
131
142
|
|
|
132
143
|
`deployments_list` and `domains_list` accept `limit` and `cursor`. Each response carries a `cursor` — pass it back to fetch the next page; `null` means you are on the last one.
|
|
133
144
|
|
|
@@ -137,9 +148,19 @@ The hosted endpoint exposes `deployments_upload` only. The local install exposes
|
|
|
137
148
|
|
|
138
149
|
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.
|
|
139
150
|
|
|
151
|
+
### Deployments that clean themselves up
|
|
152
|
+
|
|
153
|
+
`deployments_upload` accepts a `ttl` in seconds. The deployment expires when the time is up and the platform reclaims it — handy for previews and throwaway iterations you would otherwise have to remember to delete.
|
|
154
|
+
|
|
155
|
+
```json
|
|
156
|
+
{ "path": "/path/to/dist", "ttl": 3600 }
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
It needs `SHIP_TOKEN` (your API key): a keyless deploy 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 a custom domain — deploy without one when the site needs a domain.
|
|
160
|
+
|
|
140
161
|
## Registry
|
|
141
162
|
|
|
142
|
-
Published to the [MCP Registry](https://registry.modelcontextprotocol.io/v0.1/servers?search=com.shipstatic/mcp) as `com.shipstatic/mcp`. Registry-aware clients see both the hosted endpoint and the local install and pick
|
|
163
|
+
Published to the [MCP Registry](https://registry.modelcontextprotocol.io/v0.1/servers?search=com.shipstatic/mcp) as `com.shipstatic/mcp`. Registry-aware clients see both the hosted endpoint and the local install and pick whichever fits their environment.
|
|
143
164
|
|
|
144
165
|
## License
|
|
145
166
|
|
package/dist/call.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ErrorType, isShipError } from '@shipstatic/ship';
|
|
2
|
+
import { MY_API_KEY_URL } from '@shipstatic/types';
|
|
2
3
|
/**
|
|
3
4
|
* The two CREDENTIAL arms that earn a per-transport hint. Everything else
|
|
4
5
|
* relays verbatim — a credential hint on any other type sends the agent
|
|
@@ -152,9 +153,17 @@ function safeStringify(value) {
|
|
|
152
153
|
return String(value);
|
|
153
154
|
}
|
|
154
155
|
}
|
|
155
|
-
/**
|
|
156
|
+
/**
|
|
157
|
+
* stdio's hints: this package owns `SHIP_TOKEN` and is the only side that may
|
|
158
|
+
* name it. The authentication hint carries the whole chain on purpose — the
|
|
159
|
+
* variable, what its value IS (the API key; the console and the config use two
|
|
160
|
+
* words for one credential, and this sentence is where an agent learns they
|
|
161
|
+
* are the same), and where it is minted. It fires at exactly the moment a
|
|
162
|
+
* user is missing one, so a hint that names the slot without naming the value
|
|
163
|
+
* strands them holding an "API key" a config asks for as a "token".
|
|
164
|
+
*/
|
|
156
165
|
const STDIO_HINTS = {
|
|
157
|
-
authentication:
|
|
166
|
+
authentication: `Set the SHIP_TOKEN environment variable in your MCP server configuration — its value is the user's API key, free at ${MY_API_KEY_URL}.`,
|
|
158
167
|
forbidden: 'This action is not permitted. Likely cause: plan limits reached or the account is terminated. Stop retrying — the user needs to upgrade or contact support at https://my.shipstatic.com.',
|
|
159
168
|
};
|
|
160
169
|
export const call = createCall({ hints: STDIO_HINTS });
|
package/dist/server.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
-
import { DeploymentVia } from '@shipstatic/types';
|
|
2
|
+
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';
|
|
@@ -20,7 +20,7 @@ To deploy: call ${UPLOAD_TOOL_NAME} with the build output directory path. ${B.li
|
|
|
20
20
|
|
|
21
21
|
Without SHIP_TOKEN, deployments are public and expire in ${PUBLIC_EXPIRY}. ${B.claim}
|
|
22
22
|
|
|
23
|
-
With SHIP_TOKEN configured, deployments go to the user's account and never expire. Listing, managing, and domain operations also require SHIP_TOKEN.
|
|
23
|
+
With SHIP_TOKEN configured — its value is the user's API key, free at ${MY_API_KEY_URL} — deployments go to the user's account and never expire; pass \`ttl\` (seconds) to ${UPLOAD_TOOL_NAME} for one that expires on its own. Listing, managing, and domain operations also require SHIP_TOKEN.
|
|
24
24
|
|
|
25
25
|
${B.conceptsHeader}
|
|
26
26
|
${B.deploymentConcept}
|
|
@@ -50,8 +50,15 @@ export function createServer(ship, options) {
|
|
|
50
50
|
labels: z.array(z.string()).optional().describe(PARAM_DESCRIPTIONS.labels),
|
|
51
51
|
password: z.string().optional().describe(PARAM_DESCRIPTIONS.password),
|
|
52
52
|
idempotencyKey: z.string().optional().describe(PARAM_DESCRIPTIONS.idempotencyKey),
|
|
53
|
+
// A bare `z.number()`, and the absences are the point. `.min()`/`.max()`
|
|
54
|
+
// would restate `TTL_CONSTRAINTS`, and `.int()` would restate the
|
|
55
|
+
// fraction rule — all three owned by `validateTtl`, which the SDK runs
|
|
56
|
+
// in-process before a byte is uploaded and which answers in the
|
|
57
|
+
// constitution's own words. A second validator here could only ever
|
|
58
|
+
// disagree with the first, silently; its absence fails loudly instead.
|
|
59
|
+
ttl: z.number().optional().describe(PARAM_DESCRIPTIONS.ttl),
|
|
53
60
|
},
|
|
54
|
-
}, ({ path, labels, password, idempotencyKey }) => call(() => ship.deployments.upload(path, { labels, password, idempotencyKey, via })));
|
|
61
|
+
}, ({ path, labels, password, idempotencyKey, ttl }) => call(() => ship.deployments.upload(path, { labels, password, idempotencyKey, ttl, via })));
|
|
55
62
|
// The other fourteen. Identical on every transport, so they live in the
|
|
56
63
|
// shared package rather than here — see tools.ts for why upload is not
|
|
57
64
|
// among them.
|
package/dist/vocabulary.d.ts
CHANGED
|
@@ -200,4 +200,20 @@ export declare const PARAM_DESCRIPTIONS: {
|
|
|
200
200
|
* the same one on both. The window is derived, never typed out.
|
|
201
201
|
*/
|
|
202
202
|
readonly idempotencyKey: `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 the original deployment is replayed instead (within ${number} hours). Key the ATTEMPT \u2014 a run id, a commit sha, a uuid minted before the first try \u2014 never one minted fresh on each retry, which would defeat the point.`;
|
|
203
|
+
/**
|
|
204
|
+
* Shared one door ahead of its offer, for the same reason `idempotencyKey`
|
|
205
|
+
* is: only stdio declares `ttl` today (`cloudflare/mcp/CLAUDE.md`'s
|
|
206
|
+
* divergence table records the hosted deferral and its trigger), and the two
|
|
207
|
+
* refusals this teaches belong to the platform, so they read identically on
|
|
208
|
+
* every door.
|
|
209
|
+
*
|
|
210
|
+
* **Two things are deliberately absent, and both are the same rule.** The
|
|
211
|
+
* RANGE, because `@shipstatic/ship` validates it in-process before a byte is
|
|
212
|
+
* uploaded and relays the constitution's own sentence — a second copy here
|
|
213
|
+
* could only ever disagree with it. And the name of any credential: stdio
|
|
214
|
+
* owns `SHIP_TOKEN`, the hosted door owns "connect an account", and a SHARED
|
|
215
|
+
* string that named either would put one door's fact in the other's mouth.
|
|
216
|
+
* `tests/vocabulary.test.ts` fences the second half for every member.
|
|
217
|
+
*/
|
|
218
|
+
readonly ttl: "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 a custom domain: deploy without one if the site needs a domain.";
|
|
203
219
|
};
|
package/dist/vocabulary.js
CHANGED
|
@@ -184,4 +184,20 @@ export const PARAM_DESCRIPTIONS = {
|
|
|
184
184
|
* the same one on both. The window is derived, never typed out.
|
|
185
185
|
*/
|
|
186
186
|
idempotencyKey: `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 the original deployment is replayed instead (within ${IDEMPOTENCY_KEY_CONSTRAINTS.WINDOW_SECONDS / 3600} hours). 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.`,
|
|
187
|
+
/**
|
|
188
|
+
* Shared one door ahead of its offer, for the same reason `idempotencyKey`
|
|
189
|
+
* is: only stdio declares `ttl` today (`cloudflare/mcp/CLAUDE.md`'s
|
|
190
|
+
* divergence table records the hosted deferral and its trigger), and the two
|
|
191
|
+
* refusals this teaches belong to the platform, so they read identically on
|
|
192
|
+
* every door.
|
|
193
|
+
*
|
|
194
|
+
* **Two things are deliberately absent, and both are the same rule.** The
|
|
195
|
+
* RANGE, because `@shipstatic/ship` validates it in-process before a byte is
|
|
196
|
+
* uploaded and relays the constitution's own sentence — a second copy here
|
|
197
|
+
* could only ever disagree with it. And the name of any credential: stdio
|
|
198
|
+
* owns `SHIP_TOKEN`, the hosted door owns "connect an account", and a SHARED
|
|
199
|
+
* string that named either would put one door's fact in the other's mouth.
|
|
200
|
+
* `tests/vocabulary.test.ts` fences the second half for every member.
|
|
201
|
+
*/
|
|
202
|
+
ttl: "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 a custom domain: deploy without one if the site needs a domain.",
|
|
187
203
|
};
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shipstatic/mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"mcpName": "com.shipstatic/mcp",
|
|
5
|
-
"description": "
|
|
5
|
+
"description": "Deploy static websites from AI agents. Free hosted endpoint at mcp.shipstatic.com — no install, no signup. Install for the full toolset: custom domains, listing, account operations.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "./dist/index.js",
|
|
8
8
|
"sideEffects": [
|