@apicircle/mcp-server 1.0.1 → 1.0.2

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.cjs CHANGED
@@ -24,7 +24,10 @@ __export(index_exports, {
24
24
  InMemoryWorkspaceProvider: () => InMemoryWorkspaceProvider,
25
25
  InProcessMockController: () => InProcessMockController,
26
26
  McpHost: () => McpHost,
27
+ MultiWorkspaceProvider: () => MultiWorkspaceProvider,
28
+ SingleWorkspaceAdapter: () => SingleWorkspaceAdapter,
27
29
  TOOL_REGISTRY: () => TOOL_REGISTRY,
30
+ WorkspaceNotFoundError: () => WorkspaceNotFoundError,
28
31
  createMcpServer: () => createMcpServer,
29
32
  getTool: () => getTool
30
33
  });
@@ -462,18 +465,37 @@ function renderRust(req) {
462
465
  return lines.join("\n");
463
466
  }
464
467
 
465
- // src/tools/crud.ts
468
+ // src/tools/workspaceList.ts
466
469
  var import_zod4 = require("zod");
470
+ var workspaceListTool = {
471
+ name: "workspace.list",
472
+ description: "List every workspace registered with this server, including which one is currently active. Returns id, display name, last-opened timestamp, and a per-workspace summary (request count, environment count, mock-server count, plan count). Use this BEFORE drilling into a specific workspace via other tools \u2014 pass the resulting `id` as `workspaceId` to `workspace.read` or related reads when you want to scope to a non-active workspace.",
473
+ inputSchema: import_zod4.z.object({}),
474
+ async handler(_input, ctx) {
475
+ const summaries = await ctx.workspaces.list();
476
+ return {
477
+ activeWorkspaceId: ctx.workspaces.activeId(),
478
+ workspaceCount: summaries.length,
479
+ workspaces: summaries,
480
+ // Plain-text hint the AI surfaces when telling the user. Cheap to
481
+ // generate here and saves round-trips on disambiguation prompts.
482
+ hint: summaries.length === 0 ? "No workspaces are registered yet. The user should open the desktop app once or run `apicircle workspaces create <name>` from the terminal." : summaries.length === 1 ? `Only one workspace ("${summaries[0].name}") is registered \u2014 most tools will default to it without a workspaceId.` : `Multiple workspaces are registered. Pass the desired \`id\` as \`workspaceId\` to other tools to scope reads/writes to that workspace; the active one ("${summaries.find((w) => w.isActive)?.name ?? "(none)"}") is used by default.`
483
+ };
484
+ }
485
+ };
486
+
487
+ // src/tools/crud.ts
488
+ var import_zod5 = require("zod");
467
489
  var import_shared2 = require("@apicircle/shared");
