@walkeros/mcp 3.0.2 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -14,7 +14,7 @@ import { z } from "zod";
14
14
  var ValidateOutputShape = {
15
15
  valid: z.boolean().describe("Whether validation passed"),
16
16
  type: z.union([
17
- z.enum(["contract", "event", "flow", "mapping"]),
17
+ z.enum(["contract", "entry", "event", "flow", "mapping"]),
18
18
  z.string().regex(/^(destinations|sources|transformers)\.\w+$/)
19
19
  ]).describe("What was validated"),
20
20
  errors: z.array(
@@ -56,15 +56,10 @@ var SimulateOutputShape = {
56
56
  z.object({
57
57
  received: z.boolean().describe("Whether destination received the event"),
58
58
  calls: z.number().describe("Number of API calls made"),
59
- payload: z.unknown().optional().describe("Transformed payload sent")
59
+ payload: z.unknown().optional().describe("Full payload (only when verbose: true)")
60
60
  })
61
61
  ).optional().describe("Per-destination results"),
62
- exampleMatch: z.object({
63
- name: z.string(),
64
- step: z.string(),
65
- match: z.boolean(),
66
- diff: z.string().optional()
67
- }).optional().describe("Example comparison result when using example parameter"),
62
+ capturedEvents: z.array(z.record(z.string(), z.unknown())).optional().describe("Events captured by source simulation"),
68
63
  duration: z.number().optional().describe("Simulation duration in ms")
69
64
  };
70
65
  var PushOutputShape = {
@@ -85,60 +80,17 @@ var ExamplesListOutputShape = {
85
80
  hasIn: z.boolean().describe("Whether the example has an input value"),
86
81
  hasOut: z.boolean().describe("Whether the example has an output value"),
87
82
  hasMapping: z.boolean().describe("Whether the example has a mapping configuration"),
83
+ hasTrigger: z.boolean().describe("Whether the example has trigger metadata"),
88
84
  in: z.unknown().optional().describe("Input event data"),
89
85
  out: z.unknown().optional().describe("Expected output data"),
90
- mapping: z.unknown().optional().describe("Mapping configuration for destinations")
86
+ mapping: z.unknown().optional().describe("Mapping configuration for destinations"),
87
+ trigger: z.object({
88
+ type: z.string().optional(),
89
+ options: z.unknown().optional()
90
+ }).optional().describe("Trigger metadata for source simulation")
91
91
  })
92
92
  ).describe("Step examples")
93
93
  };
94
- var PackageSearchOutputShape = {
95
- package: z.string().describe("Package name"),
96
- version: z.string().describe("Package version"),
97
- description: z.string().optional().describe("Package description"),
98
- type: z.string().optional().describe("Package type (destination, source, transformer)"),
99
- platform: z.string().optional().describe("Target platform (web, server)"),
100
- hintKeys: z.array(z.string()).describe("Available hint keys (use package_get section=hints to read)"),
101
- exampleSummaries: z.array(
102
- z.object({
103
- name: z.string().describe("Example name"),
104
- description: z.string().optional().describe("What this example shows")
105
- })
106
- ).describe(
107
- "Step example names and descriptions (use package_get section=examples to read full content)"
108
- )
109
- };
110
- var PackageSchemaOutputShape = {
111
- package: z.string().describe("Package name"),
112
- version: z.string().describe("Package version"),
113
- type: z.string().describe("Package type (destination, source, transformer)"),
114
- platform: z.string().describe("Target platform (web, server)"),
115
- schemas: z.record(z.string(), z.unknown()).optional().describe("JSON Schemas for settings and mapping"),
116
- examples: z.record(z.string(), z.unknown()).optional().describe(
117
- "Full configuration examples (included when section=examples or section=all)"
118
- ),
119
- exampleSummaries: z.array(
120
- z.object({
121
- name: z.string().describe("Example name"),
122
- description: z.string().optional().describe("What this example shows")
123
- })
124
- ).optional().describe(
125
- "Example names and descriptions (included in default/summary mode)"
126
- ),
127
- hints: z.record(
128
- z.string(),
129
- z.object({
130
- text: z.string(),
131
- code: z.array(
132
- z.object({
133
- lang: z.string().optional(),
134
- code: z.string()
135
- })
136
- ).optional()
137
- })
138
- ).optional().describe(
139
- "Hints \u2014 text only in summary mode, with code blocks when section=hints or section=all"
140
- )
141
- };
142
94
 
143
95
  // src/tools/validate.ts
