@shardflux/mcp 0.3.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/CHANGELOG.md +56 -0
- package/LICENSE +202 -0
- package/README.md +289 -0
- package/dist/bin.d.ts +2 -0
- package/dist/bin.js +6 -0
- package/dist/config.d.ts +29 -0
- package/dist/config.js +75 -0
- package/dist/errors.d.ts +24 -0
- package/dist/errors.js +72 -0
- package/dist/http.d.ts +13 -0
- package/dist/http.js +21 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +10 -0
- package/dist/main.d.ts +5 -0
- package/dist/main.js +60 -0
- package/dist/server.d.ts +204 -0
- package/dist/server.js +687 -0
- package/package.json +62 -0
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/** A refusal decided by this server (argument/pinning problems, unknown workspace key). */
|
|
2
|
+
export declare class ToolError extends Error {
|
|
3
|
+
name: string;
|
|
4
|
+
readonly code: string;
|
|
5
|
+
readonly details: Record<string, unknown> | undefined;
|
|
6
|
+
constructor(code: string, message: string, details?: Record<string, unknown>);
|
|
7
|
+
}
|
|
8
|
+
export interface ToolErrorInfo {
|
|
9
|
+
code: string;
|
|
10
|
+
message: string;
|
|
11
|
+
status?: number;
|
|
12
|
+
request_id?: string;
|
|
13
|
+
retryable?: boolean;
|
|
14
|
+
operation_id?: string;
|
|
15
|
+
source?: 'api' | 'cell';
|
|
16
|
+
details?: Record<string, unknown>;
|
|
17
|
+
issues?: string[];
|
|
18
|
+
last_state?: string;
|
|
19
|
+
}
|
|
20
|
+
export declare function redact(text: string, key?: string): string;
|
|
21
|
+
export declare function describeToolError(err: unknown, context?: {
|
|
22
|
+
operationId?: string | undefined;
|
|
23
|
+
timeoutMs?: number;
|
|
24
|
+
}): ToolErrorInfo;
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool errors are returned as MCP tool results (`isError: true`) whose
|
|
3
|
+
* content is `{ "error": { code, message, ... } }` with the API's closed error
|
|
4
|
+
* code, never as protocol failures, so the calling model can react to them.
|
|
5
|
+
*/
|
|
6
|
+
import { OperationFailedError, OperationTimeoutError, ShardfluxApiError, ShardfluxProtocolError, TemplateUploadError, ToolArgumentError } from '@shardflux/sdk';
|
|
7
|
+
/** A refusal decided by this server (argument/pinning problems, unknown workspace key). */
|
|
8
|
+
export class ToolError extends Error {
|
|
9
|
+
name = 'ToolError';
|
|
10
|
+
code;
|
|
11
|
+
details;
|
|
12
|
+
constructor(code, message, details) {
|
|
13
|
+
super(message);
|
|
14
|
+
this.code = code;
|
|
15
|
+
this.details = details;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
const KEY_PATTERN = /sfk_[A-Za-z0-9]{8,}_[A-Za-z0-9]+/g;
|
|
19
|
+
export function redact(text, key) {
|
|
20
|
+
let out = text.replace(KEY_PATTERN, 'sfk_[redacted]');
|
|
21
|
+
if (key && key.length >= 8)
|
|
22
|
+
out = out.split(key).join('[redacted]');
|
|
23
|
+
return out;
|
|
24
|
+
}
|
|
25
|
+
const named = (err, name) => typeof err === 'object' && err !== null && err.name === name;
|
|
26
|
+
export function describeToolError(err, context = {}) {
|
|
27
|
+
if (err instanceof ShardfluxApiError) {
|
|
28
|
+
return {
|
|
29
|
+
code: err.code,
|
|
30
|
+
message: err.message,
|
|
31
|
+
status: err.status,
|
|
32
|
+
request_id: err.requestId,
|
|
33
|
+
retryable: err.retryable,
|
|
34
|
+
source: err.source,
|
|
35
|
+
...(err.operationId ? { operation_id: err.operationId } : {}),
|
|
36
|
+
...(err.details ? { details: err.details } : {}),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
if (err instanceof ToolArgumentError)
|
|
40
|
+
return { code: 'invalid_arguments', message: err.message, issues: err.issues };
|
|
41
|
+
if (err instanceof ToolError)
|
|
42
|
+
return { code: err.code, message: err.message, ...(err.details ? { details: err.details } : {}) };
|
|
43
|
+
if (err instanceof OperationTimeoutError) {
|
|
44
|
+
return { code: 'timeout', message: `${err.message} Call operation_wait with this operation_id to keep waiting.`, operation_id: err.operationId, last_state: err.lastState, retryable: true };
|
|
45
|
+
}
|
|
46
|
+
if (err instanceof OperationFailedError) {
|
|
47
|
+
// retryable: the operation error's own flag. capacity_unavailable (no host could admit the start before its
|
|
48
|
+
// deadline) is retryable: nothing was started, so the agent may try again later.
|
|
49
|
+
const opDetails = err.operation.error?.details;
|
|
50
|
+
const reason = typeof opDetails === 'object' && opDetails !== null ? opDetails.reason : undefined;
|
|
51
|
+
const details = { ...(err.errorCode ? { error_code: err.errorCode } : {}), ...(typeof reason === 'string' ? { reason } : {}) };
|
|
52
|
+
const hint = err.errorCode === 'capacity_unavailable' ? '. No host could admit it before its deadline and nothing was started; you may retry later.' : '';
|
|
53
|
+
return { code: 'operation_failed', message: `${err.message}${hint}`, operation_id: err.operationId, retryable: err.retryable, ...(Object.keys(details).length ? { details } : {}) };
|
|
54
|
+
}
|
|
55
|
+
if (named(err, 'TimeoutError')) {
|
|
56
|
+
return {
|
|
57
|
+
code: 'timeout',
|
|
58
|
+
message: `The tool call did not finish within ${context.timeoutMs ?? 'its'} ms${context.operationId ? '; the operation continues server side (use operation_wait)' : ''}.`,
|
|
59
|
+
retryable: true,
|
|
60
|
+
...(context.operationId ? { operation_id: context.operationId } : {}),
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
if (err instanceof TemplateUploadError)
|
|
64
|
+
return { code: 'upload_failed', message: err.message, ...(err.status ? { status: err.status } : {}), details: { sha256: err.sha256, ...(err.code ? { storage_code: err.code } : {}) } };
|
|
65
|
+
if (err instanceof ShardfluxProtocolError)
|
|
66
|
+
return { code: 'protocol_error', message: err.message, status: err.status };
|
|
67
|
+
if (err instanceof TypeError && err.message === 'fetch failed') {
|
|
68
|
+
const cause = err.cause;
|
|
69
|
+
return { code: 'network_error', message: `Cannot reach the Shardflux API or cell gateway (${cause?.code ?? cause?.message ?? 'network error'}).`, retryable: true };
|
|
70
|
+
}
|
|
71
|
+
return { code: 'internal_error', message: err instanceof Error ? err.message : String(err) };
|
|
72
|
+
}
|
package/dist/http.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The fetch given to the SDK: the runtime's fetch with `Connection: close` on
|
|
3
|
+
* every request (API and cell gateway).
|
|
4
|
+
*
|
|
5
|
+
* Why: Node 26.7's bundled undici (8.9.0) intermittently stalls a request
|
|
6
|
+
* sent on a reused keep-alive connection until an unrelated timer fires (up to
|
|
7
|
+
* ~30 s, the SDK's request timeout, after which the SDK retries). Reproduced
|
|
8
|
+
* with bare fetch against both node:http and Fastify servers; Node 22 (undici
|
|
9
|
+
* 6.28) and `Connection: close` do not stall. A fresh connection per request
|
|
10
|
+
* costs one TCP/TLS handshake, which is negligible for these call rates.
|
|
11
|
+
* Set SHARDFLUX_HTTP_KEEPALIVE=1 to use the runtime's keep-alive pooling.
|
|
12
|
+
*/
|
|
13
|
+
export declare function makeFetch(env: Record<string, string | undefined>, base?: typeof fetch): typeof fetch;
|
package/dist/http.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The fetch given to the SDK: the runtime's fetch with `Connection: close` on
|
|
3
|
+
* every request (API and cell gateway).
|
|
4
|
+
*
|
|
5
|
+
* Why: Node 26.7's bundled undici (8.9.0) intermittently stalls a request
|
|
6
|
+
* sent on a reused keep-alive connection until an unrelated timer fires (up to
|
|
7
|
+
* ~30 s, the SDK's request timeout, after which the SDK retries). Reproduced
|
|
8
|
+
* with bare fetch against both node:http and Fastify servers; Node 22 (undici
|
|
9
|
+
* 6.28) and `Connection: close` do not stall. A fresh connection per request
|
|
10
|
+
* costs one TCP/TLS handshake, which is negligible for these call rates.
|
|
11
|
+
* Set SHARDFLUX_HTTP_KEEPALIVE=1 to use the runtime's keep-alive pooling.
|
|
12
|
+
*/
|
|
13
|
+
export function makeFetch(env, base = fetch) {
|
|
14
|
+
if (env.SHARDFLUX_HTTP_KEEPALIVE === '1')
|
|
15
|
+
return base;
|
|
16
|
+
return (input, init) => {
|
|
17
|
+
const headers = new Headers(init?.headers);
|
|
18
|
+
headers.set('connection', 'close');
|
|
19
|
+
return base(input, { ...init, headers });
|
|
20
|
+
};
|
|
21
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @shardflux/mcp — local stdio MCP server exposing Shardflux workspace tools
|
|
3
|
+
* through @shardflux/sdk with a supplied scoped API key. The executable is
|
|
4
|
+
* `shardflux-mcp` (bin.ts); `createShardfluxMcpServer()` builds the same server for any
|
|
5
|
+
* MCP transport.
|
|
6
|
+
*/
|
|
7
|
+
export { ALL_TOOL_PERMISSIONS, MCP_SERVER_VERSION, compactTiming, createShardfluxMcpServer, errorResult, okResult, sdkToolDefinitions, summarizeBuild, summarizeOperation, summarizeTemplate, summarizeWorkspace } from './server.js';
|
|
8
|
+
export type { Logger, ObjectSchema, ServerOptions } from './server.js';
|
|
9
|
+
export { ConfigError, DEFAULT_TOOL_TIMEOUT_MS, DEFAULT_WAKE_TIMEOUT_MS, MAX_TOOL_TIMEOUT_MS, apiUrlFrom, loadConfig } from './config.js';
|
|
10
|
+
export type { McpConfig } from './config.js';
|
|
11
|
+
export { ToolError, describeToolError, redact } from './errors.js';
|
|
12
|
+
export type { ToolErrorInfo } from './errors.js';
|
|
13
|
+
export { main, stderrLogger } from './main.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @shardflux/mcp — local stdio MCP server exposing Shardflux workspace tools
|
|
3
|
+
* through @shardflux/sdk with a supplied scoped API key. The executable is
|
|
4
|
+
* `shardflux-mcp` (bin.ts); `createShardfluxMcpServer()` builds the same server for any
|
|
5
|
+
* MCP transport.
|
|
6
|
+
*/
|
|
7
|
+
export { ALL_TOOL_PERMISSIONS, MCP_SERVER_VERSION, compactTiming, createShardfluxMcpServer, errorResult, okResult, sdkToolDefinitions, summarizeBuild, summarizeOperation, summarizeTemplate, summarizeWorkspace } from "./server.js";
|
|
8
|
+
export { ConfigError, DEFAULT_TOOL_TIMEOUT_MS, DEFAULT_WAKE_TIMEOUT_MS, MAX_TOOL_TIMEOUT_MS, apiUrlFrom, loadConfig } from "./config.js";
|
|
9
|
+
export { ToolError, describeToolError, redact } from "./errors.js";
|
|
10
|
+
export { main, stderrLogger } from "./main.js";
|
package/dist/main.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { McpConfig } from './config.js';
|
|
2
|
+
import type { Logger } from './server.js';
|
|
3
|
+
/** One JSON line per event on stderr; the API key is redacted from every line. */
|
|
4
|
+
export declare function stderrLogger(config: Pick<McpConfig, 'apiKey' | 'logLevel'>, write?: (line: string) => void): Logger;
|
|
5
|
+
export declare function main(env?: Record<string, string | undefined>): Promise<number | null>;
|
package/dist/main.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Process wiring for the stdio MCP server: configuration from the
|
|
3
|
+
* environment, a stderr logger (stdout carries the protocol), the stdio
|
|
4
|
+
* transport, and shutdown when the client closes stdin or on SIGINT/SIGTERM.
|
|
5
|
+
*/
|
|
6
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
7
|
+
import { ConfigError, loadConfig } from "./config.js";
|
|
8
|
+
import { redact } from "./errors.js";
|
|
9
|
+
import { MCP_SERVER_VERSION, createShardfluxMcpServer } from "./server.js";
|
|
10
|
+
const LEVELS = { debug: 10, info: 20, warn: 30, error: 40 };
|
|
11
|
+
/** One JSON line per event on stderr; the API key is redacted from every line. */
|
|
12
|
+
export function stderrLogger(config, write = (l) => void process.stderr.write(l)) {
|
|
13
|
+
const min = LEVELS[config.logLevel];
|
|
14
|
+
return (level, message, fields = {}) => {
|
|
15
|
+
if (LEVELS[level] < min)
|
|
16
|
+
return;
|
|
17
|
+
write(`${redact(JSON.stringify({ time: new Date().toISOString(), level, service: 'shardflux-mcp', message, ...fields }), config.apiKey)}\n`);
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
export async function main(env = process.env) {
|
|
21
|
+
let config;
|
|
22
|
+
try {
|
|
23
|
+
config = loadConfig(env);
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
const message = err instanceof ConfigError ? err.message : String(err);
|
|
27
|
+
process.stderr.write(`${JSON.stringify({ time: new Date().toISOString(), level: 'error', service: 'shardflux-mcp', message: `configuration error: ${redact(message, env.SHARDFLUX_API_KEY)}` })}\n`);
|
|
28
|
+
return 2;
|
|
29
|
+
}
|
|
30
|
+
const log = stderrLogger(config);
|
|
31
|
+
const server = createShardfluxMcpServer(config, { log, env });
|
|
32
|
+
const transport = new StdioServerTransport();
|
|
33
|
+
let closing = false;
|
|
34
|
+
const shutdown = (reason) => {
|
|
35
|
+
if (closing)
|
|
36
|
+
return;
|
|
37
|
+
closing = true;
|
|
38
|
+
log('info', 'shutting down', { reason });
|
|
39
|
+
void server
|
|
40
|
+
.close()
|
|
41
|
+
.catch(() => undefined)
|
|
42
|
+
.finally(() => process.exit(0));
|
|
43
|
+
};
|
|
44
|
+
server.onerror = (err) => log('warn', 'protocol error', { error: redact(err.message, config.apiKey) });
|
|
45
|
+
await server.connect(transport);
|
|
46
|
+
process.stdin.on('end', () => shutdown('stdin closed'));
|
|
47
|
+
process.on('SIGINT', () => shutdown('SIGINT'));
|
|
48
|
+
process.on('SIGTERM', () => shutdown('SIGTERM'));
|
|
49
|
+
log('info', 'ready', {
|
|
50
|
+
version: MCP_SERVER_VERSION,
|
|
51
|
+
api_url: config.apiUrl,
|
|
52
|
+
pinned_workspace_key: config.workspaceKey ?? null,
|
|
53
|
+
default_template: config.template ?? null,
|
|
54
|
+
agent_label: config.agentLabel,
|
|
55
|
+
tool_timeout_ms: config.toolTimeoutMs,
|
|
56
|
+
wake: config.wake,
|
|
57
|
+
wake_timeout_ms: config.wakeTimeoutMs,
|
|
58
|
+
});
|
|
59
|
+
return null;
|
|
60
|
+
}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
2
|
+
import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
|
|
3
|
+
import type { JsonSchema, LifecycleTiming, Operation, TemplateBuild, TemplateDetail, TemplateOwner, ToolName, WorkspaceTool, WorkspaceView } from '@shardflux/sdk';
|
|
4
|
+
import type { McpConfig } from './config.js';
|
|
5
|
+
import type { ToolErrorInfo } from './errors.js';
|
|
6
|
+
export declare const MCP_SERVER_VERSION = "0.3.0";
|
|
7
|
+
export declare const ALL_TOOL_PERMISSIONS: readonly ToolName[];
|
|
8
|
+
export type ObjectSchema = JsonSchema & {
|
|
9
|
+
type: 'object';
|
|
10
|
+
properties: Record<string, JsonSchema>;
|
|
11
|
+
required: string[];
|
|
12
|
+
};
|
|
13
|
+
export interface Logger {
|
|
14
|
+
(level: 'debug' | 'info' | 'warn' | 'error', message: string, fields?: Record<string, unknown>): void;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* The SDK's workspace tool definitions without a workspace. `workspaceTools()`
|
|
18
|
+
* only touches the workspace inside `execute`, which is never called on these:
|
|
19
|
+
* the proxy throws on any access, so a change in the SDK that did would fail loudly.
|
|
20
|
+
*/
|
|
21
|
+
export declare function sdkToolDefinitions(tools?: readonly ToolName[]): WorkspaceTool[];
|
|
22
|
+
/** What tools return for a workspace (no tokens or other credentials). */
|
|
23
|
+
export declare function summarizeWorkspace(v: WorkspaceView): {
|
|
24
|
+
id: string;
|
|
25
|
+
key: string;
|
|
26
|
+
ready: boolean;
|
|
27
|
+
observed_state: "running" | "failed" | "suspended" | "deleted" | "creating" | "starting" | "suspending" | "resuming" | "forking" | "stopping" | "deleting";
|
|
28
|
+
desired_state: "running" | "suspended" | "deleted";
|
|
29
|
+
template: {
|
|
30
|
+
slug: string;
|
|
31
|
+
version: number;
|
|
32
|
+
};
|
|
33
|
+
active_operation: {
|
|
34
|
+
error?: {
|
|
35
|
+
[key: string]: unknown;
|
|
36
|
+
} | undefined;
|
|
37
|
+
id: string;
|
|
38
|
+
kind: "open" | "suspend" | "resume" | "fork" | "snapshot" | "restore" | "delete" | "move" | "resize" | "volume_create" | "volume_attach" | "volume_detach" | "volume_delete" | "reset" | "layer_snapshot";
|
|
39
|
+
state: "capacity_pending" | "queued" | "running" | "succeeded" | "failed" | "canceled";
|
|
40
|
+
state_reason: string | null;
|
|
41
|
+
workspace_id: string | null;
|
|
42
|
+
created_at: string;
|
|
43
|
+
completed_at: string | null;
|
|
44
|
+
} | null;
|
|
45
|
+
pending_reason: string | null;
|
|
46
|
+
cell_endpoint: string | null;
|
|
47
|
+
grants: {
|
|
48
|
+
[key: string]: unknown;
|
|
49
|
+
} | null;
|
|
50
|
+
ceilings: {
|
|
51
|
+
cpu_millis: number;
|
|
52
|
+
memory_mib: number;
|
|
53
|
+
disk_gib: number;
|
|
54
|
+
} | null;
|
|
55
|
+
forked_from_workspace_id: string | null;
|
|
56
|
+
lifetime: "persistent" | "session";
|
|
57
|
+
purpose: "standard" | "template_draft" | "template_test";
|
|
58
|
+
disk_layout: "legacy" | "layered";
|
|
59
|
+
idle_timeout_seconds: number | null;
|
|
60
|
+
ended_reason: "closed" | "idle_timeout" | "draft_discarded" | null;
|
|
61
|
+
/** Start commands and services of the template version; null when it has none. */
|
|
62
|
+
startup: {
|
|
63
|
+
state: "pending" | "running" | "ready" | "failed";
|
|
64
|
+
trigger: ("create" | "boot" | "resume") | null;
|
|
65
|
+
step: string | null;
|
|
66
|
+
service: string | null;
|
|
67
|
+
exit_code: number | null;
|
|
68
|
+
output_tail: string | null;
|
|
69
|
+
reason: string | null;
|
|
70
|
+
operation_id: string | null;
|
|
71
|
+
at: string | null;
|
|
72
|
+
} | null;
|
|
73
|
+
created_at: string;
|
|
74
|
+
deleted_at: string | null;
|
|
75
|
+
};
|
|
76
|
+
/** A template build without the stored recipe (the compiled steps are long): state, version and what the builder refused. */
|
|
77
|
+
export declare function summarizeBuild(b: TemplateBuild): {
|
|
78
|
+
id: string;
|
|
79
|
+
template: {
|
|
80
|
+
slug: string;
|
|
81
|
+
name: string;
|
|
82
|
+
};
|
|
83
|
+
target_version: number | null;
|
|
84
|
+
state: import("@shardflux/sdk").TemplateBuildState;
|
|
85
|
+
registration: {
|
|
86
|
+
state: import("@shardflux/sdk").TemplateBuildRegistrationState;
|
|
87
|
+
registered_at: string | null;
|
|
88
|
+
error: {
|
|
89
|
+
code: string;
|
|
90
|
+
message: string;
|
|
91
|
+
} | null;
|
|
92
|
+
};
|
|
93
|
+
template_version: {
|
|
94
|
+
id: string;
|
|
95
|
+
version: number;
|
|
96
|
+
published: boolean;
|
|
97
|
+
} | null;
|
|
98
|
+
auto_publish: boolean;
|
|
99
|
+
failure: {
|
|
100
|
+
code: string;
|
|
101
|
+
message: string;
|
|
102
|
+
} | null;
|
|
103
|
+
denied_hosts: string[];
|
|
104
|
+
network: {
|
|
105
|
+
mode: "none" | "egress_allowlist";
|
|
106
|
+
allow_hosts: string[];
|
|
107
|
+
};
|
|
108
|
+
recipe_sha256: string | null;
|
|
109
|
+
builder_availability: "available" | "unavailable";
|
|
110
|
+
created_at: string;
|
|
111
|
+
completed_at: string | null;
|
|
112
|
+
log_tail: string | null;
|
|
113
|
+
};
|
|
114
|
+
/** A template for model context: identity, what open resolves to, every version with its settings. */
|
|
115
|
+
export declare function summarizeTemplate(t: TemplateDetail): {
|
|
116
|
+
slug: string;
|
|
117
|
+
name: string;
|
|
118
|
+
owner: TemplateOwner;
|
|
119
|
+
category: import("@shardflux/sdk").TemplateCategory | null;
|
|
120
|
+
open_resolves_to: {
|
|
121
|
+
version: number;
|
|
122
|
+
owner: TemplateOwner;
|
|
123
|
+
} | null;
|
|
124
|
+
draft: {
|
|
125
|
+
workspace_key: string;
|
|
126
|
+
observed_state: string;
|
|
127
|
+
base_version: number;
|
|
128
|
+
} | null;
|
|
129
|
+
versions: {
|
|
130
|
+
version: number;
|
|
131
|
+
state: import("@shardflux/sdk").TemplateVersionState;
|
|
132
|
+
is_open_version: boolean;
|
|
133
|
+
description: string | null;
|
|
134
|
+
source: "recipe" | "workspace" | "git" | null;
|
|
135
|
+
disk_layouts: ("legacy" | "layered")[];
|
|
136
|
+
installed_tools: {
|
|
137
|
+
name: string;
|
|
138
|
+
version: string;
|
|
139
|
+
}[];
|
|
140
|
+
settings: {
|
|
141
|
+
env: {
|
|
142
|
+
[key: string]: string;
|
|
143
|
+
};
|
|
144
|
+
inputs: {
|
|
145
|
+
[key: string]: import("@shardflux/sdk").components["schemas"]["TemplateInput"];
|
|
146
|
+
};
|
|
147
|
+
start: import("@shardflux/sdk").components["schemas"]["TemplateStartCommand"][];
|
|
148
|
+
services: {
|
|
149
|
+
[key: string]: import("@shardflux/sdk").components["schemas"]["TemplateService"];
|
|
150
|
+
};
|
|
151
|
+
defaults: import("@shardflux/sdk").components["schemas"]["TemplateDefaults"];
|
|
152
|
+
};
|
|
153
|
+
created_at: string;
|
|
154
|
+
}[];
|
|
155
|
+
versions_truncated: boolean;
|
|
156
|
+
};
|
|
157
|
+
export declare function summarizeOperation(o: Operation): {
|
|
158
|
+
error?: {
|
|
159
|
+
[key: string]: unknown;
|
|
160
|
+
} | undefined;
|
|
161
|
+
id: string;
|
|
162
|
+
kind: "open" | "suspend" | "resume" | "fork" | "snapshot" | "restore" | "delete" | "move" | "resize" | "volume_create" | "volume_attach" | "volume_detach" | "volume_delete" | "reset" | "layer_snapshot";
|
|
163
|
+
state: "capacity_pending" | "queued" | "running" | "succeeded" | "failed" | "canceled";
|
|
164
|
+
state_reason: string | null;
|
|
165
|
+
workspace_id: string | null;
|
|
166
|
+
created_at: string;
|
|
167
|
+
completed_at: string | null;
|
|
168
|
+
};
|
|
169
|
+
/**
|
|
170
|
+
* The SDK's LifecycleTiming, compact enough for model context: where an open, a wait or a wake spent its time. Phases
|
|
171
|
+
* are `phase(reason) ms` in order (`request(held)`: the server held the open; `capacity_pending(no_ready_host)`:
|
|
172
|
+
* waiting for a host); `server` is the operation's own queued/run/total time; `outside_server_ms` is the rest
|
|
173
|
+
* (network, polling, view and token).
|
|
174
|
+
*/
|
|
175
|
+
export declare function compactTiming(t: LifecycleTiming): {
|
|
176
|
+
total_ms: number;
|
|
177
|
+
phases: string[];
|
|
178
|
+
server: {
|
|
179
|
+
resume_path?: string | undefined;
|
|
180
|
+
warm_fallback?: string | undefined;
|
|
181
|
+
start_path?: string | undefined;
|
|
182
|
+
queued_ms: number | null;
|
|
183
|
+
run_ms: number | null;
|
|
184
|
+
total_ms: number | null;
|
|
185
|
+
} | null;
|
|
186
|
+
outside_server_ms: number | null;
|
|
187
|
+
retries: number;
|
|
188
|
+
operation_id?: string | undefined;
|
|
189
|
+
action: import("@shardflux/sdk").LifecycleAction;
|
|
190
|
+
outcome: import("@shardflux/sdk").TimingOutcome;
|
|
191
|
+
};
|
|
192
|
+
export declare function okResult(value: unknown): CallToolResult;
|
|
193
|
+
/** `timing` (optional): where the failed open/wait/wake spent its time, next to `error`. */
|
|
194
|
+
export declare function errorResult(info: ToolErrorInfo, timing?: ReturnType<typeof compactTiming>): CallToolResult;
|
|
195
|
+
export interface ServerOptions {
|
|
196
|
+
log?: Logger;
|
|
197
|
+
/** Replaces the HTTP client entirely (tests); default: the runtime fetch via makeFetch(env). */
|
|
198
|
+
fetch?: typeof fetch;
|
|
199
|
+
/** Process environment (SHARDFLUX_HTTP_KEEPALIVE). */
|
|
200
|
+
env?: Record<string, string | undefined>;
|
|
201
|
+
/** template_build reads local files only inside this directory (default: the process's working directory). */
|
|
202
|
+
cwd?: string;
|
|
203
|
+
}
|
|
204
|
+
export declare function createShardfluxMcpServer(config: McpConfig, opts?: ServerOptions): Server;
|