468
- var HTTP_METHOD = import_zod4.z.enum(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"]);
490
+ var HTTP_METHOD = import_zod5.z.enum(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"]);
469
491
  var requestCreateTool = {
470
492
  name: "request.create",
471
493
  description: "Create a new request from explicit fields and persist it.",
472
- inputSchema: import_zod4.z.object({
473
- name: import_zod4.z.string().default("New request"),
494
+ inputSchema: import_zod5.z.object({
495
+ name: import_zod5.z.string().default("New request"),
474
496
  method: HTTP_METHOD.default("GET"),
475
- url: import_zod4.z.string().default(""),
476
- folderId: import_zod4.z.string().nullable().optional()
497
+ url: import_zod5.z.string().default(""),
498
+ folderId: import_zod5.z.string().nullable().optional()
477
499
  }),
478
500
  async handler(input, ctx) {
479
501
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -502,7 +524,7 @@ var requestCreateTool = {
502
524
  var requestReadTool = {
503
525
  name: "request.read",
504
526
  description: "Read a request by id, or list summaries (id, name, method, url) when no id is provided.",
505
- inputSchema: import_zod4.z.object({ id: import_zod4.z.string().optional() }),
527
+ inputSchema: import_zod5.z.object({ id: import_zod5.z.string().optional() }),
506
528
  async handler(input, ctx) {
507
529
  const state = await ctx.workspace.read();
508
530
  if (input.id) {
@@ -523,13 +545,13 @@ var requestReadTool = {
523
545
  var requestUpdateTool = {
524
546
  name: "request.update",
525
547
  description: "Patch fields on an existing request.",
526
- inputSchema: import_zod4.z.object({
527
- id: import_zod4.z.string(),
528
- patch: import_zod4.z.object({
529
- name: import_zod4.z.string().optional(),
548
+ inputSchema: import_zod5.z.object({
549
+ id: import_zod5.z.string(),
550
+ patch: import_zod5.z.object({
551
+ name: import_zod5.z.string().optional(),
530
552
  method: HTTP_METHOD.optional(),
531
- url: import_zod4.z.string().optional(),
532
- folderId: import_zod4.z.string().nullable().optional()
553
+ url: import_zod5.z.string().optional(),
554
+ folderId: import_zod5.z.string().nullable().optional()
533
555
  }).strict()
534
556
  }),
535
557
  async handler(input, ctx) {
@@ -544,7 +566,7 @@ var requestUpdateTool = {
544
566
  var requestDeleteTool = {
545
567
  name: "request.delete",
546
568
  description: "Delete a request by id.",
547
- inputSchema: import_zod4.z.object({ id: import_zod4.z.string() }),
569
+ inputSchema: import_zod5.z.object({ id: import_zod5.z.string() }),
548
570
  async handler(input, ctx) {
549
571
  const out = await ctx.workspace.apply({ kind: "request.delete", id: input.id });
550
572
  return { changedIds: out.changedIds };
@@ -553,9 +575,9 @@ var requestDeleteTool = {
553
575
  var folderCreateTool = {
554
576
  name: "folder.create",
555
577
  description: "Create a folder under an optional parent folder.",
556
- inputSchema: import_zod4.z.object({
557
- name: import_zod4.z.string().default("New folder"),
558
- parentId: import_zod4.z.string().nullable().optional()
578
+ inputSchema: import_zod5.z.object({
579
+ name: import_zod5.z.string().default("New folder"),
580
+ parentId: import_zod5.z.string().nullable().optional()
559
581
  }),
560
582
  async handler(input, ctx) {
561
583
  const folder = {
@@ -570,7 +592,7 @@ var folderCreateTool = {
570
592
  var folderReadTool = {
571
593
  name: "folder.read",
572
594
  description: "Read a folder by id, or list all folders when no id is provided.",
573
- inputSchema: import_zod4.z.object({ id: import_zod4.z.string().optional() }),
595
+ inputSchema: import_zod5.z.object({ id: import_zod5.z.string().optional() }),
574
596
  async handler(input, ctx) {
575
597
  const state = await ctx.workspace.read();
576
598
  if (input.id) {
@@ -586,9 +608,9 @@ var folderReadTool = {
586
608
  var folderUpdateTool = {
587
609
  name: "folder.update",
588
610
  description: "Move a folder to a new parent (or to root with parentId: null).",
589
- inputSchema: import_zod4.z.object({
590
- id: import_zod4.z.string(),
591
- parentId: import_zod4.z.string().nullable()
611
+ inputSchema: import_zod5.z.object({
612
+ id: import_zod5.z.string(),
613
+ parentId: import_zod5.z.string().nullable()
592
614
  }),
593
615
  async handler(input, ctx) {
594
616
  const out = await ctx.workspace.apply({
@@ -602,23 +624,23 @@ var folderUpdateTool = {
602
624
  var folderDeleteTool = {
603
625
  name: "folder.delete",
604
626
  description: "Delete a folder. Direct children (sub-folders + requests) are reparented to the deleted folder's parent.",
605
- inputSchema: import_zod4.z.object({ id: import_zod4.z.string() }),
627
+ inputSchema: import_zod5.z.object({ id: import_zod5.z.string() }),
606
628
  async handler(input, ctx) {
607
629
  const out = await ctx.workspace.apply({ kind: "folder.delete", id: input.id });
608
630
  return { changedIds: out.changedIds };
609
631
  }
610
632
  };
611
- var VARIABLE = import_zod4.z.object({
612
- key: import_zod4.z.string(),
613
- value: import_zod4.z.string(),
614
- encrypted: import_zod4.z.boolean().default(false)
633
+ var VARIABLE = import_zod5.z.object({
634
+ key: import_zod5.z.string(),
635
+ value: import_zod5.z.string(),
636
+ encrypted: import_zod5.z.boolean().default(false)
615
637
  });
616
638
  var environmentCreateTool = {
617
639
  name: "environment.create",
618
640
  description: "Create a new environment (or upsert one with the same name).",
619
- inputSchema: import_zod4.z.object({
620
- name: import_zod4.z.string(),
621
- variables: import_zod4.z.array(VARIABLE).default([])
641
+ inputSchema: import_zod5.z.object({
642
+ name: import_zod5.z.string(),
643
+ variables: import_zod5.z.array(VARIABLE).default([])
622
644
  }),
623
645
  async handler(input, ctx) {
624
646
  const env = { name: input.name, variables: input.variables };
@@ -629,7 +651,7 @@ var environmentCreateTool = {
629
651
  var environmentReadTool = {
630
652
  name: "environment.read",
631
653
  description: "Read environments \u2014 pass `name` for one, or omit for the full list.",
632
- inputSchema: import_zod4.z.object({ name: import_zod4.z.string().optional() }),
654
+ inputSchema: import_zod5.z.object({ name: import_zod5.z.string().optional() }),
633
655
  async handler(input, ctx) {
634
656
  const state = await ctx.workspace.read();
635
657
  if (input.name) {
@@ -646,9 +668,9 @@ var environmentReadTool = {
646
668
  var environmentUpdateTool = {
647
669
  name: "environment.update",
648
670
  description: "Replace the variables list of an environment.",
649
- inputSchema: import_zod4.z.object({
650
- name: import_zod4.z.string(),
651
- variables: import_zod4.z.array(VARIABLE)
671
+ inputSchema: import_zod5.z.object({
672
+ name: import_zod5.z.string(),
673
+ variables: import_zod5.z.array(VARIABLE)
652
674
  }),
653
675
  async handler(input, ctx) {
654
676
  const out = await ctx.workspace.apply({
@@ -661,7 +683,7 @@ var environmentUpdateTool = {
661
683
  var environmentDeleteTool = {
662
684
  name: "environment.delete",
663
685
  description: "Delete an environment by name.",
664
- inputSchema: import_zod4.z.object({ name: import_zod4.z.string() }),
686
+ inputSchema: import_zod5.z.object({ name: import_zod5.z.string() }),
665
687
  async handler(input, ctx) {
666
688
  const out = await ctx.workspace.apply({ kind: "environment.delete", name: input.name });
667
689
  return { changedIds: out.changedIds };
@@ -670,7 +692,7 @@ var environmentDeleteTool = {
670
692
  var environmentSetActiveTool = {
671
693
  name: "environment.set_active",
672
694
  description: "Set (or clear) the active environment. Pass `name: null` to deactivate the current environment.",
673
- inputSchema: import_zod4.z.object({ name: import_zod4.z.string().nullable() }),
695
+ inputSchema: import_zod5.z.object({ name: import_zod5.z.string().nullable() }),
674
696
  async handler(input, ctx) {
675
697
  const out = await ctx.workspace.apply({
676
698
  kind: "environment.setActive",
@@ -682,18 +704,18 @@ var environmentSetActiveTool = {
682
704
  var environmentSetPriorityTool = {
683
705
  name: "environment.set_priority",
684
706
  description: 'Replace the global environment priority order (highest priority first). Strings are interpreted as local env names. To target a linked env, pass `{ kind: "linked", linkedWorkspaceId, envName }` instead.',
685
- inputSchema: import_zod4.z.object({
686
- order: import_zod4.z.array(
687
- import_zod4.z.union([
688
- import_zod4.z.string(),
689
- import_zod4.z.object({
690
- kind: import_zod4.z.literal("local"),
691
- name: import_zod4.z.string()
707
+ inputSchema: import_zod5.z.object({
708
+ order: import_zod5.z.array(
709
+ import_zod5.z.union([
710
+ import_zod5.z.string(),
711
+ import_zod5.z.object({
712
+ kind: import_zod5.z.literal("local"),
713
+ name: import_zod5.z.string()
692
714
  }),
693
- import_zod4.z.object({
694
- kind: import_zod4.z.literal("linked"),
695
- linkedWorkspaceId: import_zod4.z.string(),
696
- envName: import_zod4.z.string()
715
+ import_zod5.z.object({
716
+ kind: import_zod5.z.literal("linked"),
717
+ linkedWorkspaceId: import_zod5.z.string(),
718
+ envName: import_zod5.z.string()
697
719
  })
698
720
  ])
699
721
  )
@@ -710,7 +732,7 @@ var environmentSetPriorityTool = {
710
732
  var environmentExportTool = {
711
733
  name: "environment.export",
712
734
  description: "Serialize an environment to a portable JSON string. Encrypted variables drop their value (only `secretKeyId` survives) so the export can be safely pasted elsewhere \u2014 re-attach secrets locally on the receiving side.",
713
- inputSchema: import_zod4.z.object({ name: import_zod4.z.string() }),
735
+ inputSchema: import_zod5.z.object({ name: import_zod5.z.string() }),
714
736
  async handler(input, ctx) {
715
737
  const state = await ctx.workspace.read();
716
738
  const env = state.synced.environments.items[input.name];
@@ -728,9 +750,9 @@ var environmentExportTool = {
728
750
  var environmentImportTool = {
729
751
  name: "environment.import",
730
752
  description: "Import an environment from the JSON shape produced by `environment.export`. When a target with the same name exists, pass `overwrite: true` to replace it, otherwise the import is rejected.",
731
- inputSchema: import_zod4.z.object({
732
- json: import_zod4.z.string().min(1),
733
- overwrite: import_zod4.z.boolean().default(false)
753
+ inputSchema: import_zod5.z.object({
754
+ json: import_zod5.z.string().min(1),
755
+ overwrite: import_zod5.z.boolean().default(false)
734
756
  }),
735
757
  async handler(input, ctx) {
736
758
  let parsed;
@@ -760,17 +782,17 @@ var environmentImportTool = {
760
782
  return { ok: true, name: env.name, changedIds: out.changedIds };
761
783
  }
762
784
  };
763
- var PLAN_STEP = import_zod4.z.object({
764
- requestId: import_zod4.z.string(),
765
- linkedWorkspaceId: import_zod4.z.string().optional()
785
+ var PLAN_STEP = import_zod5.z.object({
786
+ requestId: import_zod5.z.string(),
787
+ linkedWorkspaceId: import_zod5.z.string().optional()
766
788
  });
767
789
  var planCreateTool = {
768
790
  name: "plan.create",
769
791
  description: "Create a new execution plan (sequence of request steps).",
770
- inputSchema: import_zod4.z.object({
771
- name: import_zod4.z.string().default("New plan"),
772
- steps: import_zod4.z.array(PLAN_STEP).default([]),
773
- envPriorityOrder: import_zod4.z.array(import_zod4.z.string()).default([])
792
+ inputSchema: import_zod5.z.object({
793
+ name: import_zod5.z.string().default("New plan"),
794
+ steps: import_zod5.z.array(PLAN_STEP).default([]),
795
+ envPriorityOrder: import_zod5.z.array(import_zod5.z.string()).default([])
774
796
  }),
775
797
  async handler(input, ctx) {
776
798
  const id = (0, import_shared2.generateId)();
@@ -790,7 +812,7 @@ var planCreateTool = {
790
812
  var planReadTool = {
791
813
  name: "plan.read",
792
814
  description: "Read a plan by id, or list all plans when no id is provided.",
793
- inputSchema: import_zod4.z.object({ id: import_zod4.z.string().optional() }),
815
+ inputSchema: import_zod5.z.object({ id: import_zod5.z.string().optional() }),
794
816
  async handler(input, ctx) {
795
817
  const state = await ctx.workspace.read();
796
818
  if (input.id) {
@@ -806,12 +828,12 @@ var planReadTool = {
806
828
  var planUpdateTool = {
807
829
  name: "plan.update",
808
830
  description: "Patch fields on an existing plan.",
809
- inputSchema: import_zod4.z.object({
810
- id: import_zod4.z.string(),
811
- patch: import_zod4.z.object({
812
- name: import_zod4.z.string().optional(),
813
- steps: import_zod4.z.array(PLAN_STEP).optional(),
814
- envPriorityOrder: import_zod4.z.array(import_zod4.z.string()).optional()
831
+ inputSchema: import_zod5.z.object({
832
+ id: import_zod5.z.string(),
833
+ patch: import_zod5.z.object({
834
+ name: import_zod5.z.string().optional(),
835
+ steps: import_zod5.z.array(PLAN_STEP).optional(),
836
+ envPriorityOrder: import_zod5.z.array(import_zod5.z.string()).optional()
815
837
  }).strict()
816
838
  }),
817
839
  async handler(input, ctx) {
@@ -832,7 +854,7 @@ var planUpdateTool = {
832
854
  var planDeleteTool = {
833
855
  name: "plan.delete",
834
856
  description: "Delete a plan by id. Drops history rows referencing this plan.",
835
- inputSchema: import_zod4.z.object({ id: import_zod4.z.string() }),
857
+ inputSchema: import_zod5.z.object({ id: import_zod5.z.string() }),
836
858
  async handler(input, ctx) {
837
859
  const out = await ctx.workspace.apply({ kind: "plan.delete", id: input.id });
838
860
  return { changedIds: out.changedIds };
@@ -841,11 +863,11 @@ var planDeleteTool = {
841
863
  var planAddStepTool = {
842
864
  name: "plan.add_step",
843
865
  description: "Append a step to an execution plan. Optional `position` (0-based) inserts at that index instead.",
844
- inputSchema: import_zod4.z.object({
845
- planId: import_zod4.z.string(),
846
- requestId: import_zod4.z.string(),
847
- linkedWorkspaceId: import_zod4.z.string().optional(),
848
- position: import_zod4.z.number().int().nonnegative().optional()
866
+ inputSchema: import_zod5.z.object({
867
+ planId: import_zod5.z.string(),
868
+ requestId: import_zod5.z.string(),
869
+ linkedWorkspaceId: import_zod5.z.string().optional(),
870
+ position: import_zod5.z.number().int().nonnegative().optional()
849
871
  }),
850
872
  async handler(input, ctx) {
851
873
  const state = await ctx.workspace.read();
@@ -871,9 +893,9 @@ var planAddStepTool = {
871
893
  var planRemoveStepTool = {
872
894
  name: "plan.remove_step",
873
895
  description: "Remove a step from a plan by 0-based index.",
874
- inputSchema: import_zod4.z.object({
875
- planId: import_zod4.z.string(),
876
- index: import_zod4.z.number().int().nonnegative()
896
+ inputSchema: import_zod5.z.object({
897
+ planId: import_zod5.z.string(),
898
+ index: import_zod5.z.number().int().nonnegative()
877
899
  }),
878
900
  async handler(input, ctx) {
879
901
  const state = await ctx.workspace.read();
@@ -893,9 +915,9 @@ var planRemoveStepTool = {
893
915
  var planReorderStepsTool = {
894
916
  name: "plan.reorder_steps",
895
917
  description: "Replace the plan steps with a new permutation. The supplied indices must reference valid current step indices.",
896
- inputSchema: import_zod4.z.object({
897
- planId: import_zod4.z.string(),
898
- order: import_zod4.z.array(import_zod4.z.number().int().nonnegative())
918
+ inputSchema: import_zod5.z.object({
919
+ planId: import_zod5.z.string(),
920
+ order: import_zod5.z.array(import_zod5.z.number().int().nonnegative())
899
921
  }),
900
922
  async handler(input, ctx) {
901
923
  const state = await ctx.workspace.read();
@@ -917,13 +939,13 @@ var planReorderStepsTool = {
917
939
  return { ok: true, changedIds: out.changedIds };
918
940
  }
919
941
  };
920
- var PLAN_VARIABLE = import_zod4.z.object({ key: import_zod4.z.string(), value: import_zod4.z.string() });
942
+ var PLAN_VARIABLE = import_zod5.z.object({ key: import_zod5.z.string(), value: import_zod5.z.string() });
921
943
  var planSetVariablesTool = {
922
944
  name: "plan.set_variables",
923
945
  description: "Replace the plan-scoped variables. These live highest-priority during plan runs (above environment vars, below context vars).",
924
- inputSchema: import_zod4.z.object({
925
- planId: import_zod4.z.string(),
926
- variables: import_zod4.z.array(PLAN_VARIABLE)
946
+ inputSchema: import_zod5.z.object({
947
+ planId: import_zod5.z.string(),
948
+ variables: import_zod5.z.array(PLAN_VARIABLE)
927
949
  }),
928
950
  async handler(input, ctx) {
929
951
  const state = await ctx.workspace.read();
@@ -939,9 +961,9 @@ var planSetVariablesTool = {
939
961
  var planRunTool = {
940
962
  name: "plan.run",
941
963
  description: "Run a plan headlessly (server-side). Currently returns a not-implemented marker \u2014 full execution requires the Desktop or browser runtime which the MCP host does not own. The Desktop integration overrides this tool with a real runner.",
942
- inputSchema: import_zod4.z.object({
943
- id: import_zod4.z.string(),
944
- withAssertions: import_zod4.z.boolean().default(true)
964
+ inputSchema: import_zod5.z.object({
965
+ id: import_zod5.z.string(),
966
+ withAssertions: import_zod5.z.boolean().default(true)
945
967
  }),
946
968
  async handler(input, ctx) {
947
969
  const state = await ctx.workspace.read();
@@ -955,18 +977,18 @@ var planRunTool = {
955
977
  };
956
978
  }
957
979
  };
958
- var ASSERTION = import_zod4.z.object({
959
- id: import_zod4.z.string().optional(),
960
- kind: import_zod4.z.enum(["status", "header", "json-path", "duration"]),
961
- op: import_zod4.z.enum(["equals", "not-equals", "contains", "lt", "gt", "matches"]),
962
- target: import_zod4.z.string().optional(),
963
- expected: import_zod4.z.union([import_zod4.z.string(), import_zod4.z.number()])
980
+ var ASSERTION = import_zod5.z.object({
981
+ id: import_zod5.z.string().optional(),
982
+ kind: import_zod5.z.enum(["status", "header", "json-path", "duration"]),
983
+ op: import_zod5.z.enum(["equals", "not-equals", "contains", "lt", "gt", "matches"]),
984
+ target: import_zod5.z.string().optional(),
985
+ expected: import_zod5.z.union([import_zod5.z.string(), import_zod5.z.number()])
964
986
  });
965
987
  var assertionCreateTool = {
966
988
  name: "assertion.create",
967
989
  description: "Add an assertion to a request.",
968
- inputSchema: import_zod4.z.object({
969
- requestId: import_zod4.z.string(),
990
+ inputSchema: import_zod5.z.object({
991
+ requestId: import_zod5.z.string(),
970
992
  assertion: ASSERTION
971
993
  }),
972
994
  async handler(input, ctx) {
@@ -985,9 +1007,9 @@ var assertionCreateTool = {
985
1007
  var assertionReadTool = {
986
1008
  name: "assertion.read",
987
1009
  description: "List assertions for a request, or fetch a single assertion by id.",
988
- inputSchema: import_zod4.z.object({
989
- requestId: import_zod4.z.string(),
990
- assertionId: import_zod4.z.string().optional()
1010
+ inputSchema: import_zod5.z.object({
1011
+ requestId: import_zod5.z.string(),
1012
+ assertionId: import_zod5.z.string().optional()
991
1013
  }),
992
1014
  async handler(input, ctx) {
993
1015
  const state = await ctx.workspace.read();
@@ -1003,8 +1025,8 @@ var assertionReadTool = {
1003
1025
  var assertionUpdateTool = {
1004
1026
  name: "assertion.update",
1005
1027
  description: "Replace an existing assertion (matched by `assertion.id`).",
1006
- inputSchema: import_zod4.z.object({
1007
- requestId: import_zod4.z.string(),
1028
+ inputSchema: import_zod5.z.object({
1029
+ requestId: import_zod5.z.string(),
1008
1030
  assertion: ASSERTION.required({ id: true })
1009
1031
  }),
1010
1032
  async handler(input, ctx) {
@@ -1019,9 +1041,9 @@ var assertionUpdateTool = {
1019
1041
  var assertionDeleteTool = {
1020
1042
  name: "assertion.delete",
1021
1043
  description: "Remove an assertion from a request.",
1022
- inputSchema: import_zod4.z.object({
1023
- requestId: import_zod4.z.string(),
1024
- assertionId: import_zod4.z.string()
1044
+ inputSchema: import_zod5.z.object({
1045
+ requestId: import_zod5.z.string(),
1046
+ assertionId: import_zod5.z.string()
1025
1047
  }),
1026
1048
  async handler(input, ctx) {
1027
1049
  const out = await ctx.workspace.apply({
@@ -1034,21 +1056,53 @@ var assertionDeleteTool = {
1034
1056
  };
1035
1057
  var workspaceReadTool = {
1036
1058
  name: "workspace.read",
1037
- description: "Return the full `{ synced, local }` workspace pair. Use sparingly \u2014 entity-specific tools are more efficient for small reads.",
1038
- inputSchema: import_zod4.z.object({}),
1039
- async handler(_input, ctx) {
1040
- return await ctx.workspace.read();
1059
+ description: 'Return the full `{ synced, local }` workspace pair. Pass `workspaceId` to scope to a specific workspace when multiple are registered (call `workspace.list` first to discover ids). When omitted and multiple workspaces exist, the response is a structured "multiple workspaces found" envelope listing each summary so the AI can clarify before drilling in. Use sparingly \u2014 entity-specific tools are more efficient for small reads.',
1060
+ inputSchema: import_zod5.z.object({
1061
+ workspaceId: import_zod5.z.string().min(1).max(256).optional().describe(
1062
+ 'Optional workspace id (from `workspace.list`). Omit to read the active workspace; the tool will switch to the "multiple workspaces" envelope when ambiguous.'
1063
+ )
1064
+ }),
1065
+ async handler(input, ctx) {
1066
+ if (input.workspaceId) {
1067
+ const provider = ctx.workspaces.for(input.workspaceId);
1068
+ const state2 = await provider.read();
1069
+ return {
1070
+ kind: "single",
1071
+ workspaceId: state2.synced.workspaceId,
1072
+ synced: state2.synced,
1073
+ local: state2.local
1074
+ };
1075
+ }
1076
+ const summaries = await ctx.workspaces.list();
1077
+ if (summaries.length > 1) {
1078
+ return {
1079
+ kind: "multiple-workspaces",
1080
+ activeWorkspaceId: ctx.workspaces.activeId(),
1081
+ workspaceCount: summaries.length,
1082
+ workspaces: summaries,
1083
+ hint: `Found ${summaries.length} workspaces. Re-call \`workspace.read\` with \`workspaceId\` set to the desired entry, or call entity-specific tools (which default to the active workspace) when scoping to one workspace is acceptable.`
1084
+ };
1085
+ }
1086
+ const state = await ctx.workspace.read();
1087
+ return {
1088
+ kind: "single",
1089
+ workspaceId: state.synced.workspaceId,
1090
+ synced: state.synced,
1091
+ local: state.local
1092
+ };
1041
1093
  }
1042
1094
  };
1043
1095
  var workspaceWriteTool = {
1044
1096
  name: "workspace.write",
1045
- description: "Bulk-replace the workspace. Pass `synced` and/or `local` to overwrite either side. Mutating tools are preferred \u2014 this is for full-doc imports/exports.",
1046
- inputSchema: import_zod4.z.object({
1047
- synced: import_zod4.z.unknown().optional(),
1048
- local: import_zod4.z.unknown().optional()
1097
+ description: "Bulk-replace the workspace. Pass `synced` and/or `local` to overwrite either side. Use `workspaceId` to target a non-active workspace (omit to write the active one). Mutating tools are preferred \u2014 this is for full-doc imports/exports.",
1098
+ inputSchema: import_zod5.z.object({
1099
+ workspaceId: import_zod5.z.string().min(1).max(256).optional().describe("Optional workspace id; omit to write the active workspace."),
1100
+ synced: import_zod5.z.unknown().optional(),
1101
+ local: import_zod5.z.unknown().optional()
1049
1102
  }),
1050
1103
  async handler(input, ctx) {
1051
- const next = await ctx.workspace.write({
1104
+ const provider = input.workspaceId ? ctx.workspaces.for(input.workspaceId) : ctx.workspace;
1105
+ const next = await provider.write({
1052
1106
  synced: input.synced,
1053
1107
  local: input.local
1054
1108
  });
@@ -1057,16 +1111,16 @@ var workspaceWriteTool = {
1057
1111
  };
1058
1112
 
1059
1113
  // src/tools/history.ts
1060
- var import_zod5 = require("zod");
1114
+ var import_zod6 = require("zod");
1061
1115
  var historyListRunsTool = {
1062
1116
  name: "history.list_runs",
1063
1117
  description: "List request-run history rows in reverse-chronological order. Filter by `requestId`, `ok` (success/failure), or `since`/`until` ISO timestamps. `limit` caps the result set; default 100.",
1064
- inputSchema: import_zod5.z.object({
1065
- requestId: import_zod5.z.string().optional(),
1066
- ok: import_zod5.z.boolean().optional(),
1067
- since: import_zod5.z.string().optional(),
1068
- until: import_zod5.z.string().optional(),
1069
- limit: import_zod5.z.number().int().positive().max(500).default(100)
1118
+ inputSchema: import_zod6.z.object({
1119
+ requestId: import_zod6.z.string().optional(),
1120
+ ok: import_zod6.z.boolean().optional(),
1121
+ since: import_zod6.z.string().optional(),
1122
+ until: import_zod6.z.string().optional(),
1123
+ limit: import_zod6.z.number().int().positive().max(500).default(100)
1070
1124
  }),
1071
1125
  async handler(input, ctx) {
1072
1126
  const state = await ctx.workspace.read();
@@ -1100,7 +1154,7 @@ var historyListRunsTool = {
1100
1154
  var historyGetRunTool = {
1101
1155
  name: "history.get_run",
1102
1156
  description: "Fetch a single history row in full (headers, body preview, assertion results).",
1103
- inputSchema: import_zod5.z.object({ id: import_zod5.z.string() }),
1157
+ inputSchema: import_zod6.z.object({ id: import_zod6.z.string() }),
1104
1158
  async handler(input, ctx) {
1105
1159
  const state = await ctx.workspace.read();
1106
1160
  const run = state.local.history.requestRuns.find((r) => r.id === input.id);
@@ -1111,7 +1165,7 @@ var historyGetRunTool = {
1111
1165
  var historyDeleteRunTool = {
1112
1166
  name: "history.delete_run",
1113
1167
  description: "Delete a single request-run row by id.",
1114
- inputSchema: import_zod5.z.object({ id: import_zod5.z.string() }),
1168
+ inputSchema: import_zod6.z.object({ id: import_zod6.z.string() }),
1115
1169
  async handler(input, ctx) {
1116
1170
  const out = await ctx.workspace.apply({ kind: "history.delete_run", runId: input.id });
1117
1171
  return { deleted: out.changedIds.length, changedIds: out.changedIds };
@@ -1120,8 +1174,8 @@ var historyDeleteRunTool = {
1120
1174
  var historyPurgeTool = {
1121
1175
  name: "history.purge_by_age",
1122
1176
  description: "Drop every request-run + plan-run older than `olderThanDays` days. Pass 0 to clear all history.",
1123
- inputSchema: import_zod5.z.object({
1124
- olderThanDays: import_zod5.z.number().nonnegative()
1177
+ inputSchema: import_zod6.z.object({
1178
+ olderThanDays: import_zod6.z.number().nonnegative()
1125
1179
  }),
1126
1180
  async handler(input, ctx) {
1127
1181
  const olderThanMs = input.olderThanDays * 24 * 60 * 60 * 1e3;
@@ -1131,15 +1185,15 @@ var historyPurgeTool = {
1131
1185
  };
1132
1186
 
1133
1187
  // src/tools/codebase.ts
1134
- var import_zod6 = require("zod");
1188
+ var import_zod7 = require("zod");
1135
1189
  var HTTP_METHODS = ["get", "post", "put", "patch", "delete", "options", "head"];
1136
1190
  var codebaseExtractCollectionTool = {
1137
1191
  name: "codebase.extract_collection",
1138
1192
  description: "Scan source code for HTTP route definitions (Express, FastAPI, NestJS, Spring) and return candidate requests for the user to confirm before import.",
1139
- inputSchema: import_zod6.z.object({
1140
- source: import_zod6.z.string().min(1),
1193
+ inputSchema: import_zod7.z.object({
1194
+ source: import_zod7.z.string().min(1),
1141
1195
  /** Hint to limit which framework patterns to apply. Empty = try all. */
1142
- frameworks: import_zod6.z.array(import_zod6.z.enum(["express", "fastapi", "nest", "spring"])).default([])
1196
+ frameworks: import_zod7.z.array(import_zod7.z.enum(["express", "fastapi", "nest", "spring"])).default([])
1143
1197
  }),
1144
1198
  async handler(input) {
1145
1199
  const enabled = new Set(
@@ -1220,18 +1274,18 @@ var codebaseExtractCollectionTool = {
1220
1274
  };
1221
1275
 
1222
1276
  // src/tools/prompt.ts
1223
- var import_zod7 = require("zod");
1277
+ var import_zod8 = require("zod");
1224
1278
  var import_shared3 = require("@apicircle/shared");
1225
1279
  var promptCreateEnvironmentTool = {
1226
1280
  name: "prompt.create_environment",
1227
1281
  description: "Create a new environment from an LLM-shaped JSON envelope. The model produces { name, variables: [{ key, value, encrypted }] }; this tool validates and persists it.",
1228
- inputSchema: import_zod7.z.object({
1229
- name: import_zod7.z.string(),
1230
- variables: import_zod7.z.array(
1231
- import_zod7.z.object({
1232
- key: import_zod7.z.string(),
1233
- value: import_zod7.z.string(),
1234
- encrypted: import_zod7.z.boolean().default(false)
1282
+ inputSchema: import_zod8.z.object({
1283
+ name: import_zod8.z.string(),
1284
+ variables: import_zod8.z.array(
1285
+ import_zod8.z.object({
1286
+ key: import_zod8.z.string(),
1287
+ value: import_zod8.z.string(),
1288
+ encrypted: import_zod8.z.boolean().default(false)
1235
1289
  })
1236
1290
  )
1237
1291
  }),
@@ -1244,13 +1298,13 @@ var promptCreateEnvironmentTool = {
1244
1298
  var promptCreateAssertionTool = {
1245
1299
  name: "prompt.create_assertion",
1246
1300
  description: 'Add an assertion to a request from an LLM-shaped JSON envelope. Useful when the user asks "assert that the response status is 200 and body.id matches".',
1247
- inputSchema: import_zod7.z.object({
1248
- requestId: import_zod7.z.string(),
1249
- assertion: import_zod7.z.object({
1250
- kind: import_zod7.z.enum(["status", "header", "json-path", "duration"]),
1251
- op: import_zod7.z.enum(["equals", "not-equals", "contains", "lt", "gt", "matches"]),
1252
- target: import_zod7.z.string().optional(),
1253
- expected: import_zod7.z.union([import_zod7.z.string(), import_zod7.z.number()])
1301
+ inputSchema: import_zod8.z.object({
1302
+ requestId: import_zod8.z.string(),
1303
+ assertion: import_zod8.z.object({
1304
+ kind: import_zod8.z.enum(["status", "header", "json-path", "duration"]),
1305
+ op: import_zod8.z.enum(["equals", "not-equals", "contains", "lt", "gt", "matches"]),
1306
+ target: import_zod8.z.string().optional(),
1307
+ expected: import_zod8.z.union([import_zod8.z.string(), import_zod8.z.number()])
1254
1308
  })
1255
1309
  }),
1256
1310
  async handler(input, ctx) {
@@ -1269,10 +1323,10 @@ var promptCreateAssertionTool = {
1269
1323
  var promptCreatePlanTool = {
1270
1324
  name: "prompt.create_plan",
1271
1325
  description: "Create an execution plan from an LLM-shaped JSON envelope. The model produces { name, stepRequestIds: [...] } and the tool validates that each id exists in the workspace before persisting.",
1272
- inputSchema: import_zod7.z.object({
1273
- name: import_zod7.z.string(),
1274
- stepRequestIds: import_zod7.z.array(import_zod7.z.string()).default([]),
1275
- envPriorityOrder: import_zod7.z.array(import_zod7.z.string()).default([])
1326
+ inputSchema: import_zod8.z.object({
1327
+ name: import_zod8.z.string(),
1328
+ stepRequestIds: import_zod8.z.array(import_zod8.z.string()).default([]),
1329
+ envPriorityOrder: import_zod8.z.array(import_zod8.z.string()).default([])
1276
1330
  }),
1277
1331
  async handler(input, ctx) {
1278
1332
  const state = await ctx.workspace.read();
@@ -1301,51 +1355,51 @@ var promptCreatePlanTool = {
1301
1355
  return { ok: true, id, changedIds: out.changedIds };
1302
1356
  }
1303
1357
  };
1304
- var HTTP_METHOD2 = import_zod7.z.enum(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"]);
1305
- var HEADER_OR_QUERY = import_zod7.z.object({
1306
- key: import_zod7.z.string(),
1307
- value: import_zod7.z.string(),
1308
- enabled: import_zod7.z.boolean().default(true)
1358
+ var HTTP_METHOD2 = import_zod8.z.enum(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"]);
1359
+ var HEADER_OR_QUERY = import_zod8.z.object({
1360
+ key: import_zod8.z.string(),
1361
+ value: import_zod8.z.string(),
1362
+ enabled: import_zod8.z.boolean().default(true)
1309
1363
  });
1310
- var REQUEST_BODY = import_zod7.z.object({
1311
- type: import_zod7.z.enum(["none", "json", "text", "xml", "graphql", "urlencoded"]).default("none"),
1312
- content: import_zod7.z.string().default(""),
1313
- variables: import_zod7.z.string().optional()
1364
+ var REQUEST_BODY = import_zod8.z.object({
1365
+ type: import_zod8.z.enum(["none", "json", "text", "xml", "graphql", "urlencoded"]).default("none"),
1366
+ content: import_zod8.z.string().default(""),
1367
+ variables: import_zod8.z.string().optional()
1314
1368
  });
1315
- var PROMPT_AUTH = import_zod7.z.discriminatedUnion("type", [
1316
- import_zod7.z.object({ type: import_zod7.z.literal("none") }),
1317
- import_zod7.z.object({ type: import_zod7.z.literal("inherit") }),
1318
- import_zod7.z.object({ type: import_zod7.z.literal("bearer"), token: import_zod7.z.string().default("") }),
1319
- import_zod7.z.object({
1320
- type: import_zod7.z.literal("basic"),
1321
- username: import_zod7.z.string().default(""),
1322
- password: import_zod7.z.string().default("")
1369
+ var PROMPT_AUTH = import_zod8.z.discriminatedUnion("type", [
1370
+ import_zod8.z.object({ type: import_zod8.z.literal("none") }),
1371
+ import_zod8.z.object({ type: import_zod8.z.literal("inherit") }),
1372
+ import_zod8.z.object({ type: import_zod8.z.literal("bearer"), token: import_zod8.z.string().default("") }),
1373
+ import_zod8.z.object({
1374
+ type: import_zod8.z.literal("basic"),
1375
+ username: import_zod8.z.string().default(""),
1376
+ password: import_zod8.z.string().default("")
1323
1377
  }),
1324
- import_zod7.z.object({
1325
- type: import_zod7.z.literal("api-key"),
1326
- key: import_zod7.z.string().default(""),
1327
- value: import_zod7.z.string().default(""),
1328
- addTo: import_zod7.z.enum(["header", "query", "cookie"]).default("header")
1378
+ import_zod8.z.object({
1379
+ type: import_zod8.z.literal("api-key"),
1380
+ key: import_zod8.z.string().default(""),
1381
+ value: import_zod8.z.string().default(""),
1382
+ addTo: import_zod8.z.enum(["header", "query", "cookie"]).default("header")
1329
1383
  }),
1330
- import_zod7.z.object({
1331
- type: import_zod7.z.literal("custom-header"),
1332
- key: import_zod7.z.string().default(""),
1333
- value: import_zod7.z.string().default("")
1384
+ import_zod8.z.object({
1385
+ type: import_zod8.z.literal("custom-header"),
1386
+ key: import_zod8.z.string().default(""),
1387
+ value: import_zod8.z.string().default("")
1334
1388
  })
1335
1389
  ]);
1336
- var PROMPT_ASSERTION = import_zod7.z.object({
1337
- kind: import_zod7.z.enum(["status", "header", "json-path", "duration"]),
1338
- op: import_zod7.z.enum(["equals", "not-equals", "contains", "lt", "gt", "matches"]),
1339
- target: import_zod7.z.string().optional(),
1340
- expected: import_zod7.z.union([import_zod7.z.string(), import_zod7.z.number()])
1390
+ var PROMPT_ASSERTION = import_zod8.z.object({
1391
+ kind: import_zod8.z.enum(["status", "header", "json-path", "duration"]),
1392
+ op: import_zod8.z.enum(["equals", "not-equals", "contains", "lt", "gt", "matches"]),
1393
+ target: import_zod8.z.string().optional(),
1394
+ expected: import_zod8.z.union([import_zod8.z.string(), import_zod8.z.number()])
1341
1395
  });
1342
- var ENDPOINT_RESPONSE = import_zod7.z.object({
1343
- status: import_zod7.z.number().int().min(100).max(599).default(200),
1344
- jsonBody: import_zod7.z.string().default("{}"),
1345
- contentType: import_zod7.z.string().default("application/json")
1396
+ var ENDPOINT_RESPONSE = import_zod8.z.object({
1397
+ status: import_zod8.z.number().int().min(100).max(599).default(200),
1398
+ jsonBody: import_zod8.z.string().default("{}"),
1399
+ contentType: import_zod8.z.string().default("application/json")
1346
1400
  });
1347
- var VALIDATION_RULE_NL = import_zod7.z.object({
1348
- kind: import_zod7.z.enum([
1401
+ var VALIDATION_RULE_NL = import_zod8.z.object({
1402
+ kind: import_zod8.z.enum([
1349
1403
  "header-required",
1350
1404
  "header-equals",
1351
1405
  "header-matches",
@@ -1356,50 +1410,50 @@ var VALIDATION_RULE_NL = import_zod7.z.object({
1356
1410
  "body-required",
1357
1411
  "content-type-equals"
1358
1412
  ]),
1359
- target: import_zod7.z.string().default(""),
1360
- expected: import_zod7.z.string().optional(),
1361
- message: import_zod7.z.string().optional(),
1362
- enabled: import_zod7.z.boolean().default(true),
1363
- failResponse: import_zod7.z.object({
1364
- status: import_zod7.z.number().int().min(100).max(599).default(400),
1365
- jsonBody: import_zod7.z.string().default('{"error":"validation failed"}')
1413
+ target: import_zod8.z.string().default(""),
1414
+ expected: import_zod8.z.string().optional(),
1415
+ message: import_zod8.z.string().optional(),
1416
+ enabled: import_zod8.z.boolean().default(true),
1417
+ failResponse: import_zod8.z.object({
1418
+ status: import_zod8.z.number().int().min(100).max(599).default(400),
1419
+ jsonBody: import_zod8.z.string().default('{"error":"validation failed"}')
1366
1420
  }).default({})
1367
1421
  });
1368
- var CONDITION_CLAUSE_NL = import_zod7.z.object({
1369
- scope: import_zod7.z.enum(["query", "pathParam", "header", "cookie", "body-json-path"]),
1370
- target: import_zod7.z.string(),
1371
- op: import_zod7.z.enum(["equals", "not-equals", "matches", "gt", "lt", "gte", "lte", "present", "absent"]),
1372
- value: import_zod7.z.string().optional()
1422
+ var CONDITION_CLAUSE_NL = import_zod8.z.object({
1423
+ scope: import_zod8.z.enum(["query", "pathParam", "header", "cookie", "body-json-path"]),
1424
+ target: import_zod8.z.string(),
1425
+ op: import_zod8.z.enum(["equals", "not-equals", "matches", "gt", "lt", "gte", "lte", "present", "absent"]),
1426
+ value: import_zod8.z.string().optional()
1373
1427
  });
1374
- var RESPONSE_RULE_NL = import_zod7.z.object({
1375
- name: import_zod7.z.string(),
1376
- enabled: import_zod7.z.boolean().default(true),
1377
- when: import_zod7.z.array(CONDITION_CLAUSE_NL).default([]),
1378
- response: import_zod7.z.object({
1379
- status: import_zod7.z.number().int().min(100).max(599).default(200),
1380
- jsonBody: import_zod7.z.string().default("{}")
1428
+ var RESPONSE_RULE_NL = import_zod8.z.object({
1429
+ name: import_zod8.z.string(),
1430
+ enabled: import_zod8.z.boolean().default(true),
1431
+ when: import_zod8.z.array(CONDITION_CLAUSE_NL).default([]),
1432
+ response: import_zod8.z.object({
1433
+ status: import_zod8.z.number().int().min(100).max(599).default(200),
1434
+ jsonBody: import_zod8.z.string().default("{}")
1381
1435
  }).default({})
1382
1436
  });
1383
- var MULTIPLIER_NL = import_zod7.z.object({
1384
- name: import_zod7.z.string().optional(),
1385
- source: import_zod7.z.object({
1386
- kind: import_zod7.z.enum(["query", "pathParam", "header", "body-json-path"]),
1387
- key: import_zod7.z.string()
1437
+ var MULTIPLIER_NL = import_zod8.z.object({
1438
+ name: import_zod8.z.string().optional(),
1439
+ source: import_zod8.z.object({
1440
+ kind: import_zod8.z.enum(["query", "pathParam", "header", "body-json-path"]),
1441
+ key: import_zod8.z.string()
1388
1442
  }),
1389
- targetJsonPath: import_zod7.z.string(),
1390
- defaultCount: import_zod7.z.number().int().nonnegative().default(0),
1391
- min: import_zod7.z.number().int().nonnegative().optional(),
1392
- max: import_zod7.z.number().int().nonnegative().optional()
1443
+ targetJsonPath: import_zod8.z.string(),
1444
+ defaultCount: import_zod8.z.number().int().nonnegative().default(0),
1445
+ min: import_zod8.z.number().int().nonnegative().optional(),
1446
+ max: import_zod8.z.number().int().nonnegative().optional()
1393
1447
  });
1394
- var ENDPOINT_INPUT = import_zod7.z.object({
1448
+ var ENDPOINT_INPUT = import_zod8.z.object({
1395
1449
  method: HTTP_METHOD2,
1396
- pathPattern: import_zod7.z.string().min(1),
1397
- name: import_zod7.z.string().optional(),
1398
- description: import_zod7.z.string().optional(),
1450
+ pathPattern: import_zod8.z.string().min(1),
1451
+ name: import_zod8.z.string().optional(),
1452
+ description: import_zod8.z.string().optional(),
1399
1453
  response: ENDPOINT_RESPONSE.optional(),
1400
- validationRules: import_zod7.z.array(VALIDATION_RULE_NL).default([]),
1401
- responseRules: import_zod7.z.array(RESPONSE_RULE_NL).default([]),
1402
- multipliers: import_zod7.z.array(MULTIPLIER_NL).default([])
1454
+ validationRules: import_zod8.z.array(VALIDATION_RULE_NL).default([]),
1455
+ responseRules: import_zod8.z.array(RESPONSE_RULE_NL).default([]),
1456
+ multipliers: import_zod8.z.array(MULTIPLIER_NL).default([])
1403
1457
  });
1404
1458
  function buildRequestBody(input) {
1405
1459
  if (!input) return { type: "none", content: "" };
@@ -1492,17 +1546,17 @@ function patchEndpoint(mock, endpointId, patcher) {
1492
1546
  var promptCreateRequestTool = {
1493
1547
  name: "prompt.create_request",
1494
1548
  description: "Create a fully-shaped request from an LLM-shaped JSON envelope: method, url, headers, query params, body, auth, and inline assertions. The model produces a flat object; this tool generates the request id, normalizes auth (defaults to `inherit` so folder auth wins), and persists.",
1495
- inputSchema: import_zod7.z.object({
1496
- name: import_zod7.z.string().default("New request"),
1549
+ inputSchema: import_zod8.z.object({
1550
+ name: import_zod8.z.string().default("New request"),
1497
1551
  method: HTTP_METHOD2.default("GET"),
1498
- url: import_zod7.z.string().default(""),
1499
- folderId: import_zod7.z.string().nullable().optional(),
1500
- headers: import_zod7.z.array(HEADER_OR_QUERY).default([]),
1501
- queryParams: import_zod7.z.array(HEADER_OR_QUERY).default([]),
1502
- pathParams: import_zod7.z.record(import_zod7.z.string(), import_zod7.z.string()).optional(),
1552
+ url: import_zod8.z.string().default(""),
1553
+ folderId: import_zod8.z.string().nullable().optional(),
1554
+ headers: import_zod8.z.array(HEADER_OR_QUERY).default([]),
1555
+ queryParams: import_zod8.z.array(HEADER_OR_QUERY).default([]),
1556
+ pathParams: import_zod8.z.record(import_zod8.z.string(), import_zod8.z.string()).optional(),
1503
1557
  body: REQUEST_BODY.optional(),
1504
1558
  auth: PROMPT_AUTH.optional(),
1505
- assertions: import_zod7.z.array(PROMPT_ASSERTION).default([])
1559
+ assertions: import_zod8.z.array(PROMPT_ASSERTION).default([])
1506
1560
  }),
1507
1561
  async handler(input, ctx) {
1508
1562
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -1532,19 +1586,19 @@ var promptCreateRequestTool = {
1532
1586
  var promptUpdateRequestTool = {
1533
1587
  name: "prompt.update_request",
1534
1588
  description: "Patch an existing request from an LLM-shaped JSON envelope. Provided fields replace the existing values; omitted fields are left untouched. Arrays (headers, queryParams, assertions) are full replacements when supplied. Returns `{ ok: false, error }` when the id does not resolve.",
1535
- inputSchema: import_zod7.z.object({
1536
- id: import_zod7.z.string(),
1537
- patch: import_zod7.z.object({
1538
- name: import_zod7.z.string().optional(),
1589
+ inputSchema: import_zod8.z.object({
1590
+ id: import_zod8.z.string(),
1591
+ patch: import_zod8.z.object({
1592
+ name: import_zod8.z.string().optional(),
1539
1593
  method: HTTP_METHOD2.optional(),
1540
- url: import_zod7.z.string().optional(),
1541
- folderId: import_zod7.z.string().nullable().optional(),
1542
- headers: import_zod7.z.array(HEADER_OR_QUERY).optional(),
1543
- queryParams: import_zod7.z.array(HEADER_OR_QUERY).optional(),
1544
- pathParams: import_zod7.z.record(import_zod7.z.string(), import_zod7.z.string()).optional(),
1594
+ url: import_zod8.z.string().optional(),
1595
+ folderId: import_zod8.z.string().nullable().optional(),
1596
+ headers: import_zod8.z.array(HEADER_OR_QUERY).optional(),
1597
+ queryParams: import_zod8.z.array(HEADER_OR_QUERY).optional(),
1598
+ pathParams: import_zod8.z.record(import_zod8.z.string(), import_zod8.z.string()).optional(),
1545
1599
  body: REQUEST_BODY.optional(),
1546
1600
  auth: PROMPT_AUTH.optional(),
1547
- assertions: import_zod7.z.array(PROMPT_ASSERTION).optional()
1601
+ assertions: import_zod8.z.array(PROMPT_ASSERTION).optional()
1548
1602
  }).strict()
1549
1603
  }),
1550
1604
  async handler(input, ctx) {
@@ -1572,17 +1626,17 @@ var promptUpdateRequestTool = {
1572
1626
  return { ok: true, changedIds: out.changedIds };
1573
1627
  }
1574
1628
  };
1575
- var FOLDER_TREE_NODE = import_zod7.z.lazy(
1576
- () => import_zod7.z.object({
1577
- name: import_zod7.z.string(),
1578
- children: import_zod7.z.array(FOLDER_TREE_NODE).optional()
1629
+ var FOLDER_TREE_NODE = import_zod8.z.lazy(
1630
+ () => import_zod8.z.object({
1631
+ name: import_zod8.z.string(),
1632
+ children: import_zod8.z.array(FOLDER_TREE_NODE).optional()
1579
1633
  })
1580
1634
  );
1581
1635
  var promptCreateFolderTreeTool = {
1582
1636
  name: "prompt.create_folder_tree",
1583
1637
  description: "Create a recursive folder hierarchy from an LLM-shaped JSON envelope. The model produces `{ parentId?, tree: { name, children?: [...] } }` and this tool walks the tree, generating ids and persisting one folder per node. Returns the list of created ids in pre-order.",
1584
- inputSchema: import_zod7.z.object({
1585
- parentId: import_zod7.z.string().nullable().optional(),
1638
+ inputSchema: import_zod8.z.object({
1639
+ parentId: import_zod8.z.string().nullable().optional(),
1586
1640
  tree: FOLDER_TREE_NODE
1587
1641
  }),
1588
1642
  async handler(input, ctx) {
@@ -1608,9 +1662,9 @@ var promptCreateFolderTreeTool = {
1608
1662
  var promptAddPlanStepsTool = {
1609
1663
  name: "prompt.add_plan_steps",
1610
1664
  description: "Append one or more steps to an existing execution plan from an LLM-shaped JSON envelope. The model produces `{ planId, requestIds: [...] }`; each id is validated against the workspace before any step is appended. Order in the input list is preserved.",
1611
- inputSchema: import_zod7.z.object({
1612
- planId: import_zod7.z.string(),
1613
- requestIds: import_zod7.z.array(import_zod7.z.string()).min(1)
1665
+ inputSchema: import_zod8.z.object({
1666
+ planId: import_zod8.z.string(),
1667
+ requestIds: import_zod8.z.array(import_zod8.z.string()).min(1)
1614
1668
  }),
1615
1669
  async handler(input, ctx) {
1616
1670
  const state = await ctx.workspace.read();
@@ -1640,9 +1694,9 @@ var promptAddPlanStepsTool = {
1640
1694
  var promptSetPlanVariablesTool = {
1641
1695
  name: "prompt.set_plan_variables",
1642
1696
  description: "Replace the plan-scoped variables on an execution plan from an LLM-shaped JSON envelope. The model produces `{ planId, variables: [{ key, value }] }`. Empty array clears all plan variables.",
1643
- inputSchema: import_zod7.z.object({
1644
- planId: import_zod7.z.string(),
1645
- variables: import_zod7.z.array(import_zod7.z.object({ key: import_zod7.z.string(), value: import_zod7.z.string() }))
1697
+ inputSchema: import_zod8.z.object({
1698
+ planId: import_zod8.z.string(),
1699
+ variables: import_zod8.z.array(import_zod8.z.object({ key: import_zod8.z.string(), value: import_zod8.z.string() }))
1646
1700
  }),
1647
1701
  async handler(input, ctx) {
1648
1702
  const state = await ctx.workspace.read();
@@ -1658,10 +1712,10 @@ var promptSetPlanVariablesTool = {
1658
1712
  var promptCreateMockServerTool = {
1659
1713
  name: "prompt.create_mock_server",
1660
1714
  description: "Create a manual-mode mock server with optional inline endpoints from an LLM-shaped JSON envelope. The model produces `{ name, defaultPort?, endpoints: [{ method, pathPattern, name?, response?, validationRules?, responseRules?, multipliers? }] }`; this tool generates ids for the server and every endpoint / rule, then persists in one shot.",
1661
- inputSchema: import_zod7.z.object({
1662
- name: import_zod7.z.string().min(1),
1663
- defaultPort: import_zod7.z.number().int().positive().nullable().optional(),
1664
- endpoints: import_zod7.z.array(ENDPOINT_INPUT).default([])
1715
+ inputSchema: import_zod8.z.object({
1716
+ name: import_zod8.z.string().min(1),
1717
+ defaultPort: import_zod8.z.number().int().positive().nullable().optional(),
1718
+ endpoints: import_zod8.z.array(ENDPOINT_INPUT).default([])
1665
1719
  }),
1666
1720
  async handler(input, ctx) {
1667
1721
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -1688,16 +1742,16 @@ var promptCreateMockServerTool = {
1688
1742
  var promptAddMockEndpointTool = {
1689
1743
  name: "prompt.add_mock_endpoint",
1690
1744
  description: "Append a new endpoint (with optional inline validation rules, response rules, and multipliers) to an existing mock server from an LLM-shaped JSON envelope. All ids are auto-generated; the existing endpoints stay in place.",
1691
- inputSchema: import_zod7.z.object({
1692
- mockId: import_zod7.z.string(),
1745
+ inputSchema: import_zod8.z.object({
1746
+ mockId: import_zod8.z.string(),
1693
1747
  method: HTTP_METHOD2,
1694
- pathPattern: import_zod7.z.string().min(1),
1695
- name: import_zod7.z.string().optional(),
1696
- description: import_zod7.z.string().optional(),
1748
+ pathPattern: import_zod8.z.string().min(1),
1749
+ name: import_zod8.z.string().optional(),
1750
+ description: import_zod8.z.string().optional(),
1697
1751
  response: ENDPOINT_RESPONSE.optional(),
1698
- validationRules: import_zod7.z.array(VALIDATION_RULE_NL).default([]),
1699
- responseRules: import_zod7.z.array(RESPONSE_RULE_NL).default([]),
1700
- multipliers: import_zod7.z.array(MULTIPLIER_NL).default([])
1752
+ validationRules: import_zod8.z.array(VALIDATION_RULE_NL).default([]),
1753
+ responseRules: import_zod8.z.array(RESPONSE_RULE_NL).default([]),
1754
+ multipliers: import_zod8.z.array(MULTIPLIER_NL).default([])
1701
1755
  }),
1702
1756
  async handler(input, ctx) {
1703
1757
  const state = await ctx.workspace.read();
@@ -1719,10 +1773,10 @@ var promptAddMockEndpointTool = {
1719
1773
  var promptSetEndpointValidationRulesTool = {
1720
1774
  name: "prompt.set_endpoint_validation_rules",
1721
1775
  description: "Replace an endpoint's validation rules with an LLM-shaped list. Every rule gets a fresh id; the existing rules are dropped. Empty array clears all validation rules.",
1722
- inputSchema: import_zod7.z.object({
1723
- mockId: import_zod7.z.string(),
1724
- endpointId: import_zod7.z.string(),
1725
- rules: import_zod7.z.array(VALIDATION_RULE_NL)
1776
+ inputSchema: import_zod8.z.object({
1777
+ mockId: import_zod8.z.string(),
1778
+ endpointId: import_zod8.z.string(),
1779
+ rules: import_zod8.z.array(VALIDATION_RULE_NL)
1726
1780
  }),
1727
1781
  async handler(input, ctx) {
1728
1782
  const state = await ctx.workspace.read();
@@ -1753,10 +1807,10 @@ var promptSetEndpointValidationRulesTool = {
1753
1807
  var promptSetEndpointResponseRulesTool = {
1754
1808
  name: "prompt.set_endpoint_response_rules",
1755
1809
  description: "Replace an endpoint's conditional response rules with an LLM-shaped list. Rules fire in order, first match wins. Every rule + clause gets a fresh id. Empty array falls back to defaultResponse.",
1756
- inputSchema: import_zod7.z.object({
1757
- mockId: import_zod7.z.string(),
1758
- endpointId: import_zod7.z.string(),
1759
- rules: import_zod7.z.array(RESPONSE_RULE_NL)
1810
+ inputSchema: import_zod8.z.object({
1811
+ mockId: import_zod8.z.string(),
1812
+ endpointId: import_zod8.z.string(),
1813
+ rules: import_zod8.z.array(RESPONSE_RULE_NL)
1760
1814
  }),
1761
1815
  async handler(input, ctx) {
1762
1816
  const state = await ctx.workspace.read();
@@ -1791,10 +1845,10 @@ var promptSetEndpointResponseRulesTool = {
1791
1845
  var promptSetEndpointMultipliersTool = {
1792
1846
  name: "prompt.set_endpoint_multipliers",
1793
1847
  description: "Replace the response multipliers on an endpoint's defaultResponse with an LLM-shaped list. Multipliers expand an array at `targetJsonPath` to a count derived from a request value. Every multiplier gets a fresh id. Empty array clears all multipliers.",
1794
- inputSchema: import_zod7.z.object({
1795
- mockId: import_zod7.z.string(),
1796
- endpointId: import_zod7.z.string(),
1797
- multipliers: import_zod7.z.array(MULTIPLIER_NL)
1848
+ inputSchema: import_zod8.z.object({
1849
+ mockId: import_zod8.z.string(),
1850
+ endpointId: import_zod8.z.string(),
1851
+ multipliers: import_zod8.z.array(MULTIPLIER_NL)
1798
1852
  }),
1799
1853
  async handler(input, ctx) {
1800
1854
  const state = await ctx.workspace.read();
@@ -1823,7 +1877,7 @@ var promptSetEndpointMultipliersTool = {
1823
1877
  };
1824
1878
 
1825
1879
  // src/tools/mocks.ts
1826
- var import_zod8 = require("zod");
1880
+ var import_zod9 = require("zod");
1827
1881
  var import_shared4 = require("@apicircle/shared");
1828
1882
  var import_mock_server_core2 = require("@apicircle/mock-server-core");
1829
1883
  async function ingestSource(source, name) {
@@ -1846,10 +1900,10 @@ async function ingestSource(source, name) {
1846
1900
  var mockCreateFromOpenApiTool = {
1847
1901
  name: "mock.create_from_openapi",
1848
1902
  description: "Create a mock server from an OpenAPI / Swagger spec (YAML or JSON).",
1849
- inputSchema: import_zod8.z.object({
1850
- name: import_zod8.z.string(),
1851
- spec: import_zod8.z.string().min(1),
1852
- format: import_zod8.z.enum(["json", "yaml"]).default("json")
1903
+ inputSchema: import_zod9.z.object({
1904
+ name: import_zod9.z.string(),
1905
+ spec: import_zod9.z.string().min(1),
1906
+ format: import_zod9.z.enum(["json", "yaml"]).default("json")
1853
1907
  }),
1854
1908
  async handler(input, ctx) {
1855
1909
  const { mock, warnings } = await ingestSource(
@@ -1868,7 +1922,7 @@ var mockCreateFromOpenApiTool = {
1868
1922
  var mockCreateFromPostmanTool = {
1869
1923
  name: "mock.create_from_postman",
1870
1924
  description: "Create a mock server from a Postman v2/v2.1 collection.",
1871
- inputSchema: import_zod8.z.object({ name: import_zod8.z.string(), collection: import_zod8.z.string().min(1) }),
1925
+ inputSchema: import_zod9.z.object({ name: import_zod9.z.string(), collection: import_zod9.z.string().min(1) }),
1872
1926
  async handler(input, ctx) {
1873
1927
  const { mock, warnings } = await ingestSource(
1874
1928
  { kind: "postman", collection: input.collection },
@@ -1886,7 +1940,7 @@ var mockCreateFromPostmanTool = {
1886
1940
  var mockCreateFromInsomniaTool = {
1887
1941
  name: "mock.create_from_insomnia",
1888
1942
  description: "Create a mock server from an Insomnia v4 export.",
1889
- inputSchema: import_zod8.z.object({ name: import_zod8.z.string(), export: import_zod8.z.string().min(1) }),
1943
+ inputSchema: import_zod9.z.object({ name: import_zod9.z.string(), export: import_zod9.z.string().min(1) }),
1890
1944
  async handler(input, ctx) {
1891
1945
  const { mock, warnings } = await ingestSource(
1892
1946
  { kind: "insomnia", export: input.export },
@@ -1904,7 +1958,7 @@ var mockCreateFromInsomniaTool = {
1904
1958
  var mockImportPostmanMockCollectionTool = {
1905
1959
  name: "mock.import_postman_mock_collection",
1906
1960
  description: "Import a Postman Mock Collection (collections previously hosted on Postman's mock service). Same parser as a regular Postman collection but marked as a mock import.",
1907
- inputSchema: import_zod8.z.object({ name: import_zod8.z.string(), collection: import_zod8.z.string().min(1) }),
1961
+ inputSchema: import_zod9.z.object({ name: import_zod9.z.string(), collection: import_zod9.z.string().min(1) }),
1908
1962
  async handler(input, ctx) {
1909
1963
  const { mock, warnings } = await ingestSource(
1910
1964
  { kind: "postman", collection: input.collection },
@@ -1922,7 +1976,7 @@ var mockImportPostmanMockCollectionTool = {
1922
1976
  var mockListTool = {
1923
1977
  name: "mock.list",
1924
1978
  description: "List all mock servers in the workspace plus their runtime status (running / stopped, port).",
1925
- inputSchema: import_zod8.z.object({}),
1979
+ inputSchema: import_zod9.z.object({}),
1926
1980
  async handler(_input, ctx) {
1927
1981
  const state = await ctx.workspace.read();
1928
1982
  const running = await ctx.mock.list();
@@ -1944,9 +1998,9 @@ var mockListTool = {
1944
1998
  var mockStartTool = {
1945
1999
  name: "mock.start",
1946
2000
  description: "Start a mock server by id. Returns the bound port. Errors if the mock is already running or the requested port is in use.",
1947
- inputSchema: import_zod8.z.object({
1948
- id: import_zod8.z.string(),
1949
- port: import_zod8.z.number().int().positive().optional()
2001
+ inputSchema: import_zod9.z.object({
2002
+ id: import_zod9.z.string(),
2003
+ port: import_zod9.z.number().int().positive().optional()
1950
2004
  }),
1951
2005
  async handler(input, ctx) {
1952
2006
  const state = await ctx.workspace.read();
@@ -1963,7 +2017,7 @@ var mockStartTool = {
1963
2017
  var mockStopTool = {
1964
2018
  name: "mock.stop",
1965
2019
  description: "Stop a running mock server by id (no-op if not running).",
1966
- inputSchema: import_zod8.z.object({ id: import_zod8.z.string() }),
2020
+ inputSchema: import_zod9.z.object({ id: import_zod9.z.string() }),
1967
2021
  async handler(input, ctx) {
1968
2022
  try {
1969
2023
  await ctx.mock.stop(input.id);
@@ -1976,7 +2030,7 @@ var mockStopTool = {
1976
2030
  var mockDeleteTool = {
1977
2031
  name: "mock.delete",
1978
2032
  description: "Delete a mock server definition. Stops it first if it's running.",
1979
- inputSchema: import_zod8.z.object({ id: import_zod8.z.string() }),
2033
+ inputSchema: import_zod9.z.object({ id: import_zod9.z.string() }),
1980
2034
  async handler(input, ctx) {
1981
2035
  try {
1982
2036
  await ctx.mock.stop(input.id);
@@ -1986,13 +2040,13 @@ var mockDeleteTool = {
1986
2040
  return { ok: true, changedIds: out.changedIds };
1987
2041
  }
1988
2042
  };
1989
- var HTTP_METHOD3 = import_zod8.z.enum(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"]);
2043
+ var HTTP_METHOD3 = import_zod9.z.enum(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"]);
1990
2044
  var mockCreateManualTool = {
1991
2045
  name: "mock.create_manual",
1992
2046
  description: "Create an empty manual-mode mock server. Use `mock.add_endpoint` afterward to populate it. CORS defaults to off (same-origin only); enable + list explicit origins via `mock.update_cors` if cross-origin access is needed.",
1993
- inputSchema: import_zod8.z.object({
1994
- name: import_zod8.z.string().min(1),
1995
- defaultPort: import_zod8.z.number().int().positive().nullable().optional()
2047
+ inputSchema: import_zod9.z.object({
2048
+ name: import_zod9.z.string().min(1),
2049
+ defaultPort: import_zod9.z.number().int().positive().nullable().optional()
1996
2050
  }),
1997
2051
  async handler(input, ctx) {
1998
2052
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -2015,7 +2069,7 @@ var mockCreateManualTool = {
2015
2069
  var mockListEndpointsTool = {
2016
2070
  name: "mock.list_endpoints",
2017
2071
  description: "List endpoints for a mock server (id, method, path, name).",
2018
- inputSchema: import_zod8.z.object({ mockId: import_zod8.z.string() }),
2072
+ inputSchema: import_zod9.z.object({ mockId: import_zod9.z.string() }),
2019
2073
  async handler(input, ctx) {
2020
2074
  const state = await ctx.workspace.read();
2021
2075
  const mock = state.synced.mockServers[input.mockId];
@@ -2034,10 +2088,10 @@ var mockListEndpointsTool = {
2034
2088
  };
2035
2089
  }
2036
2090
  };
2037
- var ENDPOINT_RESPONSE2 = import_zod8.z.object({
2038
- status: import_zod8.z.number().int().min(100).max(599).default(200),
2039
- jsonBody: import_zod8.z.string().default("{}"),
2040
- contentType: import_zod8.z.string().default("application/json")
2091
+ var ENDPOINT_RESPONSE2 = import_zod9.z.object({
2092
+ status: import_zod9.z.number().int().min(100).max(599).default(200),
2093
+ jsonBody: import_zod9.z.string().default("{}"),
2094
+ contentType: import_zod9.z.string().default("application/json")
2041
2095
  });
2042
2096
  function buildDefaultEndpoint(args) {
2043
2097
  const response = args.response ?? {
@@ -2066,12 +2120,12 @@ function buildDefaultEndpoint(args) {
2066
2120
  var mockAddEndpointTool = {
2067
2121
  name: "mock.add_endpoint",
2068
2122
  description: "Append a new endpoint to a mock server. Defaults to a 200 JSON response of `{}`. Returns the new endpoint id.",
2069
- inputSchema: import_zod8.z.object({
2070
- mockId: import_zod8.z.string(),
2123
+ inputSchema: import_zod9.z.object({
2124
+ mockId: import_zod9.z.string(),
2071
2125
  method: HTTP_METHOD3,
2072
- pathPattern: import_zod8.z.string().min(1),
2073
- name: import_zod8.z.string().optional(),
2074
- description: import_zod8.z.string().optional(),
2126
+ pathPattern: import_zod9.z.string().min(1),
2127
+ name: import_zod9.z.string().optional(),
2128
+ description: import_zod9.z.string().optional(),
2075
2129
  response: ENDPOINT_RESPONSE2.optional()
2076
2130
  }),
2077
2131
  async handler(input, ctx) {
@@ -2094,13 +2148,13 @@ var mockAddEndpointTool = {
2094
2148
  var mockUpdateEndpointTool = {
2095
2149
  name: "mock.update_endpoint",
2096
2150
  description: "Patch fields on a single mock endpoint (method, pathPattern, name, description, defaultResponse status / contentType / json body). Pass only the fields you want to change.",
2097
- inputSchema: import_zod8.z.object({
2098
- mockId: import_zod8.z.string(),
2099
- endpointId: import_zod8.z.string(),
2151
+ inputSchema: import_zod9.z.object({
2152
+ mockId: import_zod9.z.string(),
2153
+ endpointId: import_zod9.z.string(),
2100
2154
  method: HTTP_METHOD3.optional(),
2101
- pathPattern: import_zod8.z.string().optional(),
2102
- name: import_zod8.z.string().optional(),
2103
- description: import_zod8.z.string().optional(),
2155
+ pathPattern: import_zod9.z.string().optional(),
2156
+ name: import_zod9.z.string().optional(),
2157
+ description: import_zod9.z.string().optional(),
2104
2158
  response: ENDPOINT_RESPONSE2.partial().optional()
2105
2159
  }),
2106
2160
  async handler(input, ctx) {
@@ -2141,7 +2195,7 @@ var mockUpdateEndpointTool = {
2141
2195
  var mockDeleteEndpointTool = {
2142
2196
  name: "mock.delete_endpoint",
2143
2197
  description: "Remove an endpoint from a mock server.",
2144
- inputSchema: import_zod8.z.object({ mockId: import_zod8.z.string(), endpointId: import_zod8.z.string() }),
2198
+ inputSchema: import_zod9.z.object({ mockId: import_zod9.z.string(), endpointId: import_zod9.z.string() }),
2145
2199
  async handler(input, ctx) {
2146
2200
  const state = await ctx.workspace.read();
2147
2201
  const mock = state.synced.mockServers[input.mockId];
@@ -2161,9 +2215,9 @@ var mockDeleteEndpointTool = {
2161
2215
  return { ok: true, changedIds: out.changedIds };
2162
2216
  }
2163
2217
  };
2164
- var VALIDATION_RULE = import_zod8.z.object({
2165
- id: import_zod8.z.string().optional(),
2166
- kind: import_zod8.z.enum([
2218
+ var VALIDATION_RULE = import_zod9.z.object({
2219
+ id: import_zod9.z.string().optional(),
2220
+ kind: import_zod9.z.enum([
2167
2221
  "header-required",
2168
2222
  "header-equals",
2169
2223
  "header-matches",
@@ -2174,43 +2228,43 @@ var VALIDATION_RULE = import_zod8.z.object({
2174
2228
  "body-required",
2175
2229
  "content-type-equals"
2176
2230
  ]),
2177
- target: import_zod8.z.string().default(""),
2178
- expected: import_zod8.z.string().optional(),
2179
- message: import_zod8.z.string().optional(),
2180
- enabled: import_zod8.z.boolean().default(true),
2181
- failResponse: import_zod8.z.object({
2182
- status: import_zod8.z.number().int().min(100).max(599).default(400),
2183
- jsonBody: import_zod8.z.string().default('{"error":"validation failed"}')
2231
+ target: import_zod9.z.string().default(""),
2232
+ expected: import_zod9.z.string().optional(),
2233
+ message: import_zod9.z.string().optional(),
2234
+ enabled: import_zod9.z.boolean().default(true),
2235
+ failResponse: import_zod9.z.object({
2236
+ status: import_zod9.z.number().int().min(100).max(599).default(400),
2237
+ jsonBody: import_zod9.z.string().default('{"error":"validation failed"}')
2184
2238
  }).default({})
2185
2239
  });
2186
- var CONDITION_CLAUSE = import_zod8.z.object({
2187
- id: import_zod8.z.string().optional(),
2188
- scope: import_zod8.z.enum(["query", "pathParam", "header", "cookie", "body-json-path"]),
2189
- target: import_zod8.z.string(),
2190
- op: import_zod8.z.enum(["equals", "not-equals", "matches", "gt", "lt", "gte", "lte", "present", "absent"]),
2191
- value: import_zod8.z.string().optional()
2240
+ var CONDITION_CLAUSE = import_zod9.z.object({
2241
+ id: import_zod9.z.string().optional(),
2242
+ scope: import_zod9.z.enum(["query", "pathParam", "header", "cookie", "body-json-path"]),
2243
+ target: import_zod9.z.string(),
2244
+ op: import_zod9.z.enum(["equals", "not-equals", "matches", "gt", "lt", "gte", "lte", "present", "absent"]),
2245
+ value: import_zod9.z.string().optional()
2192
2246
  });
2193
- var RESPONSE_RULE = import_zod8.z.object({
2194
- id: import_zod8.z.string().optional(),
2195
- name: import_zod8.z.string(),
2196
- enabled: import_zod8.z.boolean().default(true),
2197
- when: import_zod8.z.array(CONDITION_CLAUSE).default([]),
2198
- response: import_zod8.z.object({
2199
- status: import_zod8.z.number().int().min(100).max(599).default(200),
2200
- jsonBody: import_zod8.z.string().default("{}")
2247
+ var RESPONSE_RULE = import_zod9.z.object({
2248
+ id: import_zod9.z.string().optional(),
2249
+ name: import_zod9.z.string(),
2250
+ enabled: import_zod9.z.boolean().default(true),
2251
+ when: import_zod9.z.array(CONDITION_CLAUSE).default([]),
2252
+ response: import_zod9.z.object({
2253
+ status: import_zod9.z.number().int().min(100).max(599).default(200),
2254
+ jsonBody: import_zod9.z.string().default("{}")
2201
2255
  }).default({})
2202
2256
  });
2203
- var MULTIPLIER = import_zod8.z.object({
2204
- id: import_zod8.z.string().optional(),
2205
- name: import_zod8.z.string().optional(),
2206
- source: import_zod8.z.object({
2207
- kind: import_zod8.z.enum(["query", "pathParam", "header", "body-json-path"]),
2208
- key: import_zod8.z.string()
2257
+ var MULTIPLIER = import_zod9.z.object({
2258
+ id: import_zod9.z.string().optional(),
2259
+ name: import_zod9.z.string().optional(),
2260
+ source: import_zod9.z.object({
2261
+ kind: import_zod9.z.enum(["query", "pathParam", "header", "body-json-path"]),
2262
+ key: import_zod9.z.string()
2209
2263
  }),
2210
- targetJsonPath: import_zod8.z.string(),
2211
- defaultCount: import_zod8.z.number().int().nonnegative().default(0),
2212
- min: import_zod8.z.number().int().nonnegative().optional(),
2213
- max: import_zod8.z.number().int().nonnegative().optional()
2264
+ targetJsonPath: import_zod9.z.string(),
2265
+ defaultCount: import_zod9.z.number().int().nonnegative().default(0),
2266
+ min: import_zod9.z.number().int().nonnegative().optional(),
2267
+ max: import_zod9.z.number().int().nonnegative().optional()
2214
2268
  });
2215
2269
  function defaultJsonResponseConfig(args) {
2216
2270
  return {
@@ -2235,10 +2289,10 @@ function patchEndpoint2(mock, endpointId, patcher) {
2235
2289
  var mockSetValidationRulesTool = {
2236
2290
  name: "mock.set_validation_rules",
2237
2291
  description: "Replace an endpoint's validation rules. Rules without an `id` get a fresh one; existing rules can keep theirs to preserve client-side selection state. Empty array clears all rules.",
2238
- inputSchema: import_zod8.z.object({
2239
- mockId: import_zod8.z.string(),
2240
- endpointId: import_zod8.z.string(),
2241
- rules: import_zod8.z.array(VALIDATION_RULE)
2292
+ inputSchema: import_zod9.z.object({
2293
+ mockId: import_zod9.z.string(),
2294
+ endpointId: import_zod9.z.string(),
2295
+ rules: import_zod9.z.array(VALIDATION_RULE)
2242
2296
  }),
2243
2297
  async handler(input, ctx) {
2244
2298
  const state = await ctx.workspace.read();
@@ -2265,10 +2319,10 @@ var mockSetValidationRulesTool = {
2265
2319
  var mockSetResponseRulesTool = {
2266
2320
  name: "mock.set_response_rules",
2267
2321
  description: "Replace an endpoint's conditional response rules. Rules fire in order; the first whose every clause matches wins. Disabled rules are skipped. Empty array falls back to defaultResponse.",
2268
- inputSchema: import_zod8.z.object({
2269
- mockId: import_zod8.z.string(),
2270
- endpointId: import_zod8.z.string(),
2271
- rules: import_zod8.z.array(RESPONSE_RULE)
2322
+ inputSchema: import_zod9.z.object({
2323
+ mockId: import_zod9.z.string(),
2324
+ endpointId: import_zod9.z.string(),
2325
+ rules: import_zod9.z.array(RESPONSE_RULE)
2272
2326
  }),
2273
2327
  async handler(input, ctx) {
2274
2328
  const state = await ctx.workspace.read();
@@ -2299,10 +2353,10 @@ var mockSetResponseRulesTool = {
2299
2353
  var mockSetMultipliersTool = {
2300
2354
  name: "mock.set_multipliers",
2301
2355
  description: "Replace the response multipliers on an endpoint's defaultResponse. Multipliers expand an array at `targetJsonPath` to a count derived from a request value. Empty array clears all multipliers.",
2302
- inputSchema: import_zod8.z.object({
2303
- mockId: import_zod8.z.string(),
2304
- endpointId: import_zod8.z.string(),
2305
- multipliers: import_zod8.z.array(MULTIPLIER)
2356
+ inputSchema: import_zod9.z.object({
2357
+ mockId: import_zod9.z.string(),
2358
+ endpointId: import_zod9.z.string(),
2359
+ multipliers: import_zod9.z.array(MULTIPLIER)
2306
2360
  }),
2307
2361
  async handler(input, ctx) {
2308
2362
  const state = await ctx.workspace.read();
@@ -2338,6 +2392,7 @@ var TOOL_REGISTRY = [
2338
2392
  importInsomniaTool,
2339
2393
  importHarTool,
2340
2394
  generateCodeTool,
2395
+ workspaceListTool,
2341
2396
  workspaceReadTool,
2342
2397
  workspaceWriteTool,
2343
2398
  requestCreateTool,
@@ -2408,6 +2463,63 @@ function getTool(name) {
2408
2463
  return TOOL_REGISTRY.find((t) => t.name === name);
2409
2464
  }
2410
2465
 
2466
+ // src/providers/Workspaces.ts
2467
+ var SingleWorkspaceAdapter = class {
2468
+ constructor(provider, workspaceId, displayName = "Workspace") {
2469
+ this.provider = provider;
2470
+ this.workspaceId = workspaceId;
2471
+ this.displayName = displayName;
2472
+ }
2473
+ provider;
2474
+ workspaceId;
2475
+ displayName;
2476
+ async list() {
2477
+ const state = await this.provider.read();
2478
+ const id = state.synced.workspaceId;
2479
+ this.workspaceId = id;
2480
+ return [
2481
+ {
2482
+ id,
2483
+ name: this.displayName,
2484
+ isActive: true,
2485
+ createdAt: state.synced.meta.createdAt,
2486
+ lastOpenedAt: state.synced.meta.updatedAt,
2487
+ counts: {
2488
+ requests: Object.keys(state.synced.collections.requests).length,
2489
+ folders: Object.keys(state.synced.collections.folders).length,
2490
+ environments: Object.keys(state.synced.environments.items).length,
2491
+ mockServers: Object.keys(state.synced.mockServers ?? {}).length,
2492
+ plans: Object.keys(state.synced.executionPlans ?? {}).length
2493
+ }
2494
+ }
2495
+ ];
2496
+ }
2497
+ for(workspaceId) {
2498
+ if (this.workspaceId && workspaceId !== this.workspaceId) {
2499
+ throw new WorkspaceNotFoundError(workspaceId);
2500
+ }
2501
+ return this.provider;
2502
+ }
2503
+ activeId() {
2504
+ return this.workspaceId;
2505
+ }
2506
+ setActive(workspaceId) {
2507
+ if (this.workspaceId && workspaceId !== this.workspaceId) {
2508
+ throw new WorkspaceNotFoundError(workspaceId);
2509
+ }
2510
+ return Promise.resolve();
2511
+ }
2512
+ };
2513
+ var WorkspaceNotFoundError = class extends Error {
2514
+ code = "workspace-not-found";
2515
+ workspaceId;
2516
+ constructor(workspaceId) {
2517
+ super(`No workspace with id "${workspaceId}" is available on this server.`);
2518
+ this.name = "WorkspaceNotFoundError";
2519
+ this.workspaceId = workspaceId;
2520
+ }
2521
+ };
2522
+
2411
2523
  // src/providers/InMemoryWorkspaceProvider.ts
2412
2524
  var import_core2 = require("@apicircle/core");
2413
2525
  var InMemoryWorkspaceProvider = class {
@@ -2468,6 +2580,109 @@ var FileBackedWorkspaceProvider = class {
2468
2580
  }
2469
2581
  };
2470
2582
 
2583
+ // src/providers/MultiWorkspaceProvider.ts
2584
+ var import_registry = require("@apicircle/core/workspace/registry");
2585
+ var MultiWorkspaceProvider = class {
2586
+ constructor(registryRoot) {
2587
+ this.registryRoot = registryRoot;
2588
+ }
2589
+ registryRoot;
2590
+ active = null;
2591
+ activeWorkspaceId = null;
2592
+ /**
2593
+ * Hydrate the active provider from disk. Must be called once before the
2594
+ * MCP host boots so `ctx.workspace.read()` doesn't race the first
2595
+ * registry-load. Returns the registry the boot can log.
2596
+ */
2597
+ async init() {
2598
+ const registry = await (0, import_registry.loadRegistry)(this.registryRoot) ?? {
2599
+ schemaVersion: 1,
2600
+ activeWorkspaceId: null,
2601
+ workspaces: []
2602
+ };
2603
+ if (registry.activeWorkspaceId) {
2604
+ this.activeWorkspaceId = registry.activeWorkspaceId;
2605
+ this.active = new FileBackedWorkspaceProvider(
2606
+ (0, import_registry.workspaceDirFor)(this.registryRoot, registry.activeWorkspaceId)
2607
+ );
2608
+ }
2609
+ return registry;
2610
+ }
2611
+ /** The provider tool handlers see as `ctx.workspace`. */
2612
+ activeProvider() {
2613
+ if (!this.active) {
2614
+ throw new Error(
2615
+ "No active workspace. Open the desktop app at least once, or run `apicircle workspaces create <name>`."
2616
+ );
2617
+ }
2618
+ return this.active;
2619
+ }
2620
+ // ─── Workspaces interface ──────────────────────────────────────────────────
2621
+ async list() {
2622
+ const registry = await (0, import_registry.loadRegistry)(this.registryRoot) ?? {
2623
+ schemaVersion: 1,
2624
+ activeWorkspaceId: null,
2625
+ workspaces: []
2626
+ };
2627
+ const out = [];
2628
+ for (const entry of registry.workspaces) {
2629
+ let counts = null;
2630
+ try {
2631
+ const state = await (0, import_registry.loadWorkspaceById)(this.registryRoot, entry.id);
2632
+ if (state) {
2633
+ counts = {
2634
+ requests: Object.keys(state.synced.collections.requests).length,
2635
+ folders: Object.keys(state.synced.collections.folders).length,
2636
+ environments: Object.keys(state.synced.environments.items).length,
2637
+ mockServers: Object.keys(state.synced.mockServers ?? {}).length,
2638
+ plans: Object.keys(state.synced.executionPlans ?? {}).length
2639
+ };
2640
+ }
2641
+ } catch {
2642
+ counts = null;
2643
+ }
2644
+ out.push({
2645
+ id: entry.id,
2646
+ name: entry.name,
2647
+ isActive: entry.id === registry.activeWorkspaceId,
2648
+ createdAt: entry.createdAt,
2649
+ lastOpenedAt: entry.lastOpenedAt,
2650
+ counts
2651
+ });
2652
+ }
2653
+ return out;
2654
+ }
2655
+ for(workspaceId) {
2656
+ return new FileBackedWorkspaceProvider((0, import_registry.workspaceDirFor)(this.registryRoot, workspaceId));
2657
+ }
2658
+ activeId() {
2659
+ return this.activeWorkspaceId;
2660
+ }
2661
+ async setActive(workspaceId) {
2662
+ const registry = await (0, import_registry.loadRegistry)(this.registryRoot);
2663
+ if (!registry || !registry.workspaces.some((w) => w.id === workspaceId)) {
2664
+ throw new WorkspaceNotFoundError(workspaceId);
2665
+ }
2666
+ const next = await (0, import_registry.setActiveWorkspace)(this.registryRoot, workspaceId);
2667
+ void next;
2668
+ this.activeWorkspaceId = workspaceId;
2669
+ this.active = new FileBackedWorkspaceProvider((0, import_registry.workspaceDirFor)(this.registryRoot, workspaceId));
2670
+ }
2671
+ /**
2672
+ * Idempotent registry write — used by tests / tools that need to
2673
+ * persist registry updates that didn't go through `setActive`.
2674
+ */
2675
+ async writeRegistry(registry) {
2676
+ await (0, import_registry.saveRegistry)(this.registryRoot, registry);
2677
+ this.activeWorkspaceId = registry.activeWorkspaceId;
2678
+ if (registry.activeWorkspaceId) {
2679
+ this.active = new FileBackedWorkspaceProvider(
2680
+ (0, import_registry.workspaceDirFor)(this.registryRoot, registry.activeWorkspaceId)
2681
+ );
2682
+ }
2683
+ }
2684
+ };
2685
+
2471
2686
  // src/providers/InProcessMockController.ts
2472
2687
  var import_mock_server_core3 = require("@apicircle/mock-server-core");
2473
2688
  var InProcessMockController = class {
@@ -2508,10 +2723,19 @@ var InProcessMockController = class {
2508
2723
 
2509
2724
  // src/index.ts
2510
2725
  function createMcpServer(options) {
2726
+ const workspaces = options.workspaces ?? new SingleWorkspaceAdapter(
2727
+ options.workspace,
2728
+ null
2729
+ /* discovered on first list() */
2730
+ );
2511
2731
  return new McpHost({
2512
2732
  serverInfo: options.serverInfo,
2513
2733
  tools: options.tools ?? TOOL_REGISTRY,
2514
- context: { workspace: options.workspace, mock: options.mock }
2734
+ context: {
2735
+ workspace: options.workspace,
2736
+ workspaces,
2737
+ mock: options.mock
2738
+ }
2515
2739
  });
2516
2740
  }
2517
2741
  // Annotate the CommonJS export names for ESM import in node:
@@ -2520,7 +2744,10 @@ function createMcpServer(options) {
2520
2744
  InMemoryWorkspaceProvider,
2521
2745
  InProcessMockController,
2522
2746
  McpHost,
2747
+ MultiWorkspaceProvider,
2748
+ SingleWorkspaceAdapter,
2523
2749
  TOOL_REGISTRY,
2750
+ WorkspaceNotFoundError,
2524
2751
  createMcpServer,
2525
2752
  getTool
2526
2753
  });