@walkeros/mcp 2.0.0 → 3.0.0-next-1773236214827
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/index.js +1529 -652
- package/dist/index.js.map +1 -1
- package/package.json +8 -9
- package/README.md +0 -221
package/dist/index.js
CHANGED
|
@@ -4,23 +4,17 @@
|
|
|
4
4
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5
5
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
6
|
|
|
7
|
-
// src/tools/
|
|
8
|
-
import {
|
|
9
|
-
import { bundle, bundleRemote } from "@walkeros/cli";
|
|
7
|
+
// src/tools/validate.ts
|
|
8
|
+
import { validate } from "@walkeros/cli";
|
|
10
9
|
import { schemas } from "@walkeros/cli/dev";
|
|
10
|
+
import { mcpResult, mcpError } from "@walkeros/core";
|
|
11
11
|
|
|
12
12
|
// src/schemas/output.ts
|
|
13
13
|
import { z } from "zod";
|
|
14
|
-
var timestamp = z.string().describe("ISO 8601 timestamp");
|
|
15
|
-
var projectId = z.string().describe("Project ID (proj_...)");
|
|
16
|
-
var flowId = z.string().describe("Flow ID (cfg_...)");
|
|
17
|
-
var ErrorOutputShape = {
|
|
18
|
-
error: z.string().describe("Error message")
|
|
19
|
-
};
|
|
20
14
|
var ValidateOutputShape = {
|
|
21
15
|
valid: z.boolean().describe("Whether validation passed"),
|
|
22
16
|
type: z.union([
|
|
23
|
-
z.enum(["event", "flow", "mapping"]),
|
|
17
|
+
z.enum(["contract", "event", "flow", "mapping"]),
|
|
24
18
|
z.string().regex(/^(destinations|sources|transformers)\.\w+$/)
|
|
25
19
|
]).describe("What was validated"),
|
|
26
20
|
errors: z.array(
|
|
@@ -55,12 +49,31 @@ var BundleOutputShape = {
|
|
|
55
49
|
};
|
|
56
50
|
var SimulateOutputShape = {
|
|
57
51
|
success: z.boolean().describe("Whether simulation succeeded"),
|
|
58
|
-
error: z.string().optional().describe("Error message if
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
52
|
+
error: z.string().optional().describe("Error message if failed"),
|
|
53
|
+
summary: z.string().describe("One-line result summary"),
|
|
54
|
+
destinations: z.record(
|
|
55
|
+
z.string(),
|
|
56
|
+
z.object({
|
|
57
|
+
received: z.boolean().describe("Whether destination received the event"),
|
|
58
|
+
calls: z.number().describe("Number of API calls made"),
|
|
59
|
+
payload: z.unknown().optional().describe("Transformed payload sent"),
|
|
60
|
+
errors: z.array(z.string()).optional().describe("Errors for this destination")
|
|
61
|
+
})
|
|
62
|
+
).optional().describe("Per-destination results"),
|
|
63
|
+
transformers: z.record(
|
|
64
|
+
z.string(),
|
|
65
|
+
z.object({
|
|
66
|
+
passed: z.boolean().describe("Whether event passed through"),
|
|
67
|
+
modified: z.boolean().describe("Whether event was modified")
|
|
68
|
+
})
|
|
69
|
+
).optional().describe("Per-transformer results"),
|
|
70
|
+
exampleMatch: z.object({
|
|
71
|
+
name: z.string(),
|
|
72
|
+
step: z.string(),
|
|
73
|
+
match: z.boolean(),
|
|
74
|
+
diff: z.string().optional()
|
|
75
|
+
}).optional().describe("Example comparison result when using example parameter"),
|
|
76
|
+
duration: z.number().optional().describe("Simulation duration in ms")
|
|
64
77
|
};
|
|
65
78
|
var PushOutputShape = {
|
|
66
79
|
success: z.boolean().describe("Whether push succeeded"),
|
|
@@ -68,102 +81,134 @@ var PushOutputShape = {
|
|
|
68
81
|
duration: z.number().describe("Push duration in milliseconds"),
|
|
69
82
|
error: z.string().optional().describe("Error message if push failed")
|
|
70
83
|
};
|
|
71
|
-
var
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
var flowFields = {
|
|
89
|
-
id: flowId,
|
|
90
|
-
name: z.string().describe("Flow name"),
|
|
91
|
-
content: z.record(z.string(), z.unknown()).describe("Flow.Setup JSON content"),
|
|
92
|
-
createdAt: timestamp,
|
|
93
|
-
updatedAt: timestamp,
|
|
94
|
-
deletedAt: z.string().nullable().optional().describe("Deletion timestamp if soft-deleted")
|
|
95
|
-
};
|
|
96
|
-
var FlowOutputShape = { ...flowFields };
|
|
97
|
-
var flowSummaryFields = {
|
|
98
|
-
id: flowId,
|
|
99
|
-
name: z.string().describe("Flow name"),
|
|
100
|
-
createdAt: timestamp,
|
|
101
|
-
updatedAt: timestamp,
|
|
102
|
-
deletedAt: z.string().nullable().describe("Deletion timestamp if soft-deleted")
|
|
103
|
-
};
|
|
104
|
-
var ListFlowsOutputShape = {
|
|
105
|
-
flows: z.array(z.object(flowSummaryFields)).describe("List of flow summaries"),
|
|
106
|
-
total: z.number().describe("Total number of flows")
|
|
84
|
+
var ExamplesListOutputShape = {
|
|
85
|
+
flow: z.string().describe("Flow name"),
|
|
86
|
+
count: z.number().describe("Number of examples found"),
|
|
87
|
+
examples: z.array(
|
|
88
|
+
z.object({
|
|
89
|
+
step: z.string().describe('Step location (e.g., "destination.gtag")'),
|
|
90
|
+
stepType: z.enum(["source", "transformer", "destination"]).describe("Step type"),
|
|
91
|
+
stepName: z.string().describe("Step name"),
|
|
92
|
+
exampleName: z.string().describe("Example name"),
|
|
93
|
+
hasIn: z.boolean().describe("Whether the example has an input value"),
|
|
94
|
+
hasOut: z.boolean().describe("Whether the example has an output value"),
|
|
95
|
+
hasMapping: z.boolean().describe("Whether the example has a mapping configuration"),
|
|
96
|
+
in: z.unknown().optional().describe("Input event data"),
|
|
97
|
+
out: z.unknown().optional().describe("Expected output data"),
|
|
98
|
+
mapping: z.unknown().optional().describe("Mapping configuration for destinations")
|
|
99
|
+
})
|
|
100
|
+
).describe("Step examples")
|
|
107
101
|
};
|
|
108
|
-
var
|
|
109
|
-
|
|
102
|
+
var PackageSearchOutputShape = {
|
|
103
|
+
package: z.string().describe("Package name"),
|
|
104
|
+
version: z.string().describe("Package version"),
|
|
105
|
+
description: z.string().optional().describe("Package description"),
|
|
106
|
+
type: z.string().optional().describe("Package type (destination, source, transformer)"),
|
|
107
|
+
platform: z.string().optional().describe("Target platform (web, server)"),
|
|
108
|
+
hintKeys: z.array(z.string()).describe("Available hint keys (use package_get section=hints to read)"),
|
|
109
|
+
exampleSummaries: z.array(
|
|
110
|
+
z.object({
|
|
111
|
+
name: z.string().describe("Example name"),
|
|
112
|
+
description: z.string().optional().describe("What this example shows")
|
|
113
|
+
})
|
|
114
|
+
).describe(
|
|
115
|
+
"Step example names and descriptions (use package_get section=examples to read full content)"
|
|
116
|
+
)
|
|
110
117
|
};
|
|
111
118
|
var PackageSchemaOutputShape = {
|
|
112
119
|
package: z.string().describe("Package name"),
|
|
113
120
|
version: z.string().describe("Package version"),
|
|
114
121
|
type: z.string().describe("Package type (destination, source, transformer)"),
|
|
115
122
|
platform: z.string().describe("Target platform (web, server)"),
|
|
116
|
-
schemas: z.record(z.string(), z.unknown()).describe("JSON Schemas for settings and mapping"),
|
|
117
|
-
examples: z.record(z.string(), z.unknown()).optional().describe(
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
123
|
+
schemas: z.record(z.string(), z.unknown()).optional().describe("JSON Schemas for settings and mapping"),
|
|
124
|
+
examples: z.record(z.string(), z.unknown()).optional().describe(
|
|
125
|
+
"Full configuration examples (included when section=examples or section=all)"
|
|
126
|
+
),
|
|
127
|
+
exampleSummaries: z.array(
|
|
128
|
+
z.object({
|
|
129
|
+
name: z.string().describe("Example name"),
|
|
130
|
+
description: z.string().optional().describe("What this example shows")
|
|
131
|
+
})
|
|
132
|
+
).optional().describe(
|
|
133
|
+
"Example names and descriptions (included in default/summary mode)"
|
|
134
|
+
),
|
|
135
|
+
hints: z.record(
|
|
136
|
+
z.string(),
|
|
137
|
+
z.object({
|
|
138
|
+
text: z.string(),
|
|
139
|
+
code: z.array(
|
|
140
|
+
z.object({
|
|
141
|
+
lang: z.string().optional(),
|
|
142
|
+
code: z.string()
|
|
143
|
+
})
|
|
144
|
+
).optional()
|
|
145
|
+
})
|
|
146
|
+
).optional().describe(
|
|
147
|
+
"Hints \u2014 text only in summary mode, with code blocks when section=hints or section=all"
|
|
148
|
+
)
|
|
124
149
|
};
|
|
125
150
|
|
|
126
|
-
// src/tools/
|
|
127
|
-
function
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
})
|
|
151
|
+
// src/tools/validate.ts
|
|
152
|
+
function registerFlowValidateTool(server2) {
|
|
153
|
+
server2.registerTool(
|
|
154
|
+
"flow_validate",
|
|
155
|
+
{
|
|
156
|
+
title: "Validate Flow",
|
|
157
|
+
description: "Validate walkerOS events, flow configurations, mapping rules, or data contracts. Accepts JSON strings, file paths, or URLs as input. Returns validation results with errors, warnings, and details.",
|
|
158
|
+
inputSchema: schemas.ValidateInputShape,
|
|
159
|
+
outputSchema: ValidateOutputShape,
|
|
160
|
+
annotations: {
|
|
161
|
+
readOnlyHint: true,
|
|
162
|
+
destructiveHint: false,
|
|
163
|
+
idempotentHint: true,
|
|
164
|
+
openWorldHint: false
|
|
141
165
|
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
166
|
+
},
|
|
167
|
+
async ({ type, input, flow, path }) => {
|
|
168
|
+
try {
|
|
169
|
+
const result = await validate(type, input, {
|
|
170
|
+
flow,
|
|
171
|
+
path
|
|
172
|
+
});
|
|
173
|
+
const summary = result.valid ? "Valid" : `Invalid: ${result.errors.length} errors, ${result.warnings.length} warnings`;
|
|
174
|
+
const hints = result.valid ? {
|
|
175
|
+
next: [
|
|
176
|
+
"Use flow_simulate to test event flow",
|
|
177
|
+
"Use flow_bundle to build"
|
|
178
|
+
]
|
|
179
|
+
} : { next: ["Fix errors above, then run flow_validate again"] };
|
|
180
|
+
return mcpResult(result, summary, hints);
|
|
181
|
+
} catch (error) {
|
|
182
|
+
return mcpError(error);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
);
|
|
145
186
|
}
|
|
146
187
|
|
|
147
188
|
// src/tools/bundle.ts
|
|
148
|
-
|
|
189
|
+
import { z as z2 } from "zod";
|
|
190
|
+
import { bundle, bundleRemote } from "@walkeros/cli";
|
|
191
|
+
import { schemas as schemas2 } from "@walkeros/cli/dev";
|
|
192
|
+
import { mcpResult as mcpResult2, mcpError as mcpError2 } from "@walkeros/core";
|
|
193
|
+
function registerFlowBundleTool(server2) {
|
|
149
194
|
server2.registerTool(
|
|
150
|
-
"
|
|
195
|
+
"flow_bundle",
|
|
151
196
|
{
|
|
152
|
-
title: "Bundle",
|
|
197
|
+
title: "Bundle Flow",
|
|
153
198
|
description: "Bundle a walkerOS flow configuration into deployable JavaScript. Resolves all destinations, sources, and transformers, then outputs a tree-shaken production bundle. Returns bundle statistics. Set remote: true to use the walkerOS cloud service instead of local build tools.",
|
|
154
199
|
inputSchema: {
|
|
155
|
-
...
|
|
200
|
+
...schemas2.BundleInputShape,
|
|
156
201
|
remote: z2.boolean().optional().describe(
|
|
157
202
|
"Use remote cloud bundling (requires WALKEROS_TOKEN). Default: false (local)"
|
|
158
203
|
),
|
|
159
|
-
content: z2.record(z2.string(), z2.unknown()).optional().describe("Flow.
|
|
204
|
+
content: z2.record(z2.string(), z2.unknown()).optional().describe("Flow.Config JSON content (required when remote: true)")
|
|
160
205
|
},
|
|
161
206
|
outputSchema: BundleOutputShape,
|
|
162
207
|
annotations: {
|
|
163
208
|
readOnlyHint: false,
|
|
164
209
|
destructiveHint: false,
|
|
165
|
-
idempotentHint:
|
|
166
|
-
openWorldHint:
|
|
210
|
+
idempotentHint: false,
|
|
211
|
+
openWorldHint: true
|
|
167
212
|
}
|
|
168
213
|
},
|
|
169
214
|
async ({ configPath, flow, stats, output, remote, content }) => {
|
|
@@ -175,7 +220,16 @@ function registerBundleTool(server2) {
|
|
|
175
220
|
content,
|
|
176
221
|
flowName: flow
|
|
177
222
|
});
|
|
178
|
-
|
|
223
|
+
const r = result2;
|
|
224
|
+
const size2 = r.totalSize ?? r.size;
|
|
225
|
+
const time2 = r.buildTime;
|
|
226
|
+
const summary2 = `Bundled${size2 ? ` (${formatBytes(size2)}` : ""}${time2 ? `, ${time2}ms)` : size2 ? ")" : ""}`;
|
|
227
|
+
return mcpResult2({ success: true, ...result2 }, summary2, {
|
|
228
|
+
next: [
|
|
229
|
+
"Use flow_simulate to test",
|
|
230
|
+
"Use api({ action: 'deploy' }) to publish"
|
|
231
|
+
]
|
|
232
|
+
});
|
|
179
233
|
}
|
|
180
234
|
const result = await bundle(configPath, {
|
|
181
235
|
flowName: flow,
|
|
@@ -186,43 +240,37 @@ function registerBundleTool(server2) {
|
|
|
186
240
|
success: true,
|
|
187
241
|
message: "Bundle created"
|
|
188
242
|
};
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
};
|
|
243
|
+
const size = output_.totalSize;
|
|
244
|
+
const time = output_.buildTime;
|
|
245
|
+
const summary = `Bundled${size ? ` (${formatBytes(size)}` : ""}${time ? `, ${time}ms)` : size ? ")" : ""}`;
|
|
246
|
+
return mcpResult2(output_, summary, {
|
|
247
|
+
next: [
|
|
248
|
+
"Use flow_simulate to test",
|
|
249
|
+
"Use api({ action: 'deploy' }) to publish"
|
|
250
|
+
]
|
|
251
|
+
});
|
|
198
252
|
} catch (error) {
|
|
199
|
-
return
|
|
200
|
-
content: [
|
|
201
|
-
{
|
|
202
|
-
type: "text",
|
|
203
|
-
text: JSON.stringify({
|
|
204
|
-
success: false,
|
|
205
|
-
error: error instanceof Error ? error.message : "Unknown error"
|
|
206
|
-
})
|
|
207
|
-
}
|
|
208
|
-
],
|
|
209
|
-
isError: true
|
|
210
|
-
};
|
|
253
|
+
return mcpError2(error, "Run flow_validate for detailed error messages");
|
|
211
254
|
}
|
|
212
255
|
}
|
|
213
256
|
);
|
|
214
257
|
}
|
|
258
|
+
function formatBytes(bytes) {
|
|
259
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
260
|
+
return `${(bytes / 1024).toFixed(1)} KB`;
|
|
261
|
+
}
|
|
215
262
|
|
|
216
263
|
// src/tools/simulate.ts
|
|
217
264
|
import { simulate } from "@walkeros/cli";
|
|
218
|
-
import { schemas as
|
|
219
|
-
|
|
265
|
+
import { schemas as schemas3 } from "@walkeros/cli/dev";
|
|
266
|
+
import { mcpResult as mcpResult3, mcpError as mcpError3 } from "@walkeros/core";
|
|
267
|
+
function registerFlowSimulateTool(server2) {
|
|
220
268
|
server2.registerTool(
|
|
221
|
-
"
|
|
269
|
+
"flow_simulate",
|
|
222
270
|
{
|
|
223
|
-
title: "Simulate",
|
|
224
|
-
description: "Simulate events through a walkerOS flow without making real API calls. Processes events through the full pipeline including transformers and destinations, returning
|
|
225
|
-
inputSchema:
|
|
271
|
+
title: "Simulate Flow",
|
|
272
|
+
description: "Simulate events through a walkerOS flow without making real API calls. Processes events through the full pipeline including transformers and destinations, returning summarized per-destination results. Use the example parameter to load event input from a step example and compare output.",
|
|
273
|
+
inputSchema: schemas3.SimulateInputShape,
|
|
226
274
|
outputSchema: SimulateOutputShape,
|
|
227
275
|
annotations: {
|
|
228
276
|
readOnlyHint: true,
|
|
@@ -231,42 +279,47 @@ function registerSimulateTool(server2) {
|
|
|
231
279
|
openWorldHint: false
|
|
232
280
|
}
|
|
233
281
|
},
|
|
234
|
-
async ({ configPath, event, flow, platform }) => {
|
|
282
|
+
async ({ configPath, event, flow, platform, example, step }) => {
|
|
235
283
|
try {
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
try {
|
|
239
|
-
parsedEvent = JSON.parse(event);
|
|
240
|
-
} catch {
|
|
241
|
-
}
|
|
284
|
+
if (!event && !example) {
|
|
285
|
+
throw new Error("Either event or example must be provided");
|
|
242
286
|
}
|
|
243
|
-
const
|
|
287
|
+
const raw = await simulate(configPath, event, {
|
|
244
288
|
json: true,
|
|
245
289
|
flow,
|
|
246
|
-
platform
|
|
290
|
+
platform,
|
|
291
|
+
example,
|
|
292
|
+
step
|
|
247
293
|
});
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
294
|
+
const destinations = {};
|
|
295
|
+
if (raw.usage) {
|
|
296
|
+
for (const [name, calls] of Object.entries(raw.usage)) {
|
|
297
|
+
destinations[name] = {
|
|
298
|
+
received: calls.length > 0,
|
|
299
|
+
calls: calls.length,
|
|
300
|
+
payload: calls.length > 0 ? calls[calls.length - 1] : void 0,
|
|
301
|
+
errors: []
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
const destCount = Object.keys(destinations).length;
|
|
306
|
+
const receivedCount = Object.values(destinations).filter(
|
|
307
|
+
(d) => d.received
|
|
308
|
+
).length;
|
|
309
|
+
const summary = `${receivedCount}/${destCount} destinations received the event`;
|
|
310
|
+
const result = {
|
|
311
|
+
success: raw.success,
|
|
312
|
+
error: raw.error,
|
|
313
|
+
summary,
|
|
314
|
+
destinations: destCount > 0 ? destinations : void 0,
|
|
315
|
+
exampleMatch: raw.exampleMatch,
|
|
316
|
+
duration: raw.duration
|
|
256
317
|
};
|
|
318
|
+
return mcpResult3(result, summary, {
|
|
319
|
+
next: ["Use flow_bundle to build for production"]
|
|
320
|
+
});
|
|
257
321
|
} catch (error) {
|
|
258
|
-
return
|
|
259
|
-
content: [
|
|
260
|
-
{
|
|
261
|
-
type: "text",
|
|
262
|
-
text: JSON.stringify({
|
|
263
|
-
success: false,
|
|
264
|
-
error: error instanceof Error ? error.message : "Unknown error"
|
|
265
|
-
})
|
|
266
|
-
}
|
|
267
|
-
],
|
|
268
|
-
isError: true
|
|
269
|
-
};
|
|
322
|
+
return mcpError3(error, "Run flow_validate for detailed error messages");
|
|
270
323
|
}
|
|
271
324
|
}
|
|
272
325
|
);
|
|
@@ -274,14 +327,15 @@ function registerSimulateTool(server2) {
|
|
|
274
327
|
|
|
275
328
|
// src/tools/push.ts
|
|
276
329
|
import { push } from "@walkeros/cli";
|
|
277
|
-
import { schemas as
|
|
278
|
-
|
|
330
|
+
import { schemas as schemas4 } from "@walkeros/cli/dev";
|
|
331
|
+
import { mcpResult as mcpResult4, mcpError as mcpError4 } from "@walkeros/core";
|
|
332
|
+
function registerFlowPushTool(server2) {
|
|
279
333
|
server2.registerTool(
|
|
280
|
-
"
|
|
334
|
+
"flow_push",
|
|
281
335
|
{
|
|
282
|
-
title: "Push",
|
|
283
|
-
description: "Push a real event through a walkerOS flow to actual destinations. WARNING: This makes real API calls to real endpoints.
|
|
284
|
-
inputSchema:
|
|
336
|
+
title: "Push Events",
|
|
337
|
+
description: "Push a real event through a walkerOS flow to actual destinations. WARNING: This makes real API calls to real endpoints. Note: Web destinations (gtag, meta, etc.) require browser globals that are not available in Node.js. For web flows, use flow_simulate to test. flow_push works best for server-side flows.",
|
|
338
|
+
inputSchema: schemas4.PushInputShape,
|
|
285
339
|
outputSchema: PushOutputShape,
|
|
286
340
|
annotations: {
|
|
287
341
|
readOnlyHint: false,
|
|
@@ -292,56 +346,39 @@ function registerPushTool(server2) {
|
|
|
292
346
|
},
|
|
293
347
|
async ({ configPath, event, flow, platform }) => {
|
|
294
348
|
try {
|
|
295
|
-
|
|
296
|
-
if (event.startsWith("{") || event.startsWith("[")) {
|
|
297
|
-
try {
|
|
298
|
-
parsedEvent = JSON.parse(event);
|
|
299
|
-
} catch {
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
const result = await push(configPath, parsedEvent, {
|
|
349
|
+
const result = await push(configPath, event, {
|
|
303
350
|
json: true,
|
|
304
351
|
flow,
|
|
305
352
|
platform
|
|
306
353
|
});
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
{
|
|
310
|
-
type: "text",
|
|
311
|
-
text: JSON.stringify(result, null, 2)
|
|
312
|
-
}
|
|
313
|
-
],
|
|
314
|
-
structuredContent: result
|
|
315
|
-
};
|
|
354
|
+
const summary = `Pushed event${result.duration ? ` (${result.duration}ms)` : ""}`;
|
|
355
|
+
return mcpResult4(result, summary);
|
|
316
356
|
} catch (error) {
|
|
317
|
-
return
|
|
318
|
-
content: [
|
|
319
|
-
{
|
|
320
|
-
type: "text",
|
|
321
|
-
text: JSON.stringify({
|
|
322
|
-
success: false,
|
|
323
|
-
error: error instanceof Error ? error.message : "Unknown error"
|
|
324
|
-
})
|
|
325
|
-
}
|
|
326
|
-
],
|
|
327
|
-
isError: true
|
|
328
|
-
};
|
|
357
|
+
return mcpError4(error);
|
|
329
358
|
}
|
|
330
359
|
}
|
|
331
360
|
);
|
|
332
361
|
}
|
|
333
362
|
|
|
334
|
-
// src/tools/
|
|
335
|
-
import {
|
|
336
|
-
import {
|
|
337
|
-
|
|
363
|
+
// src/tools/examples.ts
|
|
364
|
+
import { z as z3 } from "zod";
|
|
365
|
+
import { loadJsonConfig } from "@walkeros/cli";
|
|
366
|
+
import { mcpResult as mcpResult5, mcpError as mcpError5 } from "@walkeros/core";
|
|
367
|
+
function registerFlowExamplesTool(server2) {
|
|
338
368
|
server2.registerTool(
|
|
339
|
-
"
|
|
369
|
+
"flow_examples",
|
|
340
370
|
{
|
|
341
|
-
title: "
|
|
342
|
-
description: "
|
|
343
|
-
inputSchema:
|
|
344
|
-
|
|
371
|
+
title: "Flow Examples",
|
|
372
|
+
description: "List all step examples in a walkerOS flow configuration. Shows example names, step locations, and in/out shapes. Use this to discover available test fixtures and simulation data.",
|
|
373
|
+
inputSchema: {
|
|
374
|
+
configPath: z3.string().min(1).describe("Path to flow configuration file"),
|
|
375
|
+
flow: z3.string().optional().describe("Flow name for multi-flow configs"),
|
|
376
|
+
step: z3.string().optional().describe('Filter to a specific step (e.g., "destination.gtag")'),
|
|
377
|
+
full: z3.boolean().optional().describe(
|
|
378
|
+
"Return full in/out/mapping data for each example (default: false, returns metadata only)"
|
|
379
|
+
)
|
|
380
|
+
},
|
|
381
|
+
outputSchema: ExamplesListOutputShape,
|
|
345
382
|
annotations: {
|
|
346
383
|
readOnlyHint: true,
|
|
347
384
|
destructiveHint: false,
|
|
@@ -349,251 +386,341 @@ function registerValidateTool(server2) {
|
|
|
349
386
|
openWorldHint: false
|
|
350
387
|
}
|
|
351
388
|
},
|
|
352
|
-
async ({
|
|
389
|
+
async ({ configPath, flow, step, full }) => {
|
|
353
390
|
try {
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
391
|
+
const rawConfig = await loadJsonConfig(configPath);
|
|
392
|
+
const flowNames = Object.keys(rawConfig.flows || {});
|
|
393
|
+
const flowName = flow || (flowNames.length === 1 ? flowNames[0] : void 0);
|
|
394
|
+
if (!flowName) {
|
|
395
|
+
throw new Error(
|
|
396
|
+
`Multiple flows found. Specify flow parameter. Available: ${flowNames.join(", ")}`
|
|
397
|
+
);
|
|
360
398
|
}
|
|
361
|
-
const
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
399
|
+
const flowSettings = rawConfig.flows[flowName];
|
|
400
|
+
if (!flowSettings) {
|
|
401
|
+
throw new Error(`Flow "${flowName}" not found`);
|
|
402
|
+
}
|
|
403
|
+
const examples = [];
|
|
404
|
+
const stepTypes = [
|
|
405
|
+
{ key: "sources", type: "source" },
|
|
406
|
+
{ key: "transformers", type: "transformer" },
|
|
407
|
+
{ key: "destinations", type: "destination" }
|
|
408
|
+
];
|
|
409
|
+
for (const { key, type } of stepTypes) {
|
|
410
|
+
const refs = flowSettings[key] || {};
|
|
411
|
+
for (const [name, ref] of Object.entries(refs)) {
|
|
412
|
+
if (!ref.examples) continue;
|
|
413
|
+
if (step && `${type}.${name}` !== step) continue;
|
|
414
|
+
for (const [exName, ex] of Object.entries(
|
|
415
|
+
ref.examples
|
|
416
|
+
)) {
|
|
417
|
+
examples.push({
|
|
418
|
+
step: `${type}.${name}`,
|
|
419
|
+
stepType: type,
|
|
420
|
+
stepName: name,
|
|
421
|
+
exampleName: exName,
|
|
422
|
+
hasIn: ex.in !== void 0,
|
|
423
|
+
hasOut: ex.out !== void 0,
|
|
424
|
+
hasMapping: ex.mapping !== void 0,
|
|
425
|
+
...full ? { in: ex.in, out: ex.out, mapping: ex.mapping } : {}
|
|
426
|
+
});
|
|
367
427
|
}
|
|
368
|
-
|
|
369
|
-
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
const stepSet = new Set(examples.map((e) => e.step));
|
|
431
|
+
const result = {
|
|
432
|
+
flow: flowName,
|
|
433
|
+
count: examples.length,
|
|
434
|
+
examples
|
|
370
435
|
};
|
|
436
|
+
const summary = `${examples.length} examples across ${stepSet.size} steps`;
|
|
437
|
+
return mcpResult5(result, summary, {
|
|
438
|
+
next: ["Use flow_simulate with example parameter to test"]
|
|
439
|
+
});
|
|
371
440
|
} catch (error) {
|
|
372
|
-
return
|
|
373
|
-
content: [
|
|
374
|
-
{
|
|
375
|
-
type: "text",
|
|
376
|
-
text: JSON.stringify({
|
|
377
|
-
valid: false,
|
|
378
|
-
error: error instanceof Error ? error.message : "Unknown error"
|
|
379
|
-
})
|
|
380
|
-
}
|
|
381
|
-
],
|
|
382
|
-
isError: true
|
|
383
|
-
};
|
|
441
|
+
return mcpError5(error);
|
|
384
442
|
}
|
|
385
443
|
}
|
|
386
444
|
);
|
|
387
445
|
}
|
|
388
446
|
|
|
389
|
-
// src/tools/
|
|
390
|
-
import {
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
447
|
+
// src/tools/package.ts
|
|
448
|
+
import { z as z4 } from "zod";
|
|
449
|
+
import { fetchPackage, mcpResult as mcpResult6, mcpError as mcpError6 } from "@walkeros/core";
|
|
450
|
+
|
|
451
|
+
// src/registry.ts
|
|
452
|
+
var PACKAGE_REGISTRY = [
|
|
453
|
+
// Web Destinations
|
|
454
|
+
{
|
|
455
|
+
name: "@walkeros/web-destination-gtag",
|
|
456
|
+
type: "destination",
|
|
457
|
+
platform: "web",
|
|
458
|
+
description: "Google destination (GA4, Ads, GTM via gtag.js)"
|
|
459
|
+
},
|
|
460
|
+
{
|
|
461
|
+
name: "@walkeros/web-destination-meta",
|
|
462
|
+
type: "destination",
|
|
463
|
+
platform: "web",
|
|
464
|
+
description: "Meta (Facebook) Pixel"
|
|
465
|
+
},
|
|
466
|
+
{
|
|
467
|
+
name: "@walkeros/web-destination-plausible",
|
|
468
|
+
type: "destination",
|
|
469
|
+
platform: "web",
|
|
470
|
+
description: "Plausible Analytics"
|
|
471
|
+
},
|
|
472
|
+
{
|
|
473
|
+
name: "@walkeros/web-destination-snowplow",
|
|
474
|
+
type: "destination",
|
|
475
|
+
platform: "web",
|
|
476
|
+
description: "Snowplow Analytics"
|
|
477
|
+
},
|
|
478
|
+
{
|
|
479
|
+
name: "@walkeros/web-destination-piwikpro",
|
|
480
|
+
type: "destination",
|
|
481
|
+
platform: "web",
|
|
482
|
+
description: "Piwik PRO Analytics"
|
|
483
|
+
},
|
|
484
|
+
{
|
|
485
|
+
name: "@walkeros/web-destination-api",
|
|
486
|
+
type: "destination",
|
|
487
|
+
platform: "web",
|
|
488
|
+
description: "Generic HTTP API destination"
|
|
489
|
+
},
|
|
490
|
+
// Server Destinations
|
|
491
|
+
{
|
|
492
|
+
name: "@walkeros/server-destination-gcp",
|
|
493
|
+
type: "destination",
|
|
494
|
+
platform: "server",
|
|
495
|
+
description: "Google Cloud Platform (BigQuery)"
|
|
496
|
+
},
|
|
497
|
+
{
|
|
498
|
+
name: "@walkeros/server-destination-aws",
|
|
499
|
+
type: "destination",
|
|
500
|
+
platform: "server",
|
|
501
|
+
description: "AWS (Firehose)"
|
|
502
|
+
},
|
|
503
|
+
{
|
|
504
|
+
name: "@walkeros/server-destination-meta",
|
|
505
|
+
type: "destination",
|
|
506
|
+
platform: "server",
|
|
507
|
+
description: "Meta Conversions API (server-side)"
|
|
508
|
+
},
|
|
509
|
+
{
|
|
510
|
+
name: "@walkeros/server-destination-api",
|
|
511
|
+
type: "destination",
|
|
512
|
+
platform: "server",
|
|
513
|
+
description: "Generic HTTP API destination (server)"
|
|
514
|
+
},
|
|
515
|
+
{
|
|
516
|
+
name: "@walkeros/server-destination-datamanager",
|
|
517
|
+
type: "destination",
|
|
518
|
+
platform: "server",
|
|
519
|
+
description: "Google Data Manager"
|
|
520
|
+
},
|
|
521
|
+
// Web Sources
|
|
522
|
+
{
|
|
523
|
+
name: "@walkeros/web-source-browser",
|
|
524
|
+
type: "source",
|
|
525
|
+
platform: "web",
|
|
526
|
+
description: "Browser DOM event capture (clicks, page views, forms)"
|
|
527
|
+
},
|
|
528
|
+
{
|
|
529
|
+
name: "@walkeros/web-source-datalayer",
|
|
530
|
+
type: "source",
|
|
531
|
+
platform: "web",
|
|
532
|
+
description: "Google Tag Manager dataLayer bridge"
|
|
533
|
+
},
|
|
534
|
+
{
|
|
535
|
+
name: "@walkeros/web-source-session",
|
|
536
|
+
type: "source",
|
|
537
|
+
platform: "web",
|
|
538
|
+
description: "Session tracking source"
|
|
539
|
+
},
|
|
540
|
+
// CMP Sources
|
|
541
|
+
{
|
|
542
|
+
name: "@walkeros/web-source-cmp-cookiefirst",
|
|
543
|
+
type: "source",
|
|
544
|
+
platform: "web",
|
|
545
|
+
description: "CookieFirst consent management"
|
|
546
|
+
},
|
|
547
|
+
{
|
|
548
|
+
name: "@walkeros/web-source-cmp-cookiepro",
|
|
549
|
+
type: "source",
|
|
550
|
+
platform: "web",
|
|
551
|
+
description: "CookiePro/OneTrust consent management"
|
|
552
|
+
},
|
|
553
|
+
{
|
|
554
|
+
name: "@walkeros/web-source-cmp-usercentrics",
|
|
555
|
+
type: "source",
|
|
556
|
+
platform: "web",
|
|
557
|
+
description: "Usercentrics consent management"
|
|
558
|
+
},
|
|
559
|
+
// Server Sources
|
|
560
|
+
{
|
|
561
|
+
name: "@walkeros/server-source-express",
|
|
562
|
+
type: "source",
|
|
563
|
+
platform: "server",
|
|
564
|
+
description: "Express.js HTTP event endpoint"
|
|
565
|
+
},
|
|
566
|
+
{
|
|
567
|
+
name: "@walkeros/server-source-fetch",
|
|
568
|
+
type: "source",
|
|
569
|
+
platform: "server",
|
|
570
|
+
description: "Web Fetch API source (Cloudflare, Vercel Edge, Deno, Bun)"
|
|
571
|
+
},
|
|
572
|
+
{
|
|
573
|
+
name: "@walkeros/server-source-aws",
|
|
574
|
+
type: "source",
|
|
575
|
+
platform: "server",
|
|
576
|
+
description: "AWS sources (Lambda, API Gateway, Function URLs)"
|
|
577
|
+
},
|
|
578
|
+
{
|
|
579
|
+
name: "@walkeros/server-source-gcp",
|
|
580
|
+
type: "source",
|
|
581
|
+
platform: "server",
|
|
582
|
+
description: "GCP sources (Cloud Functions)"
|
|
583
|
+
},
|
|
584
|
+
// Transformers
|
|
585
|
+
{
|
|
586
|
+
name: "@walkeros/transformer-router",
|
|
587
|
+
type: "transformer",
|
|
588
|
+
platform: "universal",
|
|
589
|
+
description: "Route events to different destination subsets"
|
|
590
|
+
},
|
|
591
|
+
{
|
|
592
|
+
name: "@walkeros/transformer-validator",
|
|
593
|
+
type: "transformer",
|
|
594
|
+
platform: "universal",
|
|
595
|
+
description: "Event validation using JSON Schema"
|
|
596
|
+
},
|
|
597
|
+
{
|
|
598
|
+
name: "@walkeros/server-transformer-fingerprint",
|
|
599
|
+
type: "transformer",
|
|
600
|
+
platform: "server",
|
|
601
|
+
description: "Device fingerprinting for anonymous user identification"
|
|
602
|
+
},
|
|
603
|
+
{
|
|
604
|
+
name: "@walkeros/server-transformer-cache",
|
|
605
|
+
type: "transformer",
|
|
606
|
+
platform: "server",
|
|
607
|
+
description: "HTTP response caching with LRU eviction"
|
|
608
|
+
},
|
|
609
|
+
{
|
|
610
|
+
name: "@walkeros/server-transformer-file",
|
|
611
|
+
type: "transformer",
|
|
612
|
+
platform: "server",
|
|
613
|
+
description: "File serving transformer for static files"
|
|
614
|
+
},
|
|
615
|
+
// Stores
|
|
616
|
+
{
|
|
617
|
+
name: "@walkeros/store-memory",
|
|
618
|
+
type: "store",
|
|
619
|
+
platform: "universal",
|
|
620
|
+
description: "In-memory key-value store with LRU eviction and TTL"
|
|
621
|
+
},
|
|
622
|
+
{
|
|
623
|
+
name: "@walkeros/server-store-fs",
|
|
624
|
+
type: "store",
|
|
625
|
+
platform: "server",
|
|
626
|
+
description: "File system key-value store"
|
|
627
|
+
},
|
|
628
|
+
{
|
|
629
|
+
name: "@walkeros/server-store-s3",
|
|
630
|
+
type: "store",
|
|
631
|
+
platform: "server",
|
|
632
|
+
description: "AWS S3 key-value store"
|
|
633
|
+
},
|
|
634
|
+
{
|
|
635
|
+
name: "@walkeros/server-store-gcs",
|
|
636
|
+
type: "store",
|
|
637
|
+
platform: "server",
|
|
638
|
+
description: "Google Cloud Storage key-value store"
|
|
639
|
+
}
|
|
640
|
+
];
|
|
641
|
+
function filterRegistry(filters) {
|
|
642
|
+
let results = PACKAGE_REGISTRY;
|
|
643
|
+
if (filters?.type) {
|
|
644
|
+
results = results.filter((p) => p.type === filters.type);
|
|
645
|
+
}
|
|
646
|
+
if (filters?.platform) {
|
|
647
|
+
results = results.filter(
|
|
648
|
+
(p) => p.platform === filters.platform || p.platform === "universal"
|
|
649
|
+
);
|
|
650
|
+
}
|
|
651
|
+
return results;
|
|
414
652
|
}
|
|
415
653
|
|
|
416
|
-
// src/tools/
|
|
417
|
-
|
|
418
|
-
import {
|
|
419
|
-
listProjects,
|
|
420
|
-
getProject,
|
|
421
|
-
createProject,
|
|
422
|
-
updateProject,
|
|
423
|
-
deleteProject
|
|
424
|
-
} from "@walkeros/cli";
|
|
425
|
-
function registerProjectTools(server2) {
|
|
426
|
-
server2.registerTool(
|
|
427
|
-
"list-projects",
|
|
428
|
-
{
|
|
429
|
-
title: "List Projects",
|
|
430
|
-
description: "List all projects you have access to. Returns project IDs, names, and your role.",
|
|
431
|
-
inputSchema: {},
|
|
432
|
-
outputSchema: ListProjectsOutputShape,
|
|
433
|
-
annotations: {
|
|
434
|
-
readOnlyHint: true,
|
|
435
|
-
destructiveHint: false,
|
|
436
|
-
idempotentHint: true,
|
|
437
|
-
openWorldHint: true
|
|
438
|
-
}
|
|
439
|
-
},
|
|
440
|
-
async () => {
|
|
441
|
-
try {
|
|
442
|
-
return apiResult(await listProjects());
|
|
443
|
-
} catch (error) {
|
|
444
|
-
return apiError(error);
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
);
|
|
654
|
+
// src/tools/package.ts
|
|
655
|
+
function registerPackageSearchTool(server2) {
|
|
448
656
|
server2.registerTool(
|
|
449
|
-
"
|
|
657
|
+
"package_search",
|
|
450
658
|
{
|
|
451
|
-
title: "
|
|
452
|
-
description: "
|
|
659
|
+
title: "Search Package",
|
|
660
|
+
description: "Browse walkerOS packages or look up a specific one. Without package name: returns catalog filtered by type/platform. With package name: returns metadata, hint keys, and example summaries.",
|
|
453
661
|
inputSchema: {
|
|
454
|
-
|
|
662
|
+
package: z4.string().min(1).optional().describe(
|
|
663
|
+
"Exact npm package name for detailed lookup (e.g., @walkeros/web-destination-snowplow)"
|
|
664
|
+
),
|
|
665
|
+
type: z4.enum(["source", "destination", "transformer", "store"]).optional().describe("Filter by package type (browse mode)"),
|
|
666
|
+
platform: z4.enum(["web", "server"]).optional().describe(
|
|
667
|
+
"Filter by platform (browse mode, includes universal packages)"
|
|
668
|
+
),
|
|
669
|
+
version: z4.string().optional().describe("Package version for detailed lookup (default: latest)")
|
|
455
670
|
},
|
|
456
|
-
outputSchema:
|
|
671
|
+
outputSchema: PackageSearchOutputShape,
|
|
457
672
|
annotations: {
|
|
458
673
|
readOnlyHint: true,
|
|
459
674
|
destructiveHint: false,
|
|
460
675
|
idempotentHint: true,
|
|
461
|
-
openWorldHint:
|
|
462
|
-
}
|
|
463
|
-
},
|
|
464
|
-
async ({ projectId: projectId2 }) => {
|
|
465
|
-
try {
|
|
466
|
-
return apiResult(await getProject({ projectId: projectId2 }));
|
|
467
|
-
} catch (error) {
|
|
468
|
-
return apiError(error);
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
);
|
|
472
|
-
server2.registerTool(
|
|
473
|
-
"create-project",
|
|
474
|
-
{
|
|
475
|
-
title: "Create Project",
|
|
476
|
-
description: "Create a new project.",
|
|
477
|
-
inputSchema: {
|
|
478
|
-
name: z3.string().min(1).max(255).describe("Project name")
|
|
479
|
-
},
|
|
480
|
-
outputSchema: ProjectOutputShape,
|
|
481
|
-
annotations: {
|
|
482
|
-
readOnlyHint: false,
|
|
483
|
-
destructiveHint: false,
|
|
484
|
-
idempotentHint: false,
|
|
485
|
-
openWorldHint: true
|
|
486
|
-
}
|
|
487
|
-
},
|
|
488
|
-
async ({ name }) => {
|
|
489
|
-
try {
|
|
490
|
-
return apiResult(await createProject({ name }));
|
|
491
|
-
} catch (error) {
|
|
492
|
-
return apiError(error);
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
);
|
|
496
|
-
server2.registerTool(
|
|
497
|
-
"update-project",
|
|
498
|
-
{
|
|
499
|
-
title: "Update Project",
|
|
500
|
-
description: "Update a project name. Uses WALKEROS_PROJECT_ID if projectId is omitted.",
|
|
501
|
-
inputSchema: {
|
|
502
|
-
projectId: z3.string().optional().describe("Project ID (defaults to WALKEROS_PROJECT_ID)"),
|
|
503
|
-
name: z3.string().min(1).max(255).describe("New project name")
|
|
504
|
-
},
|
|
505
|
-
outputSchema: ProjectOutputShape,
|
|
506
|
-
annotations: {
|
|
507
|
-
readOnlyHint: false,
|
|
508
|
-
destructiveHint: false,
|
|
509
|
-
idempotentHint: false,
|
|
510
|
-
openWorldHint: true
|
|
676
|
+
openWorldHint: false
|
|
511
677
|
}
|
|
512
678
|
},
|
|
513
|
-
async ({
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
return
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
);
|
|
521
|
-
server2.registerTool(
|
|
522
|
-
"delete-project",
|
|
523
|
-
{
|
|
524
|
-
title: "Delete Project",
|
|
525
|
-
description: "Soft-delete a project and all its flows. WARNING: This deletes the project and ALL associated flows and data. Uses WALKEROS_PROJECT_ID if projectId is omitted.",
|
|
526
|
-
inputSchema: {
|
|
527
|
-
projectId: z3.string().optional().describe("Project ID (defaults to WALKEROS_PROJECT_ID)")
|
|
528
|
-
},
|
|
529
|
-
outputSchema: DeleteOutputShape,
|
|
530
|
-
annotations: {
|
|
531
|
-
readOnlyHint: false,
|
|
532
|
-
destructiveHint: true,
|
|
533
|
-
idempotentHint: false,
|
|
534
|
-
openWorldHint: true
|
|
679
|
+
async ({ package: packageName, type, platform, version }) => {
|
|
680
|
+
if (!packageName) {
|
|
681
|
+
const catalog = filterRegistry({ type, platform });
|
|
682
|
+
const summary = `${catalog.length} packages found`;
|
|
683
|
+
return mcpResult6(catalog, summary, {
|
|
684
|
+
next: ["Use package_get for schemas and examples"]
|
|
685
|
+
});
|
|
535
686
|
}
|
|
536
|
-
},
|
|
537
|
-
async ({ projectId: projectId2 }) => {
|
|
538
687
|
try {
|
|
539
|
-
|
|
688
|
+
const info = await fetchPackage(packageName, { version });
|
|
689
|
+
const result = {
|
|
690
|
+
package: info.packageName,
|
|
691
|
+
version: info.version,
|
|
692
|
+
description: info.description,
|
|
693
|
+
type: info.type,
|
|
694
|
+
platform: info.platform,
|
|
695
|
+
hintKeys: info.hintKeys,
|
|
696
|
+
exampleSummaries: info.exampleSummaries
|
|
697
|
+
};
|
|
698
|
+
const summary = `${info.packageName} v${info.version}`;
|
|
699
|
+
return mcpResult6(result, summary, {
|
|
700
|
+
next: ["Use package_get for schemas and examples"]
|
|
701
|
+
});
|
|
540
702
|
} catch (error) {
|
|
541
|
-
return
|
|
703
|
+
return mcpError6(error);
|
|
542
704
|
}
|
|
543
705
|
}
|
|
544
706
|
);
|
|
545
707
|
}
|
|
546
|
-
|
|
547
|
-
// src/tools/flows.ts
|
|
548
|
-
import { z as z4 } from "zod";
|
|
549
|
-
import {
|
|
550
|
-
listFlows,
|
|
551
|
-
getFlow,
|
|
552
|
-
createFlow,
|
|
553
|
-
updateFlow,
|
|
554
|
-
deleteFlow,
|
|
555
|
-
duplicateFlow
|
|
556
|
-
} from "@walkeros/cli";
|
|
557
|
-
function registerFlowTools(server2) {
|
|
558
|
-
server2.registerTool(
|
|
559
|
-
"list-flows",
|
|
560
|
-
{
|
|
561
|
-
title: "List Flows",
|
|
562
|
-
description: "List all flow configurations in a project.",
|
|
563
|
-
inputSchema: {
|
|
564
|
-
projectId: z4.string().optional().describe("Project ID (defaults to WALKEROS_PROJECT_ID)"),
|
|
565
|
-
sort: z4.enum(["name", "updated_at", "created_at"]).optional().describe("Sort field (default: updated_at)"),
|
|
566
|
-
order: z4.enum(["asc", "desc"]).optional().describe("Sort order (default: desc)"),
|
|
567
|
-
includeDeleted: z4.boolean().optional().describe("Include soft-deleted flows (default: false)")
|
|
568
|
-
},
|
|
569
|
-
outputSchema: ListFlowsOutputShape,
|
|
570
|
-
annotations: {
|
|
571
|
-
readOnlyHint: true,
|
|
572
|
-
destructiveHint: false,
|
|
573
|
-
idempotentHint: true,
|
|
574
|
-
openWorldHint: true
|
|
575
|
-
}
|
|
576
|
-
},
|
|
577
|
-
async ({ projectId: projectId2, sort, order, includeDeleted }) => {
|
|
578
|
-
try {
|
|
579
|
-
return apiResult(
|
|
580
|
-
await listFlows({ projectId: projectId2, sort, order, includeDeleted })
|
|
581
|
-
);
|
|
582
|
-
} catch (error) {
|
|
583
|
-
return apiError(error);
|
|
584
|
-
}
|
|
585
|
-
}
|
|
586
|
-
);
|
|
708
|
+
function registerGetPackageSchemaTool(server2) {
|
|
587
709
|
server2.registerTool(
|
|
588
|
-
"
|
|
710
|
+
"package_get",
|
|
589
711
|
{
|
|
590
|
-
title: "Get
|
|
591
|
-
description:
|
|
712
|
+
title: "Get Package",
|
|
713
|
+
description: 'Fetch walkerOS package details from npm. By default returns schemas + hint texts + example summaries (lightweight). Use section parameter to get full content: "hints" (with code blocks), "examples" (full in/out data), or "all" (everything). Use package_search first to browse available packages.',
|
|
592
714
|
inputSchema: {
|
|
593
|
-
|
|
594
|
-
|
|
715
|
+
package: z4.string().min(1).describe(
|
|
716
|
+
"Exact npm package name (e.g., @walkeros/web-destination-snowplow)"
|
|
717
|
+
),
|
|
718
|
+
version: z4.string().optional().describe("Package version (default: latest)"),
|
|
719
|
+
section: z4.enum(["hints", "examples", "all"]).optional().describe(
|
|
720
|
+
"Section to expand with full content. Default: summary view with schemas + hint texts + example descriptions"
|
|
721
|
+
)
|
|
595
722
|
},
|
|
596
|
-
outputSchema:
|
|
723
|
+
outputSchema: PackageSchemaOutputShape,
|
|
597
724
|
annotations: {
|
|
598
725
|
readOnlyHint: true,
|
|
599
726
|
destructiveHint: false,
|
|
@@ -601,166 +728,82 @@ function registerFlowTools(server2) {
|
|
|
601
728
|
openWorldHint: true
|
|
602
729
|
}
|
|
603
730
|
},
|
|
604
|
-
async ({
|
|
731
|
+
async ({ package: packageName, version, section }) => {
|
|
605
732
|
try {
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
return
|
|
635
|
-
}
|
|
636
|
-
}
|
|
637
|
-
);
|
|
638
|
-
server2.registerTool(
|
|
639
|
-
"update-flow",
|
|
640
|
-
{
|
|
641
|
-
title: "Update Flow",
|
|
642
|
-
description: "Update a flow configuration name and/or content.",
|
|
643
|
-
inputSchema: {
|
|
644
|
-
flowId: z4.string().describe("Flow ID (cfg_...)"),
|
|
645
|
-
name: z4.string().min(1).max(255).optional().describe("New flow name"),
|
|
646
|
-
content: z4.record(z4.string(), z4.unknown()).optional().describe("New Flow.Setup JSON content"),
|
|
647
|
-
projectId: z4.string().optional().describe("Project ID (defaults to WALKEROS_PROJECT_ID)")
|
|
648
|
-
},
|
|
649
|
-
outputSchema: FlowOutputShape,
|
|
650
|
-
annotations: {
|
|
651
|
-
readOnlyHint: false,
|
|
652
|
-
destructiveHint: false,
|
|
653
|
-
idempotentHint: false,
|
|
654
|
-
openWorldHint: true
|
|
655
|
-
}
|
|
656
|
-
},
|
|
657
|
-
async ({ flowId: flowId2, name, content, projectId: projectId2 }) => {
|
|
658
|
-
try {
|
|
659
|
-
return apiResult(
|
|
660
|
-
await updateFlow({ flowId: flowId2, name, content, projectId: projectId2 })
|
|
661
|
-
);
|
|
662
|
-
} catch (error) {
|
|
663
|
-
return apiError(error);
|
|
664
|
-
}
|
|
665
|
-
}
|
|
666
|
-
);
|
|
667
|
-
server2.registerTool(
|
|
668
|
-
"delete-flow",
|
|
669
|
-
{
|
|
670
|
-
title: "Delete Flow",
|
|
671
|
-
description: "Soft-delete a flow configuration. WARNING: This removes the flow configuration. Can be restored later. Requires flowId.",
|
|
672
|
-
inputSchema: {
|
|
673
|
-
flowId: z4.string().describe("Flow ID (cfg_...)"),
|
|
674
|
-
projectId: z4.string().optional().describe("Project ID (defaults to WALKEROS_PROJECT_ID)")
|
|
675
|
-
},
|
|
676
|
-
outputSchema: DeleteOutputShape,
|
|
677
|
-
annotations: {
|
|
678
|
-
readOnlyHint: false,
|
|
679
|
-
destructiveHint: true,
|
|
680
|
-
idempotentHint: false,
|
|
681
|
-
openWorldHint: true
|
|
682
|
-
}
|
|
683
|
-
},
|
|
684
|
-
async ({ flowId: flowId2, projectId: projectId2 }) => {
|
|
685
|
-
try {
|
|
686
|
-
return apiResult(await deleteFlow({ flowId: flowId2, projectId: projectId2 }));
|
|
687
|
-
} catch (error) {
|
|
688
|
-
return apiError(error);
|
|
689
|
-
}
|
|
690
|
-
}
|
|
691
|
-
);
|
|
692
|
-
server2.registerTool(
|
|
693
|
-
"duplicate-flow",
|
|
694
|
-
{
|
|
695
|
-
title: "Duplicate Flow",
|
|
696
|
-
description: "Create a copy of an existing flow configuration.",
|
|
697
|
-
inputSchema: {
|
|
698
|
-
flowId: z4.string().describe("Flow ID to duplicate (cfg_...)"),
|
|
699
|
-
name: z4.string().optional().describe('Name for the copy (defaults to "Copy of ...")'),
|
|
700
|
-
projectId: z4.string().optional().describe("Project ID (defaults to WALKEROS_PROJECT_ID)")
|
|
701
|
-
},
|
|
702
|
-
outputSchema: FlowOutputShape,
|
|
703
|
-
annotations: {
|
|
704
|
-
readOnlyHint: false,
|
|
705
|
-
destructiveHint: false,
|
|
706
|
-
idempotentHint: false,
|
|
707
|
-
openWorldHint: true
|
|
708
|
-
}
|
|
709
|
-
},
|
|
710
|
-
async ({ flowId: flowId2, name, projectId: projectId2 }) => {
|
|
711
|
-
try {
|
|
712
|
-
return apiResult(await duplicateFlow({ flowId: flowId2, name, projectId: projectId2 }));
|
|
733
|
+
const info = await fetchPackage(packageName, { version });
|
|
734
|
+
const result = {
|
|
735
|
+
package: info.packageName,
|
|
736
|
+
version: info.version,
|
|
737
|
+
type: info.type,
|
|
738
|
+
platform: info.platform,
|
|
739
|
+
schemas: info.schemas
|
|
740
|
+
};
|
|
741
|
+
if (info.hints) {
|
|
742
|
+
if (section === "hints" || section === "all") {
|
|
743
|
+
result.hints = info.hints;
|
|
744
|
+
} else {
|
|
745
|
+
const hintSummary = {};
|
|
746
|
+
for (const [key, hint] of Object.entries(info.hints)) {
|
|
747
|
+
const h = hint;
|
|
748
|
+
hintSummary[key] = { text: h.text };
|
|
749
|
+
}
|
|
750
|
+
result.hints = hintSummary;
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
if (section === "examples" || section === "all") {
|
|
754
|
+
result.examples = info.examples;
|
|
755
|
+
} else {
|
|
756
|
+
result.exampleSummaries = info.exampleSummaries;
|
|
757
|
+
}
|
|
758
|
+
const schemaCount = Object.keys(info.schemas).length;
|
|
759
|
+
const exampleCount = info.exampleSummaries.length;
|
|
760
|
+
const summary = `${info.packageName} \u2014 ${schemaCount} schemas, ${exampleCount} examples`;
|
|
761
|
+
return mcpResult6(result, summary);
|
|
713
762
|
} catch (error) {
|
|
714
|
-
return
|
|
763
|
+
return mcpError6(error);
|
|
715
764
|
}
|
|
716
765
|
}
|
|
717
766
|
);
|
|
718
767
|
}
|
|
719
768
|
|
|
720
|
-
// src/tools/
|
|
769
|
+
// src/tools/flow-load.ts
|
|
721
770
|
import { z as z5 } from "zod";
|
|
722
|
-
import {
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
wait: z5.boolean().optional().default(true).describe(
|
|
733
|
-
"Wait for deployment to complete (default: true). Set to false to return immediately after triggering."
|
|
734
|
-
),
|
|
735
|
-
flowName: z5.string().optional().describe(
|
|
736
|
-
"Flow name for multi-config flows. Required when a flow has multiple configs."
|
|
737
|
-
)
|
|
738
|
-
},
|
|
739
|
-
annotations: {
|
|
740
|
-
readOnlyHint: false,
|
|
741
|
-
destructiveHint: false,
|
|
742
|
-
idempotentHint: false,
|
|
743
|
-
openWorldHint: true
|
|
744
|
-
}
|
|
745
|
-
},
|
|
746
|
-
async ({ flowId: flowId2, projectId: projectId2, wait, flowName }) => {
|
|
747
|
-
try {
|
|
748
|
-
return apiResult(await deploy({ flowId: flowId2, projectId: projectId2, wait, flowName }));
|
|
749
|
-
} catch (error) {
|
|
750
|
-
return apiError(error);
|
|
751
|
-
}
|
|
771
|
+
import { loadJsonConfig as loadJsonConfig2 } from "@walkeros/cli";
|
|
772
|
+
import { mcpResult as mcpResult7, mcpError as mcpError7 } from "@walkeros/core";
|
|
773
|
+
var WEB_SKELETON = {
|
|
774
|
+
version: 1,
|
|
775
|
+
flows: {
|
|
776
|
+
default: {
|
|
777
|
+
web: {},
|
|
778
|
+
packages: {},
|
|
779
|
+
sources: {},
|
|
780
|
+
destinations: {}
|
|
752
781
|
}
|
|
753
|
-
|
|
782
|
+
}
|
|
783
|
+
};
|
|
784
|
+
var SERVER_SKELETON = {
|
|
785
|
+
version: 1,
|
|
786
|
+
flows: {
|
|
787
|
+
default: {
|
|
788
|
+
server: {},
|
|
789
|
+
packages: {},
|
|
790
|
+
sources: {},
|
|
791
|
+
destinations: {}
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
};
|
|
795
|
+
function registerFlowLoadTool(server2) {
|
|
754
796
|
server2.registerTool(
|
|
755
|
-
"
|
|
797
|
+
"flow_load",
|
|
756
798
|
{
|
|
757
|
-
title: "
|
|
758
|
-
description: "
|
|
799
|
+
title: "Load or Create Flow",
|
|
800
|
+
description: "Load an existing flow configuration from a local file path, URL, or walkerOS API (by flow ID). Or create a new empty flow by specifying a platform (web or server). Use the add-step prompt to add sources, destinations, transformers, or stores to the flow.",
|
|
759
801
|
inputSchema: {
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
802
|
+
source: z5.string().optional().describe(
|
|
803
|
+
"Flow source: local file path (./flow.json), URL (https://...), or API flow ID (cfg_...). Omit to create a new flow."
|
|
804
|
+
),
|
|
805
|
+
platform: z5.enum(["web", "server"]).optional().describe(
|
|
806
|
+
"Platform for new flows. Required when source is omitted. web = browser tracking, server = Node.js HTTP."
|
|
764
807
|
)
|
|
765
808
|
},
|
|
766
809
|
annotations: {
|
|
@@ -770,68 +813,341 @@ function registerDeployTools(server2) {
|
|
|
770
813
|
openWorldHint: true
|
|
771
814
|
}
|
|
772
815
|
},
|
|
773
|
-
async ({
|
|
816
|
+
async ({ source, platform }) => {
|
|
774
817
|
try {
|
|
775
|
-
|
|
818
|
+
if (source) {
|
|
819
|
+
const config = await loadJsonConfig2(source);
|
|
820
|
+
return mcpResult7(
|
|
821
|
+
config,
|
|
822
|
+
`Loaded flow from ${source}. Use flow_validate to check, or add-step prompt to modify.`,
|
|
823
|
+
{
|
|
824
|
+
next: [
|
|
825
|
+
"Use flow_validate to check",
|
|
826
|
+
"Use add-step prompt to modify"
|
|
827
|
+
]
|
|
828
|
+
}
|
|
829
|
+
);
|
|
830
|
+
}
|
|
831
|
+
if (!platform) {
|
|
832
|
+
return mcpError7(
|
|
833
|
+
new Error(
|
|
834
|
+
"Provide source (file path, URL, or flow ID) to load existing flow, or platform (web/server) to create a new one."
|
|
835
|
+
)
|
|
836
|
+
);
|
|
837
|
+
}
|
|
838
|
+
const skeleton = platform === "web" ? WEB_SKELETON : SERVER_SKELETON;
|
|
839
|
+
return mcpResult7(
|
|
840
|
+
skeleton,
|
|
841
|
+
`Created empty ${platform} flow. Use the add-step prompt to add sources, destinations, and transformers.`,
|
|
842
|
+
{ next: ["Use add-step prompt to add sources and destinations"] }
|
|
843
|
+
);
|
|
776
844
|
} catch (error) {
|
|
777
|
-
|
|
845
|
+
const msg = error instanceof Error ? error.message : "";
|
|
846
|
+
if (msg.includes("not found") || msg.includes("ENOENT"))
|
|
847
|
+
return mcpError7(
|
|
848
|
+
error,
|
|
849
|
+
"Check configPath \u2014 expected a flow.json file"
|
|
850
|
+
);
|
|
851
|
+
return mcpError7(error);
|
|
778
852
|
}
|
|
779
853
|
}
|
|
780
854
|
);
|
|
781
855
|
}
|
|
782
856
|
|
|
783
|
-
// src/tools/
|
|
857
|
+
// src/tools/api.ts
|
|
858
|
+
import { z as z7 } from "zod";
|
|
859
|
+
import {
|
|
860
|
+
whoami,
|
|
861
|
+
listProjects,
|
|
862
|
+
getProject,
|
|
863
|
+
createProject,
|
|
864
|
+
updateProject,
|
|
865
|
+
deleteProject,
|
|
866
|
+
listFlows,
|
|
867
|
+
getFlow,
|
|
868
|
+
createFlow,
|
|
869
|
+
updateFlow,
|
|
870
|
+
deleteFlow,
|
|
871
|
+
duplicateFlow,
|
|
872
|
+
deploy,
|
|
873
|
+
getDeployment,
|
|
874
|
+
listDeployments,
|
|
875
|
+
getDeploymentBySlug,
|
|
876
|
+
createDeployment as createDep,
|
|
877
|
+
deleteDeployment as deleteDep
|
|
878
|
+
} from "@walkeros/cli";
|
|
879
|
+
import { mcpResult as mcpResult8, mcpError as mcpError8 } from "@walkeros/core";
|
|
880
|
+
|
|
881
|
+
// src/schemas/api-output.ts
|
|
784
882
|
import { z as z6 } from "zod";
|
|
785
|
-
|
|
786
|
-
|
|
883
|
+
var ApiOutputShape = {
|
|
884
|
+
action: z6.string().describe("Action that was executed"),
|
|
885
|
+
ok: z6.boolean().describe("Whether the action succeeded"),
|
|
886
|
+
data: z6.unknown().describe("Action-specific result data")
|
|
887
|
+
};
|
|
888
|
+
|
|
889
|
+
// src/tools/api.ts
|
|
890
|
+
var ACTIONS = [
|
|
891
|
+
"whoami",
|
|
892
|
+
"project.list",
|
|
893
|
+
"project.get",
|
|
894
|
+
"project.create",
|
|
895
|
+
"project.update",
|
|
896
|
+
"project.delete",
|
|
897
|
+
"flow.list",
|
|
898
|
+
"flow.get",
|
|
899
|
+
"flow.create",
|
|
900
|
+
"flow.update",
|
|
901
|
+
"flow.delete",
|
|
902
|
+
"flow.duplicate",
|
|
903
|
+
"deploy",
|
|
904
|
+
"deployment.get",
|
|
905
|
+
"deployment.list",
|
|
906
|
+
"deployment.create",
|
|
907
|
+
"deployment.delete"
|
|
908
|
+
];
|
|
909
|
+
function registerApiTool(server2) {
|
|
787
910
|
server2.registerTool(
|
|
788
|
-
"
|
|
911
|
+
"api",
|
|
789
912
|
{
|
|
790
|
-
title: "
|
|
791
|
-
description: "
|
|
913
|
+
title: "walkerOS Cloud API",
|
|
914
|
+
description: "Manage walkerOS cloud projects, flows, and deployments. Requires WALKEROS_TOKEN env var.\n\nActions:\n- whoami \u2014 verify token, get user info\n- project.list/get/create/update/delete \u2014 manage projects\n- flow.list/get/create/update/delete/duplicate \u2014 manage flow configs\n- deploy \u2014 deploy a flow (auto-detects web/server)\n- deployment.get/list/create/delete \u2014 manage deployments\n\nParameters vary by action. id = flowId/projectId/slug depending on context. content = Flow.Config JSON for flow.create/update.",
|
|
792
915
|
inputSchema: {
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
),
|
|
796
|
-
|
|
916
|
+
action: z7.enum(ACTIONS).describe("API action to perform"),
|
|
917
|
+
id: z7.string().optional().describe("Resource ID (flowId, projectId, or deployment slug)"),
|
|
918
|
+
name: z7.string().optional().describe("Name for create/update operations"),
|
|
919
|
+
content: z7.record(z7.string(), z7.unknown()).optional().describe("Flow.Config JSON for flow operations"),
|
|
920
|
+
patch: z7.boolean().optional().describe("Use merge-patch for flow.update (default: true)"),
|
|
921
|
+
wait: z7.boolean().optional().describe("Wait for deploy to complete (default: true)"),
|
|
922
|
+
flowName: z7.string().optional().describe("Flow name for multi-settings flows"),
|
|
923
|
+
fields: z7.array(z7.string()).optional().describe("Dot-path field selectors for flow.get"),
|
|
924
|
+
type: z7.enum(["web", "server"]).optional().describe("Deployment type for deployment.create"),
|
|
925
|
+
sort: z7.string().optional().describe("Sort field for list operations"),
|
|
926
|
+
order: z7.enum(["asc", "desc"]).optional().describe("Sort order"),
|
|
927
|
+
status: z7.string().optional().describe("Status filter for deployment.list"),
|
|
928
|
+
includeDeleted: z7.boolean().optional().describe("Include deleted items in lists")
|
|
797
929
|
},
|
|
798
|
-
outputSchema:
|
|
930
|
+
outputSchema: ApiOutputShape,
|
|
799
931
|
annotations: {
|
|
800
|
-
readOnlyHint:
|
|
801
|
-
destructiveHint:
|
|
802
|
-
idempotentHint:
|
|
932
|
+
readOnlyHint: false,
|
|
933
|
+
destructiveHint: true,
|
|
934
|
+
idempotentHint: false,
|
|
803
935
|
openWorldHint: true
|
|
804
936
|
}
|
|
805
937
|
},
|
|
806
|
-
async (
|
|
938
|
+
async (params, extra) => {
|
|
939
|
+
const {
|
|
940
|
+
action,
|
|
941
|
+
id,
|
|
942
|
+
name,
|
|
943
|
+
content,
|
|
944
|
+
patch,
|
|
945
|
+
wait,
|
|
946
|
+
flowName,
|
|
947
|
+
fields,
|
|
948
|
+
type,
|
|
949
|
+
sort,
|
|
950
|
+
order,
|
|
951
|
+
status,
|
|
952
|
+
includeDeleted
|
|
953
|
+
} = params;
|
|
807
954
|
try {
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
955
|
+
let data;
|
|
956
|
+
let summary;
|
|
957
|
+
switch (action) {
|
|
958
|
+
// Auth
|
|
959
|
+
case "whoami": {
|
|
960
|
+
data = await whoami();
|
|
961
|
+
summary = `Authenticated as ${data.email}`;
|
|
962
|
+
break;
|
|
963
|
+
}
|
|
964
|
+
// Projects
|
|
965
|
+
case "project.list": {
|
|
966
|
+
data = await listProjects();
|
|
967
|
+
summary = `${(data.projects ?? []).length} projects`;
|
|
968
|
+
break;
|
|
969
|
+
}
|
|
970
|
+
case "project.get": {
|
|
971
|
+
data = await getProject({ projectId: id });
|
|
972
|
+
summary = `Project "${data.name}"`;
|
|
973
|
+
break;
|
|
974
|
+
}
|
|
975
|
+
case "project.create": {
|
|
976
|
+
if (!name) throw new Error("name required for project.create");
|
|
977
|
+
data = await createProject({ name });
|
|
978
|
+
summary = `Created project "${name}"`;
|
|
979
|
+
break;
|
|
980
|
+
}
|
|
981
|
+
case "project.update": {
|
|
982
|
+
if (!name) throw new Error("name required for project.update");
|
|
983
|
+
data = await updateProject({ projectId: id, name });
|
|
984
|
+
summary = `Updated project "${name}"`;
|
|
985
|
+
break;
|
|
986
|
+
}
|
|
987
|
+
case "project.delete": {
|
|
988
|
+
data = await deleteProject({ projectId: id });
|
|
989
|
+
summary = `Deleted project ${id ?? "default"}`;
|
|
990
|
+
break;
|
|
991
|
+
}
|
|
992
|
+
// Flows
|
|
993
|
+
case "flow.list": {
|
|
994
|
+
data = await listFlows({
|
|
995
|
+
projectId: id,
|
|
996
|
+
sort,
|
|
997
|
+
order,
|
|
998
|
+
includeDeleted
|
|
999
|
+
});
|
|
1000
|
+
summary = `${(data.flows ?? []).length} flows`;
|
|
1001
|
+
break;
|
|
1002
|
+
}
|
|
1003
|
+
case "flow.get": {
|
|
1004
|
+
if (!id) throw new Error("id required for flow.get");
|
|
1005
|
+
data = await getFlow({ flowId: id, fields });
|
|
1006
|
+
summary = `Flow "${data.name}" (${id})`;
|
|
1007
|
+
break;
|
|
1008
|
+
}
|
|
1009
|
+
case "flow.create": {
|
|
1010
|
+
if (!name) throw new Error("name required for flow.create");
|
|
1011
|
+
if (!content) throw new Error("content required for flow.create");
|
|
1012
|
+
data = await createFlow({ name, content });
|
|
1013
|
+
summary = `Created flow "${name}" (${data.id})`;
|
|
1014
|
+
break;
|
|
1015
|
+
}
|
|
1016
|
+
case "flow.update": {
|
|
1017
|
+
if (!id) throw new Error("id required for flow.update");
|
|
1018
|
+
data = await updateFlow({
|
|
1019
|
+
flowId: id,
|
|
1020
|
+
name,
|
|
1021
|
+
content,
|
|
1022
|
+
mergePatch: patch ?? true
|
|
1023
|
+
});
|
|
1024
|
+
summary = `Updated flow ${id}`;
|
|
1025
|
+
break;
|
|
1026
|
+
}
|
|
1027
|
+
case "flow.delete": {
|
|
1028
|
+
if (!id) throw new Error("id required for flow.delete");
|
|
1029
|
+
data = await deleteFlow({ flowId: id });
|
|
1030
|
+
summary = `Deleted flow ${id}`;
|
|
1031
|
+
break;
|
|
1032
|
+
}
|
|
1033
|
+
case "flow.duplicate": {
|
|
1034
|
+
if (!id) throw new Error("id required for flow.duplicate");
|
|
1035
|
+
data = await duplicateFlow({ flowId: id, name });
|
|
1036
|
+
summary = `Duplicated flow ${id}`;
|
|
1037
|
+
break;
|
|
1038
|
+
}
|
|
1039
|
+
// Deploy
|
|
1040
|
+
case "deploy": {
|
|
1041
|
+
if (!id) throw new Error("id (flowId) required for deploy");
|
|
1042
|
+
const progressToken = extra._meta?.progressToken;
|
|
1043
|
+
data = await deploy({
|
|
1044
|
+
flowId: id,
|
|
1045
|
+
wait: wait ?? true,
|
|
1046
|
+
flowName,
|
|
1047
|
+
onStatus: (s, sub) => {
|
|
1048
|
+
if (!progressToken) return;
|
|
1049
|
+
const stages = {
|
|
1050
|
+
bundling: 15,
|
|
1051
|
+
deploying: 55,
|
|
1052
|
+
published: 100,
|
|
1053
|
+
active: 100,
|
|
1054
|
+
failed: 100
|
|
1055
|
+
};
|
|
1056
|
+
extra.sendNotification({
|
|
1057
|
+
method: "notifications/progress",
|
|
1058
|
+
params: {
|
|
1059
|
+
progressToken,
|
|
1060
|
+
progress: stages[s] ?? 0,
|
|
1061
|
+
total: 100,
|
|
1062
|
+
message: sub ? `${s}:${sub}` : s
|
|
1063
|
+
}
|
|
1064
|
+
});
|
|
1065
|
+
},
|
|
1066
|
+
signal: extra.signal
|
|
1067
|
+
});
|
|
1068
|
+
const st = data.status;
|
|
1069
|
+
const deployData = data;
|
|
1070
|
+
if (st === "failed") {
|
|
1071
|
+
summary = `Deploy failed: ${deployData.errorMessage ?? "unknown error"}`;
|
|
1072
|
+
} else {
|
|
1073
|
+
summary = `Deployed flow ${id} \u2014 status: ${st}`;
|
|
1074
|
+
const publicUrl = deployData.publicUrl;
|
|
1075
|
+
const containerUrl = deployData.containerUrl;
|
|
1076
|
+
const deployType = deployData.type;
|
|
1077
|
+
const nextHints = [];
|
|
1078
|
+
if (deployType === "web" && publicUrl) {
|
|
1079
|
+
nextHints.push(`Bundle at ${publicUrl}`);
|
|
1080
|
+
nextHints.push(`Add <script src='${publicUrl}'></script>`);
|
|
1081
|
+
} else if (deployType === "server" && containerUrl) {
|
|
1082
|
+
nextHints.push(`Container at ${containerUrl}`);
|
|
1083
|
+
nextHints.push(`Test: curl ${containerUrl}/health`);
|
|
1084
|
+
}
|
|
1085
|
+
if (nextHints.length > 0) {
|
|
1086
|
+
return mcpResult8({ action, ok: true, data }, summary, {
|
|
1087
|
+
next: nextHints
|
|
1088
|
+
});
|
|
1089
|
+
}
|
|
831
1090
|
}
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
1091
|
+
break;
|
|
1092
|
+
}
|
|
1093
|
+
// Deployments
|
|
1094
|
+
case "deployment.get": {
|
|
1095
|
+
if (!id)
|
|
1096
|
+
throw new Error(
|
|
1097
|
+
"id (flowId or slug) required for deployment.get"
|
|
1098
|
+
);
|
|
1099
|
+
try {
|
|
1100
|
+
data = await getDeployment({ flowId: id, flowName });
|
|
1101
|
+
} catch {
|
|
1102
|
+
data = await getDeploymentBySlug({ slug: id });
|
|
1103
|
+
}
|
|
1104
|
+
summary = `Deployment ${data.slug ?? id} \u2014 ${data.status}`;
|
|
1105
|
+
break;
|
|
1106
|
+
}
|
|
1107
|
+
case "deployment.list": {
|
|
1108
|
+
data = await listDeployments({
|
|
1109
|
+
projectId: id,
|
|
1110
|
+
type,
|
|
1111
|
+
status
|
|
1112
|
+
});
|
|
1113
|
+
summary = `${(data.deployments ?? []).length} deployments`;
|
|
1114
|
+
break;
|
|
1115
|
+
}
|
|
1116
|
+
case "deployment.create": {
|
|
1117
|
+
if (!type)
|
|
1118
|
+
throw new Error(
|
|
1119
|
+
"type (web/server) required for deployment.create"
|
|
1120
|
+
);
|
|
1121
|
+
data = await createDep({ type, label: name, projectId: id });
|
|
1122
|
+
summary = `Created ${type} deployment ${data.slug}`;
|
|
1123
|
+
break;
|
|
1124
|
+
}
|
|
1125
|
+
case "deployment.delete": {
|
|
1126
|
+
if (!id)
|
|
1127
|
+
throw new Error("id (slug) required for deployment.delete");
|
|
1128
|
+
data = await deleteDep({ slug: id });
|
|
1129
|
+
summary = `Deleted deployment ${id}`;
|
|
1130
|
+
break;
|
|
1131
|
+
}
|
|
1132
|
+
default:
|
|
1133
|
+
throw new Error(
|
|
1134
|
+
`Unknown action: ${action}. Use one of: ${ACTIONS.join(", ")}`
|
|
1135
|
+
);
|
|
1136
|
+
}
|
|
1137
|
+
return mcpResult8({ action, ok: true, data }, summary);
|
|
1138
|
+
} catch (error) {
|
|
1139
|
+
const msg = error instanceof Error ? error.message : "";
|
|
1140
|
+
if (msg.includes("401") || msg.includes("403") || msg.includes("Unauthorized"))
|
|
1141
|
+
return mcpError8(
|
|
1142
|
+
error,
|
|
1143
|
+
"Set WALKEROS_TOKEN env var or check token expiry"
|
|
1144
|
+
);
|
|
1145
|
+
if (msg.includes("required"))
|
|
1146
|
+
return mcpError8(
|
|
1147
|
+
error,
|
|
1148
|
+
`See api tool description for ${action} parameters.`
|
|
1149
|
+
);
|
|
1150
|
+
return mcpError8(error);
|
|
835
1151
|
}
|
|
836
1152
|
}
|
|
837
1153
|
);
|
|
@@ -839,25 +1155,14 @@ function registerGetPackageSchemaTool(server2) {
|
|
|
839
1155
|
|
|
840
1156
|
// src/resources/package-schemas.ts
|
|
841
1157
|
import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
842
|
-
import { fetchPackageSchema
|
|
843
|
-
var KNOWN_PACKAGES = [
|
|
844
|
-
"@walkeros/web-destination-google-ga4",
|
|
845
|
-
"@walkeros/web-destination-meta-pixel",
|
|
846
|
-
"@walkeros/web-destination-plausible",
|
|
847
|
-
"@walkeros/web-destination-snowplow",
|
|
848
|
-
"@walkeros/web-destination-piwikpro",
|
|
849
|
-
"@walkeros/web-destination-etag",
|
|
850
|
-
"@walkeros/web-destination-bigquery",
|
|
851
|
-
"@walkeros/web-source-walker",
|
|
852
|
-
"@walkeros/web-source-datalayer"
|
|
853
|
-
];
|
|
1158
|
+
import { fetchPackageSchema } from "@walkeros/core";
|
|
854
1159
|
function registerPackageSchemaResources(server2) {
|
|
855
1160
|
const template = new ResourceTemplate("walkeros://schema/{packageName}", {
|
|
856
1161
|
list: async () => ({
|
|
857
|
-
resources:
|
|
858
|
-
uri: `walkeros://schema/${encodeURIComponent(pkg)}`,
|
|
859
|
-
name: pkg,
|
|
860
|
-
description: `Schema and examples for ${pkg}`,
|
|
1162
|
+
resources: PACKAGE_REGISTRY.map((pkg) => ({
|
|
1163
|
+
uri: `walkeros://schema/${encodeURIComponent(pkg.name)}`,
|
|
1164
|
+
name: pkg.name,
|
|
1165
|
+
description: `Schema and examples for ${pkg.name}`,
|
|
861
1166
|
mimeType: "application/json"
|
|
862
1167
|
}))
|
|
863
1168
|
})
|
|
@@ -871,7 +1176,7 @@ function registerPackageSchemaResources(server2) {
|
|
|
871
1176
|
mimeType: "application/json"
|
|
872
1177
|
},
|
|
873
1178
|
async (uri, { packageName }) => {
|
|
874
|
-
const info = await
|
|
1179
|
+
const info = await fetchPackageSchema(
|
|
875
1180
|
decodeURIComponent(packageName)
|
|
876
1181
|
);
|
|
877
1182
|
return {
|
|
@@ -887,72 +1192,644 @@ function registerPackageSchemaResources(server2) {
|
|
|
887
1192
|
);
|
|
888
1193
|
}
|
|
889
1194
|
|
|
890
|
-
// src/resources/
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
1195
|
+
// src/resources/references.ts
|
|
1196
|
+
var FLOW_SCHEMA_REFERENCE = {
|
|
1197
|
+
structure: {
|
|
1198
|
+
version: "1 (required, use 1 for new flows)",
|
|
1199
|
+
flows: {
|
|
1200
|
+
"<flowName>": {
|
|
1201
|
+
"web: {} | server: {}": "Platform marker (exactly one, use empty object as value)",
|
|
1202
|
+
packages: "Record<packageName, {} | { path?, imports? }> \u2014 all referenced packages",
|
|
1203
|
+
sources: "Record<name, { package, config?, env?, next? }> \u2014 event capture",
|
|
1204
|
+
destinations: "Record<name, { package, config?, env?, mapping?, before? }> \u2014 event delivery",
|
|
1205
|
+
transformers: "Record<name, { package, config?, env?, next? }> \u2014 event processing",
|
|
1206
|
+
stores: "Record<name, { package, config?, env? }> \u2014 key-value storage",
|
|
1207
|
+
collector: "{ consent?, globals? } \u2014 collector settings (optional)"
|
|
1208
|
+
}
|
|
1209
|
+
},
|
|
1210
|
+
variables: "Record<string, string> \u2014 shared variables (optional)",
|
|
1211
|
+
definitions: "Record<string, object> \u2014 reusable definitions (optional)",
|
|
1212
|
+
contract: "Event contract for validation (optional)"
|
|
1213
|
+
},
|
|
1214
|
+
connectionRules: [
|
|
1215
|
+
'Sources have `next` \u2192 links to pre-collector transformer chain (e.g., next: "transformerName")',
|
|
1216
|
+
'Destinations have `before` \u2192 links to post-collector transformer chain (e.g., before: "transformerName")',
|
|
1217
|
+
'Transformers have `next` \u2192 chains to next transformer (e.g., next: "anotherTransformer")',
|
|
1218
|
+
"Stores are passive \u2014 injected via `env` values using `$store:storeName` syntax",
|
|
1219
|
+
"Mapping on destinations transforms vendor-agnostic events into vendor-specific formats"
|
|
1220
|
+
],
|
|
1221
|
+
platformOptions: {
|
|
1222
|
+
web: "Browser environment \u2014 uses @walkeros/web-source-browser as default source",
|
|
1223
|
+
server: "Node.js environment \u2014 uses @walkeros/server-source-express as default source"
|
|
1224
|
+
},
|
|
1225
|
+
minimalExample: {
|
|
1226
|
+
version: 1,
|
|
1227
|
+
flows: {
|
|
1228
|
+
default: {
|
|
1229
|
+
web: {},
|
|
1230
|
+
packages: {
|
|
1231
|
+
"@walkeros/web-source-browser": {},
|
|
1232
|
+
"@walkeros/web-destination-gtag": {}
|
|
1233
|
+
},
|
|
1234
|
+
sources: {
|
|
1235
|
+
browser: { package: "@walkeros/web-source-browser", config: {} }
|
|
1236
|
+
},
|
|
1237
|
+
destinations: {
|
|
1238
|
+
gtag: {
|
|
1239
|
+
package: "@walkeros/web-destination-gtag",
|
|
1240
|
+
config: { measurementId: "G-XXXXXXXXXX" }
|
|
1241
|
+
}
|
|
1242
|
+
}
|
|
907
1243
|
}
|
|
908
1244
|
}
|
|
909
|
-
}
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
1245
|
+
}
|
|
1246
|
+
};
|
|
1247
|
+
function registerReferenceResources(server2) {
|
|
1248
|
+
server2.resource(
|
|
1249
|
+
"flow-schema",
|
|
1250
|
+
"walkeros://reference/flow-schema",
|
|
1251
|
+
{
|
|
1252
|
+
description: "Annotated Flow.Config structure reference with connection rules and minimal example",
|
|
1253
|
+
mimeType: "application/json"
|
|
1254
|
+
},
|
|
1255
|
+
async () => ({
|
|
1256
|
+
contents: [
|
|
1257
|
+
{
|
|
1258
|
+
uri: "walkeros://reference/flow-schema",
|
|
1259
|
+
text: JSON.stringify(FLOW_SCHEMA_REFERENCE, null, 2),
|
|
1260
|
+
mimeType: "application/json"
|
|
1261
|
+
}
|
|
1262
|
+
]
|
|
1263
|
+
})
|
|
1264
|
+
);
|
|
1265
|
+
server2.resource(
|
|
1266
|
+
"event-model",
|
|
1267
|
+
"walkeros://reference/event-model",
|
|
1268
|
+
{
|
|
1269
|
+
description: "walkerOS event structure: entity-action naming, properties (data, context, globals, nested, consent, user)",
|
|
1270
|
+
mimeType: "application/json"
|
|
1271
|
+
},
|
|
1272
|
+
async () => ({
|
|
1273
|
+
contents: [
|
|
1274
|
+
{
|
|
1275
|
+
uri: "walkeros://reference/event-model",
|
|
1276
|
+
text: JSON.stringify(
|
|
1277
|
+
{
|
|
1278
|
+
naming: 'Events use "entity action" format: "page view", "product add", "order complete"',
|
|
1279
|
+
minimalEvent: { name: "page view", data: { title: "Home" } },
|
|
1280
|
+
properties: {
|
|
1281
|
+
data: "Entity-specific properties (product name, price, etc.)",
|
|
1282
|
+
context: "State/environment info (page type, test group)",
|
|
1283
|
+
globals: "Cross-event properties set once (language, currency)",
|
|
1284
|
+
nested: "Nested entities (products inside an order)",
|
|
1285
|
+
user: "User identifiers (id, device, session, hash)",
|
|
1286
|
+
consent: "Granted permissions (functional, analytics, marketing)",
|
|
1287
|
+
custom: "Application-specific data"
|
|
1288
|
+
},
|
|
1289
|
+
autoPopulated: [
|
|
1290
|
+
"timestamp",
|
|
1291
|
+
"timing",
|
|
1292
|
+
"group",
|
|
1293
|
+
"count",
|
|
1294
|
+
"version",
|
|
1295
|
+
"source",
|
|
1296
|
+
"entity",
|
|
1297
|
+
"action"
|
|
1298
|
+
]
|
|
1299
|
+
},
|
|
1300
|
+
null,
|
|
1301
|
+
2
|
|
1302
|
+
),
|
|
1303
|
+
mimeType: "application/json"
|
|
1304
|
+
}
|
|
1305
|
+
]
|
|
1306
|
+
})
|
|
1307
|
+
);
|
|
1308
|
+
server2.resource(
|
|
1309
|
+
"mapping",
|
|
1310
|
+
"walkeros://reference/mapping",
|
|
1311
|
+
{
|
|
1312
|
+
description: "walkerOS mapping syntax: data/map/loop/set/condition/consent/policy rules for event transformation",
|
|
1313
|
+
mimeType: "application/json"
|
|
1314
|
+
},
|
|
1315
|
+
async () => ({
|
|
1316
|
+
contents: [
|
|
1317
|
+
{
|
|
1318
|
+
uri: "walkeros://reference/mapping",
|
|
1319
|
+
text: JSON.stringify(
|
|
1320
|
+
{
|
|
1321
|
+
overview: "Mapping transforms walkerOS events into vendor-specific formats. Same syntax on sources (input normalization) and destinations (output transformation).",
|
|
1322
|
+
config: {
|
|
1323
|
+
consent: "Record<string, boolean> \u2014 destination-level consent requirements",
|
|
1324
|
+
data: "Mapping.ValueConfig[] \u2014 field extraction rules",
|
|
1325
|
+
policy: "Pre-processing rules applied before mapping",
|
|
1326
|
+
mapping: "Record<entityAction, Mapping.Rule[]> \u2014 per-event mapping rules"
|
|
1327
|
+
},
|
|
1328
|
+
rules: {
|
|
1329
|
+
keying: 'entity.action format with wildcards: "product.add", "*.view", "order.*", "*.*"',
|
|
1330
|
+
priority: "Exact match > entity wildcard > action wildcard > global wildcard",
|
|
1331
|
+
example: {
|
|
1332
|
+
"product.add": [
|
|
1333
|
+
{
|
|
1334
|
+
name: "add_to_cart",
|
|
1335
|
+
data: { map: { value: "data.price" } }
|
|
1336
|
+
}
|
|
1337
|
+
],
|
|
1338
|
+
"*.view": [{ name: "page_view" }]
|
|
1339
|
+
}
|
|
1340
|
+
},
|
|
1341
|
+
valueConfig: {
|
|
1342
|
+
key: 'Source property path (e.g., "data.title", "context.page")',
|
|
1343
|
+
value: "Static value or fallback",
|
|
1344
|
+
fn: "$code:(event) => event.data.price * 100 \u2014 inline function",
|
|
1345
|
+
map: "Record<string, ValueConfig> \u2014 object transformation",
|
|
1346
|
+
loop: "Array iteration (e.g., loop nested entities)",
|
|
1347
|
+
set: "Create array from multiple values",
|
|
1348
|
+
condition: 'Conditional inclusion: { if: "data.price", value: "paid" }',
|
|
1349
|
+
consent: 'Field-level consent: { key: "user.email", consent: { marketing: true } }',
|
|
1350
|
+
validate: "Schema validation for the value"
|
|
1351
|
+
},
|
|
1352
|
+
codeFunction: "$code:(event, mapping, options) => expression \u2014 inline JavaScript. Access event data, mapping context, and options.",
|
|
1353
|
+
policyRules: {
|
|
1354
|
+
overview: "Pre-processing rules applied before mapping transforms events",
|
|
1355
|
+
types: [
|
|
1356
|
+
"consent \u2014 require specific consent before processing",
|
|
1357
|
+
"ignore \u2014 skip events matching conditions",
|
|
1358
|
+
"redact \u2014 remove sensitive fields"
|
|
1359
|
+
]
|
|
1360
|
+
}
|
|
1361
|
+
},
|
|
1362
|
+
null,
|
|
1363
|
+
2
|
|
1364
|
+
),
|
|
1365
|
+
mimeType: "application/json"
|
|
1366
|
+
}
|
|
1367
|
+
]
|
|
1368
|
+
})
|
|
1369
|
+
);
|
|
1370
|
+
server2.resource(
|
|
1371
|
+
"consent",
|
|
1372
|
+
"walkeros://reference/consent",
|
|
1373
|
+
{
|
|
1374
|
+
description: "walkerOS consent model: destination-level, rule-level, and field-level consent gating",
|
|
1375
|
+
mimeType: "application/json"
|
|
1376
|
+
},
|
|
1377
|
+
async () => ({
|
|
1378
|
+
contents: [
|
|
1379
|
+
{
|
|
1380
|
+
uri: "walkeros://reference/consent",
|
|
1381
|
+
text: JSON.stringify(
|
|
1382
|
+
{
|
|
1383
|
+
levels: {
|
|
1384
|
+
destination: "config.consent: { marketing: true } \u2014 entire destination requires consent",
|
|
1385
|
+
rule: "mapping.product.add.consent: { analytics: true } \u2014 specific mapping rule requires consent",
|
|
1386
|
+
field: 'data.map.email: { key: "user.email", consent: { marketing: true } } \u2014 individual field requires consent'
|
|
1387
|
+
},
|
|
1388
|
+
deferredInit: {
|
|
1389
|
+
require: '["consent"] \u2014 destination waits for consent before initializing',
|
|
1390
|
+
queue: "true (default) \u2014 events are queued while waiting for consent, replayed when granted"
|
|
1391
|
+
},
|
|
1392
|
+
collectorDefault: "Collector starts with empty consent state. Sources (CMP) push consent updates.",
|
|
1393
|
+
example: {
|
|
1394
|
+
destinations: {
|
|
1395
|
+
gtag: {
|
|
1396
|
+
package: "@walkeros/web-destination-gtag",
|
|
1397
|
+
config: { measurementId: "G-XXX" },
|
|
1398
|
+
consent: { analytics: true }
|
|
1399
|
+
},
|
|
1400
|
+
meta: {
|
|
1401
|
+
package: "@walkeros/web-destination-meta",
|
|
1402
|
+
config: { pixelId: "123" },
|
|
1403
|
+
consent: { marketing: true }
|
|
1404
|
+
}
|
|
1405
|
+
}
|
|
1406
|
+
}
|
|
1407
|
+
},
|
|
1408
|
+
null,
|
|
1409
|
+
2
|
|
1410
|
+
),
|
|
1411
|
+
mimeType: "application/json"
|
|
1412
|
+
}
|
|
1413
|
+
]
|
|
1414
|
+
})
|
|
1415
|
+
);
|
|
1416
|
+
server2.resource(
|
|
1417
|
+
"variables",
|
|
1418
|
+
"walkeros://reference/variables",
|
|
1419
|
+
{
|
|
1420
|
+
description: "walkerOS variable patterns: $var, $env, $def, $contract, $code, $store substitution",
|
|
1421
|
+
mimeType: "application/json"
|
|
1422
|
+
},
|
|
1423
|
+
async () => ({
|
|
1424
|
+
contents: [
|
|
1425
|
+
{
|
|
1426
|
+
uri: "walkeros://reference/variables",
|
|
1427
|
+
text: JSON.stringify(
|
|
1428
|
+
{
|
|
1429
|
+
patterns: {
|
|
1430
|
+
"$var.name": "Variable substitution \u2014 cascade: step settings > flow settings > config variables",
|
|
1431
|
+
"$env.NAME": "Environment variable \u2014 $env.GA_ID reads process.env.GA_ID",
|
|
1432
|
+
"$env.NAME:default": "Environment variable with fallback \u2014 $env.GA_ID:G-DEFAULT",
|
|
1433
|
+
"$def.name": "Definition reference \u2014 reusable config blocks from definitions section",
|
|
1434
|
+
"$def.name.path.deep": "Nested definition access \u2014 $def.ga4Events.purchase",
|
|
1435
|
+
"$contract.name": "Contract reference \u2014 links to named contract for validation",
|
|
1436
|
+
"$contract.name.path": "Nested contract access \u2014 $contract.ecommerce.product",
|
|
1437
|
+
"$code:(expr)": "Inline JavaScript \u2014 $code:(event) => event.data.price * 100",
|
|
1438
|
+
"$store:storeId": "Store injection in env values \u2014 wires runtime store access"
|
|
1439
|
+
},
|
|
1440
|
+
cascade: {
|
|
1441
|
+
priority: [
|
|
1442
|
+
"1. Step-level settings (highest)",
|
|
1443
|
+
"2. Flow-level settings",
|
|
1444
|
+
"3. Config-level variables (lowest)"
|
|
1445
|
+
],
|
|
1446
|
+
example: {
|
|
1447
|
+
variables: { apiKey: "default-key" },
|
|
1448
|
+
flows: {
|
|
1449
|
+
production: {
|
|
1450
|
+
destinations: {
|
|
1451
|
+
api: {
|
|
1452
|
+
config: { key: "$var.apiKey" },
|
|
1453
|
+
settings: { apiKey: "prod-key" }
|
|
1454
|
+
}
|
|
1455
|
+
}
|
|
1456
|
+
}
|
|
1457
|
+
}
|
|
1458
|
+
}
|
|
1459
|
+
}
|
|
1460
|
+
},
|
|
1461
|
+
null,
|
|
1462
|
+
2
|
|
1463
|
+
),
|
|
1464
|
+
mimeType: "application/json"
|
|
1465
|
+
}
|
|
1466
|
+
]
|
|
1467
|
+
})
|
|
1468
|
+
);
|
|
1469
|
+
server2.resource(
|
|
1470
|
+
"contract",
|
|
1471
|
+
"walkeros://reference/contract",
|
|
913
1472
|
{
|
|
914
|
-
|
|
915
|
-
description: "Flow configurations from your walkerOS project",
|
|
1473
|
+
description: "walkerOS contracts: event schema validation with entity-action keying, wildcards, and inheritance",
|
|
916
1474
|
mimeType: "application/json"
|
|
917
1475
|
},
|
|
918
|
-
async (
|
|
919
|
-
|
|
1476
|
+
async () => ({
|
|
1477
|
+
contents: [
|
|
1478
|
+
{
|
|
1479
|
+
uri: "walkeros://reference/contract",
|
|
1480
|
+
text: JSON.stringify(
|
|
1481
|
+
{
|
|
1482
|
+
overview: "Contracts define event schemas using entity-action keying. Used by the validator transformer to enforce data quality.",
|
|
1483
|
+
structure: {
|
|
1484
|
+
$tagging: "1 \u2014 contract format version (required)",
|
|
1485
|
+
namedContracts: "Top-level keys are contract names with extends support",
|
|
1486
|
+
entityAction: 'Keys use entity.action format: "product.add", "order.*", "*.*"',
|
|
1487
|
+
wildcards: {
|
|
1488
|
+
"*.*": "Matches all events",
|
|
1489
|
+
"*.action": "Matches any entity with specific action",
|
|
1490
|
+
"entity.*": "Matches all actions of specific entity"
|
|
1491
|
+
}
|
|
1492
|
+
},
|
|
1493
|
+
inheritance: {
|
|
1494
|
+
extends: 'Named contracts can extend other contracts: { extends: "base" }',
|
|
1495
|
+
merging: "Child properties merge with parent. Child overrides take precedence."
|
|
1496
|
+
},
|
|
1497
|
+
schema: {
|
|
1498
|
+
properties: {
|
|
1499
|
+
data: "JSON Schema for entity data properties",
|
|
1500
|
+
globals: "JSON Schema for global properties",
|
|
1501
|
+
context: "JSON Schema for context properties",
|
|
1502
|
+
custom: "JSON Schema for custom properties",
|
|
1503
|
+
user: "JSON Schema for user identifiers",
|
|
1504
|
+
consent: "Required consent state"
|
|
1505
|
+
}
|
|
1506
|
+
},
|
|
1507
|
+
reference: "$contract.name \u2014 use in flow config to reference a named contract",
|
|
1508
|
+
example: {
|
|
1509
|
+
$tagging: 1,
|
|
1510
|
+
ecommerce: {
|
|
1511
|
+
"product.*": {
|
|
1512
|
+
properties: {
|
|
1513
|
+
data: {
|
|
1514
|
+
type: "object",
|
|
1515
|
+
properties: {
|
|
1516
|
+
name: { type: "string" },
|
|
1517
|
+
price: { type: "number" }
|
|
1518
|
+
},
|
|
1519
|
+
required: ["name"]
|
|
1520
|
+
}
|
|
1521
|
+
}
|
|
1522
|
+
},
|
|
1523
|
+
"order.complete": {
|
|
1524
|
+
properties: {
|
|
1525
|
+
data: {
|
|
1526
|
+
type: "object",
|
|
1527
|
+
properties: {
|
|
1528
|
+
total: { type: "number" },
|
|
1529
|
+
orderId: { type: "string" }
|
|
1530
|
+
},
|
|
1531
|
+
required: ["total", "orderId"]
|
|
1532
|
+
}
|
|
1533
|
+
}
|
|
1534
|
+
}
|
|
1535
|
+
}
|
|
1536
|
+
}
|
|
1537
|
+
},
|
|
1538
|
+
null,
|
|
1539
|
+
2
|
|
1540
|
+
),
|
|
1541
|
+
mimeType: "application/json"
|
|
1542
|
+
}
|
|
1543
|
+
]
|
|
1544
|
+
})
|
|
1545
|
+
);
|
|
1546
|
+
server2.resource(
|
|
1547
|
+
"api",
|
|
1548
|
+
"walkeros://reference/api",
|
|
1549
|
+
{
|
|
1550
|
+
description: "walkerOS cloud API \u2014 OpenAPI 3.1 specification",
|
|
1551
|
+
mimeType: "application/json"
|
|
1552
|
+
},
|
|
1553
|
+
async () => {
|
|
1554
|
+
let openApiSpec;
|
|
1555
|
+
try {
|
|
1556
|
+
const { readFileSync } = await import("fs");
|
|
1557
|
+
const { createRequire } = await import("module");
|
|
1558
|
+
const require2 = createRequire(import.meta.url);
|
|
1559
|
+
const specPath = require2.resolve("@walkeros/cli/openapi/spec.json");
|
|
1560
|
+
openApiSpec = readFileSync(specPath, "utf-8");
|
|
1561
|
+
} catch {
|
|
1562
|
+
openApiSpec = JSON.stringify({ error: "OpenAPI spec not found" });
|
|
1563
|
+
}
|
|
920
1564
|
return {
|
|
921
1565
|
contents: [
|
|
922
1566
|
{
|
|
923
|
-
uri:
|
|
924
|
-
|
|
925
|
-
|
|
1567
|
+
uri: "walkeros://reference/api",
|
|
1568
|
+
text: openApiSpec,
|
|
1569
|
+
mimeType: "application/json"
|
|
926
1570
|
}
|
|
927
1571
|
]
|
|
928
1572
|
};
|
|
929
1573
|
}
|
|
930
1574
|
);
|
|
1575
|
+
server2.resource(
|
|
1576
|
+
"packages",
|
|
1577
|
+
"walkeros://reference/packages",
|
|
1578
|
+
{
|
|
1579
|
+
description: "Complete walkerOS package catalog \u2014 all sources, destinations, transformers, and stores",
|
|
1580
|
+
mimeType: "application/json"
|
|
1581
|
+
},
|
|
1582
|
+
async () => ({
|
|
1583
|
+
contents: [
|
|
1584
|
+
{
|
|
1585
|
+
uri: "walkeros://reference/packages",
|
|
1586
|
+
text: JSON.stringify(PACKAGE_REGISTRY, null, 2),
|
|
1587
|
+
mimeType: "application/json"
|
|
1588
|
+
}
|
|
1589
|
+
]
|
|
1590
|
+
})
|
|
1591
|
+
);
|
|
1592
|
+
}
|
|
1593
|
+
|
|
1594
|
+
// src/prompts/add-step.ts
|
|
1595
|
+
import { z as z8 } from "zod";
|
|
1596
|
+
function registerAddStepPrompt(server2) {
|
|
1597
|
+
server2.registerPrompt(
|
|
1598
|
+
"add-step",
|
|
1599
|
+
{
|
|
1600
|
+
description: "Add a source, destination, transformer, or store step to a flow configuration. Guides through package selection, config scaffolding, and wiring.",
|
|
1601
|
+
argsSchema: {
|
|
1602
|
+
stepType: z8.string().optional().describe(
|
|
1603
|
+
"Type of step to add: source, destination, transformer, or store"
|
|
1604
|
+
),
|
|
1605
|
+
flowPath: z8.string().optional().describe("Path to the flow.json file to modify")
|
|
1606
|
+
}
|
|
1607
|
+
},
|
|
1608
|
+
async ({ stepType, flowPath }) => ({
|
|
1609
|
+
messages: [
|
|
1610
|
+
{
|
|
1611
|
+
role: "user",
|
|
1612
|
+
content: {
|
|
1613
|
+
type: "text",
|
|
1614
|
+
text: [
|
|
1615
|
+
`Help me add a ${stepType || "new"} step to my flow${flowPath ? ` at ${flowPath}` : ""}.`,
|
|
1616
|
+
"",
|
|
1617
|
+
"Follow these steps:",
|
|
1618
|
+
`1. ${stepType ? "" : "Ask what type of step (source, destination, transformer, store). Then "}Use package_search to browse available packages for the selected type and platform.`,
|
|
1619
|
+
`2. Use package_get with section="hints" to read the selected package's configuration guidance.`,
|
|
1620
|
+
'3. Use package_get with section="examples" to see working configuration examples.',
|
|
1621
|
+
"4. Scaffold the step config using the package schemas \u2014 include required settings with placeholder values.",
|
|
1622
|
+
"5. Wire the step into the flow: add to packages section, connect via next/before chains if needed.",
|
|
1623
|
+
"6. Use flow_validate to verify the result.",
|
|
1624
|
+
"",
|
|
1625
|
+
"Important:",
|
|
1626
|
+
"- Read the walkeros://reference/flow-schema resource to understand connection rules.",
|
|
1627
|
+
"- Sources connect to pre-collector transformers via `next`.",
|
|
1628
|
+
"- Destinations connect to post-collector transformers via `before`.",
|
|
1629
|
+
"- Stores are passive \u2014 referenced via `$store:storeName` in env values.",
|
|
1630
|
+
"- Use variables ($var) for values that change between environments."
|
|
1631
|
+
].join("\n")
|
|
1632
|
+
}
|
|
1633
|
+
}
|
|
1634
|
+
]
|
|
1635
|
+
})
|
|
1636
|
+
);
|
|
1637
|
+
}
|
|
1638
|
+
|
|
1639
|
+
// src/prompts/setup-mapping.ts
|
|
1640
|
+
import { z as z9 } from "zod";
|
|
1641
|
+
function registerSetupMappingPrompt(server2) {
|
|
1642
|
+
server2.registerPrompt(
|
|
1643
|
+
"setup-mapping",
|
|
1644
|
+
{
|
|
1645
|
+
description: "Set up event mapping for any step in a flow. Teaches mapping syntax and uses package examples as templates.",
|
|
1646
|
+
argsSchema: {
|
|
1647
|
+
stepName: z9.string().optional().describe('Step name in the flow (e.g., "gtag", "meta", "express")')
|
|
1648
|
+
}
|
|
1649
|
+
},
|
|
1650
|
+
async ({ stepName }) => ({
|
|
1651
|
+
messages: [
|
|
1652
|
+
{
|
|
1653
|
+
role: "user",
|
|
1654
|
+
content: {
|
|
1655
|
+
type: "text",
|
|
1656
|
+
text: [
|
|
1657
|
+
`Help me set up mapping${stepName ? ` for the "${stepName}" step` : ""}.`,
|
|
1658
|
+
"",
|
|
1659
|
+
"Follow these steps:",
|
|
1660
|
+
"1. Read the walkeros://reference/mapping resource to understand mapping syntax.",
|
|
1661
|
+
`2. ${stepName ? `Identify the package for "${stepName}" in the flow, then u` : "U"}se package_get with section="examples" to see how events are mapped for this package.`,
|
|
1662
|
+
'3. Ask which events I want to map (e.g., "product view", "order complete").',
|
|
1663
|
+
"4. Generate mapping rules using the package examples as templates.",
|
|
1664
|
+
"5. Use flow_validate to verify the mapping.",
|
|
1665
|
+
"",
|
|
1666
|
+
"Mapping operates at two levels:",
|
|
1667
|
+
"- **Source mapping**: normalizes raw input \u2192 walkerOS events",
|
|
1668
|
+
"- **Destination mapping**: transforms walkerOS events \u2192 vendor format",
|
|
1669
|
+
"",
|
|
1670
|
+
"Key mapping operators: data (extract), map (object transform), loop (array processing), ",
|
|
1671
|
+
"set (create array), fn ($code function), condition (conditional), consent (consent-gated).",
|
|
1672
|
+
"",
|
|
1673
|
+
"Use $def references for shared mapping patterns across destinations."
|
|
1674
|
+
].join("\n")
|
|
1675
|
+
}
|
|
1676
|
+
}
|
|
1677
|
+
]
|
|
1678
|
+
})
|
|
1679
|
+
);
|
|
1680
|
+
}
|
|
1681
|
+
|
|
1682
|
+
// src/prompts/manage-contract.ts
|
|
1683
|
+
import { z as z10 } from "zod";
|
|
1684
|
+
function registerManageContractPrompt(server2) {
|
|
1685
|
+
server2.registerPrompt(
|
|
1686
|
+
"manage-contract",
|
|
1687
|
+
{
|
|
1688
|
+
description: "Create or update event contracts for a flow. Can generate contracts from existing mappings or scaffold mappings from contracts.",
|
|
1689
|
+
argsSchema: {
|
|
1690
|
+
direction: z10.string().optional().describe(
|
|
1691
|
+
'Direction: "from-mappings" (extract contract from existing mappings), "from-scratch" (create new contract), or "to-mappings" (scaffold mappings from contract)'
|
|
1692
|
+
)
|
|
1693
|
+
}
|
|
1694
|
+
},
|
|
1695
|
+
async ({ direction }) => ({
|
|
1696
|
+
messages: [
|
|
1697
|
+
{
|
|
1698
|
+
role: "user",
|
|
1699
|
+
content: {
|
|
1700
|
+
type: "text",
|
|
1701
|
+
text: [
|
|
1702
|
+
`Help me ${direction === "to-mappings" ? "scaffold mappings from a contract" : direction === "from-mappings" ? "generate a contract from existing mappings" : "manage event contracts"}.`,
|
|
1703
|
+
"",
|
|
1704
|
+
"Follow these steps:",
|
|
1705
|
+
"1. Read the walkeros://reference/contract resource to understand contract structure.",
|
|
1706
|
+
direction === "from-mappings" ? "2. Read all destination mappings in the flow, extract referenced event fields, and generate a contract with those as required properties." : direction === "to-mappings" ? "2. Read the contract from the flow, then scaffold mapping stubs for each destination based on the contract fields." : "2. Ask for entity-action names and required properties, or ask whether to generate from existing mappings.",
|
|
1707
|
+
"3. Use entity-action keying with wildcards (*.*, *.action, entity.*) for broad rules.",
|
|
1708
|
+
"4. Define JSON Schema for events, globals, context, custom, user, and consent.",
|
|
1709
|
+
"5. Use flow_validate to verify the contract.",
|
|
1710
|
+
"",
|
|
1711
|
+
"Contracts and mappings are bidirectional:",
|
|
1712
|
+
"- **Contract \u2192 Mappings**: contract defines what events look like, mappings are scaffolded to match.",
|
|
1713
|
+
"- **Mappings \u2192 Contract**: existing mappings reveal which fields are used, contract formalizes them.",
|
|
1714
|
+
"",
|
|
1715
|
+
"Use $contract.name references to link contracts in the flow.",
|
|
1716
|
+
"Contracts support extends for inheritance between event types."
|
|
1717
|
+
].join("\n")
|
|
1718
|
+
}
|
|
1719
|
+
}
|
|
1720
|
+
]
|
|
1721
|
+
})
|
|
1722
|
+
);
|
|
1723
|
+
}
|
|
1724
|
+
|
|
1725
|
+
// src/prompts/use-definitions.ts
|
|
1726
|
+
import { z as z11 } from "zod";
|
|
1727
|
+
function registerUseDefinitionsPrompt(server2) {
|
|
1728
|
+
server2.registerPrompt(
|
|
1729
|
+
"use-definitions",
|
|
1730
|
+
{
|
|
1731
|
+
description: "Extract shared patterns into definitions and variables for DRY, environment-aware flow configurations.",
|
|
1732
|
+
argsSchema: {
|
|
1733
|
+
flowPath: z11.string().optional().describe("Path to the flow.json file to analyze")
|
|
1734
|
+
}
|
|
1735
|
+
},
|
|
1736
|
+
async ({ flowPath }) => ({
|
|
1737
|
+
messages: [
|
|
1738
|
+
{
|
|
1739
|
+
role: "user",
|
|
1740
|
+
content: {
|
|
1741
|
+
type: "text",
|
|
1742
|
+
text: [
|
|
1743
|
+
`Help me extract shared patterns into definitions and variables${flowPath ? ` in ${flowPath}` : ""}.`,
|
|
1744
|
+
"",
|
|
1745
|
+
"Follow these steps:",
|
|
1746
|
+
"1. Read the walkeros://reference/variables resource to understand variable syntax.",
|
|
1747
|
+
"2. Analyze the flow config for repeated patterns (same mapping blocks, same config values).",
|
|
1748
|
+
"3. Extract repeated mapping patterns into the `definitions` section with `$def.name` references.",
|
|
1749
|
+
"4. Extract environment-specific values into `variables` with `$var.name` references.",
|
|
1750
|
+
"5. Show the cascade priority: step > settings > config.",
|
|
1751
|
+
"6. Use flow_validate to verify the result.",
|
|
1752
|
+
"",
|
|
1753
|
+
"Variable types:",
|
|
1754
|
+
"- `$var.name` \u2014 variable substitution (cascade: step > settings > config)",
|
|
1755
|
+
"- `$env.NAME` and `$env.NAME:default` \u2014 environment variables",
|
|
1756
|
+
"- `$def.name` and `$def.name.path.deep` \u2014 definition references",
|
|
1757
|
+
"- `$contract.name` \u2014 contract references",
|
|
1758
|
+
"- `$code:(expr)` \u2014 inline JavaScript functions",
|
|
1759
|
+
"- `$store:storeId` \u2014 store injection in env values",
|
|
1760
|
+
"",
|
|
1761
|
+
"Look for:",
|
|
1762
|
+
"- Same API keys or URLs across multiple destinations \u2192 $var or $env",
|
|
1763
|
+
"- Identical mapping rules in multiple destinations \u2192 $def",
|
|
1764
|
+
"- Environment-specific values (dev/staging/prod) \u2192 $var with overrides"
|
|
1765
|
+
].join("\n")
|
|
1766
|
+
}
|
|
1767
|
+
}
|
|
1768
|
+
]
|
|
1769
|
+
})
|
|
1770
|
+
);
|
|
931
1771
|
}
|
|
932
1772
|
|
|
933
1773
|
// src/index.ts
|
|
934
|
-
var server = new McpServer(
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
1774
|
+
var server = new McpServer(
|
|
1775
|
+
{
|
|
1776
|
+
name: "walkeros-flow",
|
|
1777
|
+
version: "3.0.0-next-1773236214827"
|
|
1778
|
+
},
|
|
1779
|
+
{
|
|
1780
|
+
instructions: `walkerOS is an open-source, privacy-first event data collection platform. Define event pipelines as code using JSON flow configurations.
|
|
1781
|
+
|
|
1782
|
+
## Architecture: Source \u2192 Collector \u2192 Destination(s)
|
|
1783
|
+
|
|
1784
|
+
Every component in a flow is a **step**: sources capture events, transformers process them, destinations deliver them, stores provide shared state. Steps connect via \`next\` (pre-collector) and \`before\` (post-collector) chains.
|
|
1785
|
+
|
|
1786
|
+
## Getting Started
|
|
1787
|
+
|
|
1788
|
+
1. \`flow_load({ platform: "web" })\` or \`flow_load({ source: "./flow.json" })\` \u2014 create or load a flow
|
|
1789
|
+
2. Use the \`add-step\` prompt to add sources, destinations, transformers, or stores
|
|
1790
|
+
3. Use the \`setup-mapping\` prompt to configure event transformations
|
|
1791
|
+
4. \`flow_validate({ type: "flow", input: "flow.json" })\` \u2014 verify configuration
|
|
1792
|
+
5. \`flow_simulate({ configPath: "flow.json", event: "..." })\` \u2014 test with mocked API calls
|
|
1793
|
+
6. \`flow_bundle({ configPath: "flow.json" })\` \u2014 build deployable JavaScript
|
|
1794
|
+
7. \`api({ action: "deploy", id: "cfg_..." })\` \u2014 deploy to walkerOS cloud (requires WALKEROS_TOKEN)
|
|
1795
|
+
|
|
1796
|
+
## Reference Resources
|
|
1797
|
+
|
|
1798
|
+
Attach these for context: \`walkeros://reference/flow-schema\`, \`walkeros://reference/mapping\`, \`walkeros://reference/event-model\`, \`walkeros://reference/consent\`, \`walkeros://reference/variables\`, \`walkeros://reference/contract\`.
|
|
1799
|
+
|
|
1800
|
+
## Key Concepts
|
|
1801
|
+
|
|
1802
|
+
- **Steps** are sources, destinations, transformers, or stores \u2014 each backed by an npm package with schemas, hints, and examples.
|
|
1803
|
+
- **Mapping** transforms events using data/map/loop/set/condition rules. Same syntax on sources and destinations.
|
|
1804
|
+
- **Contracts** define event schemas using entity-action keying. Can generate FROM mappings or scaffold mappings FROM contracts.
|
|
1805
|
+
- **Variables** ($var, $env, $def, $code, $store) enable DRY, environment-aware config. Use the \`use-definitions\` prompt to extract shared patterns.
|
|
1806
|
+
- **Consent** gates destinations, mapping rules, and individual fields. Privacy-first by design.`
|
|
1807
|
+
}
|
|
1808
|
+
);
|
|
1809
|
+
registerFlowValidateTool(server);
|
|
1810
|
+
registerFlowBundleTool(server);
|
|
1811
|
+
registerFlowSimulateTool(server);
|
|
1812
|
+
registerFlowPushTool(server);
|
|
1813
|
+
registerFlowExamplesTool(server);
|
|
1814
|
+
registerPackageSearchTool(server);
|
|
946
1815
|
registerGetPackageSchemaTool(server);
|
|
1816
|
+
registerFlowLoadTool(server);
|
|
947
1817
|
registerPackageSchemaResources(server);
|
|
948
|
-
|
|
1818
|
+
registerReferenceResources(server);
|
|
1819
|
+
registerAddStepPrompt(server);
|
|
1820
|
+
registerSetupMappingPrompt(server);
|
|
1821
|
+
registerManageContractPrompt(server);
|
|
1822
|
+
registerUseDefinitionsPrompt(server);
|
|
1823
|
+
if (process.env.WALKEROS_TOKEN) {
|
|
1824
|
+
registerApiTool(server);
|
|
1825
|
+
}
|
|
949
1826
|
async function main() {
|
|
950
1827
|
const transport = new StdioServerTransport();
|
|
951
1828
|
await server.connect(transport);
|
|
952
|
-
console.error("walkerOS MCP server running on stdio");
|
|
1829
|
+
console.error("walkerOS Flow MCP server running on stdio");
|
|
953
1830
|
}
|
|
954
1831
|
main().catch((error) => {
|
|
955
|
-
console.error("Failed to start MCP server:", error);
|
|
1832
|
+
console.error("Failed to start Flow MCP server:", error);
|
|
956
1833
|
process.exit(1);
|
|
957
1834
|
});
|
|
958
1835
|
//# sourceMappingURL=index.js.map
|