144
96
  function registerFlowValidateTool(server2) {
@@ -270,6 +222,7 @@ function formatBytes(bytes) {
270
222
  }
271
223
 
272
224
  // src/tools/simulate.ts
225
+ import { z as z3 } from "zod";
273
226
  import { simulate } from "@walkeros/cli";
274
227
  import { schemas as schemas3 } from "@walkeros/cli/dev";
275
228
  import { mcpResult as mcpResult3, mcpError as mcpError3 } from "@walkeros/core";
@@ -278,8 +231,17 @@ function registerFlowSimulateTool(server2) {
278
231
  "flow_simulate",
279
232
  {
280
233
  title: "Simulate Flow",
281
- description: 'Simulate events through a walkerOS flow without making real API calls. Events must be in walkerOS event format (post-source output): { name: "entity action", data: {...} }. Use package_get on your source to check its output shape. Use the example parameter to load event input from a step example and compare output.',
282
- inputSchema: schemas3.SimulateInputShape,
234
+ description: 'Simulate events through a walkerOS flow without making real API calls. For destinations: event is a walkerOS event { name: "entity action", data: {...} }. For sources: event is { content: ..., trigger?: { type?, options? }, env?: {...} }. Use step to target a specific step. Use flow_examples to discover available test data.',
235
+ inputSchema: {
236
+ configPath: schemas3.SimulateInputShape.configPath,
237
+ event: z3.union([z3.record(z3.string(), z3.unknown()), z3.string()]).optional().describe(
238
+ "For destinations: { name, data }. For sources: { content, trigger?, env? }. Can also be a JSON string or file path."
239
+ ),
240
+ flow: schemas3.SimulateInputShape.flow,
241
+ platform: schemas3.SimulateInputShape.platform,
242
+ step: schemas3.SimulateInputShape.step,
243
+ verbose: z3.boolean().optional().describe("Include full payload per destination (default: false)")
244
+ },
283
245
  outputSchema: SimulateOutputShape,
284
246
  annotations: {
285
247
  readOnlyHint: true,
@@ -288,26 +250,51 @@ function registerFlowSimulateTool(server2) {
288
250
  openWorldHint: false
289
251
  }
290
252
  },
291
- async ({ configPath, event, flow, platform, example, step }) => {
253
+ async ({ configPath, event, flow, platform, step, verbose }) => {
292
254
  try {
293
- if (!event && !example) {
294
- throw new Error("Either event or example must be provided");
255
+ if (!event) {
256
+ throw new Error(
257
+ "event is required. For sources provide { content, trigger? }, for destinations provide { name, data }."
258
+ );
295
259
  }
296
260
  const raw = await simulate(configPath, event, {
297
261
  json: true,
298
262
  flow,
299
263
  platform,
300
- example,
301
264
  step
302
265
  });
266
+ if (raw.capturedEvents) {
267
+ const eventCount = raw.capturedEvents.length;
268
+ const summary2 = `Source captured ${eventCount} event${eventCount !== 1 ? "s" : ""}`;
269
+ return mcpResult3(
270
+ {
271
+ success: raw.success,
272
+ error: raw.error,
273
+ summary: summary2,
274
+ capturedEvents: raw.capturedEvents,
275
+ duration: raw.duration
276
+ },
277
+ summary2,
278
+ {
279
+ next: eventCount > 0 ? [
280
+ "Use flow_simulate with a destination step to test downstream processing"
281
+ ] : [
282
+ "Check source package examples with package_get, verify trigger type matches"
283
+ ]
284
+ }
285
+ );
286
+ }
303
287
  const destinations = {};
304
288
  if (raw.usage) {
305
289
  for (const [name, calls] of Object.entries(raw.usage)) {
306
- destinations[name] = {
290
+ const summary2 = {
307
291
  received: calls.length > 0,
308
- calls: calls.length,
309
- payload: calls.length > 0 ? calls[calls.length - 1] : void 0
292
+ calls: calls.length
310
293
  };
294
+ if (verbose && calls.length > 0) {
295
+ summary2.payload = calls[calls.length - 1];
296
+ }
297
+ destinations[name] = summary2;
311
298
  }
312
299
  }
313
300
  const destCount = Object.keys(destinations).length;
@@ -316,13 +303,11 @@ function registerFlowSimulateTool(server2) {
316
303
  ).length;
317
304
  const warnings = [];
318
305
  if (destCount === 0) {
319
- warnings.push(
320
- "No destinations found in flow configuration. Check that your flow defines at least one destination."
321
- );
306
+ warnings.push("No destinations found in flow configuration.");
322
307
  }
323
308
  if (destCount > 0 && receivedCount === 0) {
324
309
  warnings.push(
325
- "No destinations received the event. Check: mapping keys use nested entity\u2192action structure (not dot-separated), event name matches, consent is granted. Use package_get on the destination for mapping examples."
310
+ "No destinations received the event. Check: mapping keys use nested entity\u2192action structure, event name matches, consent is granted."
326
311
  );
327
312
  }
328
313
  const summary = `${receivedCount}/${destCount} destinations received the event`;
@@ -331,7 +316,6 @@ function registerFlowSimulateTool(server2) {
331
316
  error: raw.error,
332
317
  summary,
333
318
  destinations: destCount > 0 ? destinations : void 0,
334
- exampleMatch: raw.exampleMatch,
335
319
  duration: raw.duration
336
320
  };
337
321
  return mcpResult3(result, summary, {
@@ -346,6 +330,7 @@ function registerFlowSimulateTool(server2) {
346
330
  }
347
331
 
348
332
  // src/tools/push.ts
333
+ import { z as z4 } from "zod";
349
334
  import { push } from "@walkeros/cli";
350
335
  import { schemas as schemas4 } from "@walkeros/cli/dev";
351
336
  import { mcpResult as mcpResult4, mcpError as mcpError4 } from "@walkeros/core";
@@ -355,7 +340,14 @@ function registerFlowPushTool(server2) {
355
340
  {
356
341
  title: "Push Events",
357
342
  description: "Push a real event through a walkerOS flow to actual destinations. Makes real API calls to real endpoints. Best suited for server-side flows \u2014 web flows should use flow_simulate for testing.",
358
- inputSchema: schemas4.PushInputShape,
343
+ inputSchema: {
344
+ configPath: schemas4.PushInputShape.configPath,
345
+ event: z4.record(z4.string(), z4.unknown()).describe(
346
+ 'Event object, e.g. { name: "page view", data: { title: "Home" } }'
347
+ ),
348
+ flow: schemas4.PushInputShape.flow,
349
+ platform: schemas4.PushInputShape.platform
350
+ },
359
351
  outputSchema: PushOutputShape,
360
352
  annotations: {
361
353
  readOnlyHint: false,
@@ -390,7 +382,7 @@ function registerFlowPushTool(server2) {
390
382
  }
391
383
 
392
384
  // src/tools/examples.ts
393
- import { z as z3 } from "zod";
385
+ import { z as z5 } from "zod";
394
386
  import { loadJsonConfig } from "@walkeros/cli";
395
387
  import { mcpResult as mcpResult5, mcpError as mcpError5 } from "@walkeros/core";
396
388
  function registerFlowExamplesTool(server2) {
@@ -400,10 +392,12 @@ function registerFlowExamplesTool(server2) {
400
392
  title: "Flow Examples",
401
393
  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.",
402
394
  inputSchema: {
403
- configPath: z3.string().min(1).describe("Path to flow configuration file"),
404
- flow: z3.string().optional().describe("Flow name for multi-flow configs"),
405
- step: z3.string().optional().describe('Filter to a specific step (e.g., "destination.gtag")'),
406
- full: z3.boolean().optional().describe(
395
+ configPath: z5.string().min(1).describe(
396
+ "Path to flow configuration file, URL, or inline JSON string"
397
+ ),
398
+ flow: z5.string().optional().describe("Flow name for multi-flow configs"),
399
+ step: z5.string().optional().describe('Filter to a specific step (e.g., "destination.gtag")'),
400
+ full: z5.boolean().optional().describe(
407
401
  "Return full in/out/mapping data for each example (default: false, returns metadata only)"
408
402
  )
409
403
  },
@@ -451,7 +445,13 @@ function registerFlowExamplesTool(server2) {
451
445
  hasIn: ex.in !== void 0,
452
446
  hasOut: ex.out !== void 0,
453
447
  hasMapping: ex.mapping !== void 0,
454
- ...full ? { in: ex.in, out: ex.out, mapping: ex.mapping } : {}
448
+ hasTrigger: ex.trigger !== void 0,
449
+ ...full ? {
450
+ in: ex.in,
451
+ out: ex.out,
452
+ mapping: ex.mapping,
453
+ trigger: ex.trigger
454
+ } : {}
455
455
  });
456
456
  }
457
457
  }
@@ -465,7 +465,7 @@ function registerFlowExamplesTool(server2) {
465
465
  const totalExamples = examples.length;
466
466
  const summary = `${totalExamples} examples across ${stepSet.size} steps`;
467
467
  const hints = {
468
- next: ["Use flow_simulate with example parameter to test"]
468
+ next: ["Use flow_simulate with step and event to simulate"]
469
469
  };
470
470
  if (totalExamples === 0) {
471
471
  hints.warnings = [
@@ -481,207 +481,85 @@ function registerFlowExamplesTool(server2) {
481
481
  }
482
482
 
483
483
  // src/tools/package.ts
484
- import { z as z4 } from "zod";
485
- import { fetchPackage, mcpResult as mcpResult6, mcpError as mcpError6 } from "@walkeros/core";
484
+ import { z as z6 } from "zod";
485
+ import {
486
+ fetchPackage,
487
+ mergeConfigSchema,
488
+ mcpResult as mcpResult6,
489
+ mcpError as mcpError6
490
+ } from "@walkeros/core";
486
491
 
487
- // src/registry.ts
488
- var PACKAGE_REGISTRY = [
489
- // Web Destinations
490
- {
491
- name: "@walkeros/web-destination-gtag",
492
- type: "destination",
493
- platform: "web",
494
- description: "Google destination (GA4, Ads, GTM via gtag.js)"
495
- },
496
- {
497
- name: "@walkeros/web-destination-meta",
498
- type: "destination",
499
- platform: "web",
500
- description: "Meta (Facebook) Pixel"
501
- },
502
- {
503
- name: "@walkeros/web-destination-plausible",
504
- type: "destination",
505
- platform: "web",
506
- description: "Plausible Analytics"
507
- },
508
- {
509
- name: "@walkeros/web-destination-snowplow",
510
- type: "destination",
511
- platform: "web",
512
- description: "Snowplow Analytics"
513
- },
514
- {
515
- name: "@walkeros/web-destination-piwikpro",
516
- type: "destination",
517
- platform: "web",
518
- description: "Piwik PRO Analytics"
519
- },
520
- {
521
- name: "@walkeros/web-destination-api",
522
- type: "destination",
523
- platform: "web",
524
- description: "Generic HTTP API destination"
525
- },
526
- // Server Destinations
527
- {
528
- name: "@walkeros/server-destination-gcp",
529
- type: "destination",
530
- platform: "server",
531
- description: "Google Cloud Platform (BigQuery)"
532
- },
533
- {
534
- name: "@walkeros/server-destination-aws",
535
- type: "destination",
536
- platform: "server",
537
- description: "AWS (Firehose)"
538
- },
539
- {
540
- name: "@walkeros/server-destination-meta",
541
- type: "destination",
542
- platform: "server",
543
- description: "Meta Conversions API (server-side)"
544
- },
545
- {
546
- name: "@walkeros/server-destination-api",
547
- type: "destination",
548
- platform: "server",
549
- description: "Generic HTTP API destination (server)"
550
- },
551
- {
552
- name: "@walkeros/server-destination-datamanager",
553
- type: "destination",
554
- platform: "server",
555
- description: "Google Data Manager"
556
- },
557
- // Web Sources
558
- {
559
- name: "@walkeros/web-source-browser",
560
- type: "source",
561
- platform: "web",
562
- description: "Browser DOM event capture (clicks, page views, forms)"
563
- },
564
- {
565
- name: "@walkeros/web-source-datalayer",
566
- type: "source",
567
- platform: "web",
568
- description: "Google Tag Manager dataLayer bridge"
569
- },
570
- {
571
- name: "@walkeros/web-source-session",
572
- type: "source",
573
- platform: "web",
574
- description: "Session tracking source"
575
- },
576
- // CMP Sources
577
- {
578
- name: "@walkeros/web-source-cmp-cookiefirst",
579
- type: "source",
580
- platform: "web",
581
- description: "CookieFirst consent management"
582
- },
583
- {
584
- name: "@walkeros/web-source-cmp-cookiepro",
585
- type: "source",
586
- platform: "web",
587
- description: "CookiePro/OneTrust consent management"
588
- },
589
- {
590
- name: "@walkeros/web-source-cmp-usercentrics",
591
- type: "source",
592
- platform: "web",
593
- description: "Usercentrics consent management"
594
- },
595
- // Server Sources
596
- {
597
- name: "@walkeros/server-source-express",
598
- type: "source",
599
- platform: "server",
600
- description: "Express.js HTTP event endpoint"
601
- },
602
- {
603
- name: "@walkeros/server-source-fetch",
604
- type: "source",
605
- platform: "server",
606
- description: "Web Fetch API source (Cloudflare, Vercel Edge, Deno, Bun)"
607
- },
608
- {
609
- name: "@walkeros/server-source-aws",
610
- type: "source",
611
- platform: "server",
612
- description: "AWS sources (Lambda, API Gateway, Function URLs)"
613
- },
614
- {
615
- name: "@walkeros/server-source-gcp",
616
- type: "source",
617
- platform: "server",
618
- description: "GCP sources (Cloud Functions)"
619
- },
620
- // Transformers
621
- {
622
- name: "@walkeros/transformer-router",
623
- type: "transformer",
624
- platform: "universal",
625
- description: "Route events to different destination subsets"
626
- },
627
- {
628
- name: "@walkeros/transformer-validator",
629
- type: "transformer",
630
- platform: "universal",
631
- description: "Event validation using JSON Schema"
632
- },
633
- {
634
- name: "@walkeros/server-transformer-fingerprint",
635
- type: "transformer",
636
- platform: "server",
637
- description: "Device fingerprinting for anonymous user identification"
638
- },
639
- {
640
- name: "@walkeros/server-transformer-cache",
641
- type: "transformer",
642
- platform: "server",
643
- description: "HTTP response caching with LRU eviction"
644
- },
645
- {
646
- name: "@walkeros/server-transformer-file",
647
- type: "transformer",
648
- platform: "server",
649
- description: "File serving transformer for static files"
650
- },
651
- // Stores
652
- {
653
- name: "@walkeros/store-memory",
654
- type: "store",
655
- platform: "universal",
656
- description: "In-memory key-value store with LRU eviction and TTL"
657
- },
658
- {
659
- name: "@walkeros/server-store-fs",
660
- type: "store",
661
- platform: "server",
662
- description: "File system key-value store"
663
- },
664
- {
665
- name: "@walkeros/server-store-s3",
666
- type: "store",
667
- platform: "server",
668
- description: "AWS S3 key-value store"
669
- },
670
- {
671
- name: "@walkeros/server-store-gcs",
672
- type: "store",
673
- platform: "server",
674
- description: "Google Cloud Storage key-value store"
492
+ // src/catalog.ts
493
+ var NPM_SEARCH_URL = "https://registry.npmjs.org/-/v1/search";
494
+ var JSDELIVR_BASE = "https://cdn.jsdelivr.net/npm";
495
+ var WALKEROS_JSON_PATH = "dist/walkerOS.json";
496
+ var CACHE_TTL = 5 * 60 * 1e3;
497
+ var cache;
498
+ function normalizePlatform(platform) {
499
+ if (platform == null) return [];
500
+ if (typeof platform === "string") {
501
+ return platform === "universal" ? ["web", "server"] : [platform];
675
502
  }
676
- ];
677
- function filterRegistry(filters) {
678
- let results = PACKAGE_REGISTRY;
503
+ if (Array.isArray(platform)) {
504
+ return platform.filter((v) => typeof v === "string");
505
+ }
506
+ return [];
507
+ }
508
+ async function fetchCatalog(filters) {
509
+ if (cache && Date.now() - cache.timestamp < CACHE_TTL) {
510
+ return applyFilters(cache.entries, filters);
511
+ }
512
+ let entries;
513
+ try {
514
+ entries = await fetchFromNpm();
515
+ } catch {
516
+ return [];
517
+ }
518
+ cache = { entries, timestamp: Date.now() };
519
+ return applyFilters(entries, filters);
520
+ }
521
+ async function fetchFromNpm() {
522
+ const res = await fetch(`${NPM_SEARCH_URL}?text=@walkeros/&size=250`, {
523
+ signal: AbortSignal.timeout(1e4)
524
+ });
525
+ if (!res.ok) throw new Error(`npm search failed: ${res.status}`);
526
+ const data = await res.json();
527
+ const metaResults = await Promise.allSettled(
528
+ data.objects.map((obj) => enrichWithMeta(obj.package))
529
+ );
530
+ return metaResults.filter(
531
+ (r) => r.status === "fulfilled"
532
+ ).map((r) => r.value).filter((entry) => entry !== void 0);
533
+ }
534
+ async function enrichWithMeta(pkg) {
535
+ try {
536
+ const res = await fetch(
537
+ `${JSDELIVR_BASE}/${pkg.name}@${pkg.version}/${WALKEROS_JSON_PATH}`,
538
+ { signal: AbortSignal.timeout(5e3) }
539
+ );
540
+ if (!res.ok) return void 0;
541
+ const json = await res.json();
542
+ const meta = json.$meta;
543
+ if (!meta || typeof meta.type !== "string") return void 0;
544
+ return {
545
+ name: pkg.name,
546
+ version: pkg.version,
547
+ description: pkg.description,
548
+ type: meta.type,
549
+ platform: normalizePlatform(meta.platform)
550
+ };
551
+ } catch {
552
+ return void 0;
553
+ }
554
+ }
555
+ function applyFilters(entries, filters) {
556
+ let results = entries;
679
557
  if (filters?.type) {
680
- results = results.filter((p) => p.type === filters.type);
558
+ results = results.filter((e) => e.type === filters.type);
681
559
  }
682
560
  if (filters?.platform) {
683
561
  results = results.filter(
684
- (p) => p.platform === filters.platform || p.platform === "universal"
562
+ (e) => e.platform.length === 0 || e.platform.includes(filters.platform)
685
563
  );
686
564
  }
687
565
  return results;
@@ -695,14 +573,14 @@ function registerPackageSearchTool(server2) {
695
573
  title: "Search Package",
696
574
  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.",
697
575
  inputSchema: {
698
- package: z4.string().min(1).optional().describe(
576
+ package: z6.string().min(1).optional().describe(
699
577
  "Exact npm package name for detailed lookup (e.g., @walkeros/web-destination-snowplow)"
700
578
  ),
701
- type: z4.enum(["source", "destination", "transformer", "store"]).optional().describe("Filter by package type (browse mode)"),
702
- platform: z4.enum(["web", "server"]).optional().describe(
579
+ type: z6.enum(["source", "destination", "transformer", "store"]).optional().describe("Filter by package type (browse mode)"),
580
+ platform: z6.enum(["web", "server"]).optional().describe(
703
581
  "Filter by platform (browse mode, includes universal packages)"
704
582
  ),
705
- version: z4.string().optional().describe("Package version for detailed lookup (default: latest)")
583
+ version: z6.string().optional().describe("Package version for detailed lookup (default: latest)")
706
584
  },
707
585
  // No outputSchema: browse mode returns {catalog, count}, lookup returns metadata — incompatible shapes
708
586
  annotations: {
@@ -714,7 +592,7 @@ function registerPackageSearchTool(server2) {
714
592
  },
715
593
  async ({ package: packageName, type, platform, version }) => {
716
594
  if (!packageName) {
717
- const catalog = filterRegistry({ type, platform });
595
+ const catalog = await fetchCatalog({ type, platform });
718
596
  const result = { catalog, count: catalog.length };
719
597
  const summary = `${catalog.length} packages found`;
720
598
  return mcpResult6(result, summary, {
@@ -728,7 +606,7 @@ function registerPackageSearchTool(server2) {
728
606
  version: info.version,
729
607
  description: info.description,
730
608
  type: info.type,
731
- platform: info.platform,
609
+ platform: normalizePlatform(info.platform),
732
610
  hintKeys: info.hintKeys,
733
611
  exampleSummaries: info.exampleSummaries
734
612
  };
@@ -752,15 +630,15 @@ function registerGetPackageSchemaTool(server2) {
752
630
  title: "Get Package",
753
631
  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.',
754
632
  inputSchema: {
755
- package: z4.string().min(1).describe(
633
+ package: z6.string().min(1).describe(
756
634
  "Exact npm package name (e.g., @walkeros/web-destination-snowplow)"
757
635
  ),
758
- version: z4.string().optional().describe("Package version (default: latest)"),
759
- section: z4.enum(["hints", "examples", "all"]).optional().describe(
636
+ version: z6.string().optional().describe("Package version (default: latest)"),
637
+ section: z6.enum(["hints", "examples", "all"]).optional().describe(
760
638
  "Section to expand with full content. Default: summary view with schemas + hint texts + example descriptions"
761
639
  )
762
640
  },
763
- outputSchema: PackageSchemaOutputShape,
641
+ // No outputSchema — removed to avoid SDK -32602 crashes on unexpected field values
764
642
  annotations: {
765
643
  readOnlyHint: true,
766
644
  destructiveHint: false,
@@ -771,12 +649,24 @@ function registerGetPackageSchemaTool(server2) {
771
649
  async ({ package: packageName, version, section }) => {
772
650
  try {
773
651
  const info = await fetchPackage(packageName, { version });
652
+ const mergedSchemas = {};
653
+ if (info.type) {
654
+ mergedSchemas.config = mergeConfigSchema(
655
+ info.type,
656
+ info.schemas
657
+ );
658
+ }
659
+ for (const [key, value] of Object.entries(info.schemas)) {
660
+ if (key !== "settings") {
661
+ mergedSchemas[key] = value;
662
+ }
663
+ }
774
664
  const result = {
775
665
  package: info.packageName,
776
666
  version: info.version,
777
667
  type: info.type,
778
- platform: info.platform,
779
- schemas: info.schemas
668
+ platform: normalizePlatform(info.platform),
669
+ schemas: mergedSchemas
780
670
  };
781
671
  if (info.hints) {
782
672
  if (section === "hints" || section === "all") {
@@ -810,7 +700,7 @@ function registerGetPackageSchemaTool(server2) {
810
700
  }
811
701
 
812
702
  // src/tools/flow-load.ts
813
- import { z as z5 } from "zod";
703
+ import { z as z7 } from "zod";
814
704
  import { loadJsonConfig as loadJsonConfig2 } from "@walkeros/cli";
815
705
  import { mcpResult as mcpResult7, mcpError as mcpError7 } from "@walkeros/core";
816
706
  var WEB_SKELETON = {
@@ -842,16 +732,16 @@ function registerFlowLoadTool(server2) {
842
732
  title: "Load or Create Flow",
843
733
  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.",
844
734
  inputSchema: {
845
- source: z5.string().optional().describe(
846
- "Flow source: local file path (./flow.json), URL (https://...), or API flow ID (cfg_...). Omit to create a new flow."
735
+ source: z7.string().optional().describe(
736
+ "Flow source: local file path (./flow.json), URL (https://...), inline JSON string, or API flow ID (cfg_...). Omit to create a new flow."
847
737
  ),
848
- platform: z5.enum(["web", "server"]).optional().describe(
738
+ platform: z7.enum(["web", "server"]).optional().describe(
849
739
  "Platform for new flows. Required when source is omitted. web = browser tracking, server = Node.js HTTP."
850
740
  )
851
741
  },
852
742
  outputSchema: {
853
- version: z5.number().describe("Flow config version"),
854
- flows: z5.record(z5.string(), z5.unknown()).describe("Flow definitions")
743
+ version: z7.number().describe("Flow config version"),
744
+ flows: z7.record(z7.string(), z7.unknown()).describe("Flow definitions")
855
745
  },
856
746
  annotations: {
857
747
  readOnlyHint: true,
@@ -907,7 +797,7 @@ function registerFlowLoadTool(server2) {
907
797
  }
908
798
 
909
799
  // src/tools/feedback.ts
910
- import { z as z6 } from "zod";
800
+ import { z as z8 } from "zod";
911
801
  import { feedback, readConfig, writeConfig } from "@walkeros/cli";
912
802
  import { mcpResult as mcpResult8, mcpError as mcpError8 } from "@walkeros/core";
913
803
  function registerFeedbackTool(server2) {
@@ -917,8 +807,8 @@ function registerFeedbackTool(server2) {
917
807
  title: "Send Feedback",
918
808
  description: "Send feedback about walkerOS",
919
809
  inputSchema: {
920
- text: z6.string().describe("Your feedback text"),
921
- anonymous: z6.boolean().optional().describe(
810
+ text: z8.string().describe("Your feedback text"),
811
+ anonymous: z8.boolean().optional().describe(
922
812
  "Include user/project info? false = include, true = anonymous. Only needed on first call if not yet configured."
923
813
  )
924
814
  },
@@ -952,7 +842,7 @@ function registerFeedbackTool(server2) {
952
842
  writeConfig({ ...base, anonymousFeedback: anonymous });
953
843
  }
954
844
  const isAnonymous = explicitAnonymous ?? anonymous ?? true;
955
- await feedback(text, { anonymous: isAnonymous });
845
+ await feedback(text, { anonymous: isAnonymous, version: "3.1.0" });
956
846
  return mcpResult8({ ok: true }, "Feedback sent. Thanks!");
957
847
  } catch (error) {
958
848
  return mcpError8(error);
@@ -962,7 +852,7 @@ function registerFeedbackTool(server2) {
962
852
  }
963
853
 
964
854
  // src/tools/api.ts
965
- import { z as z8 } from "zod";
855
+ import { z as z10 } from "zod";
966
856
  import {
967
857
  whoami,
968
858
  listProjects,
@@ -986,11 +876,11 @@ import {
986
876
  import { mcpResult as mcpResult9, mcpError as mcpError9 } from "@walkeros/core";
987
877
 
988
878
  // src/schemas/api-output.ts
989
- import { z as z7 } from "zod";
879
+ import { z as z9 } from "zod";
990
880
  var ApiOutputShape = {
991
- action: z7.string().describe("Action that was executed"),
992
- ok: z7.boolean().describe("Whether the action succeeded"),
993
- data: z7.unknown().describe("Action-specific result data")
881
+ action: z9.string().describe("Action that was executed"),
882
+ ok: z9.boolean().describe("Whether the action succeeded"),
883
+ data: z9.unknown().describe("Action-specific result data")
994
884
  };
995
885
 
996
886
  // src/tools/api.ts
@@ -1018,21 +908,26 @@ function registerApiTool(server2) {
1018
908
  "api",
1019
909
  {
1020
910
  title: "walkerOS Cloud API",
1021
- 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.",
911
+ 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. content = Flow.Config JSON for flow.create/update.",
1022
912
  inputSchema: {
1023
- action: z8.enum(ACTIONS).describe("API action to perform"),
1024
- id: z8.string().optional().describe("Resource ID (flowId, projectId, or deployment slug)"),
1025
- name: z8.string().optional().describe("Name for create/update operations"),
1026
- content: z8.record(z8.string(), z8.unknown()).optional().describe("Flow.Config JSON for flow operations"),
1027
- patch: z8.boolean().optional().describe("Use merge-patch for flow.update (default: true)"),
1028
- wait: z8.boolean().optional().describe("Wait for deploy to complete (default: true)"),
1029
- flowName: z8.string().optional().describe("Flow name for multi-settings flows"),
1030
- fields: z8.array(z8.string()).optional().describe("Dot-path field selectors for flow.get"),
1031
- type: z8.enum(["web", "server"]).optional().describe("Deployment type for deployment.create"),
1032
- sort: z8.string().optional().describe("Sort field for list operations"),
1033
- order: z8.enum(["asc", "desc"]).optional().describe("Sort order"),
1034
- status: z8.string().optional().describe("Status filter for deployment.list"),
1035
- includeDeleted: z8.boolean().optional().describe("Include deleted items in lists")
913
+ action: z10.enum(ACTIONS).describe("API action to perform"),
914
+ projectId: z10.string().optional().describe(
915
+ "Project ID (proj_...). Required for: project.get/update/delete, flow.create, flow.list. Falls back to WALKEROS_PROJECT_ID env var."
916
+ ),
917
+ flowId: z10.string().optional().describe(
918
+ "Flow ID (flow_...) or config ID (cfg_...). Required for: flow.get, flow.update, flow.delete, flow.duplicate, deploy. For deployment.get/delete: can be a deployment slug."
919
+ ),
920
+ name: z10.string().optional().describe("Name for create/update operations"),
921
+ content: z10.record(z10.string(), z10.unknown()).optional().describe("Flow.Config JSON for flow operations"),
922
+ patch: z10.boolean().optional().describe("Use merge-patch for flow.update (default: true)"),
923
+ wait: z10.boolean().optional().describe("Wait for deploy to complete (default: true)"),
924
+ flowName: z10.string().optional().describe("Flow name for multi-settings flows"),
925
+ fields: z10.array(z10.string()).optional().describe("Dot-path field selectors for flow.get"),
926
+ type: z10.enum(["web", "server"]).optional().describe("Deployment type for deployment.create"),
927
+ sort: z10.string().optional().describe("Sort field for list operations"),
928
+ order: z10.enum(["asc", "desc"]).optional().describe("Sort order"),
929
+ status: z10.string().optional().describe("Status filter for deployment.list"),
930
+ includeDeleted: z10.boolean().optional().describe("Include deleted items in lists")
1036
931
  },
1037
932
  outputSchema: ApiOutputShape,
1038
933
  annotations: {
@@ -1045,7 +940,8 @@ function registerApiTool(server2) {
1045
940
  async (params, extra) => {
1046
941
  const {
1047
942
  action,
1048
- id,
943
+ projectId,
944
+ flowId,
1049
945
  name,
1050
946
  content,
1051
947
  patch,
@@ -1075,7 +971,7 @@ function registerApiTool(server2) {
1075
971
  break;
1076
972
  }
1077
973
  case "project.get": {
1078
- data = await getProject({ projectId: id });
974
+ data = await getProject({ projectId });
1079
975
  summary = `Project "${data.name}"`;
1080
976
  break;
1081
977
  }
@@ -1087,19 +983,19 @@ function registerApiTool(server2) {
1087
983
  }
1088
984
  case "project.update": {
1089
985
  if (!name) throw new Error("name required for project.update");
1090
- data = await updateProject({ projectId: id, name });
986
+ data = await updateProject({ projectId, name });
1091
987
  summary = `Updated project "${name}"`;
1092
988
  break;
1093
989
  }
1094
990
  case "project.delete": {
1095
- data = await deleteProject({ projectId: id });
1096
- summary = `Deleted project ${id ?? "default"}`;
991
+ data = await deleteProject({ projectId });
992
+ summary = `Deleted project ${projectId ?? "default"}`;
1097
993
  break;
1098
994
  }
1099
995
  // Flows
1100
996
  case "flow.list": {
1101
997
  data = await listFlows({
1102
- projectId: id,
998
+ projectId,
1103
999
  sort,
1104
1000
  order,
1105
1001
  includeDeleted
@@ -1108,70 +1004,97 @@ function registerApiTool(server2) {
1108
1004
  break;
1109
1005
  }
1110
1006
  case "flow.get": {
1111
- if (!id) throw new Error("id required for flow.get");
1112
- data = await getFlow({ flowId: id, fields });
1113
- summary = `Flow "${data.name}" (${id})`;
1007
+ if (!flowId) throw new Error("flowId required for flow.get");
1008
+ data = await getFlow({ flowId, projectId, fields });
1009
+ summary = `Flow "${data.name}" (${flowId})`;
1114
1010
  break;
1115
1011
  }
1116
1012
  case "flow.create": {
1117
1013
  if (!name) throw new Error("name required for flow.create");
1118
1014
  if (!content) throw new Error("content required for flow.create");
1119
- data = await createFlow({ name, content });
1015
+ data = await createFlow({ name, content, projectId });
1120
1016
  summary = `Created flow "${name}" (${data.id})`;
1121
1017
  break;
1122
1018
  }
1123
1019
  case "flow.update": {
1124
- if (!id) throw new Error("id required for flow.update");
1020
+ if (!flowId) throw new Error("flowId required for flow.update");
1125
1021
  data = await updateFlow({
1126
- flowId: id,
1022
+ flowId,
1127
1023
  name,
1128
1024
  content,
1025
+ projectId,
1129
1026
  mergePatch: patch ?? true
1130
1027
  });
1131
- summary = `Updated flow ${id}`;
1028
+ summary = `Updated flow ${flowId}`;
1132
1029
  break;
1133
1030
  }
1134
1031
  case "flow.delete": {
1135
- if (!id) throw new Error("id required for flow.delete");
1136
- data = await deleteFlow({ flowId: id });
1137
- summary = `Deleted flow ${id}`;
1032
+ if (!flowId) throw new Error("flowId required for flow.delete");
1033
+ data = await deleteFlow({ flowId, projectId });
1034
+ summary = `Deleted flow ${flowId}`;
1138
1035
  break;
1139
1036
  }
1140
1037
  case "flow.duplicate": {
1141
- if (!id) throw new Error("id required for flow.duplicate");
1142
- data = await duplicateFlow({ flowId: id, name });
1143
- summary = `Duplicated flow ${id}`;
1038
+ if (!flowId) throw new Error("flowId required for flow.duplicate");
1039
+ data = await duplicateFlow({ flowId, name, projectId });
1040
+ summary = `Duplicated flow ${flowId}`;
1144
1041
  break;
1145
1042
  }
1146
1043
  // Deploy
1147
1044
  case "deploy": {
1148
- if (!id) throw new Error("id (flowId) required for deploy");
1045
+ if (!flowId) throw new Error("flowId required for deploy");
1149
1046
  const progressToken = extra._meta?.progressToken;
1047
+ const DEPLOY_TIMEOUT_MS = 9e4;
1048
+ const timeoutSignal = AbortSignal.timeout(DEPLOY_TIMEOUT_MS);
1049
+ const combinedAbort = new AbortController();
1050
+ const onAbort = () => combinedAbort.abort();
1051
+ timeoutSignal.addEventListener("abort", onAbort);
1052
+ extra.signal?.addEventListener("abort", onAbort);
1150
1053
  data = await deploy({
1151
- flowId: id,
1054
+ flowId,
1055
+ projectId,
1152
1056
  wait: wait ?? true,
1153
1057
  flowName,
1058
+ timeout: DEPLOY_TIMEOUT_MS,
1154
1059
  onStatus: (s, sub) => {
1155
1060
  if (!progressToken) return;
1061
+ const key = sub ? `${s}:${sub}` : s;
1156
1062
  const stages = {
1157
- bundling: 15,
1158
- deploying: 55,
1159
- published: 100,
1160
- active: 100,
1161
- failed: 100
1063
+ "bundling:building": {
1064
+ progress: 20,
1065
+ label: "Building bundle..."
1066
+ },
1067
+ "deploying:publishing": {
1068
+ progress: 60,
1069
+ label: "Publishing to CDN..."
1070
+ },
1071
+ "deploying:provisioning": {
1072
+ progress: 60,
1073
+ label: "Provisioning container..."
1074
+ },
1075
+ "deploying:starting": {
1076
+ progress: 80,
1077
+ label: "Starting container..."
1078
+ },
1079
+ published: { progress: 100, label: "Published" },
1080
+ active: { progress: 100, label: "Active" },
1081
+ failed: { progress: 100, label: "Failed" }
1162
1082
  };
1083
+ const stage = stages[key] ?? stages[s] ?? { progress: 10, label: key };
1163
1084
  extra.sendNotification({
1164
1085
  method: "notifications/progress",
1165
1086
  params: {
1166
1087
  progressToken,
1167
- progress: stages[s] ?? 0,
1088
+ progress: stage.progress,
1168
1089
  total: 100,
1169
- message: sub ? `${s}:${sub}` : s
1090
+ message: stage.label
1170
1091
  }
1171
1092
  });
1172
1093
  },
1173
- signal: extra.signal
1094
+ signal: combinedAbort.signal
1174
1095
  });
1096
+ timeoutSignal.removeEventListener("abort", onAbort);
1097
+ extra.signal?.removeEventListener("abort", onAbort);
1175
1098
  const st = data.status;
1176
1099
  const deployData = data;
1177
1100
  if (st === "failed") {
@@ -1180,7 +1103,7 @@ function registerApiTool(server2) {
1180
1103
  next: ["Run flow_validate to check your configuration"]
1181
1104
  });
1182
1105
  } else {
1183
- summary = `Deployed flow ${id} \u2014 status: ${st}`;
1106
+ summary = `Deployed flow ${flowId} \u2014 status: ${st}`;
1184
1107
  const publicUrl = deployData.publicUrl;
1185
1108
  const containerUrl = deployData.containerUrl;
1186
1109
  const deployType = deployData.type;
@@ -1202,21 +1125,21 @@ function registerApiTool(server2) {
1202
1125
  }
1203
1126
  // Deployments
1204
1127
  case "deployment.get": {
1205
- if (!id)
1128
+ if (!flowId)
1206
1129
  throw new Error(
1207
- "id (flowId or slug) required for deployment.get"
1130
+ "flowId (flowId or slug) required for deployment.get"
1208
1131
  );
1209
1132
  try {
1210
- data = await getDeployment({ flowId: id, flowName });
1133
+ data = await getDeployment({ flowId, flowName });
1211
1134
  } catch {
1212
- data = await getDeploymentBySlug({ slug: id });
1135
+ data = await getDeploymentBySlug({ slug: flowId });
1213
1136
  }
1214
- summary = `Deployment ${data.slug ?? id} \u2014 ${data.status}`;
1137
+ summary = `Deployment ${data.slug ?? flowId} \u2014 ${data.status}`;
1215
1138
  break;
1216
1139
  }
1217
1140
  case "deployment.list": {
1218
1141
  data = await listDeployments({
1219
- projectId: id,
1142
+ projectId,
1220
1143
  type,
1221
1144
  status
1222
1145
  });
@@ -1228,15 +1151,15 @@ function registerApiTool(server2) {
1228
1151
  throw new Error(
1229
1152
  "type (web/server) required for deployment.create"
1230
1153
  );
1231
- data = await createDep({ type, label: name, projectId: id });
1154
+ data = await createDep({ type, label: name, projectId });
1232
1155
  summary = `Created ${type} deployment ${data.slug}`;
1233
1156
  break;
1234
1157
  }
1235
1158
  case "deployment.delete": {
1236
- if (!id)
1237
- throw new Error("id (slug) required for deployment.delete");
1238
- data = await deleteDep({ slug: id });
1239
- summary = `Deleted deployment ${id}`;
1159
+ if (!flowId)
1160
+ throw new Error("flowId (slug) required for deployment.delete");
1161
+ data = await deleteDep({ slug: flowId });
1162
+ summary = `Deleted deployment ${flowId}`;
1240
1163
  break;
1241
1164
  }
1242
1165
  default:
@@ -1247,6 +1170,22 @@ function registerApiTool(server2) {
1247
1170
  return mcpResult9({ action, ok: true, data }, summary);
1248
1171
  } catch (error) {
1249
1172
  const msg = error instanceof Error ? error.message : "";
1173
+ const name2 = error instanceof Error ? error.name : "";
1174
+ if (action === "deploy" && (name2 === "AbortError" || name2 === "TimeoutError" || msg.includes("abort"))) {
1175
+ return mcpResult9(
1176
+ {
1177
+ action,
1178
+ ok: true,
1179
+ data: { status: "deploying", flowId }
1180
+ },
1181
+ `Deploy in progress (timed out waiting). Use deployment.list with projectId to check status.`,
1182
+ {
1183
+ next: [
1184
+ 'Use api(action: "deployment.list") to check current status'
1185
+ ]
1186
+ }
1187
+ );
1188
+ }
1250
1189
  if (msg.includes("401") || msg.includes("403") || msg.includes("Unauthorized"))
1251
1190
  return mcpError9(
1252
1191
  error,
@@ -1268,14 +1207,17 @@ import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
1268
1207
  import { fetchPackageSchema } from "@walkeros/core";
1269
1208
  function registerPackageSchemaResources(server2) {
1270
1209
  const template = new ResourceTemplate("walkeros://schema/{packageName}", {
1271
- list: async () => ({
1272
- resources: PACKAGE_REGISTRY.map((pkg) => ({
1273
- uri: `walkeros://schema/${encodeURIComponent(pkg.name)}`,
1274
- name: pkg.name,
1275
- description: `Schema and examples for ${pkg.name}`,
1276
- mimeType: "application/json"
1277
- }))
1278
- })
1210
+ list: async () => {
1211
+ const catalog = await fetchCatalog();
1212
+ return {
1213
+ resources: catalog.map((pkg) => ({
1214
+ uri: `walkeros://schema/${encodeURIComponent(pkg.name)}`,
1215
+ name: pkg.name,
1216
+ description: `Schema and examples for ${pkg.name}`,
1217
+ mimeType: "application/json"
1218
+ }))
1219
+ };
1220
+ }
1279
1221
  });
1280
1222
  server2.registerResource(
1281
1223
  "package-schema",
@@ -1517,30 +1459,33 @@ function registerReferenceResources(server2) {
1517
1459
  description: "Complete walkerOS package catalog \u2014 all sources, destinations, transformers, and stores",
1518
1460
  mimeType: "application/json"
1519
1461
  },
1520
- async () => ({
1521
- contents: [
1522
- {
1523
- uri: "walkeros://reference/packages",
1524
- text: JSON.stringify(PACKAGE_REGISTRY, null, 2),
1525
- mimeType: "application/json"
1526
- }
1527
- ]
1528
- })
1462
+ async () => {
1463
+ const catalog = await fetchCatalog();
1464
+ return {
1465
+ contents: [
1466
+ {
1467
+ uri: "walkeros://reference/packages",
1468
+ text: JSON.stringify(catalog, null, 2),
1469
+ mimeType: "application/json"
1470
+ }
1471
+ ]
1472
+ };
1473
+ }
1529
1474
  );
1530
1475
  }
1531
1476
 
1532
1477
  // src/prompts/add-step.ts
1533
- import { z as z9 } from "zod";
1478
+ import { z as z11 } from "zod";
1534
1479
  function registerAddStepPrompt(server2) {
1535
1480
  server2.registerPrompt(
1536
1481
  "add-step",
1537
1482
  {
1538
1483
  description: "Add a source, destination, transformer, or store step to a flow configuration. Guides through package selection, config scaffolding, and wiring.",
1539
1484
  argsSchema: {
1540
- stepType: z9.string().optional().describe(
1485
+ stepType: z11.string().optional().describe(
1541
1486
  "Type of step to add: source, destination, transformer, or store"
1542
1487
  ),
1543
- flowPath: z9.string().optional().describe("Path to the flow.json file to modify")
1488
+ flowPath: z11.string().optional().describe("Path to the flow.json file to modify")
1544
1489
  }
1545
1490
  },
1546
1491
  async ({ stepType, flowPath }) => ({
@@ -1554,7 +1499,7 @@ function registerAddStepPrompt(server2) {
1554
1499
  "",
1555
1500
  "Follow these steps:",
1556
1501
  `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.`,
1557
- `2. Use package_get with section="hints" to read the selected package's configuration guidance.`,
1502
+ `2. Use package_get to read the package's config schema (schemas.config contains the full config shape: base fields like consent/require/logger + package-specific settings). Use section="hints" for additional guidance.`,
1558
1503
  '3. Use package_get with section="examples" to see working configuration examples.',
1559
1504
  "4. Scaffold the step config using the package schemas \u2014 include required settings with placeholder values.",
1560
1505
  "5. Wire the step into the flow: add to packages section (with version if needed), connect via next/before chains if needed.",
@@ -1580,14 +1525,14 @@ function registerAddStepPrompt(server2) {
1580
1525
  }
1581
1526
 
1582
1527
  // src/prompts/setup-mapping.ts
1583
- import { z as z10 } from "zod";
1528
+ import { z as z12 } from "zod";
1584
1529
  function registerSetupMappingPrompt(server2) {
1585
1530
  server2.registerPrompt(
1586
1531
  "setup-mapping",
1587
1532
  {
1588
1533
  description: "Set up event mapping for any step in a flow. Teaches mapping syntax and uses package examples as templates.",
1589
1534
  argsSchema: {
1590
- stepName: z10.string().optional().describe('Step name in the flow (e.g., "gtag", "meta", "express")')
1535
+ stepName: z12.string().optional().describe('Step name in the flow (e.g., "gtag", "meta", "express")')
1591
1536
  }
1592
1537
  },
1593
1538
  async ({ stepName }) => ({
@@ -1619,14 +1564,14 @@ function registerSetupMappingPrompt(server2) {
1619
1564
  }
1620
1565
 
1621
1566
  // src/prompts/manage-contract.ts
1622
- import { z as z11 } from "zod";
1567
+ import { z as z13 } from "zod";
1623
1568
  function registerManageContractPrompt(server2) {
1624
1569
  server2.registerPrompt(
1625
1570
  "manage-contract",
1626
1571
  {
1627
1572
  description: "Create or update event contracts for a flow. Can generate contracts from existing mappings or scaffold mappings from contracts.",
1628
1573
  argsSchema: {
1629
- direction: z11.string().optional().describe(
1574
+ direction: z13.string().optional().describe(
1630
1575
  'Direction: "from-mappings" (extract contract from existing mappings), "from-scratch" (create new contract), or "to-mappings" (scaffold mappings from contract)'
1631
1576
  )
1632
1577
  }
@@ -1664,14 +1609,14 @@ function registerManageContractPrompt(server2) {
1664
1609
  }
1665
1610
 
1666
1611
  // src/prompts/use-definitions.ts
1667
- import { z as z12 } from "zod";
1612
+ import { z as z14 } from "zod";
1668
1613
  function registerUseDefinitionsPrompt(server2) {
1669
1614
  server2.registerPrompt(
1670
1615
  "use-definitions",
1671
1616
  {
1672
1617
  description: "Extract shared patterns into definitions and variables for DRY, environment-aware flow configurations.",
1673
1618
  argsSchema: {
1674
- flowPath: z12.string().optional().describe("Path to the flow.json file to analyze")
1619
+ flowPath: z14.string().optional().describe("Path to the flow.json file to analyze")
1675
1620
  }
1676
1621
  },
1677
1622
  async ({ flowPath }) => ({
@@ -1715,7 +1660,7 @@ function registerUseDefinitionsPrompt(server2) {
1715
1660
  var server = new McpServer(
1716
1661
  {
1717
1662
  name: "walkeros-flow",
1718
- version: "3.0.2"
1663
+ version: "3.1.0"
1719
1664
  },
1720
1665
  {
1721
1666
  instructions: `walkerOS is an open-source, privacy-first event data collection platform. Define event pipelines as code using JSON flow configurations.
@@ -1751,7 +1696,7 @@ Key rules:
1751
1696
 
1752
1697
  ## Getting Started
1753
1698
 
1754
- 1. \`flow_load({ platform: "web" })\` or \`flow_load({ source: "./flow.json" })\` \u2014 create or load a flow
1699
+ 1. \`flow_load({ platform: "web" })\` or \`flow_load({ source: "./flow.json" })\` \u2014 create or load a flow (also accepts inline JSON strings or URLs)
1755
1700
  2. \`package_search({ type: "destination", platform: "web" })\` \u2014 discover available packages
1756
1701
  3. Use the \`add-step\` prompt to add sources, destinations, transformers, or stores
1757
1702
  4. Use the \`setup-mapping\` prompt to configure event transformations
@@ -1768,7 +1713,7 @@ Read these before constructing configs manually: \`walkeros://reference/flow-sch
1768
1713
 
1769
1714
  ## Key Concepts
1770
1715
 
1771
- - **Steps** are sources, destinations, transformers, or stores \u2014 each backed by an npm package. Use \`package_search\` to browse, \`package_get\` for schemas and examples.
1716
+ - **Steps** are sources, destinations, transformers, or stores \u2014 each backed by an npm package. Use \`package_search\` to browse, \`package_get\` for schemas and examples. \`package_get\` returns \`schemas.config\` \u2014 a merged JSON Schema combining base config fields (consent, require, logger, mapping, etc.) with the package's typed settings. Non-config schemas (mapping rules, utility schemas) remain as sibling keys.
1772
1717
  - **Mapping** transforms events using data/map/loop/set/condition rules. Same syntax on sources and destinations. Mapping rules use NESTED entity \u2192 action keying: event name "product add" maps to \`{ "product": { "add": Rule } }\`. Wildcards: \`{ "*": { "view": Rule } }\`.
1773
1718
  - **Contracts** define event schemas using entity-action keying. Can generate FROM mappings or scaffold mappings FROM contracts.
1774
1719
  - **Variables** ($var, $env, $def, $code, $store) enable DRY, environment-aware config. Use the \`use-definitions\` prompt to extract shared patterns.