@shipstatic/mcp 0.4.5 → 0.4.8

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 CHANGED
@@ -52,9 +52,11 @@ Same config format — `npx @shipstatic/mcp` via stdio. Works with any MCP-compa
52
52
 
53
53
  Ask your AI agent to deploy a site. No API key, no sign-up, no configuration.
54
54
 
55
- You get a live, shareable URL on `*.shipstatic.com` instantly.
55
+ Your site is live instantly on `*.shipstatic.com`.
56
56
 
57
- Deployments without an API key are public and expire in 3 days.
57
+ Deployments without an API key are public and expire in 3 days. The response includes a **claim URL** — always show it to the user so they can keep the site permanently.
58
+
59
+ Want a private site? Ask your agent to set a password when deploying — visitors will be prompted to unlock before viewing, on the deployment URL and on any custom domains pointing at it.
58
60
 
59
61
  ## All Tools — Free API Key
60
62
 
@@ -68,9 +70,9 @@ claude mcp add shipstatic -e SHIP_API_KEY=ship-... -- npx @shipstatic/mcp
68
70
 
69
71
  | Tool | Description |
70
72
  |------|-------------|
71
- | `deployments_upload` | Publish files and get a live URL instantly |
72
- | `deployments_list` | List all your deployed sites with their URLs, status, and labels |
73
- | `deployments_get` | Get details for a specific deployment including URL, status, and file count |
73
+ | `deployments_upload` | Publish files and get a live URL instantly, optionally protected by a password |
74
+ | `deployments_list` | List all deployments with their URLs, status, labels, and password protection state |
75
+ | `deployments_get` | Get deployment details including URL, status, file count, size, labels, and password protection state |
74
76
  | `deployments_set` | Update the labels on a deployment for organization and filtering |
75
77
  | `deployments_remove` | Permanently remove a deployment and all its files |
76
78
 
@@ -79,8 +81,8 @@ claude mcp add shipstatic -e SHIP_API_KEY=ship-... -- npx @shipstatic/mcp
79
81
  | Tool | Description |
80
82
  |------|-------------|
81
83
  | `domains_set` | Connect a custom domain to your site, switch deployments, or update labels |
82
- | `domains_list` | List all your custom domains with their linked sites and verification status |
83
- | `domains_get` | Get details for a specific domain including its linked site and DNS status |
84
+ | `domains_list` | List all domains with their linked deployments and verification status |
85
+ | `domains_get` | Get domain details including linked deployment, verification status, and labels |
84
86
  | `domains_records` | Get the DNS records you need to configure at your DNS provider |
85
87
  | `domains_dns` | Look up which DNS provider hosts a domain (e.g. Cloudflare, Namecheap) |
86
88
  | `domains_share` | Get a shareable link so someone else can see the required DNS records |
