@shipstatic/mcp 1.0.0-beta.6 → 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 +2 -1
- package/dist/call.d.ts +6 -2
- package/dist/call.js +31 -0
- package/dist/index.d.ts +51 -21
- package/dist/index.js +51 -21
- package/dist/server.d.ts +31 -6
- package/dist/server.js +4 -7
- package/dist/vocabulary.d.ts +33 -9
- package/dist/vocabulary.js +34 -9
- package/package.json +3 -2
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
|
-
|
|
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
|
|
29
|
-
* Hosted-only
|
|
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
|
@@ -1,34 +1,64 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The library entry — importing this file has NO side effects.
|
|
3
3
|
*
|
|
4
|
-
* `bin.ts` is the executable; this is what a consumer imports.
|
|
5
|
-
*
|
|
6
|
-
* private `cloudflare/mcp`, and
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
4
|
+
* `bin.ts` is the executable; this is what a consumer imports. There are two
|
|
5
|
+
* such consumers: the hosted Streamable-HTTP transport in the platform's
|
|
6
|
+
* private `cloudflare/mcp`, and the VS Code extension
|
|
7
|
+
* (`integrations/vscode`), which bundles a stdio server into its `.vsix`.
|
|
8
|
+
* Both transports are converging on the same product — the complete toolset
|
|
9
|
+
* for authenticated callers, the anonymous deploy for everyone else — and
|
|
10
|
+
* "one product, two transports" is only true if one of them can import the
|
|
11
|
+
* other.
|
|
10
12
|
*
|
|
11
|
-
* **The surface is exactly what a SECOND
|
|
12
|
-
* That is the rule, and it is stricter than "curated".
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* internals, plus some shared bits" instead of a contract.
|
|
13
|
+
* **The surface is exactly what a SECOND CONSUMER needs — nothing more.**
|
|
14
|
+
* That is the rule, and it is stricter than "curated". It read "a second
|
|
15
|
+
* TRANSPORT" until 1.0.0-beta.7, when the VS Code extension arrived as a
|
|
16
|
+
* consumer that is not a transport: it wants stdio's own composition,
|
|
17
|
+
* verbatim, running on the user's machine. The wording widened; the strictness
|
|
18
|
+
* did not.
|
|
18
19
|
*
|
|
19
|
-
* Every name below answers a question
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
20
|
+
* Every name below answers a question a consumer must otherwise answer for
|
|
21
|
+
* itself, and each admission was a restatement deleted, not a convenience
|
|
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`
|
|
24
|
+
* was the same duration written out eight times, `DESCRIPTION_BLOCKS` the
|
|
25
|
+
* fragments two tool descriptions genuinely share, `ACCOUNT_TOOL_NAMES` is
|
|
26
|
+
* what lets the hosted catalogue fence name the fourteen without counting them
|
|
27
|
+
* again, and `createServer` deleted three regexes in another repo's build (see
|
|
28
|
+
* below).
|
|
29
|
+
*
|
|
30
|
+
* **`createServer` is exported; the configured `call` is not.** The extension
|
|
31
|
+
* previously reached stdio's composition by REGEX-PATCHING this package's
|
|
32
|
+
* compiled `dist/` at bundle time — stripping `bin`'s shebang, and rewriting
|
|
33
|
+
* the `createRequire(import.meta.url)('../package.json')` line inside
|
|
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 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
|
+
* `call` stays internal because a consumer configures its own hints through
|
|
39
|
+
* `createCall`, and stdio's instance is not a contract anyone needs.
|
|
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
|
+
*
|
|
48
|
+
* The old reason for withholding `createServer` — that its upload tool takes a
|
|
49
|
+
* filesystem PATH, a footgun to offer a Worker — is still true and is now the
|
|
50
|
+
* CALLER's judgement rather than an absence: `cloudflare/mcp` must keep
|
|
51
|
+
* authoring its own upload tool, and does. An absence cannot express "correct
|
|
52
|
+
* for one consumer, wrong for another"; a documented rule can. What makes the
|
|
53
|
+
* export safe to publish at all is that `createServer` takes its `version` as
|
|
54
|
+
* an ARGUMENT — so exporting it adds no `node:module` to the import graph of a
|
|
55
|
+
* module the Workers-hosted transport loads.
|
|
27
56
|
*
|
|
28
57
|
* `tests/index.test.ts` fences both directions — nothing missing, nothing
|
|
29
58
|
* extra — because adding an export is the quiet failure: everything published
|
|
30
59
|
* becomes a breaking change to remove.
|
|
31
60
|
*/
|
|
32
61
|
export { type CallFn, type CallOptions, createCall, type ErrorHints } from './call.js';
|
|
62
|
+
export { createServer } from './server.js';
|
|
33
63
|
export { ACCOUNT_TOOL_NAMES, registerAccountTools } from './tools.js';
|
|
34
64
|
export { ANNOTATIONS, DESCRIPTION_BLOCKS, INSTRUCTION_BLOCKS, PARAM_DESCRIPTIONS, PUBLIC_EXPIRY, SERVER_NAME, UPLOAD_TOOL_NAME, } from './vocabulary.js';
|
package/dist/index.js
CHANGED
|
@@ -1,34 +1,64 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The library entry — importing this file has NO side effects.
|
|
3
3
|
*
|
|
4
|
-
* `bin.ts` is the executable; this is what a consumer imports.
|
|
5
|
-
*
|
|
6
|
-
* private `cloudflare/mcp`, and
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
4
|
+
* `bin.ts` is the executable; this is what a consumer imports. There are two
|
|
5
|
+
* such consumers: the hosted Streamable-HTTP transport in the platform's
|
|
6
|
+
* private `cloudflare/mcp`, and the VS Code extension
|
|
7
|
+
* (`integrations/vscode`), which bundles a stdio server into its `.vsix`.
|
|
8
|
+
* Both transports are converging on the same product — the complete toolset
|
|
9
|
+
* for authenticated callers, the anonymous deploy for everyone else — and
|
|
10
|
+
* "one product, two transports" is only true if one of them can import the
|
|
11
|
+
* other.
|
|
10
12
|
*
|
|
11
|
-
* **The surface is exactly what a SECOND
|
|
12
|
-
* That is the rule, and it is stricter than "curated".
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* internals, plus some shared bits" instead of a contract.
|
|
13
|
+
* **The surface is exactly what a SECOND CONSUMER needs — nothing more.**
|
|
14
|
+
* That is the rule, and it is stricter than "curated". It read "a second
|
|
15
|
+
* TRANSPORT" until 1.0.0-beta.7, when the VS Code extension arrived as a
|
|
16
|
+
* consumer that is not a transport: it wants stdio's own composition,
|
|
17
|
+
* verbatim, running on the user's machine. The wording widened; the strictness
|
|
18
|
+
* did not.
|
|
18
19
|
*
|
|
19
|
-
* Every name below answers a question
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
20
|
+
* Every name below answers a question a consumer must otherwise answer for
|
|
21
|
+
* itself, and each admission was a restatement deleted, not a convenience
|
|
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`
|
|
24
|
+
* was the same duration written out eight times, `DESCRIPTION_BLOCKS` the
|
|
25
|
+
* fragments two tool descriptions genuinely share, `ACCOUNT_TOOL_NAMES` is
|
|
26
|
+
* what lets the hosted catalogue fence name the fourteen without counting them
|
|
27
|
+
* again, and `createServer` deleted three regexes in another repo's build (see
|
|
28
|
+
* below).
|
|
29
|
+
*
|
|
30
|
+
* **`createServer` is exported; the configured `call` is not.** The extension
|
|
31
|
+
* previously reached stdio's composition by REGEX-PATCHING this package's
|
|
32
|
+
* compiled `dist/` at bundle time — stripping `bin`'s shebang, and rewriting
|
|
33
|
+
* the `createRequire(import.meta.url)('../package.json')` line inside
|
|
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 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
|
+
* `call` stays internal because a consumer configures its own hints through
|
|
39
|
+
* `createCall`, and stdio's instance is not a contract anyone needs.
|
|
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
|
+
*
|
|
48
|
+
* The old reason for withholding `createServer` — that its upload tool takes a
|
|
49
|
+
* filesystem PATH, a footgun to offer a Worker — is still true and is now the
|
|
50
|
+
* CALLER's judgement rather than an absence: `cloudflare/mcp` must keep
|
|
51
|
+
* authoring its own upload tool, and does. An absence cannot express "correct
|
|
52
|
+
* for one consumer, wrong for another"; a documented rule can. What makes the
|
|
53
|
+
* export safe to publish at all is that `createServer` takes its `version` as
|
|
54
|
+
* an ARGUMENT — so exporting it adds no `node:module` to the import graph of a
|
|
55
|
+
* module the Workers-hosted transport loads.
|
|
27
56
|
*
|
|
28
57
|
* `tests/index.test.ts` fences both directions — nothing missing, nothing
|
|
29
58
|
* extra — because adding an export is the quiet failure: everything published
|
|
30
59
|
* becomes a breaking change to remove.
|
|
31
60
|
*/
|
|
32
61
|
export { createCall } from './call.js';
|
|
62
|
+
export { createServer } from './server.js';
|
|
33
63
|
export { ACCOUNT_TOOL_NAMES, registerAccountTools } from './tools.js';
|
|
34
64
|
export { ANNOTATIONS, DESCRIPTION_BLOCKS, INSTRUCTION_BLOCKS, PARAM_DESCRIPTIONS, PUBLIC_EXPIRY, SERVER_NAME, UPLOAD_TOOL_NAME, } from './vocabulary.js';
|
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
|
-
*
|
|
5
|
+
* What the HOST knows about itself and this library must not assume.
|
|
5
6
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
|
|
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,
|
|
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,
|
|
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
|
|
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/dist/vocabulary.d.ts
CHANGED
|
@@ -27,6 +27,23 @@
|
|
|
27
27
|
* Everything else should be here, and adding a shared fact anywhere else is
|
|
28
28
|
* how the next year's drift starts.
|
|
29
29
|
*/
|
|
30
|
+
/**
|
|
31
|
+
* Two packages, and the split is a rule rather than an accident: **read a
|
|
32
|
+
* constant from whatever will act on it.**
|
|
33
|
+
*
|
|
34
|
+
* The label, password and idempotency-key constraints come from
|
|
35
|
+
* `@shipstatic/ship` because the SDK is what validates a value against them
|
|
36
|
+
* before it reaches the wire — describing a bound the client in the same
|
|
37
|
+
* process will not honour is the drift that matters, and reading both from one
|
|
38
|
+
* module makes it impossible. `@shipstatic/types` declares them, but ship
|
|
39
|
+
* bundles its own copy, so importing them from types here would let a describe
|
|
40
|
+
* advertise a limit the validator beside it rejects.
|
|
41
|
+
*
|
|
42
|
+
* The public-deploy lifetime is the other kind of fact. Ship never reads it —
|
|
43
|
+
* the API stamps it — so there is no validator to agree with, and taking it
|
|
44
|
+
* from the package that merely forwards it would mean a ship release every
|
|
45
|
+
* time the platform's own vocabulary grows.
|
|
46
|
+
*/
|
|
30
47
|
/**
|
|
31
48
|
* The server name every transport reports in `serverInfo`.
|
|
32
49
|
*
|
|
@@ -46,18 +63,25 @@ export declare const UPLOAD_TOOL_NAME = "deployments_upload";
|
|
|
46
63
|
/**
|
|
47
64
|
* How long an anonymous deployment lives, in the words an agent reads.
|
|
48
65
|
*
|
|
49
|
-
* **
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
66
|
+
* **Derived, since `@shipstatic/types@2.5.0-beta.19`.** It was a restatement
|
|
67
|
+
* until then, and deliberately the only one — the duration had appeared in
|
|
68
|
+
* eight places across the two servers and the widget, so a TTL change had to
|
|
69
|
+
* find all eight. Both halves of the fix landed together: types declares the
|
|
70
|
+
* number and `cloudflare/api` imports it back, because exporting without the
|
|
71
|
+
* import-back would have given the fact two owners instead of ending the
|
|
72
|
+
* duplication.
|
|
55
73
|
*
|
|
56
74
|
* A phrase rather than a number because every consumer is prose: the value has
|
|
57
|
-
* to carry its own unit, and
|
|
58
|
-
*
|
|
75
|
+
* to carry its own unit, and dividing by 86400 at eight sites would restate the
|
|
76
|
+
* unit eight times instead of the number.
|
|
77
|
+
*
|
|
78
|
+
* The unit stays literal, and that is the one assumption here: this reads
|
|
79
|
+
* correctly while the TTL is a whole number of days, which it has always been.
|
|
80
|
+
* A TTL of hours would need the prose reviewed anyway — the widget's own
|
|
81
|
+
* `formatExpires` speaks in days and hours too — so the honest failure is a
|
|
82
|
+
* sentence someone must rewrite, not a number that silently rounds.
|
|
59
83
|
*/
|
|
60
|
-
export declare const PUBLIC_EXPIRY
|
|
84
|
+
export declare const PUBLIC_EXPIRY: string;
|
|
61
85
|
/**
|
|
62
86
|
* MCP tool annotations by kind of operation. An agent reads these to decide
|
|
63
87
|
* whether it may call speculatively (`readOnlyHint`), whether a retry is free
|
package/dist/vocabulary.js
CHANGED
|
@@ -28,6 +28,24 @@
|
|
|
28
28
|
* how the next year's drift starts.
|
|
29
29
|
*/
|
|
30
30
|
import { IDEMPOTENCY_KEY_CONSTRAINTS, LABEL_CONSTRAINTS, PASSWORD_CONSTRAINTS, } from '@shipstatic/ship';
|
|
31
|
+
import { PUBLIC_DEPLOYMENT_TTL_SECONDS } from '@shipstatic/types';
|
|
32
|
+
/**
|
|
33
|
+
* Two packages, and the split is a rule rather than an accident: **read a
|
|
34
|
+
* constant from whatever will act on it.**
|
|
35
|
+
*
|
|
36
|
+
* The label, password and idempotency-key constraints come from
|
|
37
|
+
* `@shipstatic/ship` because the SDK is what validates a value against them
|
|
38
|
+
* before it reaches the wire — describing a bound the client in the same
|
|
39
|
+
* process will not honour is the drift that matters, and reading both from one
|
|
40
|
+
* module makes it impossible. `@shipstatic/types` declares them, but ship
|
|
41
|
+
* bundles its own copy, so importing them from types here would let a describe
|
|
42
|
+
* advertise a limit the validator beside it rejects.
|
|
43
|
+
*
|
|
44
|
+
* The public-deploy lifetime is the other kind of fact. Ship never reads it —
|
|
45
|
+
* the API stamps it — so there is no validator to agree with, and taking it
|
|
46
|
+
* from the package that merely forwards it would mean a ship release every
|
|
47
|
+
* time the platform's own vocabulary grows.
|
|
48
|
+
*/
|
|
31
49
|
/**
|
|
32
50
|
* The server name every transport reports in `serverInfo`.
|
|
33
51
|
*
|
|
@@ -47,18 +65,25 @@ export const UPLOAD_TOOL_NAME = 'deployments_upload';
|
|
|
47
65
|
/**
|
|
48
66
|
* How long an anonymous deployment lives, in the words an agent reads.
|
|
49
67
|
*
|
|
50
|
-
* **
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
68
|
+
* **Derived, since `@shipstatic/types@2.5.0-beta.19`.** It was a restatement
|
|
69
|
+
* until then, and deliberately the only one — the duration had appeared in
|
|
70
|
+
* eight places across the two servers and the widget, so a TTL change had to
|
|
71
|
+
* find all eight. Both halves of the fix landed together: types declares the
|
|
72
|
+
* number and `cloudflare/api` imports it back, because exporting without the
|
|
73
|
+
* import-back would have given the fact two owners instead of ending the
|
|
74
|
+
* duplication.
|
|
56
75
|
*
|
|
57
76
|
* A phrase rather than a number because every consumer is prose: the value has
|
|
58
|
-
* to carry its own unit, and
|
|
59
|
-
*
|
|
77
|
+
* to carry its own unit, and dividing by 86400 at eight sites would restate the
|
|
78
|
+
* unit eight times instead of the number.
|
|
79
|
+
*
|
|
80
|
+
* The unit stays literal, and that is the one assumption here: this reads
|
|
81
|
+
* correctly while the TTL is a whole number of days, which it has always been.
|
|
82
|
+
* A TTL of hours would need the prose reviewed anyway — the widget's own
|
|
83
|
+
* `formatExpires` speaks in days and hours too — so the honest failure is a
|
|
84
|
+
* sentence someone must rewrite, not a number that silently rounds.
|
|
60
85
|
*/
|
|
61
|
-
export const PUBLIC_EXPIRY =
|
|
86
|
+
export const PUBLIC_EXPIRY = `${PUBLIC_DEPLOYMENT_TTL_SECONDS / 86_400} days`;
|
|
62
87
|
const OPEN_WORLD = { openWorldHint: true };
|
|
63
88
|
/**
|
|
64
89
|
* MCP tool annotations by kind of operation. An agent reads these to decide
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shipstatic/mcp",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
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",
|
|
@@ -64,13 +64,14 @@
|
|
|
64
64
|
"dependencies": {
|
|
65
65
|
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
66
66
|
"@shipstatic/ship": "2.0.0-beta.15",
|
|
67
|
+
"@shipstatic/types": "2.5.0-beta.20",
|
|
67
68
|
"zod": "^4.4.3"
|
|
68
69
|
},
|
|
69
70
|
"devDependencies": {
|
|
70
71
|
"@biomejs/biome": "2.5.5",
|
|
71
|
-
"@shipstatic/types": "2.5.0-beta.18",
|
|
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
|
},
|