jetty-mcp-server 1.0.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 ADDED
@@ -0,0 +1,113 @@
1
+ # jetty-mcp-server
2
+
3
+ MCP server for the [Jetty](https://jetty.io) AI/ML workflow platform. Works with Claude Code, Cursor, Gemini CLI, Codex, and any MCP-compatible tool.
4
+
5
+ ## Quick Start
6
+
7
+ ```bash
8
+ npx -y jetty-mcp-server
9
+ ```
10
+
11
+ Set your API token:
12
+
13
+ ```bash
14
+ export JETTY_API_TOKEN="mlc_your_token_here"
15
+ ```
16
+
17
+ Get a token at [flows.jetty.io](https://flows.jetty.io) → Settings → API Tokens.
18
+
19
+ ## Environment Variables
20
+
21
+ | Variable | Required | Default | Description |
22
+ |----------|----------|---------|-------------|
23
+ | `JETTY_API_TOKEN` | Yes | — | Your Jetty API token (`mlc_...`) |
24
+ | `JETTY_DOCK_URL` | No | `https://dock.jetty.io` | Dock API base URL |
25
+ | `JETTY_FLOWS_URL` | No | `https://flows-api.jetty.io` | Flows API base URL |
26
+
27
+ ## Configuration
28
+
29
+ ### Claude Code
30
+
31
+ ```bash
32
+ claude mcp add jetty -- npx -y jetty-mcp-server
33
+ ```
34
+
35
+ Or add to `.mcp.json`:
36
+
37
+ ```json
38
+ {
39
+ "mcpServers": {
40
+ "jetty": {
41
+ "command": "npx",
42
+ "args": ["-y", "jetty-mcp-server"],
43
+ "env": { "JETTY_API_TOKEN": "mlc_your_token" }
44
+ }
45
+ }
46
+ }
47
+ ```
48
+
49
+ ### Cursor
50
+
51
+ Add to `.cursor/mcp.json`:
52
+
53
+ ```json
54
+ {
55
+ "mcpServers": {
56
+ "jetty": {
57
+ "command": "npx",
58
+ "args": ["-y", "jetty-mcp-server"],
59
+ "env": { "JETTY_API_TOKEN": "mlc_your_token" }
60
+ }
61
+ }
62
+ }
63
+ ```
64
+
65
+ ### Gemini CLI
66
+
67
+ ```bash
68
+ gemini extensions install jetty-extension.json
69
+ ```
70
+
71
+ ### Generic MCP Client
72
+
73
+ ```bash
74
+ JETTY_API_TOKEN=mlc_your_token npx -y jetty-mcp-server
75
+ ```
76
+
77
+ ## Tools
78
+
79
+ | Tool | Description |
80
+ |------|-------------|
81
+ | `list-collections` | List all collections |
82
+ | `get-collection` | Get collection details + env var keys |
83
+ | `list-tasks` | List tasks in a collection |
84
+ | `get-task` | Get task details + workflow definition |
85
+ | `create-task` | Create a task with a workflow |
86
+ | `update-task` | Update a task's workflow or description |
87
+ | `run-workflow` | Run a workflow asynchronously |
88
+ | `run-workflow-sync` | Run a workflow synchronously (blocks until done) |
89
+ | `list-trajectories` | List recent workflow runs |
90
+ | `get-trajectory` | Get full run details |
91
+ | `get-stats` | Get execution statistics |
92
+ | `add-label` | Label a trajectory (e.g., quality=high) |
93
+ | `list-step-templates` | List available step templates |
94
+ | `get-step-template` | Get template details and schema |
95
+
96
+ ## Development
97
+
98
+ ```bash
99
+ cd mcp-server
100
+ npm install
101
+ npm run build
102
+ JETTY_API_TOKEN=mlc_... node dist/index.js
103
+ ```
104
+
105
+ Test with [MCP Inspector](https://github.com/modelcontextprotocol/inspector):
106
+
107
+ ```bash
108
+ npx @modelcontextprotocol/inspector node dist/index.js
109
+ ```
110
+
111
+ ## License
112
+
113
+ MIT
@@ -0,0 +1,30 @@
1
+ export declare class JettyClient {
2
+ private token;
3
+ private dockUrl;
4
+ private flowsUrl;
5
+ constructor();
6
+ private request;
7
+ private dock;
8
+ private flows;
9
+ listCollections(): Promise<unknown>;
10
+ getCollection(collection: string): Promise<unknown>;
11
+ listTasks(collection: string): Promise<unknown>;
12
+ getTask(collection: string, task: string): Promise<unknown>;
13
+ createTask(collection: string, name: string, workflow: unknown, description?: string): Promise<unknown>;
14
+ updateTask(collection: string, task: string, updates: {
15
+ workflow?: unknown;
16
+ description?: string;
17
+ }): Promise<unknown>;
18
+ deleteTask(collection: string, task: string): Promise<unknown>;
19
+ runWorkflow(collection: string, task: string, initParams?: Record<string, unknown>): Promise<unknown>;
20
+ runWorkflowSync(collection: string, task: string, initParams?: Record<string, unknown>): Promise<unknown>;
21
+ listTrajectories(collection: string, task: string, limit?: number, page?: number): Promise<unknown>;
22
+ getTrajectory(collection: string, task: string, trajectoryId: string): Promise<unknown>;
23
+ getStats(collection: string, task: string): Promise<unknown>;
24
+ addLabel(collection: string, task: string, trajectoryId: string, key: string, value: string, author: string): Promise<unknown>;
25
+ getWorkflowLogs(workflowId: string): Promise<unknown>;
26
+ listStepTemplates(): Promise<unknown>;
27
+ getStepTemplate(name: string): Promise<unknown>;
28
+ setEnvironmentVars(collection: string, vars: Record<string, string>): Promise<unknown>;
29
+ }
30
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAGA,qBAAa,WAAW;IACtB,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,QAAQ,CAAS;;YAeX,OAAO;IAyBrB,OAAO,CAAC,IAAI;IAIZ,OAAO,CAAC,KAAK;IAKP,eAAe;IAIf,aAAa,CAAC,UAAU,EAAE,MAAM;IAKhC,SAAS,CAAC,UAAU,EAAE,MAAM;IAI5B,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;IAIxC,UAAU,CACd,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,OAAO,EACjB,WAAW,CAAC,EAAE,MAAM;IAShB,UAAU,CACd,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE;IASjD,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;IAO3C,WAAW,CACf,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,EACZ,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAYhC,eAAe,CACnB,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,EACZ,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAahC,gBAAgB,CACpB,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,EACZ,KAAK,SAAK,EACV,IAAI,SAAI;IAOJ,aAAa,CACjB,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,MAAM;IAQhB,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;IAKzC,QAAQ,CACZ,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,MAAM,EACpB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM;IAaV,eAAe,CAAC,UAAU,EAAE,MAAM;IAKlC,iBAAiB;IAIjB,eAAe,CAAC,IAAI,EAAE,MAAM;IAK5B,kBAAkB,CACtB,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;CAQ/B"}
package/dist/client.js ADDED
@@ -0,0 +1,131 @@
1
+ const DOCK_URL = process.env.JETTY_DOCK_URL || "https://dock.jetty.io";
2
+ const FLOWS_URL = process.env.JETTY_FLOWS_URL || "https://flows-api.jetty.io";
3
+ export class JettyClient {
4
+ token;
5
+ dockUrl;
6
+ flowsUrl;
7
+ constructor() {
8
+ const token = process.env.JETTY_API_TOKEN;
9
+ if (!token) {
10
+ throw new Error("JETTY_API_TOKEN environment variable is required. " +
11
+ "Get your token at https://flows.jetty.io → Settings → API Tokens");
12
+ }
13
+ this.token = token;
14
+ this.dockUrl = DOCK_URL;
15
+ this.flowsUrl = FLOWS_URL;
16
+ }
17
+ async request(baseUrl, path, options = {}) {
18
+ const url = `${baseUrl}${path}`;
19
+ const headers = {
20
+ Authorization: `Bearer ${this.token}`,
21
+ ...(options.headers || {}),
22
+ };
23
+ const res = await fetch(url, { ...options, headers });
24
+ if (!res.ok) {
25
+ const body = await res.text();
26
+ throw new Error(`Jetty API error ${res.status}: ${body}`);
27
+ }
28
+ const contentType = res.headers.get("content-type") || "";
29
+ if (contentType.includes("application/json")) {
30
+ return res.json();
31
+ }
32
+ return res.text();
33
+ }
34
+ dock(path, options) {
35
+ return this.request(this.dockUrl, path, options);
36
+ }
37
+ flows(path, options) {
38
+ return this.request(this.flowsUrl, path, options);
39
+ }
40
+ // Collections
41
+ async listCollections() {
42
+ return this.dock("/api/v1/collections/");
43
+ }
44
+ async getCollection(collection) {
45
+ return this.dock(`/api/v1/collections/${collection}`);
46
+ }
47
+ // Tasks
48
+ async listTasks(collection) {
49
+ return this.dock(`/api/v1/tasks/${collection}/`);
50
+ }
51
+ async getTask(collection, task) {
52
+ return this.dock(`/api/v1/tasks/${collection}/${task}`);
53
+ }
54
+ async createTask(collection, name, workflow, description) {
55
+ return this.dock(`/api/v1/tasks/${collection}`, {
56
+ method: "POST",
57
+ headers: { "Content-Type": "application/json" },
58
+ body: JSON.stringify({ name, description: description || "", workflow }),
59
+ });
60
+ }
61
+ async updateTask(collection, task, updates) {
62
+ return this.dock(`/api/v1/tasks/${collection}/${task}`, {
63
+ method: "PUT",
64
+ headers: { "Content-Type": "application/json" },
65
+ body: JSON.stringify(updates),
66
+ });
67
+ }
68
+ async deleteTask(collection, task) {
69
+ return this.dock(`/api/v1/tasks/${collection}/${task}`, {
70
+ method: "DELETE",
71
+ });
72
+ }
73
+ // Run workflows
74
+ async runWorkflow(collection, task, initParams) {
75
+ const formData = new FormData();
76
+ formData.append("bakery_host", this.dockUrl);
77
+ formData.append("init_params", JSON.stringify(initParams || {}));
78
+ return this.flows(`/api/v1/run/${collection}/${task}`, {
79
+ method: "POST",
80
+ body: formData,
81
+ });
82
+ }
83
+ async runWorkflowSync(collection, task, initParams) {
84
+ const formData = new FormData();
85
+ formData.append("bakery_host", this.dockUrl);
86
+ formData.append("init_params", JSON.stringify(initParams || {}));
87
+ return this.flows(`/api/v1/run-sync/${collection}/${task}`, {
88
+ method: "POST",
89
+ body: formData,
90
+ });
91
+ }
92
+ // Trajectories
93
+ async listTrajectories(collection, task, limit = 10, page = 1) {
94
+ return this.flows(`/api/v1/db/trajectories/${collection}/${task}?limit=${limit}&page=${page}`);
95
+ }
96
+ async getTrajectory(collection, task, trajectoryId) {
97
+ return this.flows(`/api/v1/db/trajectory/${collection}/${task}/${trajectoryId}`);
98
+ }
99
+ // Stats
100
+ async getStats(collection, task) {
101
+ return this.flows(`/api/v1/db/stats/${collection}/${task}`);
102
+ }
103
+ // Labels
104
+ async addLabel(collection, task, trajectoryId, key, value, author) {
105
+ return this.flows(`/api/v1/trajectory/${collection}/${task}/${trajectoryId}/labels`, {
106
+ method: "POST",
107
+ headers: { "Content-Type": "application/json" },
108
+ body: JSON.stringify({ key, value, author }),
109
+ });
110
+ }
111
+ // Workflow logs
112
+ async getWorkflowLogs(workflowId) {
113
+ return this.flows(`/api/v1/workflows-logs/${workflowId}`);
114
+ }
115
+ // Step templates
116
+ async listStepTemplates() {
117
+ return this.request(this.flowsUrl, "/api/v1/step-templates");
118
+ }
119
+ async getStepTemplate(name) {
120
+ return this.request(this.flowsUrl, `/api/v1/step-templates/${name}`);
121
+ }
122
+ // Environment variables
123
+ async setEnvironmentVars(collection, vars) {
124
+ return this.dock(`/api/v1/collections/${collection}/environment`, {
125
+ method: "PATCH",
126
+ headers: { "Content-Type": "application/json" },
127
+ body: JSON.stringify({ environment_variables: vars }),
128
+ });
129
+ }
130
+ }
131
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import { JettyClient } from "./client.js";
5
+ import { registerTools } from "./tools.js";
6
+ const server = new McpServer({
7
+ name: "jetty",
8
+ version: "1.0.0",
9
+ });
10
+ const client = new JettyClient();
11
+ registerTools(server, client);
12
+ const transport = new StdioServerTransport();
13
+ await server.connect(transport);
14
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3C,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;IAC3B,IAAI,EAAE,OAAO;IACb,OAAO,EAAE,OAAO;CACjB,CAAC,CAAC;AAEH,MAAM,MAAM,GAAG,IAAI,WAAW,EAAE,CAAC;AACjC,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAE9B,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;AAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { JettyClient } from "./client.js";
3
+ export declare function registerTools(server: McpServer, client: JettyClient): void;
4
+ //# sourceMappingURL=tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAQ1C,wBAAgB,aAAa,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,QAmNnE"}
package/dist/tools.js ADDED
@@ -0,0 +1,114 @@
1
+ import { z } from "zod";
2
+ function jsonResult(data) {
3
+ return {
4
+ content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
5
+ };
6
+ }
7
+ export function registerTools(server, client) {
8
+ // ── Collections ──────────────────────────────────────────────
9
+ server.tool("list-collections", "List all collections", {}, async () => {
10
+ return jsonResult(await client.listCollections());
11
+ });
12
+ server.tool("get-collection", "Get collection details including environment variable keys", { collection: z.string().describe("Collection name") }, async ({ collection }) => {
13
+ return jsonResult(await client.getCollection(collection));
14
+ });
15
+ // ── Tasks ────────────────────────────────────────────────────
16
+ server.tool("list-tasks", "List tasks in a collection", { collection: z.string().describe("Collection name") }, async ({ collection }) => {
17
+ return jsonResult(await client.listTasks(collection));
18
+ });
19
+ server.tool("get-task", "Get task details including workflow definition", {
20
+ collection: z.string().describe("Collection name"),
21
+ task: z.string().describe("Task name"),
22
+ }, async ({ collection, task }) => {
23
+ return jsonResult(await client.getTask(collection, task));
24
+ });
25
+ server.tool("create-task", "Create a new task with a workflow definition", {
26
+ collection: z.string().describe("Collection name"),
27
+ name: z.string().describe("Task name"),
28
+ description: z.string().optional().describe("Task description"),
29
+ workflow: z
30
+ .record(z.unknown())
31
+ .describe("Workflow JSON with init_params, step_configs, and steps"),
32
+ }, async ({ collection, name, description, workflow }) => {
33
+ return jsonResult(await client.createTask(collection, name, workflow, description));
34
+ });
35
+ server.tool("update-task", "Update a task's workflow or description", {
36
+ collection: z.string().describe("Collection name"),
37
+ task: z.string().describe("Task name"),
38
+ workflow: z
39
+ .record(z.unknown())
40
+ .optional()
41
+ .describe("Updated workflow JSON"),
42
+ description: z.string().optional().describe("Updated description"),
43
+ }, async ({ collection, task, workflow, description }) => {
44
+ const updates = {};
45
+ if (workflow)
46
+ updates.workflow = workflow;
47
+ if (description)
48
+ updates.description = description;
49
+ return jsonResult(await client.updateTask(collection, task, updates));
50
+ });
51
+ // ── Run Workflows ────────────────────────────────────────────
52
+ server.tool("run-workflow", "Run a workflow asynchronously (returns immediately with workflow_id)", {
53
+ collection: z.string().describe("Collection name"),
54
+ task: z.string().describe("Task name"),
55
+ init_params: z
56
+ .record(z.unknown())
57
+ .optional()
58
+ .describe("Input parameters for the workflow"),
59
+ }, async ({ collection, task, init_params }) => {
60
+ return jsonResult(await client.runWorkflow(collection, task, init_params));
61
+ });
62
+ server.tool("run-workflow-sync", "Run a workflow synchronously (blocks until completion, may take 30-60s)", {
63
+ collection: z.string().describe("Collection name"),
64
+ task: z.string().describe("Task name"),
65
+ init_params: z
66
+ .record(z.unknown())
67
+ .optional()
68
+ .describe("Input parameters for the workflow"),
69
+ }, async ({ collection, task, init_params }) => {
70
+ return jsonResult(await client.runWorkflowSync(collection, task, init_params));
71
+ });
72
+ // ── Trajectories ─────────────────────────────────────────────
73
+ server.tool("list-trajectories", "List recent workflow runs (trajectories) for a task", {
74
+ collection: z.string().describe("Collection name"),
75
+ task: z.string().describe("Task name"),
76
+ limit: z.number().optional().default(10).describe("Max results"),
77
+ page: z.number().optional().default(1).describe("Page number"),
78
+ }, async ({ collection, task, limit, page }) => {
79
+ return jsonResult(await client.listTrajectories(collection, task, limit, page));
80
+ });
81
+ server.tool("get-trajectory", "Get full details of a specific workflow run", {
82
+ collection: z.string().describe("Collection name"),
83
+ task: z.string().describe("Task name"),
84
+ trajectory_id: z.string().describe("Trajectory ID"),
85
+ }, async ({ collection, task, trajectory_id }) => {
86
+ return jsonResult(await client.getTrajectory(collection, task, trajectory_id));
87
+ });
88
+ // ── Stats ────────────────────────────────────────────────────
89
+ server.tool("get-stats", "Get execution statistics for a task", {
90
+ collection: z.string().describe("Collection name"),
91
+ task: z.string().describe("Task name"),
92
+ }, async ({ collection, task }) => {
93
+ return jsonResult(await client.getStats(collection, task));
94
+ });
95
+ // ── Labels ───────────────────────────────────────────────────
96
+ server.tool("add-label", "Add a label to a trajectory (e.g., quality=high)", {
97
+ collection: z.string().describe("Collection name"),
98
+ task: z.string().describe("Task name"),
99
+ trajectory_id: z.string().describe("Trajectory ID"),
100
+ key: z.string().describe("Label key (e.g., 'quality', 'status')"),
101
+ value: z.string().describe("Label value (e.g., 'high', 'approved')"),
102
+ author: z.string().describe("Author email"),
103
+ }, async ({ collection, task, trajectory_id, key, value, author }) => {
104
+ return jsonResult(await client.addLabel(collection, task, trajectory_id, key, value, author));
105
+ });
106
+ // ── Step Templates ───────────────────────────────────────────
107
+ server.tool("list-step-templates", "List all available workflow step templates", {}, async () => {
108
+ return jsonResult(await client.listStepTemplates());
109
+ });
110
+ server.tool("get-step-template", "Get details and schema for a step template", { name: z.string().describe("Step template activity name") }, async ({ name }) => {
111
+ return jsonResult(await client.getStepTemplate(name));
112
+ });
113
+ }
114
+ //# sourceMappingURL=tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.js","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,SAAS,UAAU,CAAC,IAAa;IAC/B,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;KAC1E,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,MAAiB,EAAE,MAAmB;IAClE,gEAAgE;IAEhE,MAAM,CAAC,IAAI,CAAC,kBAAkB,EAAE,sBAAsB,EAAE,EAAE,EAAE,KAAK,IAAI,EAAE;QACrE,OAAO,UAAU,CAAC,MAAM,MAAM,CAAC,eAAe,EAAE,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,IAAI,CACT,gBAAgB,EAChB,4DAA4D,EAC5D,EAAE,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,EACtD,KAAK,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE;QACvB,OAAO,UAAU,CAAC,MAAM,MAAM,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,CAAC;IAC5D,CAAC,CACF,CAAC;IAEF,gEAAgE;IAEhE,MAAM,CAAC,IAAI,CACT,YAAY,EACZ,4BAA4B,EAC5B,EAAE,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,EACtD,KAAK,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE;QACvB,OAAO,UAAU,CAAC,MAAM,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC;IACxD,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,UAAU,EACV,gDAAgD,EAChD;QACE,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,iBAAiB,CAAC;QAClD,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC;KACvC,EACD,KAAK,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,EAAE,EAAE;QAC7B,OAAO,UAAU,CAAC,MAAM,MAAM,CAAC,OAAO,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC,CAAC;IAC5D,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,aAAa,EACb,8CAA8C,EAC9C;QACE,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,iBAAiB,CAAC;QAClD,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC;QACtC,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,kBAAkB,CAAC;QAC/D,QAAQ,EAAE,CAAC;aACR,MAAM,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;aACnB,QAAQ,CACP,yDAAyD,CAC1D;KACJ,EACD,KAAK,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,EAAE,EAAE;QACpD,OAAO,UAAU,CACf,MAAM,MAAM,CAAC,UAAU,CAAC,UAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,CAAC,CACjE,CAAC;IACJ,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,aAAa,EACb,yCAAyC,EACzC;QACE,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,iBAAiB,CAAC;QAClD,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC;QACtC,QAAQ,EAAE,CAAC;aACR,MAAM,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;aACnB,QAAQ,EAAE;aACV,QAAQ,CAAC,uBAAuB,CAAC;QACpC,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,qBAAqB,CAAC;KACnE,EACD,KAAK,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,EAAE,EAAE;QACpD,MAAM,OAAO,GAAiD,EAAE,CAAC;QACjE,IAAI,QAAQ;YAAE,OAAO,CAAC,QAAQ,GAAG,QAAQ,CAAC;QAC1C,IAAI,WAAW;YAAE,OAAO,CAAC,WAAW,GAAG,WAAW,CAAC;QACnD,OAAO,UAAU,CAAC,MAAM,MAAM,CAAC,UAAU,CAAC,UAAU,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;IACxE,CAAC,CACF,CAAC;IAEF,gEAAgE;IAEhE,MAAM,CAAC,IAAI,CACT,cAAc,EACd,sEAAsE,EACtE;QACE,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,iBAAiB,CAAC;QAClD,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC;QACtC,WAAW,EAAE,CAAC;aACX,MAAM,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;aACnB,QAAQ,EAAE;aACV,QAAQ,CAAC,mCAAmC,CAAC;KACjD,EACD,KAAK,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,EAAE;QAC1C,OAAO,UAAU,CACf,MAAM,MAAM,CAAC,WAAW,CACtB,UAAU,EACV,IAAI,EACJ,WAAsC,CACvC,CACF,CAAC;IACJ,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,mBAAmB,EACnB,yEAAyE,EACzE;QACE,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,iBAAiB,CAAC;QAClD,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC;QACtC,WAAW,EAAE,CAAC;aACX,MAAM,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;aACnB,QAAQ,EAAE;aACV,QAAQ,CAAC,mCAAmC,CAAC;KACjD,EACD,KAAK,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,EAAE;QAC1C,OAAO,UAAU,CACf,MAAM,MAAM,CAAC,eAAe,CAC1B,UAAU,EACV,IAAI,EACJ,WAAsC,CACvC,CACF,CAAC;IACJ,CAAC,CACF,CAAC;IAEF,gEAAgE;IAEhE,MAAM,CAAC,IAAI,CACT,mBAAmB,EACnB,qDAAqD,EACrD;QACE,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,iBAAiB,CAAC;QAClD,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC;QACtC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC;QAChE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC;KAC/D,EACD,KAAK,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE;QAC1C,OAAO,UAAU,CACf,MAAM,MAAM,CAAC,gBAAgB,CAAC,UAAU,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,CAC7D,CAAC;IACJ,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,gBAAgB,EAChB,6CAA6C,EAC7C;QACE,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,iBAAiB,CAAC;QAClD,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC;QACtC,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,eAAe,CAAC;KACpD,EACD,KAAK,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,aAAa,EAAE,EAAE,EAAE;QAC5C,OAAO,UAAU,CACf,MAAM,MAAM,CAAC,aAAa,CAAC,UAAU,EAAE,IAAI,EAAE,aAAa,CAAC,CAC5D,CAAC;IACJ,CAAC,CACF,CAAC;IAEF,gEAAgE;IAEhE,MAAM,CAAC,IAAI,CACT,WAAW,EACX,qCAAqC,EACrC;QACE,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,iBAAiB,CAAC;QAClD,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC;KACvC,EACD,KAAK,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,EAAE,EAAE;QAC7B,OAAO,UAAU,CAAC,MAAM,MAAM,CAAC,QAAQ,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC,CAAC;IAC7D,CAAC,CACF,CAAC;IAEF,gEAAgE;IAEhE,MAAM,CAAC,IAAI,CACT,WAAW,EACX,kDAAkD,EAClD;QACE,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,iBAAiB,CAAC;QAClD,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC;QACtC,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,eAAe,CAAC;QACnD,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,uCAAuC,CAAC;QACjE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,wCAAwC,CAAC;QACpE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC;KAC5C,EACD,KAAK,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,aAAa,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE;QAChE,OAAO,UAAU,CACf,MAAM,MAAM,CAAC,QAAQ,CAAC,UAAU,EAAE,IAAI,EAAE,aAAa,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,CAAC,CAC3E,CAAC;IACJ,CAAC,CACF,CAAC;IAEF,gEAAgE;IAEhE,MAAM,CAAC,IAAI,CACT,qBAAqB,EACrB,4CAA4C,EAC5C,EAAE,EACF,KAAK,IAAI,EAAE;QACT,OAAO,UAAU,CAAC,MAAM,MAAM,CAAC,iBAAiB,EAAE,CAAC,CAAC;IACtD,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,mBAAmB,EACnB,4CAA4C,EAC5C,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,6BAA6B,CAAC,EAAE,EAC5D,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE;QACjB,OAAO,UAAU,CAAC,MAAM,MAAM,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC;IACxD,CAAC,CACF,CAAC;AACJ,CAAC"}
package/package.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "jetty-mcp-server",
3
+ "version": "1.0.0",
4
+ "description": "MCP server for Jetty AI/ML workflow platform",
5
+ "type": "module",
6
+ "bin": {
7
+ "jetty-mcp-server": "dist/index.js"
8
+ },
9
+ "main": "dist/index.js",
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "dev": "tsc --watch",
13
+ "start": "node dist/index.js",
14
+ "prepublishOnly": "npm run build"
15
+ },
16
+ "keywords": ["mcp", "jetty", "ai", "ml", "workflows"],
17
+ "license": "MIT",
18
+ "dependencies": {
19
+ "@modelcontextprotocol/sdk": "^1.12.1",
20
+ "zod": "^3.24.4"
21
+ },
22
+ "devDependencies": {
23
+ "@types/node": "^22.15.3",
24
+ "typescript": "^5.8.3"
25
+ },
26
+ "engines": {
27
+ "node": ">=18"
28
+ }
29
+ }
package/src/client.ts ADDED
@@ -0,0 +1,206 @@
1
+ const DOCK_URL = process.env.JETTY_DOCK_URL || "https://dock.jetty.io";
2
+ const FLOWS_URL = process.env.JETTY_FLOWS_URL || "https://flows-api.jetty.io";
3
+
4
+ export class JettyClient {
5
+ private token: string;
6
+ private dockUrl: string;
7
+ private flowsUrl: string;
8
+
9
+ constructor() {
10
+ const token = process.env.JETTY_API_TOKEN;
11
+ if (!token) {
12
+ throw new Error(
13
+ "JETTY_API_TOKEN environment variable is required. " +
14
+ "Get your token at https://flows.jetty.io → Settings → API Tokens"
15
+ );
16
+ }
17
+ this.token = token;
18
+ this.dockUrl = DOCK_URL;
19
+ this.flowsUrl = FLOWS_URL;
20
+ }
21
+
22
+ private async request(
23
+ baseUrl: string,
24
+ path: string,
25
+ options: RequestInit = {}
26
+ ): Promise<unknown> {
27
+ const url = `${baseUrl}${path}`;
28
+ const headers: Record<string, string> = {
29
+ Authorization: `Bearer ${this.token}`,
30
+ ...((options.headers as Record<string, string>) || {}),
31
+ };
32
+
33
+ const res = await fetch(url, { ...options, headers });
34
+
35
+ if (!res.ok) {
36
+ const body = await res.text();
37
+ throw new Error(`Jetty API error ${res.status}: ${body}`);
38
+ }
39
+
40
+ const contentType = res.headers.get("content-type") || "";
41
+ if (contentType.includes("application/json")) {
42
+ return res.json();
43
+ }
44
+ return res.text();
45
+ }
46
+
47
+ private dock(path: string, options?: RequestInit) {
48
+ return this.request(this.dockUrl, path, options);
49
+ }
50
+
51
+ private flows(path: string, options?: RequestInit) {
52
+ return this.request(this.flowsUrl, path, options);
53
+ }
54
+
55
+ // Collections
56
+ async listCollections() {
57
+ return this.dock("/api/v1/collections/");
58
+ }
59
+
60
+ async getCollection(collection: string) {
61
+ return this.dock(`/api/v1/collections/${collection}`);
62
+ }
63
+
64
+ // Tasks
65
+ async listTasks(collection: string) {
66
+ return this.dock(`/api/v1/tasks/${collection}/`);
67
+ }
68
+
69
+ async getTask(collection: string, task: string) {
70
+ return this.dock(`/api/v1/tasks/${collection}/${task}`);
71
+ }
72
+
73
+ async createTask(
74
+ collection: string,
75
+ name: string,
76
+ workflow: unknown,
77
+ description?: string
78
+ ) {
79
+ return this.dock(`/api/v1/tasks/${collection}`, {
80
+ method: "POST",
81
+ headers: { "Content-Type": "application/json" },
82
+ body: JSON.stringify({ name, description: description || "", workflow }),
83
+ });
84
+ }
85
+
86
+ async updateTask(
87
+ collection: string,
88
+ task: string,
89
+ updates: { workflow?: unknown; description?: string }
90
+ ) {
91
+ return this.dock(`/api/v1/tasks/${collection}/${task}`, {
92
+ method: "PUT",
93
+ headers: { "Content-Type": "application/json" },
94
+ body: JSON.stringify(updates),
95
+ });
96
+ }
97
+
98
+ async deleteTask(collection: string, task: string) {
99
+ return this.dock(`/api/v1/tasks/${collection}/${task}`, {
100
+ method: "DELETE",
101
+ });
102
+ }
103
+
104
+ // Run workflows
105
+ async runWorkflow(
106
+ collection: string,
107
+ task: string,
108
+ initParams?: Record<string, unknown>
109
+ ) {
110
+ const formData = new FormData();
111
+ formData.append("bakery_host", this.dockUrl);
112
+ formData.append("init_params", JSON.stringify(initParams || {}));
113
+
114
+ return this.flows(`/api/v1/run/${collection}/${task}`, {
115
+ method: "POST",
116
+ body: formData,
117
+ });
118
+ }
119
+
120
+ async runWorkflowSync(
121
+ collection: string,
122
+ task: string,
123
+ initParams?: Record<string, unknown>
124
+ ) {
125
+ const formData = new FormData();
126
+ formData.append("bakery_host", this.dockUrl);
127
+ formData.append("init_params", JSON.stringify(initParams || {}));
128
+
129
+ return this.flows(`/api/v1/run-sync/${collection}/${task}`, {
130
+ method: "POST",
131
+ body: formData,
132
+ });
133
+ }
134
+
135
+ // Trajectories
136
+ async listTrajectories(
137
+ collection: string,
138
+ task: string,
139
+ limit = 10,
140
+ page = 1
141
+ ) {
142
+ return this.flows(
143
+ `/api/v1/db/trajectories/${collection}/${task}?limit=${limit}&page=${page}`
144
+ );
145
+ }
146
+
147
+ async getTrajectory(
148
+ collection: string,
149
+ task: string,
150
+ trajectoryId: string
151
+ ) {
152
+ return this.flows(
153
+ `/api/v1/db/trajectory/${collection}/${task}/${trajectoryId}`
154
+ );
155
+ }
156
+
157
+ // Stats
158
+ async getStats(collection: string, task: string) {
159
+ return this.flows(`/api/v1/db/stats/${collection}/${task}`);
160
+ }
161
+
162
+ // Labels
163
+ async addLabel(
164
+ collection: string,
165
+ task: string,
166
+ trajectoryId: string,
167
+ key: string,
168
+ value: string,
169
+ author: string
170
+ ) {
171
+ return this.flows(
172
+ `/api/v1/trajectory/${collection}/${task}/${trajectoryId}/labels`,
173
+ {
174
+ method: "POST",
175
+ headers: { "Content-Type": "application/json" },
176
+ body: JSON.stringify({ key, value, author }),
177
+ }
178
+ );
179
+ }
180
+
181
+ // Workflow logs
182
+ async getWorkflowLogs(workflowId: string) {
183
+ return this.flows(`/api/v1/workflows-logs/${workflowId}`);
184
+ }
185
+
186
+ // Step templates
187
+ async listStepTemplates() {
188
+ return this.request(this.flowsUrl, "/api/v1/step-templates");
189
+ }
190
+
191
+ async getStepTemplate(name: string) {
192
+ return this.request(this.flowsUrl, `/api/v1/step-templates/${name}`);
193
+ }
194
+
195
+ // Environment variables
196
+ async setEnvironmentVars(
197
+ collection: string,
198
+ vars: Record<string, string>
199
+ ) {
200
+ return this.dock(`/api/v1/collections/${collection}/environment`, {
201
+ method: "PATCH",
202
+ headers: { "Content-Type": "application/json" },
203
+ body: JSON.stringify({ environment_variables: vars }),
204
+ });
205
+ }
206
+ }
package/src/index.ts ADDED
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
4
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
5
+ import { JettyClient } from "./client.js";
6
+ import { registerTools } from "./tools.js";
7
+
8
+ const server = new McpServer({
9
+ name: "jetty",
10
+ version: "1.0.0",
11
+ });
12
+
13
+ const client = new JettyClient();
14
+ registerTools(server, client);
15
+
16
+ const transport = new StdioServerTransport();
17
+ await server.connect(transport);
package/src/tools.ts ADDED
@@ -0,0 +1,222 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { z } from "zod";
3
+ import { JettyClient } from "./client.js";
4
+
5
+ function jsonResult(data: unknown) {
6
+ return {
7
+ content: [{ type: "text" as const, text: JSON.stringify(data, null, 2) }],
8
+ };
9
+ }
10
+
11
+ export function registerTools(server: McpServer, client: JettyClient) {
12
+ // ── Collections ──────────────────────────────────────────────
13
+
14
+ server.tool("list-collections", "List all collections", {}, async () => {
15
+ return jsonResult(await client.listCollections());
16
+ });
17
+
18
+ server.tool(
19
+ "get-collection",
20
+ "Get collection details including environment variable keys",
21
+ { collection: z.string().describe("Collection name") },
22
+ async ({ collection }) => {
23
+ return jsonResult(await client.getCollection(collection));
24
+ }
25
+ );
26
+
27
+ // ── Tasks ────────────────────────────────────────────────────
28
+
29
+ server.tool(
30
+ "list-tasks",
31
+ "List tasks in a collection",
32
+ { collection: z.string().describe("Collection name") },
33
+ async ({ collection }) => {
34
+ return jsonResult(await client.listTasks(collection));
35
+ }
36
+ );
37
+
38
+ server.tool(
39
+ "get-task",
40
+ "Get task details including workflow definition",
41
+ {
42
+ collection: z.string().describe("Collection name"),
43
+ task: z.string().describe("Task name"),
44
+ },
45
+ async ({ collection, task }) => {
46
+ return jsonResult(await client.getTask(collection, task));
47
+ }
48
+ );
49
+
50
+ server.tool(
51
+ "create-task",
52
+ "Create a new task with a workflow definition",
53
+ {
54
+ collection: z.string().describe("Collection name"),
55
+ name: z.string().describe("Task name"),
56
+ description: z.string().optional().describe("Task description"),
57
+ workflow: z
58
+ .record(z.unknown())
59
+ .describe(
60
+ "Workflow JSON with init_params, step_configs, and steps"
61
+ ),
62
+ },
63
+ async ({ collection, name, description, workflow }) => {
64
+ return jsonResult(
65
+ await client.createTask(collection, name, workflow, description)
66
+ );
67
+ }
68
+ );
69
+
70
+ server.tool(
71
+ "update-task",
72
+ "Update a task's workflow or description",
73
+ {
74
+ collection: z.string().describe("Collection name"),
75
+ task: z.string().describe("Task name"),
76
+ workflow: z
77
+ .record(z.unknown())
78
+ .optional()
79
+ .describe("Updated workflow JSON"),
80
+ description: z.string().optional().describe("Updated description"),
81
+ },
82
+ async ({ collection, task, workflow, description }) => {
83
+ const updates: { workflow?: unknown; description?: string } = {};
84
+ if (workflow) updates.workflow = workflow;
85
+ if (description) updates.description = description;
86
+ return jsonResult(await client.updateTask(collection, task, updates));
87
+ }
88
+ );
89
+
90
+ // ── Run Workflows ────────────────────────────────────────────
91
+
92
+ server.tool(
93
+ "run-workflow",
94
+ "Run a workflow asynchronously (returns immediately with workflow_id)",
95
+ {
96
+ collection: z.string().describe("Collection name"),
97
+ task: z.string().describe("Task name"),
98
+ init_params: z
99
+ .record(z.unknown())
100
+ .optional()
101
+ .describe("Input parameters for the workflow"),
102
+ },
103
+ async ({ collection, task, init_params }) => {
104
+ return jsonResult(
105
+ await client.runWorkflow(
106
+ collection,
107
+ task,
108
+ init_params as Record<string, unknown>
109
+ )
110
+ );
111
+ }
112
+ );
113
+
114
+ server.tool(
115
+ "run-workflow-sync",
116
+ "Run a workflow synchronously (blocks until completion, may take 30-60s)",
117
+ {
118
+ collection: z.string().describe("Collection name"),
119
+ task: z.string().describe("Task name"),
120
+ init_params: z
121
+ .record(z.unknown())
122
+ .optional()
123
+ .describe("Input parameters for the workflow"),
124
+ },
125
+ async ({ collection, task, init_params }) => {
126
+ return jsonResult(
127
+ await client.runWorkflowSync(
128
+ collection,
129
+ task,
130
+ init_params as Record<string, unknown>
131
+ )
132
+ );
133
+ }
134
+ );
135
+
136
+ // ── Trajectories ─────────────────────────────────────────────
137
+
138
+ server.tool(
139
+ "list-trajectories",
140
+ "List recent workflow runs (trajectories) for a task",
141
+ {
142
+ collection: z.string().describe("Collection name"),
143
+ task: z.string().describe("Task name"),
144
+ limit: z.number().optional().default(10).describe("Max results"),
145
+ page: z.number().optional().default(1).describe("Page number"),
146
+ },
147
+ async ({ collection, task, limit, page }) => {
148
+ return jsonResult(
149
+ await client.listTrajectories(collection, task, limit, page)
150
+ );
151
+ }
152
+ );
153
+
154
+ server.tool(
155
+ "get-trajectory",
156
+ "Get full details of a specific workflow run",
157
+ {
158
+ collection: z.string().describe("Collection name"),
159
+ task: z.string().describe("Task name"),
160
+ trajectory_id: z.string().describe("Trajectory ID"),
161
+ },
162
+ async ({ collection, task, trajectory_id }) => {
163
+ return jsonResult(
164
+ await client.getTrajectory(collection, task, trajectory_id)
165
+ );
166
+ }
167
+ );
168
+
169
+ // ── Stats ────────────────────────────────────────────────────
170
+
171
+ server.tool(
172
+ "get-stats",
173
+ "Get execution statistics for a task",
174
+ {
175
+ collection: z.string().describe("Collection name"),
176
+ task: z.string().describe("Task name"),
177
+ },
178
+ async ({ collection, task }) => {
179
+ return jsonResult(await client.getStats(collection, task));
180
+ }
181
+ );
182
+
183
+ // ── Labels ───────────────────────────────────────────────────
184
+
185
+ server.tool(
186
+ "add-label",
187
+ "Add a label to a trajectory (e.g., quality=high)",
188
+ {
189
+ collection: z.string().describe("Collection name"),
190
+ task: z.string().describe("Task name"),
191
+ trajectory_id: z.string().describe("Trajectory ID"),
192
+ key: z.string().describe("Label key (e.g., 'quality', 'status')"),
193
+ value: z.string().describe("Label value (e.g., 'high', 'approved')"),
194
+ author: z.string().describe("Author email"),
195
+ },
196
+ async ({ collection, task, trajectory_id, key, value, author }) => {
197
+ return jsonResult(
198
+ await client.addLabel(collection, task, trajectory_id, key, value, author)
199
+ );
200
+ }
201
+ );
202
+
203
+ // ── Step Templates ───────────────────────────────────────────
204
+
205
+ server.tool(
206
+ "list-step-templates",
207
+ "List all available workflow step templates",
208
+ {},
209
+ async () => {
210
+ return jsonResult(await client.listStepTemplates());
211
+ }
212
+ );
213
+
214
+ server.tool(
215
+ "get-step-template",
216
+ "Get details and schema for a step template",
217
+ { name: z.string().describe("Step template activity name") },
218
+ async ({ name }) => {
219
+ return jsonResult(await client.getStepTemplate(name));
220
+ }
221
+ );
222
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,18 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "Node16",
5
+ "moduleResolution": "Node16",
6
+ "outDir": "dist",
7
+ "rootDir": "src",
8
+ "strict": true,
9
+ "esModuleInterop": true,
10
+ "skipLibCheck": true,
11
+ "forceConsistentCasingInFileNames": true,
12
+ "declaration": true,
13
+ "declarationMap": true,
14
+ "sourceMap": true
15
+ },
16
+ "include": ["src"],
17
+ "exclude": ["node_modules", "dist"]
18
+ }