@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/LICENSE +110 -110
- package/README.md +191 -38
- package/dist/bin/mcp-server.cjs +606 -352
- package/dist/bin/mcp-server.cjs.map +1 -1
- package/dist/index.cjs +577 -350
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +88 -1
- package/dist/index.d.ts +88 -1
- package/dist/index.js +580 -350
- package/dist/index.js.map +1 -1
- package/package.json +33 -26
package/dist/index.js
CHANGED
|
@@ -434,18 +434,37 @@ function renderRust(req) {
|
|
|
434
434
|
return lines.join("\n");
|
|
435
435
|
}
|
|
436
436
|
|
|
437
|
-
// src/tools/
|
|
437
|
+
// src/tools/workspaceList.ts
|
|
438
438
|
import { z as z4 } from "zod";
|
|
439
|
+
var workspaceListTool = {
|
|
440
|
+
name: "workspace.list",
|
|
441
|
+
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.",
|
|
442
|
+
inputSchema: z4.object({}),
|
|
443
|
+
async handler(_input, ctx) {
|
|
444
|
+
const summaries = await ctx.workspaces.list();
|
|
445
|
+
return {
|
|
446
|
+
activeWorkspaceId: ctx.workspaces.activeId(),
|
|
447
|
+
workspaceCount: summaries.length,
|
|
448
|
+
workspaces: summaries,
|
|
449
|
+
// Plain-text hint the AI surfaces when telling the user. Cheap to
|
|
450
|
+
// generate here and saves round-trips on disambiguation prompts.
|
|
451
|
+
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.`
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
};
|
|
455
|
+
|
|
456
|
+
// src/tools/crud.ts
|
|
457
|
+
import { z as z5 } from "zod";
|
|
439
458
|
import { generateId as generateId2 } from "@apicircle/shared";
|
|
440
|
-
var HTTP_METHOD =
|
|
459
|
+
var HTTP_METHOD = z5.enum(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"]);
|
|
441
460
|
var requestCreateTool = {
|
|
442
461
|
name: "request.create",
|
|
443
462
|
description: "Create a new request from explicit fields and persist it.",
|
|
444
|
-
inputSchema:
|
|
445
|
-
name:
|
|
463
|
+
inputSchema: z5.object({
|
|
464
|
+
name: z5.string().default("New request"),
|
|
446
465
|
method: HTTP_METHOD.default("GET"),
|
|
447
|
-
url:
|
|
448
|
-
folderId:
|
|
466
|
+
url: z5.string().default(""),
|
|
467
|
+
folderId: z5.string().nullable().optional()
|
|
449
468
|
}),
|
|
450
469
|
async handler(input, ctx) {
|
|
451
470
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -474,7 +493,7 @@ var requestCreateTool = {
|
|
|
474
493
|
var requestReadTool = {
|
|
475
494
|
name: "request.read",
|
|
476
495
|
description: "Read a request by id, or list summaries (id, name, method, url) when no id is provided.",
|
|
477
|
-
inputSchema:
|
|
496
|
+
inputSchema: z5.object({ id: z5.string().optional() }),
|
|
478
497
|
async handler(input, ctx) {
|
|
479
498
|
const state = await ctx.workspace.read();
|
|
480
499
|
if (input.id) {
|
|
@@ -495,13 +514,13 @@ var requestReadTool = {
|
|
|
495
514
|
var requestUpdateTool = {
|
|
496
515
|
name: "request.update",
|
|
497
516
|
description: "Patch fields on an existing request.",
|
|
498
|
-
inputSchema:
|
|
499
|
-
id:
|
|
500
|
-
patch:
|
|
501
|
-
name:
|
|
517
|
+
inputSchema: z5.object({
|
|
518
|
+
id: z5.string(),
|
|
519
|
+
patch: z5.object({
|
|
520
|
+
name: z5.string().optional(),
|
|
502
521
|
method: HTTP_METHOD.optional(),
|
|
503
|
-
url:
|
|
504
|
-
folderId:
|
|
522
|
+
url: z5.string().optional(),
|
|
523
|
+
folderId: z5.string().nullable().optional()
|
|
505
524
|
}).strict()
|
|
506
525
|
}),
|
|
507
526
|
async handler(input, ctx) {
|
|
@@ -516,7 +535,7 @@ var requestUpdateTool = {
|
|
|
516
535
|
var requestDeleteTool = {
|
|
517
536
|
name: "request.delete",
|
|
518
537
|
description: "Delete a request by id.",
|
|
519
|
-
inputSchema:
|
|
538
|
+
inputSchema: z5.object({ id: z5.string() }),
|
|
520
539
|
async handler(input, ctx) {
|
|
521
540
|
const out = await ctx.workspace.apply({ kind: "request.delete", id: input.id });
|
|
522
541
|
return { changedIds: out.changedIds };
|
|
@@ -525,9 +544,9 @@ var requestDeleteTool = {
|
|
|
525
544
|
var folderCreateTool = {
|
|
526
545
|
name: "folder.create",
|
|
527
546
|
description: "Create a folder under an optional parent folder.",
|
|
528
|
-
inputSchema:
|
|
529
|
-
name:
|
|
530
|
-
parentId:
|
|
547
|
+
inputSchema: z5.object({
|
|
548
|
+
name: z5.string().default("New folder"),
|
|
549
|
+
parentId: z5.string().nullable().optional()
|
|
531
550
|
}),
|
|
532
551
|
async handler(input, ctx) {
|
|
533
552
|
const folder = {
|
|
@@ -542,7 +561,7 @@ var folderCreateTool = {
|
|
|
542
561
|
var folderReadTool = {
|
|
543
562
|
name: "folder.read",
|
|
544
563
|
description: "Read a folder by id, or list all folders when no id is provided.",
|
|
545
|
-
inputSchema:
|
|
564
|
+
inputSchema: z5.object({ id: z5.string().optional() }),
|
|
546
565
|
async handler(input, ctx) {
|
|
547
566
|
const state = await ctx.workspace.read();
|
|
548
567
|
if (input.id) {
|
|
@@ -558,9 +577,9 @@ var folderReadTool = {
|
|
|
558
577
|
var folderUpdateTool = {
|
|
559
578
|
name: "folder.update",
|
|
560
579
|
description: "Move a folder to a new parent (or to root with parentId: null).",
|
|
561
|
-
inputSchema:
|
|
562
|
-
id:
|
|
563
|
-
parentId:
|
|
580
|
+
inputSchema: z5.object({
|
|
581
|
+
id: z5.string(),
|
|
582
|
+
parentId: z5.string().nullable()
|
|
564
583
|
}),
|
|
565
584
|
async handler(input, ctx) {
|
|
566
585
|
const out = await ctx.workspace.apply({
|
|
@@ -574,23 +593,23 @@ var folderUpdateTool = {
|
|
|
574
593
|
var folderDeleteTool = {
|
|
575
594
|
name: "folder.delete",
|
|
576
595
|
description: "Delete a folder. Direct children (sub-folders + requests) are reparented to the deleted folder's parent.",
|
|
577
|
-
inputSchema:
|
|
596
|
+
inputSchema: z5.object({ id: z5.string() }),
|
|
578
597
|
async handler(input, ctx) {
|
|
579
598
|
const out = await ctx.workspace.apply({ kind: "folder.delete", id: input.id });
|
|
580
599
|
return { changedIds: out.changedIds };
|
|
581
600
|
}
|
|
582
601
|
};
|
|
583
|
-
var VARIABLE =
|
|
584
|
-
key:
|
|
585
|
-
value:
|
|
586
|
-
encrypted:
|
|
602
|
+
var VARIABLE = z5.object({
|
|
603
|
+
key: z5.string(),
|
|
604
|
+
value: z5.string(),
|
|
605
|
+
encrypted: z5.boolean().default(false)
|
|
587
606
|
});
|
|
588
607
|
var environmentCreateTool = {
|
|
589
608
|
name: "environment.create",
|
|
590
609
|
description: "Create a new environment (or upsert one with the same name).",
|
|
591
|
-
inputSchema:
|
|
592
|
-
name:
|
|
593
|
-
variables:
|
|
610
|
+
inputSchema: z5.object({
|
|
611
|
+
name: z5.string(),
|
|
612
|
+
variables: z5.array(VARIABLE).default([])
|
|
594
613
|
}),
|
|
595
614
|
async handler(input, ctx) {
|
|
596
615
|
const env = { name: input.name, variables: input.variables };
|
|
@@ -601,7 +620,7 @@ var environmentCreateTool = {
|
|
|
601
620
|
var environmentReadTool = {
|
|
602
621
|
name: "environment.read",
|
|
603
622
|
description: "Read environments \u2014 pass `name` for one, or omit for the full list.",
|
|
604
|
-
inputSchema:
|
|
623
|
+
inputSchema: z5.object({ name: z5.string().optional() }),
|
|
605
624
|
async handler(input, ctx) {
|
|
606
625
|
const state = await ctx.workspace.read();
|
|
607
626
|
if (input.name) {
|
|
@@ -618,9 +637,9 @@ var environmentReadTool = {
|
|
|
618
637
|
var environmentUpdateTool = {
|
|
619
638
|
name: "environment.update",
|
|
620
639
|
description: "Replace the variables list of an environment.",
|
|
621
|
-
inputSchema:
|
|
622
|
-
name:
|
|
623
|
-
variables:
|
|
640
|
+
inputSchema: z5.object({
|
|
641
|
+
name: z5.string(),
|
|
642
|
+
variables: z5.array(VARIABLE)
|
|
624
643
|
}),
|
|
625
644
|
async handler(input, ctx) {
|
|
626
645
|
const out = await ctx.workspace.apply({
|
|
@@ -633,7 +652,7 @@ var environmentUpdateTool = {
|
|
|
633
652
|
var environmentDeleteTool = {
|
|
634
653
|
name: "environment.delete",
|
|
635
654
|
description: "Delete an environment by name.",
|
|
636
|
-
inputSchema:
|
|
655
|
+
inputSchema: z5.object({ name: z5.string() }),
|
|
637
656
|
async handler(input, ctx) {
|
|
638
657
|
const out = await ctx.workspace.apply({ kind: "environment.delete", name: input.name });
|
|
639
658
|
return { changedIds: out.changedIds };
|
|
@@ -642,7 +661,7 @@ var environmentDeleteTool = {
|
|
|
642
661
|
var environmentSetActiveTool = {
|
|
643
662
|
name: "environment.set_active",
|
|
644
663
|
description: "Set (or clear) the active environment. Pass `name: null` to deactivate the current environment.",
|
|
645
|
-
inputSchema:
|
|
664
|
+
inputSchema: z5.object({ name: z5.string().nullable() }),
|
|
646
665
|
async handler(input, ctx) {
|
|
647
666
|
const out = await ctx.workspace.apply({
|
|
648
667
|
kind: "environment.setActive",
|
|
@@ -654,18 +673,18 @@ var environmentSetActiveTool = {
|
|
|
654
673
|
var environmentSetPriorityTool = {
|
|
655
674
|
name: "environment.set_priority",
|
|
656
675
|
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.',
|
|
657
|
-
inputSchema:
|
|
658
|
-
order:
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
kind:
|
|
663
|
-
name:
|
|
676
|
+
inputSchema: z5.object({
|
|
677
|
+
order: z5.array(
|
|
678
|
+
z5.union([
|
|
679
|
+
z5.string(),
|
|
680
|
+
z5.object({
|
|
681
|
+
kind: z5.literal("local"),
|
|
682
|
+
name: z5.string()
|
|
664
683
|
}),
|
|
665
|
-
|
|
666
|
-
kind:
|
|
667
|
-
linkedWorkspaceId:
|
|
668
|
-
envName:
|
|
684
|
+
z5.object({
|
|
685
|
+
kind: z5.literal("linked"),
|
|
686
|
+
linkedWorkspaceId: z5.string(),
|
|
687
|
+
envName: z5.string()
|
|
669
688
|
})
|
|
670
689
|
])
|
|
671
690
|
)
|
|
@@ -682,7 +701,7 @@ var environmentSetPriorityTool = {
|
|
|
682
701
|
var environmentExportTool = {
|
|
683
702
|
name: "environment.export",
|
|
684
703
|
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.",
|
|
685
|
-
inputSchema:
|
|
704
|
+
inputSchema: z5.object({ name: z5.string() }),
|
|
686
705
|
async handler(input, ctx) {
|
|
687
706
|
const state = await ctx.workspace.read();
|
|
688
707
|
const env = state.synced.environments.items[input.name];
|
|
@@ -700,9 +719,9 @@ var environmentExportTool = {
|
|
|
700
719
|
var environmentImportTool = {
|
|
701
720
|
name: "environment.import",
|
|
702
721
|
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.",
|
|
703
|
-
inputSchema:
|
|
704
|
-
json:
|
|
705
|
-
overwrite:
|
|
722
|
+
inputSchema: z5.object({
|
|
723
|
+
json: z5.string().min(1),
|
|
724
|
+
overwrite: z5.boolean().default(false)
|
|
706
725
|
}),
|
|
707
726
|
async handler(input, ctx) {
|
|
708
727
|
let parsed;
|
|
@@ -732,17 +751,17 @@ var environmentImportTool = {
|
|
|
732
751
|
return { ok: true, name: env.name, changedIds: out.changedIds };
|
|
733
752
|
}
|
|
734
753
|
};
|
|
735
|
-
var PLAN_STEP =
|
|
736
|
-
requestId:
|
|
737
|
-
linkedWorkspaceId:
|
|
754
|
+
var PLAN_STEP = z5.object({
|
|
755
|
+
requestId: z5.string(),
|
|
756
|
+
linkedWorkspaceId: z5.string().optional()
|
|
738
757
|
});
|
|
739
758
|
var planCreateTool = {
|
|
740
759
|
name: "plan.create",
|
|
741
760
|
description: "Create a new execution plan (sequence of request steps).",
|
|
742
|
-
inputSchema:
|
|
743
|
-
name:
|
|
744
|
-
steps:
|
|
745
|
-
envPriorityOrder:
|
|
761
|
+
inputSchema: z5.object({
|
|
762
|
+
name: z5.string().default("New plan"),
|
|
763
|
+
steps: z5.array(PLAN_STEP).default([]),
|
|
764
|
+
envPriorityOrder: z5.array(z5.string()).default([])
|
|
746
765
|
}),
|
|
747
766
|
async handler(input, ctx) {
|
|
748
767
|
const id = generateId2();
|
|
@@ -762,7 +781,7 @@ var planCreateTool = {
|
|
|
762
781
|
var planReadTool = {
|
|
763
782
|
name: "plan.read",
|
|
764
783
|
description: "Read a plan by id, or list all plans when no id is provided.",
|
|
765
|
-
inputSchema:
|
|
784
|
+
inputSchema: z5.object({ id: z5.string().optional() }),
|
|
766
785
|
async handler(input, ctx) {
|
|
767
786
|
const state = await ctx.workspace.read();
|
|
768
787
|
if (input.id) {
|
|
@@ -778,12 +797,12 @@ var planReadTool = {
|
|
|
778
797
|
var planUpdateTool = {
|
|
779
798
|
name: "plan.update",
|
|
780
799
|
description: "Patch fields on an existing plan.",
|
|
781
|
-
inputSchema:
|
|
782
|
-
id:
|
|
783
|
-
patch:
|
|
784
|
-
name:
|
|
785
|
-
steps:
|
|
786
|
-
envPriorityOrder:
|
|
800
|
+
inputSchema: z5.object({
|
|
801
|
+
id: z5.string(),
|
|
802
|
+
patch: z5.object({
|
|
803
|
+
name: z5.string().optional(),
|
|
804
|
+
steps: z5.array(PLAN_STEP).optional(),
|
|
805
|
+
envPriorityOrder: z5.array(z5.string()).optional()
|
|
787
806
|
}).strict()
|
|
788
807
|
}),
|
|
789
808
|
async handler(input, ctx) {
|
|
@@ -804,7 +823,7 @@ var planUpdateTool = {
|
|
|
804
823
|
var planDeleteTool = {
|
|
805
824
|
name: "plan.delete",
|
|
806
825
|
description: "Delete a plan by id. Drops history rows referencing this plan.",
|
|
807
|
-
inputSchema:
|
|
826
|
+
inputSchema: z5.object({ id: z5.string() }),
|
|
808
827
|
async handler(input, ctx) {
|
|
809
828
|
const out = await ctx.workspace.apply({ kind: "plan.delete", id: input.id });
|
|
810
829
|
return { changedIds: out.changedIds };
|
|
@@ -813,11 +832,11 @@ var planDeleteTool = {
|
|
|
813
832
|
var planAddStepTool = {
|
|
814
833
|
name: "plan.add_step",
|
|
815
834
|
description: "Append a step to an execution plan. Optional `position` (0-based) inserts at that index instead.",
|
|
816
|
-
inputSchema:
|
|
817
|
-
planId:
|
|
818
|
-
requestId:
|
|
819
|
-
linkedWorkspaceId:
|
|
820
|
-
position:
|
|
835
|
+
inputSchema: z5.object({
|
|
836
|
+
planId: z5.string(),
|
|
837
|
+
requestId: z5.string(),
|
|
838
|
+
linkedWorkspaceId: z5.string().optional(),
|
|
839
|
+
position: z5.number().int().nonnegative().optional()
|
|
821
840
|
}),
|
|
822
841
|
async handler(input, ctx) {
|
|
823
842
|
const state = await ctx.workspace.read();
|
|
@@ -843,9 +862,9 @@ var planAddStepTool = {
|
|
|
843
862
|
var planRemoveStepTool = {
|
|
844
863
|
name: "plan.remove_step",
|
|
845
864
|
description: "Remove a step from a plan by 0-based index.",
|
|
846
|
-
inputSchema:
|
|
847
|
-
planId:
|
|
848
|
-
index:
|
|
865
|
+
inputSchema: z5.object({
|
|
866
|
+
planId: z5.string(),
|
|
867
|
+
index: z5.number().int().nonnegative()
|
|
849
868
|
}),
|
|
850
869
|
async handler(input, ctx) {
|
|
851
870
|
const state = await ctx.workspace.read();
|
|
@@ -865,9 +884,9 @@ var planRemoveStepTool = {
|
|
|
865
884
|
var planReorderStepsTool = {
|
|
866
885
|
name: "plan.reorder_steps",
|
|
867
886
|
description: "Replace the plan steps with a new permutation. The supplied indices must reference valid current step indices.",
|
|
868
|
-
inputSchema:
|
|
869
|
-
planId:
|
|
870
|
-
order:
|
|
887
|
+
inputSchema: z5.object({
|
|
888
|
+
planId: z5.string(),
|
|
889
|
+
order: z5.array(z5.number().int().nonnegative())
|
|
871
890
|
}),
|
|
872
891
|
async handler(input, ctx) {
|
|
873
892
|
const state = await ctx.workspace.read();
|
|
@@ -889,13 +908,13 @@ var planReorderStepsTool = {
|
|
|
889
908
|
return { ok: true, changedIds: out.changedIds };
|
|
890
909
|
}
|
|
891
910
|
};
|
|
892
|
-
var PLAN_VARIABLE =
|
|
911
|
+
var PLAN_VARIABLE = z5.object({ key: z5.string(), value: z5.string() });
|
|
893
912
|
var planSetVariablesTool = {
|
|
894
913
|
name: "plan.set_variables",
|
|
895
914
|
description: "Replace the plan-scoped variables. These live highest-priority during plan runs (above environment vars, below context vars).",
|
|
896
|
-
inputSchema:
|
|
897
|
-
planId:
|
|
898
|
-
variables:
|
|
915
|
+
inputSchema: z5.object({
|
|
916
|
+
planId: z5.string(),
|
|
917
|
+
variables: z5.array(PLAN_VARIABLE)
|
|
899
918
|
}),
|
|
900
919
|
async handler(input, ctx) {
|
|
901
920
|
const state = await ctx.workspace.read();
|
|
@@ -911,9 +930,9 @@ var planSetVariablesTool = {
|
|
|
911
930
|
var planRunTool = {
|
|
912
931
|
name: "plan.run",
|
|
913
932
|
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.",
|
|
914
|
-
inputSchema:
|
|
915
|
-
id:
|
|
916
|
-
withAssertions:
|
|
933
|
+
inputSchema: z5.object({
|
|
934
|
+
id: z5.string(),
|
|
935
|
+
withAssertions: z5.boolean().default(true)
|
|
917
936
|
}),
|
|
918
937
|
async handler(input, ctx) {
|
|
919
938
|
const state = await ctx.workspace.read();
|
|
@@ -927,18 +946,18 @@ var planRunTool = {
|
|
|
927
946
|
};
|
|
928
947
|
}
|
|
929
948
|
};
|
|
930
|
-
var ASSERTION =
|
|
931
|
-
id:
|
|
932
|
-
kind:
|
|
933
|
-
op:
|
|
934
|
-
target:
|
|
935
|
-
expected:
|
|
949
|
+
var ASSERTION = z5.object({
|
|
950
|
+
id: z5.string().optional(),
|
|
951
|
+
kind: z5.enum(["status", "header", "json-path", "duration"]),
|
|
952
|
+
op: z5.enum(["equals", "not-equals", "contains", "lt", "gt", "matches"]),
|
|
953
|
+
target: z5.string().optional(),
|
|
954
|
+
expected: z5.union([z5.string(), z5.number()])
|
|
936
955
|
});
|
|
937
956
|
var assertionCreateTool = {
|
|
938
957
|
name: "assertion.create",
|
|
939
958
|
description: "Add an assertion to a request.",
|
|
940
|
-
inputSchema:
|
|
941
|
-
requestId:
|
|
959
|
+
inputSchema: z5.object({
|
|
960
|
+
requestId: z5.string(),
|
|
942
961
|
assertion: ASSERTION
|
|
943
962
|
}),
|
|
944
963
|
async handler(input, ctx) {
|
|
@@ -957,9 +976,9 @@ var assertionCreateTool = {
|
|
|
957
976
|
var assertionReadTool = {
|
|
958
977
|
name: "assertion.read",
|
|
959
978
|
description: "List assertions for a request, or fetch a single assertion by id.",
|
|
960
|
-
inputSchema:
|
|
961
|
-
requestId:
|
|
962
|
-
assertionId:
|
|
979
|
+
inputSchema: z5.object({
|
|
980
|
+
requestId: z5.string(),
|
|
981
|
+
assertionId: z5.string().optional()
|
|
963
982
|
}),
|
|
964
983
|
async handler(input, ctx) {
|
|
965
984
|
const state = await ctx.workspace.read();
|
|
@@ -975,8 +994,8 @@ var assertionReadTool = {
|
|
|
975
994
|
var assertionUpdateTool = {
|
|
976
995
|
name: "assertion.update",
|
|
977
996
|
description: "Replace an existing assertion (matched by `assertion.id`).",
|
|
978
|
-
inputSchema:
|
|
979
|
-
requestId:
|
|
997
|
+
inputSchema: z5.object({
|
|
998
|
+
requestId: z5.string(),
|
|
980
999
|
assertion: ASSERTION.required({ id: true })
|
|
981
1000
|
}),
|
|
982
1001
|
async handler(input, ctx) {
|
|
@@ -991,9 +1010,9 @@ var assertionUpdateTool = {
|
|
|
991
1010
|
var assertionDeleteTool = {
|
|
992
1011
|
name: "assertion.delete",
|
|
993
1012
|
description: "Remove an assertion from a request.",
|
|
994
|
-
inputSchema:
|
|
995
|
-
requestId:
|
|
996
|
-
assertionId:
|
|
1013
|
+
inputSchema: z5.object({
|
|
1014
|
+
requestId: z5.string(),
|
|
1015
|
+
assertionId: z5.string()
|
|
997
1016
|
}),
|
|
998
1017
|
async handler(input, ctx) {
|
|
999
1018
|
const out = await ctx.workspace.apply({
|
|
@@ -1006,21 +1025,53 @@ var assertionDeleteTool = {
|
|
|
1006
1025
|
};
|
|
1007
1026
|
var workspaceReadTool = {
|
|
1008
1027
|
name: "workspace.read",
|
|
1009
|
-
description:
|
|
1010
|
-
inputSchema:
|
|
1011
|
-
|
|
1012
|
-
|
|
1028
|
+
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.',
|
|
1029
|
+
inputSchema: z5.object({
|
|
1030
|
+
workspaceId: z5.string().min(1).max(256).optional().describe(
|
|
1031
|
+
'Optional workspace id (from `workspace.list`). Omit to read the active workspace; the tool will switch to the "multiple workspaces" envelope when ambiguous.'
|
|
1032
|
+
)
|
|
1033
|
+
}),
|
|
1034
|
+
async handler(input, ctx) {
|
|
1035
|
+
if (input.workspaceId) {
|
|
1036
|
+
const provider = ctx.workspaces.for(input.workspaceId);
|
|
1037
|
+
const state2 = await provider.read();
|
|
1038
|
+
return {
|
|
1039
|
+
kind: "single",
|
|
1040
|
+
workspaceId: state2.synced.workspaceId,
|
|
1041
|
+
synced: state2.synced,
|
|
1042
|
+
local: state2.local
|
|
1043
|
+
};
|
|
1044
|
+
}
|
|
1045
|
+
const summaries = await ctx.workspaces.list();
|
|
1046
|
+
if (summaries.length > 1) {
|
|
1047
|
+
return {
|
|
1048
|
+
kind: "multiple-workspaces",
|
|
1049
|
+
activeWorkspaceId: ctx.workspaces.activeId(),
|
|
1050
|
+
workspaceCount: summaries.length,
|
|
1051
|
+
workspaces: summaries,
|
|
1052
|
+
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.`
|
|
1053
|
+
};
|
|
1054
|
+
}
|
|
1055
|
+
const state = await ctx.workspace.read();
|
|
1056
|
+
return {
|
|
1057
|
+
kind: "single",
|
|
1058
|
+
workspaceId: state.synced.workspaceId,
|
|
1059
|
+
synced: state.synced,
|
|
1060
|
+
local: state.local
|
|
1061
|
+
};
|
|
1013
1062
|
}
|
|
1014
1063
|
};
|
|
1015
1064
|
var workspaceWriteTool = {
|
|
1016
1065
|
name: "workspace.write",
|
|
1017
|
-
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.",
|
|
1018
|
-
inputSchema:
|
|
1019
|
-
|
|
1020
|
-
|
|
1066
|
+
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.",
|
|
1067
|
+
inputSchema: z5.object({
|
|
1068
|
+
workspaceId: z5.string().min(1).max(256).optional().describe("Optional workspace id; omit to write the active workspace."),
|
|
1069
|
+
synced: z5.unknown().optional(),
|
|
1070
|
+
local: z5.unknown().optional()
|
|
1021
1071
|
}),
|
|
1022
1072
|
async handler(input, ctx) {
|
|
1023
|
-
const
|
|
1073
|
+
const provider = input.workspaceId ? ctx.workspaces.for(input.workspaceId) : ctx.workspace;
|
|
1074
|
+
const next = await provider.write({
|
|
1024
1075
|
synced: input.synced,
|
|
1025
1076
|
local: input.local
|
|
1026
1077
|
});
|
|
@@ -1029,16 +1080,16 @@ var workspaceWriteTool = {
|
|
|
1029
1080
|
};
|
|
1030
1081
|
|
|
1031
1082
|
// src/tools/history.ts
|
|
1032
|
-
import { z as
|
|
1083
|
+
import { z as z6 } from "zod";
|
|
1033
1084
|
var historyListRunsTool = {
|
|
1034
1085
|
name: "history.list_runs",
|
|
1035
1086
|
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.",
|
|
1036
|
-
inputSchema:
|
|
1037
|
-
requestId:
|
|
1038
|
-
ok:
|
|
1039
|
-
since:
|
|
1040
|
-
until:
|
|
1041
|
-
limit:
|
|
1087
|
+
inputSchema: z6.object({
|
|
1088
|
+
requestId: z6.string().optional(),
|
|
1089
|
+
ok: z6.boolean().optional(),
|
|
1090
|
+
since: z6.string().optional(),
|
|
1091
|
+
until: z6.string().optional(),
|
|
1092
|
+
limit: z6.number().int().positive().max(500).default(100)
|
|
1042
1093
|
}),
|
|
1043
1094
|
async handler(input, ctx) {
|
|
1044
1095
|
const state = await ctx.workspace.read();
|
|
@@ -1072,7 +1123,7 @@ var historyListRunsTool = {
|
|
|
1072
1123
|
var historyGetRunTool = {
|
|
1073
1124
|
name: "history.get_run",
|
|
1074
1125
|
description: "Fetch a single history row in full (headers, body preview, assertion results).",
|
|
1075
|
-
inputSchema:
|
|
1126
|
+
inputSchema: z6.object({ id: z6.string() }),
|
|
1076
1127
|
async handler(input, ctx) {
|
|
1077
1128
|
const state = await ctx.workspace.read();
|
|
1078
1129
|
const run = state.local.history.requestRuns.find((r) => r.id === input.id);
|
|
@@ -1083,7 +1134,7 @@ var historyGetRunTool = {
|
|
|
1083
1134
|
var historyDeleteRunTool = {
|
|
1084
1135
|
name: "history.delete_run",
|
|
1085
1136
|
description: "Delete a single request-run row by id.",
|
|
1086
|
-
inputSchema:
|
|
1137
|
+
inputSchema: z6.object({ id: z6.string() }),
|
|
1087
1138
|
async handler(input, ctx) {
|
|
1088
1139
|
const out = await ctx.workspace.apply({ kind: "history.delete_run", runId: input.id });
|
|
1089
1140
|
return { deleted: out.changedIds.length, changedIds: out.changedIds };
|
|
@@ -1092,8 +1143,8 @@ var historyDeleteRunTool = {
|
|
|
1092
1143
|
var historyPurgeTool = {
|
|
1093
1144
|
name: "history.purge_by_age",
|
|
1094
1145
|
description: "Drop every request-run + plan-run older than `olderThanDays` days. Pass 0 to clear all history.",
|
|
1095
|
-
inputSchema:
|
|
1096
|
-
olderThanDays:
|
|
1146
|
+
inputSchema: z6.object({
|
|
1147
|
+
olderThanDays: z6.number().nonnegative()
|
|
1097
1148
|
}),
|
|
1098
1149
|
async handler(input, ctx) {
|
|
1099
1150
|
const olderThanMs = input.olderThanDays * 24 * 60 * 60 * 1e3;
|
|
@@ -1103,15 +1154,15 @@ var historyPurgeTool = {
|
|
|
1103
1154
|
};
|
|
1104
1155
|
|
|
1105
1156
|
// src/tools/codebase.ts
|
|
1106
|
-
import { z as
|
|
1157
|
+
import { z as z7 } from "zod";
|
|
1107
1158
|
var HTTP_METHODS = ["get", "post", "put", "patch", "delete", "options", "head"];
|
|
1108
1159
|
var codebaseExtractCollectionTool = {
|
|
1109
1160
|
name: "codebase.extract_collection",
|
|
1110
1161
|
description: "Scan source code for HTTP route definitions (Express, FastAPI, NestJS, Spring) and return candidate requests for the user to confirm before import.",
|
|
1111
|
-
inputSchema:
|
|
1112
|
-
source:
|
|
1162
|
+
inputSchema: z7.object({
|
|
1163
|
+
source: z7.string().min(1),
|
|
1113
1164
|
/** Hint to limit which framework patterns to apply. Empty = try all. */
|
|
1114
|
-
frameworks:
|
|
1165
|
+
frameworks: z7.array(z7.enum(["express", "fastapi", "nest", "spring"])).default([])
|
|
1115
1166
|
}),
|
|
1116
1167
|
async handler(input) {
|
|
1117
1168
|
const enabled = new Set(
|
|
@@ -1192,18 +1243,18 @@ var codebaseExtractCollectionTool = {
|
|
|
1192
1243
|
};
|
|
1193
1244
|
|
|
1194
1245
|
// src/tools/prompt.ts
|
|
1195
|
-
import { z as
|
|
1246
|
+
import { z as z8 } from "zod";
|
|
1196
1247
|
import { generateId as generateId3, makeDefaultMockResponse, makeDefaultRequestSchema } from "@apicircle/shared";
|
|
1197
1248
|
var promptCreateEnvironmentTool = {
|
|
1198
1249
|
name: "prompt.create_environment",
|
|
1199
1250
|
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.",
|
|
1200
|
-
inputSchema:
|
|
1201
|
-
name:
|
|
1202
|
-
variables:
|
|
1203
|
-
|
|
1204
|
-
key:
|
|
1205
|
-
value:
|
|
1206
|
-
encrypted:
|
|
1251
|
+
inputSchema: z8.object({
|
|
1252
|
+
name: z8.string(),
|
|
1253
|
+
variables: z8.array(
|
|
1254
|
+
z8.object({
|
|
1255
|
+
key: z8.string(),
|
|
1256
|
+
value: z8.string(),
|
|
1257
|
+
encrypted: z8.boolean().default(false)
|
|
1207
1258
|
})
|
|
1208
1259
|
)
|
|
1209
1260
|
}),
|
|
@@ -1216,13 +1267,13 @@ var promptCreateEnvironmentTool = {
|
|
|
1216
1267
|
var promptCreateAssertionTool = {
|
|
1217
1268
|
name: "prompt.create_assertion",
|
|
1218
1269
|
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".',
|
|
1219
|
-
inputSchema:
|
|
1220
|
-
requestId:
|
|
1221
|
-
assertion:
|
|
1222
|
-
kind:
|
|
1223
|
-
op:
|
|
1224
|
-
target:
|
|
1225
|
-
expected:
|
|
1270
|
+
inputSchema: z8.object({
|
|
1271
|
+
requestId: z8.string(),
|
|
1272
|
+
assertion: z8.object({
|
|
1273
|
+
kind: z8.enum(["status", "header", "json-path", "duration"]),
|
|
1274
|
+
op: z8.enum(["equals", "not-equals", "contains", "lt", "gt", "matches"]),
|
|
1275
|
+
target: z8.string().optional(),
|
|
1276
|
+
expected: z8.union([z8.string(), z8.number()])
|
|
1226
1277
|
})
|
|
1227
1278
|
}),
|
|
1228
1279
|
async handler(input, ctx) {
|
|
@@ -1241,10 +1292,10 @@ var promptCreateAssertionTool = {
|
|
|
1241
1292
|
var promptCreatePlanTool = {
|
|
1242
1293
|
name: "prompt.create_plan",
|
|
1243
1294
|
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.",
|
|
1244
|
-
inputSchema:
|
|
1245
|
-
name:
|
|
1246
|
-
stepRequestIds:
|
|
1247
|
-
envPriorityOrder:
|
|
1295
|
+
inputSchema: z8.object({
|
|
1296
|
+
name: z8.string(),
|
|
1297
|
+
stepRequestIds: z8.array(z8.string()).default([]),
|
|
1298
|
+
envPriorityOrder: z8.array(z8.string()).default([])
|
|
1248
1299
|
}),
|
|
1249
1300
|
async handler(input, ctx) {
|
|
1250
1301
|
const state = await ctx.workspace.read();
|
|
@@ -1273,51 +1324,51 @@ var promptCreatePlanTool = {
|
|
|
1273
1324
|
return { ok: true, id, changedIds: out.changedIds };
|
|
1274
1325
|
}
|
|
1275
1326
|
};
|
|
1276
|
-
var HTTP_METHOD2 =
|
|
1277
|
-
var HEADER_OR_QUERY =
|
|
1278
|
-
key:
|
|
1279
|
-
value:
|
|
1280
|
-
enabled:
|
|
1327
|
+
var HTTP_METHOD2 = z8.enum(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"]);
|
|
1328
|
+
var HEADER_OR_QUERY = z8.object({
|
|
1329
|
+
key: z8.string(),
|
|
1330
|
+
value: z8.string(),
|
|
1331
|
+
enabled: z8.boolean().default(true)
|
|
1281
1332
|
});
|
|
1282
|
-
var REQUEST_BODY =
|
|
1283
|
-
type:
|
|
1284
|
-
content:
|
|
1285
|
-
variables:
|
|
1333
|
+
var REQUEST_BODY = z8.object({
|
|
1334
|
+
type: z8.enum(["none", "json", "text", "xml", "graphql", "urlencoded"]).default("none"),
|
|
1335
|
+
content: z8.string().default(""),
|
|
1336
|
+
variables: z8.string().optional()
|
|
1286
1337
|
});
|
|
1287
|
-
var PROMPT_AUTH =
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
type:
|
|
1293
|
-
username:
|
|
1294
|
-
password:
|
|
1338
|
+
var PROMPT_AUTH = z8.discriminatedUnion("type", [
|
|
1339
|
+
z8.object({ type: z8.literal("none") }),
|
|
1340
|
+
z8.object({ type: z8.literal("inherit") }),
|
|
1341
|
+
z8.object({ type: z8.literal("bearer"), token: z8.string().default("") }),
|
|
1342
|
+
z8.object({
|
|
1343
|
+
type: z8.literal("basic"),
|
|
1344
|
+
username: z8.string().default(""),
|
|
1345
|
+
password: z8.string().default("")
|
|
1295
1346
|
}),
|
|
1296
|
-
|
|
1297
|
-
type:
|
|
1298
|
-
key:
|
|
1299
|
-
value:
|
|
1300
|
-
addTo:
|
|
1347
|
+
z8.object({
|
|
1348
|
+
type: z8.literal("api-key"),
|
|
1349
|
+
key: z8.string().default(""),
|
|
1350
|
+
value: z8.string().default(""),
|
|
1351
|
+
addTo: z8.enum(["header", "query", "cookie"]).default("header")
|
|
1301
1352
|
}),
|
|
1302
|
-
|
|
1303
|
-
type:
|
|
1304
|
-
key:
|
|
1305
|
-
value:
|
|
1353
|
+
z8.object({
|
|
1354
|
+
type: z8.literal("custom-header"),
|
|
1355
|
+
key: z8.string().default(""),
|
|
1356
|
+
value: z8.string().default("")
|
|
1306
1357
|
})
|
|
1307
1358
|
]);
|
|
1308
|
-
var PROMPT_ASSERTION =
|
|
1309
|
-
kind:
|
|
1310
|
-
op:
|
|
1311
|
-
target:
|
|
1312
|
-
expected:
|
|
1359
|
+
var PROMPT_ASSERTION = z8.object({
|
|
1360
|
+
kind: z8.enum(["status", "header", "json-path", "duration"]),
|
|
1361
|
+
op: z8.enum(["equals", "not-equals", "contains", "lt", "gt", "matches"]),
|
|
1362
|
+
target: z8.string().optional(),
|
|
1363
|
+
expected: z8.union([z8.string(), z8.number()])
|
|
1313
1364
|
});
|
|
1314
|
-
var ENDPOINT_RESPONSE =
|
|
1315
|
-
status:
|
|
1316
|
-
jsonBody:
|
|
1317
|
-
contentType:
|
|
1365
|
+
var ENDPOINT_RESPONSE = z8.object({
|
|
1366
|
+
status: z8.number().int().min(100).max(599).default(200),
|
|
1367
|
+
jsonBody: z8.string().default("{}"),
|
|
1368
|
+
contentType: z8.string().default("application/json")
|
|
1318
1369
|
});
|
|
1319
|
-
var VALIDATION_RULE_NL =
|
|
1320
|
-
kind:
|
|
1370
|
+
var VALIDATION_RULE_NL = z8.object({
|
|
1371
|
+
kind: z8.enum([
|
|
1321
1372
|
"header-required",
|
|
1322
1373
|
"header-equals",
|
|
1323
1374
|
"header-matches",
|
|
@@ -1328,50 +1379,50 @@ var VALIDATION_RULE_NL = z7.object({
|
|
|
1328
1379
|
"body-required",
|
|
1329
1380
|
"content-type-equals"
|
|
1330
1381
|
]),
|
|
1331
|
-
target:
|
|
1332
|
-
expected:
|
|
1333
|
-
message:
|
|
1334
|
-
enabled:
|
|
1335
|
-
failResponse:
|
|
1336
|
-
status:
|
|
1337
|
-
jsonBody:
|
|
1382
|
+
target: z8.string().default(""),
|
|
1383
|
+
expected: z8.string().optional(),
|
|
1384
|
+
message: z8.string().optional(),
|
|
1385
|
+
enabled: z8.boolean().default(true),
|
|
1386
|
+
failResponse: z8.object({
|
|
1387
|
+
status: z8.number().int().min(100).max(599).default(400),
|
|
1388
|
+
jsonBody: z8.string().default('{"error":"validation failed"}')
|
|
1338
1389
|
}).default({})
|
|
1339
1390
|
});
|
|
1340
|
-
var CONDITION_CLAUSE_NL =
|
|
1341
|
-
scope:
|
|
1342
|
-
target:
|
|
1343
|
-
op:
|
|
1344
|
-
value:
|
|
1391
|
+
var CONDITION_CLAUSE_NL = z8.object({
|
|
1392
|
+
scope: z8.enum(["query", "pathParam", "header", "cookie", "body-json-path"]),
|
|
1393
|
+
target: z8.string(),
|
|
1394
|
+
op: z8.enum(["equals", "not-equals", "matches", "gt", "lt", "gte", "lte", "present", "absent"]),
|
|
1395
|
+
value: z8.string().optional()
|
|
1345
1396
|
});
|
|
1346
|
-
var RESPONSE_RULE_NL =
|
|
1347
|
-
name:
|
|
1348
|
-
enabled:
|
|
1349
|
-
when:
|
|
1350
|
-
response:
|
|
1351
|
-
status:
|
|
1352
|
-
jsonBody:
|
|
1397
|
+
var RESPONSE_RULE_NL = z8.object({
|
|
1398
|
+
name: z8.string(),
|
|
1399
|
+
enabled: z8.boolean().default(true),
|
|
1400
|
+
when: z8.array(CONDITION_CLAUSE_NL).default([]),
|
|
1401
|
+
response: z8.object({
|
|
1402
|
+
status: z8.number().int().min(100).max(599).default(200),
|
|
1403
|
+
jsonBody: z8.string().default("{}")
|
|
1353
1404
|
}).default({})
|
|
1354
1405
|
});
|
|
1355
|
-
var MULTIPLIER_NL =
|
|
1356
|
-
name:
|
|
1357
|
-
source:
|
|
1358
|
-
kind:
|
|
1359
|
-
key:
|
|
1406
|
+
var MULTIPLIER_NL = z8.object({
|
|
1407
|
+
name: z8.string().optional(),
|
|
1408
|
+
source: z8.object({
|
|
1409
|
+
kind: z8.enum(["query", "pathParam", "header", "body-json-path"]),
|
|
1410
|
+
key: z8.string()
|
|
1360
1411
|
}),
|
|
1361
|
-
targetJsonPath:
|
|
1362
|
-
defaultCount:
|
|
1363
|
-
min:
|
|
1364
|
-
max:
|
|
1412
|
+
targetJsonPath: z8.string(),
|
|
1413
|
+
defaultCount: z8.number().int().nonnegative().default(0),
|
|
1414
|
+
min: z8.number().int().nonnegative().optional(),
|
|
1415
|
+
max: z8.number().int().nonnegative().optional()
|
|
1365
1416
|
});
|
|
1366
|
-
var ENDPOINT_INPUT =
|
|
1417
|
+
var ENDPOINT_INPUT = z8.object({
|
|
1367
1418
|
method: HTTP_METHOD2,
|
|
1368
|
-
pathPattern:
|
|
1369
|
-
name:
|
|
1370
|
-
description:
|
|
1419
|
+
pathPattern: z8.string().min(1),
|
|
1420
|
+
name: z8.string().optional(),
|
|
1421
|
+
description: z8.string().optional(),
|
|
1371
1422
|
response: ENDPOINT_RESPONSE.optional(),
|
|
1372
|
-
validationRules:
|
|
1373
|
-
responseRules:
|
|
1374
|
-
multipliers:
|
|
1423
|
+
validationRules: z8.array(VALIDATION_RULE_NL).default([]),
|
|
1424
|
+
responseRules: z8.array(RESPONSE_RULE_NL).default([]),
|
|
1425
|
+
multipliers: z8.array(MULTIPLIER_NL).default([])
|
|
1375
1426
|
});
|
|
1376
1427
|
function buildRequestBody(input) {
|
|
1377
1428
|
if (!input) return { type: "none", content: "" };
|
|
@@ -1464,17 +1515,17 @@ function patchEndpoint(mock, endpointId, patcher) {
|
|
|
1464
1515
|
var promptCreateRequestTool = {
|
|
1465
1516
|
name: "prompt.create_request",
|
|
1466
1517
|
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.",
|
|
1467
|
-
inputSchema:
|
|
1468
|
-
name:
|
|
1518
|
+
inputSchema: z8.object({
|
|
1519
|
+
name: z8.string().default("New request"),
|
|
1469
1520
|
method: HTTP_METHOD2.default("GET"),
|
|
1470
|
-
url:
|
|
1471
|
-
folderId:
|
|
1472
|
-
headers:
|
|
1473
|
-
queryParams:
|
|
1474
|
-
pathParams:
|
|
1521
|
+
url: z8.string().default(""),
|
|
1522
|
+
folderId: z8.string().nullable().optional(),
|
|
1523
|
+
headers: z8.array(HEADER_OR_QUERY).default([]),
|
|
1524
|
+
queryParams: z8.array(HEADER_OR_QUERY).default([]),
|
|
1525
|
+
pathParams: z8.record(z8.string(), z8.string()).optional(),
|
|
1475
1526
|
body: REQUEST_BODY.optional(),
|
|
1476
1527
|
auth: PROMPT_AUTH.optional(),
|
|
1477
|
-
assertions:
|
|
1528
|
+
assertions: z8.array(PROMPT_ASSERTION).default([])
|
|
1478
1529
|
}),
|
|
1479
1530
|
async handler(input, ctx) {
|
|
1480
1531
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -1504,19 +1555,19 @@ var promptCreateRequestTool = {
|
|
|
1504
1555
|
var promptUpdateRequestTool = {
|
|
1505
1556
|
name: "prompt.update_request",
|
|
1506
1557
|
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.",
|
|
1507
|
-
inputSchema:
|
|
1508
|
-
id:
|
|
1509
|
-
patch:
|
|
1510
|
-
name:
|
|
1558
|
+
inputSchema: z8.object({
|
|
1559
|
+
id: z8.string(),
|
|
1560
|
+
patch: z8.object({
|
|
1561
|
+
name: z8.string().optional(),
|
|
1511
1562
|
method: HTTP_METHOD2.optional(),
|
|
1512
|
-
url:
|
|
1513
|
-
folderId:
|
|
1514
|
-
headers:
|
|
1515
|
-
queryParams:
|
|
1516
|
-
pathParams:
|
|
1563
|
+
url: z8.string().optional(),
|
|
1564
|
+
folderId: z8.string().nullable().optional(),
|
|
1565
|
+
headers: z8.array(HEADER_OR_QUERY).optional(),
|
|
1566
|
+
queryParams: z8.array(HEADER_OR_QUERY).optional(),
|
|
1567
|
+
pathParams: z8.record(z8.string(), z8.string()).optional(),
|
|
1517
1568
|
body: REQUEST_BODY.optional(),
|
|
1518
1569
|
auth: PROMPT_AUTH.optional(),
|
|
1519
|
-
assertions:
|
|
1570
|
+
assertions: z8.array(PROMPT_ASSERTION).optional()
|
|
1520
1571
|
}).strict()
|
|
1521
1572
|
}),
|
|
1522
1573
|
async handler(input, ctx) {
|
|
@@ -1544,17 +1595,17 @@ var promptUpdateRequestTool = {
|
|
|
1544
1595
|
return { ok: true, changedIds: out.changedIds };
|
|
1545
1596
|
}
|
|
1546
1597
|
};
|
|
1547
|
-
var FOLDER_TREE_NODE =
|
|
1548
|
-
() =>
|
|
1549
|
-
name:
|
|
1550
|
-
children:
|
|
1598
|
+
var FOLDER_TREE_NODE = z8.lazy(
|
|
1599
|
+
() => z8.object({
|
|
1600
|
+
name: z8.string(),
|
|
1601
|
+
children: z8.array(FOLDER_TREE_NODE).optional()
|
|
1551
1602
|
})
|
|
1552
1603
|
);
|
|
1553
1604
|
var promptCreateFolderTreeTool = {
|
|
1554
1605
|
name: "prompt.create_folder_tree",
|
|
1555
1606
|
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.",
|
|
1556
|
-
inputSchema:
|
|
1557
|
-
parentId:
|
|
1607
|
+
inputSchema: z8.object({
|
|
1608
|
+
parentId: z8.string().nullable().optional(),
|
|
1558
1609
|
tree: FOLDER_TREE_NODE
|
|
1559
1610
|
}),
|
|
1560
1611
|
async handler(input, ctx) {
|
|
@@ -1580,9 +1631,9 @@ var promptCreateFolderTreeTool = {
|
|
|
1580
1631
|
var promptAddPlanStepsTool = {
|
|
1581
1632
|
name: "prompt.add_plan_steps",
|
|
1582
1633
|
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.",
|
|
1583
|
-
inputSchema:
|
|
1584
|
-
planId:
|
|
1585
|
-
requestIds:
|
|
1634
|
+
inputSchema: z8.object({
|
|
1635
|
+
planId: z8.string(),
|
|
1636
|
+
requestIds: z8.array(z8.string()).min(1)
|
|
1586
1637
|
}),
|
|
1587
1638
|
async handler(input, ctx) {
|
|
1588
1639
|
const state = await ctx.workspace.read();
|
|
@@ -1612,9 +1663,9 @@ var promptAddPlanStepsTool = {
|
|
|
1612
1663
|
var promptSetPlanVariablesTool = {
|
|
1613
1664
|
name: "prompt.set_plan_variables",
|
|
1614
1665
|
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.",
|
|
1615
|
-
inputSchema:
|
|
1616
|
-
planId:
|
|
1617
|
-
variables:
|
|
1666
|
+
inputSchema: z8.object({
|
|
1667
|
+
planId: z8.string(),
|
|
1668
|
+
variables: z8.array(z8.object({ key: z8.string(), value: z8.string() }))
|
|
1618
1669
|
}),
|
|
1619
1670
|
async handler(input, ctx) {
|
|
1620
1671
|
const state = await ctx.workspace.read();
|
|
@@ -1630,10 +1681,10 @@ var promptSetPlanVariablesTool = {
|
|
|
1630
1681
|
var promptCreateMockServerTool = {
|
|
1631
1682
|
name: "prompt.create_mock_server",
|
|
1632
1683
|
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.",
|
|
1633
|
-
inputSchema:
|
|
1634
|
-
name:
|
|
1635
|
-
defaultPort:
|
|
1636
|
-
endpoints:
|
|
1684
|
+
inputSchema: z8.object({
|
|
1685
|
+
name: z8.string().min(1),
|
|
1686
|
+
defaultPort: z8.number().int().positive().nullable().optional(),
|
|
1687
|
+
endpoints: z8.array(ENDPOINT_INPUT).default([])
|
|
1637
1688
|
}),
|
|
1638
1689
|
async handler(input, ctx) {
|
|
1639
1690
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -1660,16 +1711,16 @@ var promptCreateMockServerTool = {
|
|
|
1660
1711
|
var promptAddMockEndpointTool = {
|
|
1661
1712
|
name: "prompt.add_mock_endpoint",
|
|
1662
1713
|
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.",
|
|
1663
|
-
inputSchema:
|
|
1664
|
-
mockId:
|
|
1714
|
+
inputSchema: z8.object({
|
|
1715
|
+
mockId: z8.string(),
|
|
1665
1716
|
method: HTTP_METHOD2,
|
|
1666
|
-
pathPattern:
|
|
1667
|
-
name:
|
|
1668
|
-
description:
|
|
1717
|
+
pathPattern: z8.string().min(1),
|
|
1718
|
+
name: z8.string().optional(),
|
|
1719
|
+
description: z8.string().optional(),
|
|
1669
1720
|
response: ENDPOINT_RESPONSE.optional(),
|
|
1670
|
-
validationRules:
|
|
1671
|
-
responseRules:
|
|
1672
|
-
multipliers:
|
|
1721
|
+
validationRules: z8.array(VALIDATION_RULE_NL).default([]),
|
|
1722
|
+
responseRules: z8.array(RESPONSE_RULE_NL).default([]),
|
|
1723
|
+
multipliers: z8.array(MULTIPLIER_NL).default([])
|
|
1673
1724
|
}),
|
|
1674
1725
|
async handler(input, ctx) {
|
|
1675
1726
|
const state = await ctx.workspace.read();
|
|
@@ -1691,10 +1742,10 @@ var promptAddMockEndpointTool = {
|
|
|
1691
1742
|
var promptSetEndpointValidationRulesTool = {
|
|
1692
1743
|
name: "prompt.set_endpoint_validation_rules",
|
|
1693
1744
|
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.",
|
|
1694
|
-
inputSchema:
|
|
1695
|
-
mockId:
|
|
1696
|
-
endpointId:
|
|
1697
|
-
rules:
|
|
1745
|
+
inputSchema: z8.object({
|
|
1746
|
+
mockId: z8.string(),
|
|
1747
|
+
endpointId: z8.string(),
|
|
1748
|
+
rules: z8.array(VALIDATION_RULE_NL)
|
|
1698
1749
|
}),
|
|
1699
1750
|
async handler(input, ctx) {
|
|
1700
1751
|
const state = await ctx.workspace.read();
|
|
@@ -1725,10 +1776,10 @@ var promptSetEndpointValidationRulesTool = {
|
|
|
1725
1776
|
var promptSetEndpointResponseRulesTool = {
|
|
1726
1777
|
name: "prompt.set_endpoint_response_rules",
|
|
1727
1778
|
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.",
|
|
1728
|
-
inputSchema:
|
|
1729
|
-
mockId:
|
|
1730
|
-
endpointId:
|
|
1731
|
-
rules:
|
|
1779
|
+
inputSchema: z8.object({
|
|
1780
|
+
mockId: z8.string(),
|
|
1781
|
+
endpointId: z8.string(),
|
|
1782
|
+
rules: z8.array(RESPONSE_RULE_NL)
|
|
1732
1783
|
}),
|
|
1733
1784
|
async handler(input, ctx) {
|
|
1734
1785
|
const state = await ctx.workspace.read();
|
|
@@ -1763,10 +1814,10 @@ var promptSetEndpointResponseRulesTool = {
|
|
|
1763
1814
|
var promptSetEndpointMultipliersTool = {
|
|
1764
1815
|
name: "prompt.set_endpoint_multipliers",
|
|
1765
1816
|
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.",
|
|
1766
|
-
inputSchema:
|
|
1767
|
-
mockId:
|
|
1768
|
-
endpointId:
|
|
1769
|
-
multipliers:
|
|
1817
|
+
inputSchema: z8.object({
|
|
1818
|
+
mockId: z8.string(),
|
|
1819
|
+
endpointId: z8.string(),
|
|
1820
|
+
multipliers: z8.array(MULTIPLIER_NL)
|
|
1770
1821
|
}),
|
|
1771
1822
|
async handler(input, ctx) {
|
|
1772
1823
|
const state = await ctx.workspace.read();
|
|
@@ -1795,7 +1846,7 @@ var promptSetEndpointMultipliersTool = {
|
|
|
1795
1846
|
};
|
|
1796
1847
|
|
|
1797
1848
|
// src/tools/mocks.ts
|
|
1798
|
-
import { z as
|
|
1849
|
+
import { z as z9 } from "zod";
|
|
1799
1850
|
import { generateId as generateId4, makeDefaultMockResponse as makeDefaultMockResponse2, makeDefaultRequestSchema as makeDefaultRequestSchema2 } from "@apicircle/shared";
|
|
1800
1851
|
import { parseSourceToEndpoints } from "@apicircle/mock-server-core";
|
|
1801
1852
|
async function ingestSource(source, name) {
|
|
@@ -1818,10 +1869,10 @@ async function ingestSource(source, name) {
|
|
|
1818
1869
|
var mockCreateFromOpenApiTool = {
|
|
1819
1870
|
name: "mock.create_from_openapi",
|
|
1820
1871
|
description: "Create a mock server from an OpenAPI / Swagger spec (YAML or JSON).",
|
|
1821
|
-
inputSchema:
|
|
1822
|
-
name:
|
|
1823
|
-
spec:
|
|
1824
|
-
format:
|
|
1872
|
+
inputSchema: z9.object({
|
|
1873
|
+
name: z9.string(),
|
|
1874
|
+
spec: z9.string().min(1),
|
|
1875
|
+
format: z9.enum(["json", "yaml"]).default("json")
|
|
1825
1876
|
}),
|
|
1826
1877
|
async handler(input, ctx) {
|
|
1827
1878
|
const { mock, warnings } = await ingestSource(
|
|
@@ -1840,7 +1891,7 @@ var mockCreateFromOpenApiTool = {
|
|
|
1840
1891
|
var mockCreateFromPostmanTool = {
|
|
1841
1892
|
name: "mock.create_from_postman",
|
|
1842
1893
|
description: "Create a mock server from a Postman v2/v2.1 collection.",
|
|
1843
|
-
inputSchema:
|
|
1894
|
+
inputSchema: z9.object({ name: z9.string(), collection: z9.string().min(1) }),
|
|
1844
1895
|
async handler(input, ctx) {
|
|
1845
1896
|
const { mock, warnings } = await ingestSource(
|
|
1846
1897
|
{ kind: "postman", collection: input.collection },
|
|
@@ -1858,7 +1909,7 @@ var mockCreateFromPostmanTool = {
|
|
|
1858
1909
|
var mockCreateFromInsomniaTool = {
|
|
1859
1910
|
name: "mock.create_from_insomnia",
|
|
1860
1911
|
description: "Create a mock server from an Insomnia v4 export.",
|
|
1861
|
-
inputSchema:
|
|
1912
|
+
inputSchema: z9.object({ name: z9.string(), export: z9.string().min(1) }),
|
|
1862
1913
|
async handler(input, ctx) {
|
|
1863
1914
|
const { mock, warnings } = await ingestSource(
|
|
1864
1915
|
{ kind: "insomnia", export: input.export },
|
|
@@ -1876,7 +1927,7 @@ var mockCreateFromInsomniaTool = {
|
|
|
1876
1927
|
var mockImportPostmanMockCollectionTool = {
|
|
1877
1928
|
name: "mock.import_postman_mock_collection",
|
|
1878
1929
|
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.",
|
|
1879
|
-
inputSchema:
|
|
1930
|
+
inputSchema: z9.object({ name: z9.string(), collection: z9.string().min(1) }),
|
|
1880
1931
|
async handler(input, ctx) {
|
|
1881
1932
|
const { mock, warnings } = await ingestSource(
|
|
1882
1933
|
{ kind: "postman", collection: input.collection },
|
|
@@ -1894,7 +1945,7 @@ var mockImportPostmanMockCollectionTool = {
|
|
|
1894
1945
|
var mockListTool = {
|
|
1895
1946
|
name: "mock.list",
|
|
1896
1947
|
description: "List all mock servers in the workspace plus their runtime status (running / stopped, port).",
|
|
1897
|
-
inputSchema:
|
|
1948
|
+
inputSchema: z9.object({}),
|
|
1898
1949
|
async handler(_input, ctx) {
|
|
1899
1950
|
const state = await ctx.workspace.read();
|
|
1900
1951
|
const running = await ctx.mock.list();
|
|
@@ -1916,9 +1967,9 @@ var mockListTool = {
|
|
|
1916
1967
|
var mockStartTool = {
|
|
1917
1968
|
name: "mock.start",
|
|
1918
1969
|
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.",
|
|
1919
|
-
inputSchema:
|
|
1920
|
-
id:
|
|
1921
|
-
port:
|
|
1970
|
+
inputSchema: z9.object({
|
|
1971
|
+
id: z9.string(),
|
|
1972
|
+
port: z9.number().int().positive().optional()
|
|
1922
1973
|
}),
|
|
1923
1974
|
async handler(input, ctx) {
|
|
1924
1975
|
const state = await ctx.workspace.read();
|
|
@@ -1935,7 +1986,7 @@ var mockStartTool = {
|
|
|
1935
1986
|
var mockStopTool = {
|
|
1936
1987
|
name: "mock.stop",
|
|
1937
1988
|
description: "Stop a running mock server by id (no-op if not running).",
|
|
1938
|
-
inputSchema:
|
|
1989
|
+
inputSchema: z9.object({ id: z9.string() }),
|
|
1939
1990
|
async handler(input, ctx) {
|
|
1940
1991
|
try {
|
|
1941
1992
|
await ctx.mock.stop(input.id);
|
|
@@ -1948,7 +1999,7 @@ var mockStopTool = {
|
|
|
1948
1999
|
var mockDeleteTool = {
|
|
1949
2000
|
name: "mock.delete",
|
|
1950
2001
|
description: "Delete a mock server definition. Stops it first if it's running.",
|
|
1951
|
-
inputSchema:
|
|
2002
|
+
inputSchema: z9.object({ id: z9.string() }),
|
|
1952
2003
|
async handler(input, ctx) {
|
|
1953
2004
|
try {
|
|
1954
2005
|
await ctx.mock.stop(input.id);
|
|
@@ -1958,13 +2009,13 @@ var mockDeleteTool = {
|
|
|
1958
2009
|
return { ok: true, changedIds: out.changedIds };
|
|
1959
2010
|
}
|
|
1960
2011
|
};
|
|
1961
|
-
var HTTP_METHOD3 =
|
|
2012
|
+
var HTTP_METHOD3 = z9.enum(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"]);
|
|
1962
2013
|
var mockCreateManualTool = {
|
|
1963
2014
|
name: "mock.create_manual",
|
|
1964
2015
|
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.",
|
|
1965
|
-
inputSchema:
|
|
1966
|
-
name:
|
|
1967
|
-
defaultPort:
|
|
2016
|
+
inputSchema: z9.object({
|
|
2017
|
+
name: z9.string().min(1),
|
|
2018
|
+
defaultPort: z9.number().int().positive().nullable().optional()
|
|
1968
2019
|
}),
|
|
1969
2020
|
async handler(input, ctx) {
|
|
1970
2021
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -1987,7 +2038,7 @@ var mockCreateManualTool = {
|
|
|
1987
2038
|
var mockListEndpointsTool = {
|
|
1988
2039
|
name: "mock.list_endpoints",
|
|
1989
2040
|
description: "List endpoints for a mock server (id, method, path, name).",
|
|
1990
|
-
inputSchema:
|
|
2041
|
+
inputSchema: z9.object({ mockId: z9.string() }),
|
|
1991
2042
|
async handler(input, ctx) {
|
|
1992
2043
|
const state = await ctx.workspace.read();
|
|
1993
2044
|
const mock = state.synced.mockServers[input.mockId];
|
|
@@ -2006,10 +2057,10 @@ var mockListEndpointsTool = {
|
|
|
2006
2057
|
};
|
|
2007
2058
|
}
|
|
2008
2059
|
};
|
|
2009
|
-
var ENDPOINT_RESPONSE2 =
|
|
2010
|
-
status:
|
|
2011
|
-
jsonBody:
|
|
2012
|
-
contentType:
|
|
2060
|
+
var ENDPOINT_RESPONSE2 = z9.object({
|
|
2061
|
+
status: z9.number().int().min(100).max(599).default(200),
|
|
2062
|
+
jsonBody: z9.string().default("{}"),
|
|
2063
|
+
contentType: z9.string().default("application/json")
|
|
2013
2064
|
});
|
|
2014
2065
|
function buildDefaultEndpoint(args) {
|
|
2015
2066
|
const response = args.response ?? {
|
|
@@ -2038,12 +2089,12 @@ function buildDefaultEndpoint(args) {
|
|
|
2038
2089
|
var mockAddEndpointTool = {
|
|
2039
2090
|
name: "mock.add_endpoint",
|
|
2040
2091
|
description: "Append a new endpoint to a mock server. Defaults to a 200 JSON response of `{}`. Returns the new endpoint id.",
|
|
2041
|
-
inputSchema:
|
|
2042
|
-
mockId:
|
|
2092
|
+
inputSchema: z9.object({
|
|
2093
|
+
mockId: z9.string(),
|
|
2043
2094
|
method: HTTP_METHOD3,
|
|
2044
|
-
pathPattern:
|
|
2045
|
-
name:
|
|
2046
|
-
description:
|
|
2095
|
+
pathPattern: z9.string().min(1),
|
|
2096
|
+
name: z9.string().optional(),
|
|
2097
|
+
description: z9.string().optional(),
|
|
2047
2098
|
response: ENDPOINT_RESPONSE2.optional()
|
|
2048
2099
|
}),
|
|
2049
2100
|
async handler(input, ctx) {
|
|
@@ -2066,13 +2117,13 @@ var mockAddEndpointTool = {
|
|
|
2066
2117
|
var mockUpdateEndpointTool = {
|
|
2067
2118
|
name: "mock.update_endpoint",
|
|
2068
2119
|
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.",
|
|
2069
|
-
inputSchema:
|
|
2070
|
-
mockId:
|
|
2071
|
-
endpointId:
|
|
2120
|
+
inputSchema: z9.object({
|
|
2121
|
+
mockId: z9.string(),
|
|
2122
|
+
endpointId: z9.string(),
|
|
2072
2123
|
method: HTTP_METHOD3.optional(),
|
|
2073
|
-
pathPattern:
|
|
2074
|
-
name:
|
|
2075
|
-
description:
|
|
2124
|
+
pathPattern: z9.string().optional(),
|
|
2125
|
+
name: z9.string().optional(),
|
|
2126
|
+
description: z9.string().optional(),
|
|
2076
2127
|
response: ENDPOINT_RESPONSE2.partial().optional()
|
|
2077
2128
|
}),
|
|
2078
2129
|
async handler(input, ctx) {
|
|
@@ -2113,7 +2164,7 @@ var mockUpdateEndpointTool = {
|
|
|
2113
2164
|
var mockDeleteEndpointTool = {
|
|
2114
2165
|
name: "mock.delete_endpoint",
|
|
2115
2166
|
description: "Remove an endpoint from a mock server.",
|
|
2116
|
-
inputSchema:
|
|
2167
|
+
inputSchema: z9.object({ mockId: z9.string(), endpointId: z9.string() }),
|
|
2117
2168
|
async handler(input, ctx) {
|
|
2118
2169
|
const state = await ctx.workspace.read();
|
|
2119
2170
|
const mock = state.synced.mockServers[input.mockId];
|
|
@@ -2133,9 +2184,9 @@ var mockDeleteEndpointTool = {
|
|
|
2133
2184
|
return { ok: true, changedIds: out.changedIds };
|
|
2134
2185
|
}
|
|
2135
2186
|
};
|
|
2136
|
-
var VALIDATION_RULE =
|
|
2137
|
-
id:
|
|
2138
|
-
kind:
|
|
2187
|
+
var VALIDATION_RULE = z9.object({
|
|
2188
|
+
id: z9.string().optional(),
|
|
2189
|
+
kind: z9.enum([
|
|
2139
2190
|
"header-required",
|
|
2140
2191
|
"header-equals",
|
|
2141
2192
|
"header-matches",
|
|
@@ -2146,43 +2197,43 @@ var VALIDATION_RULE = z8.object({
|
|
|
2146
2197
|
"body-required",
|
|
2147
2198
|
"content-type-equals"
|
|
2148
2199
|
]),
|
|
2149
|
-
target:
|
|
2150
|
-
expected:
|
|
2151
|
-
message:
|
|
2152
|
-
enabled:
|
|
2153
|
-
failResponse:
|
|
2154
|
-
status:
|
|
2155
|
-
jsonBody:
|
|
2200
|
+
target: z9.string().default(""),
|
|
2201
|
+
expected: z9.string().optional(),
|
|
2202
|
+
message: z9.string().optional(),
|
|
2203
|
+
enabled: z9.boolean().default(true),
|
|
2204
|
+
failResponse: z9.object({
|
|
2205
|
+
status: z9.number().int().min(100).max(599).default(400),
|
|
2206
|
+
jsonBody: z9.string().default('{"error":"validation failed"}')
|
|
2156
2207
|
}).default({})
|
|
2157
2208
|
});
|
|
2158
|
-
var CONDITION_CLAUSE =
|
|
2159
|
-
id:
|
|
2160
|
-
scope:
|
|
2161
|
-
target:
|
|
2162
|
-
op:
|
|
2163
|
-
value:
|
|
2209
|
+
var CONDITION_CLAUSE = z9.object({
|
|
2210
|
+
id: z9.string().optional(),
|
|
2211
|
+
scope: z9.enum(["query", "pathParam", "header", "cookie", "body-json-path"]),
|
|
2212
|
+
target: z9.string(),
|
|
2213
|
+
op: z9.enum(["equals", "not-equals", "matches", "gt", "lt", "gte", "lte", "present", "absent"]),
|
|
2214
|
+
value: z9.string().optional()
|
|
2164
2215
|
});
|
|
2165
|
-
var RESPONSE_RULE =
|
|
2166
|
-
id:
|
|
2167
|
-
name:
|
|
2168
|
-
enabled:
|
|
2169
|
-
when:
|
|
2170
|
-
response:
|
|
2171
|
-
status:
|
|
2172
|
-
jsonBody:
|
|
2216
|
+
var RESPONSE_RULE = z9.object({
|
|
2217
|
+
id: z9.string().optional(),
|
|
2218
|
+
name: z9.string(),
|
|
2219
|
+
enabled: z9.boolean().default(true),
|
|
2220
|
+
when: z9.array(CONDITION_CLAUSE).default([]),
|
|
2221
|
+
response: z9.object({
|
|
2222
|
+
status: z9.number().int().min(100).max(599).default(200),
|
|
2223
|
+
jsonBody: z9.string().default("{}")
|
|
2173
2224
|
}).default({})
|
|
2174
2225
|
});
|
|
2175
|
-
var MULTIPLIER =
|
|
2176
|
-
id:
|
|
2177
|
-
name:
|
|
2178
|
-
source:
|
|
2179
|
-
kind:
|
|
2180
|
-
key:
|
|
2226
|
+
var MULTIPLIER = z9.object({
|
|
2227
|
+
id: z9.string().optional(),
|
|
2228
|
+
name: z9.string().optional(),
|
|
2229
|
+
source: z9.object({
|
|
2230
|
+
kind: z9.enum(["query", "pathParam", "header", "body-json-path"]),
|
|
2231
|
+
key: z9.string()
|
|
2181
2232
|
}),
|
|
2182
|
-
targetJsonPath:
|
|
2183
|
-
defaultCount:
|
|
2184
|
-
min:
|
|
2185
|
-
max:
|
|
2233
|
+
targetJsonPath: z9.string(),
|
|
2234
|
+
defaultCount: z9.number().int().nonnegative().default(0),
|
|
2235
|
+
min: z9.number().int().nonnegative().optional(),
|
|
2236
|
+
max: z9.number().int().nonnegative().optional()
|
|
2186
2237
|
});
|
|
2187
2238
|
function defaultJsonResponseConfig(args) {
|
|
2188
2239
|
return {
|
|
@@ -2207,10 +2258,10 @@ function patchEndpoint2(mock, endpointId, patcher) {
|
|
|
2207
2258
|
var mockSetValidationRulesTool = {
|
|
2208
2259
|
name: "mock.set_validation_rules",
|
|
2209
2260
|
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.",
|
|
2210
|
-
inputSchema:
|
|
2211
|
-
mockId:
|
|
2212
|
-
endpointId:
|
|
2213
|
-
rules:
|
|
2261
|
+
inputSchema: z9.object({
|
|
2262
|
+
mockId: z9.string(),
|
|
2263
|
+
endpointId: z9.string(),
|
|
2264
|
+
rules: z9.array(VALIDATION_RULE)
|
|
2214
2265
|
}),
|
|
2215
2266
|
async handler(input, ctx) {
|
|
2216
2267
|
const state = await ctx.workspace.read();
|
|
@@ -2237,10 +2288,10 @@ var mockSetValidationRulesTool = {
|
|
|
2237
2288
|
var mockSetResponseRulesTool = {
|
|
2238
2289
|
name: "mock.set_response_rules",
|
|
2239
2290
|
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.",
|
|
2240
|
-
inputSchema:
|
|
2241
|
-
mockId:
|
|
2242
|
-
endpointId:
|
|
2243
|
-
rules:
|
|
2291
|
+
inputSchema: z9.object({
|
|
2292
|
+
mockId: z9.string(),
|
|
2293
|
+
endpointId: z9.string(),
|
|
2294
|
+
rules: z9.array(RESPONSE_RULE)
|
|
2244
2295
|
}),
|
|
2245
2296
|
async handler(input, ctx) {
|
|
2246
2297
|
const state = await ctx.workspace.read();
|
|
@@ -2271,10 +2322,10 @@ var mockSetResponseRulesTool = {
|
|
|
2271
2322
|
var mockSetMultipliersTool = {
|
|
2272
2323
|
name: "mock.set_multipliers",
|
|
2273
2324
|
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.",
|
|
2274
|
-
inputSchema:
|
|
2275
|
-
mockId:
|
|
2276
|
-
endpointId:
|
|
2277
|
-
multipliers:
|
|
2325
|
+
inputSchema: z9.object({
|
|
2326
|
+
mockId: z9.string(),
|
|
2327
|
+
endpointId: z9.string(),
|
|
2328
|
+
multipliers: z9.array(MULTIPLIER)
|
|
2278
2329
|
}),
|
|
2279
2330
|
async handler(input, ctx) {
|
|
2280
2331
|
const state = await ctx.workspace.read();
|
|
@@ -2310,6 +2361,7 @@ var TOOL_REGISTRY = [
|
|
|
2310
2361
|
importInsomniaTool,
|
|
2311
2362
|
importHarTool,
|
|
2312
2363
|
generateCodeTool,
|
|
2364
|
+
workspaceListTool,
|
|
2313
2365
|
workspaceReadTool,
|
|
2314
2366
|
workspaceWriteTool,
|
|
2315
2367
|
requestCreateTool,
|
|
@@ -2380,6 +2432,63 @@ function getTool(name) {
|
|
|
2380
2432
|
return TOOL_REGISTRY.find((t) => t.name === name);
|
|
2381
2433
|
}
|
|
2382
2434
|
|
|
2435
|
+
// src/providers/Workspaces.ts
|
|
2436
|
+
var SingleWorkspaceAdapter = class {
|
|
2437
|
+
constructor(provider, workspaceId, displayName = "Workspace") {
|
|
2438
|
+
this.provider = provider;
|
|
2439
|
+
this.workspaceId = workspaceId;
|
|
2440
|
+
this.displayName = displayName;
|
|
2441
|
+
}
|
|
2442
|
+
provider;
|
|
2443
|
+
workspaceId;
|
|
2444
|
+
displayName;
|
|
2445
|
+
async list() {
|
|
2446
|
+
const state = await this.provider.read();
|
|
2447
|
+
const id = state.synced.workspaceId;
|
|
2448
|
+
this.workspaceId = id;
|
|
2449
|
+
return [
|
|
2450
|
+
{
|
|
2451
|
+
id,
|
|
2452
|
+
name: this.displayName,
|
|
2453
|
+
isActive: true,
|
|
2454
|
+
createdAt: state.synced.meta.createdAt,
|
|
2455
|
+
lastOpenedAt: state.synced.meta.updatedAt,
|
|
2456
|
+
counts: {
|
|
2457
|
+
requests: Object.keys(state.synced.collections.requests).length,
|
|
2458
|
+
folders: Object.keys(state.synced.collections.folders).length,
|
|
2459
|
+
environments: Object.keys(state.synced.environments.items).length,
|
|
2460
|
+
mockServers: Object.keys(state.synced.mockServers ?? {}).length,
|
|
2461
|
+
plans: Object.keys(state.synced.executionPlans ?? {}).length
|
|
2462
|
+
}
|
|
2463
|
+
}
|
|
2464
|
+
];
|
|
2465
|
+
}
|
|
2466
|
+
for(workspaceId) {
|
|
2467
|
+
if (this.workspaceId && workspaceId !== this.workspaceId) {
|
|
2468
|
+
throw new WorkspaceNotFoundError(workspaceId);
|
|
2469
|
+
}
|
|
2470
|
+
return this.provider;
|
|
2471
|
+
}
|
|
2472
|
+
activeId() {
|
|
2473
|
+
return this.workspaceId;
|
|
2474
|
+
}
|
|
2475
|
+
setActive(workspaceId) {
|
|
2476
|
+
if (this.workspaceId && workspaceId !== this.workspaceId) {
|
|
2477
|
+
throw new WorkspaceNotFoundError(workspaceId);
|
|
2478
|
+
}
|
|
2479
|
+
return Promise.resolve();
|
|
2480
|
+
}
|
|
2481
|
+
};
|
|
2482
|
+
var WorkspaceNotFoundError = class extends Error {
|
|
2483
|
+
code = "workspace-not-found";
|
|
2484
|
+
workspaceId;
|
|
2485
|
+
constructor(workspaceId) {
|
|
2486
|
+
super(`No workspace with id "${workspaceId}" is available on this server.`);
|
|
2487
|
+
this.name = "WorkspaceNotFoundError";
|
|
2488
|
+
this.workspaceId = workspaceId;
|
|
2489
|
+
}
|
|
2490
|
+
};
|
|
2491
|
+
|
|
2383
2492
|
// src/providers/InMemoryWorkspaceProvider.ts
|
|
2384
2493
|
import { applyMutation } from "@apicircle/core";
|
|
2385
2494
|
var InMemoryWorkspaceProvider = class {
|
|
@@ -2440,6 +2549,115 @@ var FileBackedWorkspaceProvider = class {
|
|
|
2440
2549
|
}
|
|
2441
2550
|
};
|
|
2442
2551
|
|
|
2552
|
+
// src/providers/MultiWorkspaceProvider.ts
|
|
2553
|
+
import {
|
|
2554
|
+
loadRegistry,
|
|
2555
|
+
loadWorkspaceById,
|
|
2556
|
+
saveRegistry,
|
|
2557
|
+
setActiveWorkspace as setActiveWorkspaceOnDisk,
|
|
2558
|
+
workspaceDirFor
|
|
2559
|
+
} from "@apicircle/core/workspace/registry";
|
|
2560
|
+
var MultiWorkspaceProvider = class {
|
|
2561
|
+
constructor(registryRoot) {
|
|
2562
|
+
this.registryRoot = registryRoot;
|
|
2563
|
+
}
|
|
2564
|
+
registryRoot;
|
|
2565
|
+
active = null;
|
|
2566
|
+
activeWorkspaceId = null;
|
|
2567
|
+
/**
|
|
2568
|
+
* Hydrate the active provider from disk. Must be called once before the
|
|
2569
|
+
* MCP host boots so `ctx.workspace.read()` doesn't race the first
|
|
2570
|
+
* registry-load. Returns the registry the boot can log.
|
|
2571
|
+
*/
|
|
2572
|
+
async init() {
|
|
2573
|
+
const registry = await loadRegistry(this.registryRoot) ?? {
|
|
2574
|
+
schemaVersion: 1,
|
|
2575
|
+
activeWorkspaceId: null,
|
|
2576
|
+
workspaces: []
|
|
2577
|
+
};
|
|
2578
|
+
if (registry.activeWorkspaceId) {
|
|
2579
|
+
this.activeWorkspaceId = registry.activeWorkspaceId;
|
|
2580
|
+
this.active = new FileBackedWorkspaceProvider(
|
|
2581
|
+
workspaceDirFor(this.registryRoot, registry.activeWorkspaceId)
|
|
2582
|
+
);
|
|
2583
|
+
}
|
|
2584
|
+
return registry;
|
|
2585
|
+
}
|
|
2586
|
+
/** The provider tool handlers see as `ctx.workspace`. */
|
|
2587
|
+
activeProvider() {
|
|
2588
|
+
if (!this.active) {
|
|
2589
|
+
throw new Error(
|
|
2590
|
+
"No active workspace. Open the desktop app at least once, or run `apicircle workspaces create <name>`."
|
|
2591
|
+
);
|
|
2592
|
+
}
|
|
2593
|
+
return this.active;
|
|
2594
|
+
}
|
|
2595
|
+
// ─── Workspaces interface ──────────────────────────────────────────────────
|
|
2596
|
+
async list() {
|
|
2597
|
+
const registry = await loadRegistry(this.registryRoot) ?? {
|
|
2598
|
+
schemaVersion: 1,
|
|
2599
|
+
activeWorkspaceId: null,
|
|
2600
|
+
workspaces: []
|
|
2601
|
+
};
|
|
2602
|
+
const out = [];
|
|
2603
|
+
for (const entry of registry.workspaces) {
|
|
2604
|
+
let counts = null;
|
|
2605
|
+
try {
|
|
2606
|
+
const state = await loadWorkspaceById(this.registryRoot, entry.id);
|
|
2607
|
+
if (state) {
|
|
2608
|
+
counts = {
|
|
2609
|
+
requests: Object.keys(state.synced.collections.requests).length,
|
|
2610
|
+
folders: Object.keys(state.synced.collections.folders).length,
|
|
2611
|
+
environments: Object.keys(state.synced.environments.items).length,
|
|
2612
|
+
mockServers: Object.keys(state.synced.mockServers ?? {}).length,
|
|
2613
|
+
plans: Object.keys(state.synced.executionPlans ?? {}).length
|
|
2614
|
+
};
|
|
2615
|
+
}
|
|
2616
|
+
} catch {
|
|
2617
|
+
counts = null;
|
|
2618
|
+
}
|
|
2619
|
+
out.push({
|
|
2620
|
+
id: entry.id,
|
|
2621
|
+
name: entry.name,
|
|
2622
|
+
isActive: entry.id === registry.activeWorkspaceId,
|
|
2623
|
+
createdAt: entry.createdAt,
|
|
2624
|
+
lastOpenedAt: entry.lastOpenedAt,
|
|
2625
|
+
counts
|
|
2626
|
+
});
|
|
2627
|
+
}
|
|
2628
|
+
return out;
|
|
2629
|
+
}
|
|
2630
|
+
for(workspaceId) {
|
|
2631
|
+
return new FileBackedWorkspaceProvider(workspaceDirFor(this.registryRoot, workspaceId));
|
|
2632
|
+
}
|
|
2633
|
+
activeId() {
|
|
2634
|
+
return this.activeWorkspaceId;
|
|
2635
|
+
}
|
|
2636
|
+
async setActive(workspaceId) {
|
|
2637
|
+
const registry = await loadRegistry(this.registryRoot);
|
|
2638
|
+
if (!registry || !registry.workspaces.some((w) => w.id === workspaceId)) {
|
|
2639
|
+
throw new WorkspaceNotFoundError(workspaceId);
|
|
2640
|
+
}
|
|
2641
|
+
const next = await setActiveWorkspaceOnDisk(this.registryRoot, workspaceId);
|
|
2642
|
+
void next;
|
|
2643
|
+
this.activeWorkspaceId = workspaceId;
|
|
2644
|
+
this.active = new FileBackedWorkspaceProvider(workspaceDirFor(this.registryRoot, workspaceId));
|
|
2645
|
+
}
|
|
2646
|
+
/**
|
|
2647
|
+
* Idempotent registry write — used by tests / tools that need to
|
|
2648
|
+
* persist registry updates that didn't go through `setActive`.
|
|
2649
|
+
*/
|
|
2650
|
+
async writeRegistry(registry) {
|
|
2651
|
+
await saveRegistry(this.registryRoot, registry);
|
|
2652
|
+
this.activeWorkspaceId = registry.activeWorkspaceId;
|
|
2653
|
+
if (registry.activeWorkspaceId) {
|
|
2654
|
+
this.active = new FileBackedWorkspaceProvider(
|
|
2655
|
+
workspaceDirFor(this.registryRoot, registry.activeWorkspaceId)
|
|
2656
|
+
);
|
|
2657
|
+
}
|
|
2658
|
+
}
|
|
2659
|
+
};
|
|
2660
|
+
|
|
2443
2661
|
// src/providers/InProcessMockController.ts
|
|
2444
2662
|
import {
|
|
2445
2663
|
startMockServer,
|
|
@@ -2483,10 +2701,19 @@ var InProcessMockController = class {
|
|
|
2483
2701
|
|
|
2484
2702
|
// src/index.ts
|
|
2485
2703
|
function createMcpServer(options) {
|
|
2704
|
+
const workspaces = options.workspaces ?? new SingleWorkspaceAdapter(
|
|
2705
|
+
options.workspace,
|
|
2706
|
+
null
|
|
2707
|
+
/* discovered on first list() */
|
|
2708
|
+
);
|
|
2486
2709
|
return new McpHost({
|
|
2487
2710
|
serverInfo: options.serverInfo,
|
|
2488
2711
|
tools: options.tools ?? TOOL_REGISTRY,
|
|
2489
|
-
context: {
|
|
2712
|
+
context: {
|
|
2713
|
+
workspace: options.workspace,
|
|
2714
|
+
workspaces,
|
|
2715
|
+
mock: options.mock
|
|
2716
|
+
}
|
|
2490
2717
|
});
|
|
2491
2718
|
}
|
|
2492
2719
|
export {
|
|
@@ -2494,7 +2721,10 @@ export {
|
|
|
2494
2721
|
InMemoryWorkspaceProvider,
|
|
2495
2722
|
InProcessMockController,
|
|
2496
2723
|
McpHost,
|
|
2724
|
+
MultiWorkspaceProvider,
|
|
2725
|
+
SingleWorkspaceAdapter,
|
|
2497
2726
|
TOOL_REGISTRY,
|
|
2727
|
+
WorkspaceNotFoundError,
|
|
2498
2728
|
createMcpServer,
|
|
2499
2729
|
getTool
|
|
2500
2730
|
};
|