package/dist/call.js CHANGED
@@ -14,11 +14,14 @@ export async function call(fn) {
14
14
  function handleError(error) {
15
15
  if (isShipError(error)) {
16
16
  let message = error.message;
17
- if (error.isType(ErrorType.Authentication) && !message.includes('Too many requests')) {
17
+ if (error.isType(ErrorType.Authentication)) {
18
18
  message += '\n\nHint: Set a free SHIP_API_KEY environment variable in your MCP server configuration.';
19
19
  }
20
+ if (error.isType(ErrorType.Forbidden)) {
21
+ message += '\n\nHint: 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.';
22
+ }
20
23
  if (error.isType(ErrorType.Validation) && error.details) {
21
- message += `\n\nDetails: ${JSON.stringify(error.details)}`;
24
+ message += `\n\nDetails: ${safeStringify(error.details)}`;
22
25
  }
23
26
  return {
24
27
  content: [{ type: 'text', text: message }],
@@ -31,3 +34,11 @@ function handleError(error) {
31
34
  isError: true,
32
35
  };
33
36
  }
37
+ function safeStringify(value) {
38
+ try {
39
+ return JSON.stringify(value);
40
+ }
41
+ catch {
42
+ return String(value);
43
+ }
44
+ }
package/dist/index.js CHANGED
@@ -2,9 +2,10 @@
2
2
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
3
3
  import Ship from '@shipstatic/ship';
4
4
  import { createServer } from './server.js';
5
- const apiKey = process.env.SHIP_API_KEY;
6
5
  async function main() {
7
- const ship = apiKey ? new Ship({ apiKey }) : new Ship({});
6
+ // SHIP_API_KEY is optional without it, deployments are public (3-day expiry).
7
+ // The SDK coerces empty strings to undefined, so we can pass through directly.
8
+ const ship = new Ship({ apiKey: process.env.SHIP_API_KEY });
8
9
  const server = createServer(ship);
9
10
  const transport = new StdioServerTransport();
10
11
  await server.connect(transport);
package/dist/server.js CHANGED
@@ -1,14 +1,17 @@
1
+ import { LABEL_CONSTRAINTS, PASSWORD_CONSTRAINTS } from '@shipstatic/ship';
1
2
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
+ import { createRequire } from 'node:module';
2
4
  import { z } from 'zod';
3
5
  import { call } from './call.js';
6
+ const { version } = createRequire(import.meta.url)('../package.json');
4
7
  const OPEN_WORLD = { openWorldHint: true };
5
8
  const READ = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, ...OPEN_WORLD };
6
- const CREATE = { destructiveHint: false, ...OPEN_WORLD };
7
- const WRITE = { destructiveHint: false, idempotentHint: true, ...OPEN_WORLD };
8
- const DESTRUCTIVE = { destructiveHint: true, idempotentHint: true, ...OPEN_WORLD };
9
+ const CREATE = { readOnlyHint: false, destructiveHint: false, ...OPEN_WORLD };
10
+ const WRITE = { readOnlyHint: false, destructiveHint: false, idempotentHint: true, ...OPEN_WORLD };
11
+ const DESTRUCTIVE = { readOnlyHint: false, destructiveHint: true, idempotentHint: true, ...OPEN_WORLD };
9
12
  const INSTRUCTIONS = `ShipStatic deploys static websites instantly. No account required.
10
13
 
11
- To deploy: call deployments_upload with the build output directory path. The site is live immediately.
14
+ To deploy: call deployments_upload with the build output directory path. The site is live immediately. To make the site private, pass \`password\` — visitors must unlock before viewing, including on any custom domains pointing at it.
12
15
 
13
16
  Without SHIP_API_KEY, deployments are public and expire in 3 days. The response includes a claim URL — always show the deployment URL and the claim URL to the user so they can keep the site permanently.
14
17
 
@@ -22,25 +25,26 @@ To add a custom domain: domains_validate → domains_set → domains_records (sh
22
25
  export function createServer(ship) {
23
26
  const server = new McpServer({
24
27
  name: 'shipstatic',
25
- version: '0.4.3',
28
+ version,
26
29
  }, {
27
30
  instructions: INSTRUCTIONS,
28
31
  });
29
32
  // Deployments
30
33
  server.registerTool('deployments_upload', {
31
- description: 'Deploy a static site instantly. No account or API key required. Returns the live URL, file count, and size. Without SHIP_API_KEY, the response includes a claim URL (site expires in 3 days) — always show both the deployment URL and claim URL to the user.',
34
+ description: 'Deploy a static site instantly. No account or API key required. Returns the live URL, file count, and size. Without SHIP_API_KEY, the response includes a claim URL (site expires in 3 days) — always show both the deployment URL and claim URL to the user. To make the site private, pass `password`; always show the password to the user if you set one.',
32
35
  annotations: CREATE,
33
36
  inputSchema: {
34
37
  path: z.string().describe('Absolute path to the build output directory to deploy (e.g. "/Users/me/project/dist")'),
35
- labels: z.array(z.string()).optional().describe('Labels for organizing deployments (e.g. ["production", "v1.2"]). Lowercase, 3-25 chars, allows . _ - separators.'),
38
+ labels: z.array(z.string()).optional().describe(`Labels for organizing deployments (e.g. ["production", "v1.2"]). Lowercase, ${LABEL_CONSTRAINTS.MIN_LENGTH}-${LABEL_CONSTRAINTS.MAX_LENGTH} chars, allows . _ - separators.`),
39
+ password: z.string().optional().describe(`Optional password to gate the deployment behind an unlock prompt (${PASSWORD_CONSTRAINTS.MIN_LENGTH}–${PASSWORD_CONSTRAINTS.MAX_LENGTH} characters; whitespace significant). Visitors must enter this password before viewing the site, including on any custom domains pointing at it.`),
36
40
  },
37
- }, ({ path, labels }) => call(() => ship.deployments.upload(path, { labels, via: 'mcp' })));
41
+ }, ({ path, labels, password }) => call(() => ship.deployments.upload(path, { labels, password, via: 'mcp' })));
38
42
  server.registerTool('deployments_list', {
39
- description: 'List all deployments with their URLs, status, and labels.',
43
+ description: 'List all deployments with their URLs, status, labels, and password protection state.',
40
44
  annotations: READ,
41
45
  }, () => call(() => ship.deployments.list()));
42
46
  server.registerTool('deployments_get', {
43
- description: 'Get deployment details including URL, status, file count, size, and labels.',
47
+ description: 'Get deployment details including URL, status, file count, size, labels, and password protection state.',
44
48
  annotations: READ,
45
49
  inputSchema: {
46
50
  deployment: z.string().describe('Deployment hostname (e.g. "happy-cat-abc1234.shipstatic.com"). Returned by deployments_upload or deployments_list.'),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shipstatic/mcp",
3
- "version": "0.4.5",
3
+ "version": "0.4.8",
4
4
  "mcpName": "com.shipstatic/mcp",
5
5
  "description": "Free, no account needed — deploy static websites, landing pages, and prototypes instantly from AI agents",
6
6
  "type": "module",
@@ -45,11 +45,11 @@
45
45
  "license": "MIT",
46
46
  "dependencies": {
47
47
  "@modelcontextprotocol/sdk": "^1.29.0",
48
- "@shipstatic/ship": "^0.8.9",
48
+ "@shipstatic/ship": "^0.9.6",
49
49
  "zod": "^4.3.6"
50
50
  },
51
51
  "devDependencies": {
52
- "@shipstatic/types": "^0.8.7",
52
+ "@shipstatic/types": "^0.9.8",
53
53
  "@types/node": "^25.6.0",
54
54
  "husky": "^9.1.7",
55
55
  "typescript": "^6.0.2",
@@ -58,6 +58,7 @@
58
58
  "scripts": {
59
59
  "build": "tsc",
60
60
  "clean": "rm -rf dist",
61
- "test": "vitest"
61
+ "test": "vitest",
62
+ "typecheck": "tsc --noEmit -p tsconfig.test.json"
62
63
  }
63
64
  }