@shipstatic/mcp 1.0.0-beta.7 → 1.0.0-beta.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/dist/bin.js CHANGED
@@ -29,7 +29,8 @@ async function main() {
29
29
  // bearer) and the server classifies it. MCP never has to know which kind it
30
30
  // holds.
31
31
  const ship = new Ship({ token: process.env.SHIP_TOKEN });
32
- const server = createServer(ship, version);
32
+ // No `via` — this executable IS the `mcp` origin, which is the default.
33
+ const server = createServer(ship, { version });
33
34
  const transport = new StdioServerTransport();
34
35
  await server.connect(transport);
35
36
  console.error('ShipStatic MCP Server running on stdio');
package/dist/call.d.ts CHANGED
@@ -25,12 +25,16 @@ export type CallFn = <T>(fn: () => Promise<T>) => Promise<CallToolResult>;
25
25
  export interface CallOptions {
26
26
  hints: ErrorHints;
27
27
  /**
28
- * Attach a plain-object result as `structuredContent` beside the text.
29
- * Hosted-only today: it is what feeds the Apps-SDK widget, and the MCP spec
28
+ * Attach a plain-object SUCCESS result as `structuredContent` beside the
29
+ * text. Hosted-only: it is what feeds the Apps-SDK widget, and the MCP spec
30
30
  * pairs it with an `outputSchema`, which is a hand-maintained zod twin of a
31
31
  * published type. One such twin is worth it for a widget; fifteen would be a
32
32
  * drift surface with no consumer asking for it. See
33
33
  * `cloudflare/mcp/CLAUDE.md`, "What deliberately differs".
34
+ *
35
+ * It does NOT gate the ERROR envelope, which every transport carries — see
36
+ * `toErrorResult`. The objection above is about fifteen success shapes; a
37
+ * failure has exactly one published shape, and no schema to keep in step.
34
38
  */
35
39
  structuredContent?: boolean;
36
40
  }
package/dist/call.js CHANGED
@@ -35,6 +35,34 @@ export function createCall(options) {
35
35
  function isPlainObject(value) {
36
36
  return typeof value === 'object' && value !== null && !Array.isArray(value);
37
37
  }
38
+ /**
39
+ * The failure envelope: authoritative prose, with the wire's own structure
40
+ * riding beside it.
41
+ *
42
+ * The TEXT is unchanged and stays the contract — hints included. It has to be:
43
+ * the API authors its messages for the end user at the throw site
44
+ * (`cloudflare/api/CLAUDE.md`, "Message authoring law"), so the sentence
45
+ * always contains what the agent needs, and a client that ignores everything
46
+ * else still works.
47
+ *
48
+ * `structuredContent` carries `ShipError.toResponse()` verbatim — the same
49
+ * `ErrorResponse` the wire itself uses. Until 1.0.0-beta.8 the typed contract
50
+ * terminated here: `status`, `ErrorType`, and every `details` payload except
51
+ * the Validation arm's were dropped, so the platform's own law — *clients
52
+ * branch on error type and status, never on message strings* — held for every
53
+ * consumer EXCEPT the one best equipped to obey it. The recorded bite was a
54
+ * 429: `details.expires` died at this boundary, leaving the caller most in
55
+ * need of a precise backoff to parse "try again in 9 minutes" out of English.
56
+ *
57
+ * Safe on every arm, and checked rather than assumed: the MCP SDK validates
58
+ * `structuredContent` only when a tool declares an `outputSchema`, and returns
59
+ * early again when `isError` is set. No tool here declares one. So this is
60
+ * additive for every client and invisible to any that does not look.
61
+ *
62
+ * It is deliberately NOT behind `CallOptions.structuredContent` — that flag
63
+ * governs success shapes, where the schema-twin objection lives. A failure has
64
+ * one published shape on every transport.
65
+ */
38
66
  function toErrorResult(error, hints) {
39
67
  if (isShipError(error)) {
40
68
  let message = error.message;
@@ -49,9 +77,12 @@ function toErrorResult(error, hints) {
49
77
  }
50
78
  return {
51
79
  content: [{ type: 'text', text: message }],
80
+ structuredContent: { ...error.toResponse() },
52
81
  isError: true,
53
82
  };
54
83
  }
84
+ // No structure for a non-ShipError: there is no wire shape to report, and
85
+ // inventing one would tell an agent this failure came from the platform.
55
86
  const fallback = error instanceof Error ? error.message : 'An unexpected error occurred';
56
87
  return {
57
88
  content: [{ type: 'text', text: fallback }],
package/dist/index.d.ts CHANGED
@@ -32,12 +32,19 @@
32
32
  * compiled `dist/` at bundle time — stripping `bin`'s shebang, and rewriting
33
33
  * the `createRequire(import.meta.url)('../package.json')` line inside
34
34
  * `server.js` to inline a version literal. Three hacks against another
35
- * package's build output, each of which the 1.x library split broke. A
36
- * fifteen-line entry point calling `createServer(ship, version)` replaces all
37
- * of them, which is a restatement deleted rather than a convenience added.
35
+ * package's build output, each of which the 1.x library split broke. A short
36
+ * entry point calling `createServer(ship, { version, via })` replaces all of
37
+ * them, which is a restatement deleted rather than a convenience added.
38
38
  * `call` stays internal because a consumer configures its own hints through
39
39
  * `createCall`, and stdio's instance is not a contract anyone needs.
40
40
  *
41
+ * Its second argument is the HOST's own facts — the version it reports and the
42
+ * deploy origin its uploads carry — because a library has no manifest to read
43
+ * and no idea which product it was installed inside. A `startStdio` absorbing
44
+ * the transport as well was proposed and rejected; `CLAUDE.md` records why, and
45
+ * `tests/architecture/worker-safety.test.ts` is the fence that makes the reason
46
+ * mechanical rather than remembered.
47
+ *
41
48
  * The old reason for withholding `createServer` — that its upload tool takes a
42
49
  * filesystem PATH, a footgun to offer a Worker — is still true and is now the
43
50
  * CALLER's judgement rather than an absence: `cloudflare/mcp` must keep
package/dist/index.js CHANGED
@@ -32,12 +32,19 @@
32
32
  * compiled `dist/` at bundle time — stripping `bin`'s shebang, and rewriting
33
33
  * the `createRequire(import.meta.url)('../package.json')` line inside
34
34
  * `server.js` to inline a version literal. Three hacks against another
35
- * package's build output, each of which the 1.x library split broke. A
36
- * fifteen-line entry point calling `createServer(ship, version)` replaces all
37
- * of them, which is a restatement deleted rather than a convenience added.
35
+ * package's build output, each of which the 1.x library split broke. A short
36
+ * entry point calling `createServer(ship, { version, via })` replaces all of
37
+ * them, which is a restatement deleted rather than a convenience added.
38
38
  * `call` stays internal because a consumer configures its own hints through
39
39
  * `createCall`, and stdio's instance is not a contract anyone needs.
40
40
  *
41
+ * Its second argument is the HOST's own facts — the version it reports and the
42
+ * deploy origin its uploads carry — because a library has no manifest to read
43
+ * and no idea which product it was installed inside. A `startStdio` absorbing
44
+ * the transport as well was proposed and rejected; `CLAUDE.md` records why, and
45
+ * `tests/architecture/worker-safety.test.ts` is the fence that makes the reason
46
+ * mechanical rather than remembered.
47
+ *
41
48
  * The old reason for withholding `createServer` — that its upload tool takes a
42
49
  * filesystem PATH, a footgun to offer a Worker — is still true and is now the
43
50
  * CALLER's judgement rather than an absence: `cloudflare/mcp` must keep
package/dist/server.d.ts CHANGED
@@ -1,11 +1,36 @@
1
1
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
2
  import type Ship from '@shipstatic/ship';
3
+ import { type DeploymentViaType } from '@shipstatic/types';
3
4
  /**
4
- * Builds the stdio server's full 15-tool surface over an injected client.
5
+ * What the HOST knows about itself and this library must not assume.
5
6
  *
6
- * `version` is a parameter rather than something this module reads for itself:
7
- * the executable knows its own package manifest, a library must not assume it
8
- * has one, and reaching for `node:module` here would put a Node builtin in the
9
- * import graph of a module the Workers-hosted transport also loads.
7
+ * Both fields are the same category of fact, which is why they travel together
8
+ * rather than as a growing positional tail: a library has no manifest to read
9
+ * and no idea which product it was installed inside.
10
+ */
11
+ export interface ServerOptions {
12
+ /**
13
+ * The server's reported `serverInfo.version`. A parameter rather than
14
+ * something this module reads for itself: the executable knows its own
15
+ * package manifest, a library must not assume it has one, and reaching for
16
+ * `node:module` here would put a Node builtin in the import graph of a
17
+ * module the Workers-hosted transport also loads.
18
+ */
19
+ version: string;
20
+ /**
21
+ * The deploy origin this server's uploads are attributed to. Defaults to
22
+ * `mcp` — an npx install in some MCP client, which is what this package is
23
+ * on its own.
24
+ *
25
+ * It is a parameter because `via` names the DISTRIBUTION SURFACE, not the
26
+ * protocol: the GitHub Action reports `git` whatever invoked the workflow,
27
+ * and the web apps report `web`. The VS Code extension bundles this server
28
+ * into its `.vsix`, so its agent-mode deploys are the extension's — it
29
+ * passes `vsc`, and `mcp` goes back to meaning what it says.
30
+ */
31
+ via?: DeploymentViaType;
32
+ }
33
+ /**
34
+ * Builds the stdio server's full 15-tool surface over an injected client.
10
35
  */
11
- export declare function createServer(ship: Ship, version: string): McpServer;
36
+ export declare function createServer(ship: Ship, options: ServerOptions): McpServer;
package/dist/server.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { DeploymentVia } from '@shipstatic/types';
2
3
  import { z } from 'zod';
3
4
  import { call } from './call.js';
4
5
  import { registerAccountTools } from './tools.js';
@@ -28,13 +29,9 @@ ${B.domainConcept}
28
29
  ${B.domainWorkflow}`;
29
30
  /**
30
31
  * Builds the stdio server's full 15-tool surface over an injected client.
31
- *
32
- * `version` is a parameter rather than something this module reads for itself:
33
- * the executable knows its own package manifest, a library must not assume it
34
- * has one, and reaching for `node:module` here would put a Node builtin in the
35
- * import graph of a module the Workers-hosted transport also loads.
36
32
  */
37
- export function createServer(ship, version) {
33
+ export function createServer(ship, options) {
34
+ const { version, via = DeploymentVia.MCP } = options;
38
35
  const server = new McpServer({
39
36
  name: SERVER_NAME,
40
37
  version,
@@ -53,7 +50,7 @@ export function createServer(ship, version) {
53
50
  password: z.string().optional().describe(PARAM_DESCRIPTIONS.password),
54
51
  idempotencyKey: z.string().optional().describe(PARAM_DESCRIPTIONS.idempotencyKey),
55
52
  },
56
- }, ({ path, labels, password, idempotencyKey }) => call(() => ship.deployments.upload(path, { labels, password, idempotencyKey, via: 'mcp' })));
53
+ }, ({ path, labels, password, idempotencyKey }) => call(() => ship.deployments.upload(path, { labels, password, idempotencyKey, via })));
57
54
  // The other fourteen. Identical on every transport, so they live in the
58
55
  // shared package rather than here — see tools.ts for why upload is not
59
56
  // among them.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shipstatic/mcp",
3
- "version": "1.0.0-beta.7",
3
+ "version": "1.0.0-beta.8",
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",
@@ -71,6 +71,7 @@
71
71
  "@biomejs/biome": "2.5.5",
72
72
  "@types/node": "^25.9.5",
73
73
  "@vitest/coverage-v8": "4.1.10",
74
+ "esbuild": "^0.25.12",
74
75
  "typescript": "^6.0.3",
75
76
  "vitest": "4.1.10"
76
77
  },