callman-mcp 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +36 -59
- package/README.md +18 -24
- package/dist/client/api.d.ts +18 -40
- package/dist/client/api.d.ts.map +1 -1
- package/dist/client/api.js +7 -54
- package/dist/client/api.js.map +1 -1
- package/dist/client/types.d.ts +19 -44
- package/dist/client/types.d.ts.map +1 -1
- package/dist/config.d.ts +4 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +5 -0
- package/dist/config.js.map +1 -1
- package/dist/domain/diagram/build.d.ts +17 -17
- package/dist/domain/diagram/build.d.ts.map +1 -1
- package/dist/domain/diagram/build.js +3 -3
- package/dist/domain/diagram/build.js.map +1 -1
- package/dist/domain/diagram/layout.d.ts +1 -3
- package/dist/domain/diagram/layout.d.ts.map +1 -1
- package/dist/domain/diagram/layout.js +3 -9
- package/dist/domain/diagram/layout.js.map +1 -1
- package/dist/domain/diagram/patch.d.ts +22 -723
- package/dist/domain/diagram/patch.d.ts.map +1 -1
- package/dist/domain/diagram/patch.js +0 -53
- package/dist/domain/diagram/patch.js.map +1 -1
- package/dist/domain/diagram/summarize.d.ts +0 -1
- package/dist/domain/diagram/summarize.d.ts.map +1 -1
- package/dist/domain/diagram/summarize.js +0 -1
- package/dist/domain/diagram/summarize.js.map +1 -1
- package/dist/domain/requestIntegrations.d.ts +13 -468
- package/dist/domain/requestIntegrations.d.ts.map +1 -1
- package/dist/domain/requestIntegrations.js +4 -95
- package/dist/domain/requestIntegrations.js.map +1 -1
- package/dist/domain/requestShape.d.ts +37 -679
- package/dist/domain/requestShape.d.ts.map +1 -1
- package/dist/domain/requestShape.js +2 -2
- package/dist/domain/requestShape.js.map +1 -1
- package/dist/domain/scenario/build.d.ts +6 -6
- package/dist/domain/scenario/build.d.ts.map +1 -1
- package/dist/domain/scenario/build.js +17 -68
- package/dist/domain/scenario/build.js.map +1 -1
- package/dist/domain/scenario/nodeConfig.d.ts.map +1 -1
- package/dist/domain/scenario/nodeConfig.js +16 -0
- package/dist/domain/scenario/nodeConfig.js.map +1 -1
- package/dist/domain/scenario/summarize.d.ts +0 -1
- package/dist/domain/scenario/summarize.d.ts.map +1 -1
- package/dist/domain/scenario/summarize.js +6 -1
- package/dist/domain/scenario/summarize.js.map +1 -1
- package/dist/index.js +16 -1
- package/dist/index.js.map +1 -1
- package/dist/resources/docs/collectionScripts.d.ts +2 -0
- package/dist/resources/docs/collectionScripts.d.ts.map +1 -0
- package/dist/resources/docs/collectionScripts.js +51 -0
- package/dist/resources/docs/collectionScripts.js.map +1 -0
- package/dist/resources/docs/diagramSchema.d.ts +1 -2
- package/dist/resources/docs/diagramSchema.d.ts.map +1 -1
- package/dist/resources/docs/diagramSchema.js +4 -63
- package/dist/resources/docs/diagramSchema.js.map +1 -1
- package/dist/resources/docs/overview.d.ts +1 -1
- package/dist/resources/docs/overview.d.ts.map +1 -1
- package/dist/resources/docs/overview.js +13 -34
- package/dist/resources/docs/overview.js.map +1 -1
- package/dist/resources/docs/requestSchema.d.ts +1 -1
- package/dist/resources/docs/requestSchema.d.ts.map +1 -1
- package/dist/resources/docs/requestSchema.js +11 -16
- package/dist/resources/docs/requestSchema.js.map +1 -1
- package/dist/resources/generated/aiPacks.d.ts +1 -1
- package/dist/resources/generated/aiPacks.js +6 -6
- package/dist/resources/generated/aiPacks.js.map +1 -1
- package/dist/resources/index.d.ts.map +1 -1
- package/dist/resources/index.js +5 -3
- package/dist/resources/index.js.map +1 -1
- package/dist/run/executeCollection.d.ts.map +1 -1
- package/dist/run/executeCollection.js +19 -3
- package/dist/run/executeCollection.js.map +1 -1
- package/dist/run/loadBundle.d.ts.map +1 -1
- package/dist/run/loadBundle.js +28 -3
- package/dist/run/loadBundle.js.map +1 -1
- package/dist/run/summarize.d.ts +4 -4
- package/dist/run/types.d.ts +5 -1
- package/dist/run/types.d.ts.map +1 -1
- package/dist/server.d.ts +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +2 -2
- package/dist/server.js.map +1 -1
- package/dist/tools/catalog.d.ts.map +1 -1
- package/dist/tools/catalog.js +3 -11
- package/dist/tools/catalog.js.map +1 -1
- package/dist/tools/collections.d.ts.map +1 -1
- package/dist/tools/collections.js +137 -16
- package/dist/tools/collections.js.map +1 -1
- package/dist/tools/contracts.js +2 -2
- package/dist/tools/contracts.js.map +1 -1
- package/dist/tools/diagrams.d.ts.map +1 -1
- package/dist/tools/diagrams.js +42 -331
- package/dist/tools/diagrams.js.map +1 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +4 -3
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/loadTest.d.ts +4 -0
- package/dist/tools/loadTest.d.ts.map +1 -0
- package/dist/tools/loadTest.js +299 -0
- package/dist/tools/loadTest.js.map +1 -0
- package/dist/tools/lookups.d.ts +1 -5
- package/dist/tools/lookups.d.ts.map +1 -1
- package/dist/tools/lookups.js +0 -41
- package/dist/tools/lookups.js.map +1 -1
- package/dist/tools/requests.js +3 -3
- package/dist/tools/requests.js.map +1 -1
- package/dist/tools/run.d.ts +18 -0
- package/dist/tools/run.d.ts.map +1 -1
- package/dist/tools/run.js +14 -5
- package/dist/tools/run.js.map +1 -1
- package/dist/tools/scenarios.d.ts +0 -4
- package/dist/tools/scenarios.d.ts.map +1 -1
- package/dist/tools/scenarios.js +17 -112
- package/dist/tools/scenarios.js.map +1 -1
- package/dist-cjs/client/api.js +7 -54
- package/dist-cjs/config.js +5 -0
- package/dist-cjs/domain/diagram/build.js +3 -3
- package/dist-cjs/domain/diagram/layout.js +3 -10
- package/dist-cjs/domain/diagram/patch.js +1 -54
- package/dist-cjs/domain/diagram/summarize.js +0 -1
- package/dist-cjs/domain/requestIntegrations.js +4 -95
- package/dist-cjs/domain/requestShape.js +2 -2
- package/dist-cjs/domain/scenario/build.js +17 -68
- package/dist-cjs/domain/scenario/nodeConfig.js +16 -0
- package/dist-cjs/domain/scenario/summarize.js +6 -1
- package/dist-cjs/resources/docs/collectionScripts.js +53 -0
- package/dist-cjs/resources/docs/diagramSchema.js +5 -65
- package/dist-cjs/resources/docs/overview.js +13 -34
- package/dist-cjs/resources/docs/requestSchema.js +11 -16
- package/dist-cjs/resources/generated/aiPacks.js +6 -6
- package/dist-cjs/resources/index.js +4 -2
- package/dist-cjs/run/executeCollection.js +18 -2
- package/dist-cjs/run/loadBundle.js +28 -3
- package/dist-cjs/server.js +2 -2
- package/dist-cjs/tools/catalog.js +3 -11
- package/dist-cjs/tools/collections.js +137 -16
- package/dist-cjs/tools/contracts.js +2 -2
- package/dist-cjs/tools/diagrams.js +37 -326
- package/dist-cjs/tools/index.js +4 -3
- package/dist-cjs/tools/loadTest.js +335 -0
- package/dist-cjs/tools/lookups.js +1 -46
- package/dist-cjs/tools/requests.js +3 -3
- package/dist-cjs/tools/run.js +17 -7
- package/dist-cjs/tools/scenarios.js +18 -114
- package/package.json +3 -3
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.registerScenarioTools =
|
|
3
|
+
exports.registerScenarioTools = void 0;
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
5
|
const errors_js_1 = require("../client/errors.js");
|
|
6
6
|
const resolve_js_1 = require("../domain/resolve.js");
|
|
@@ -43,67 +43,7 @@ const resolveGroup = async (ctx, ws, ref) => {
|
|
|
43
43
|
return { id: null, note: "Scenario groups exist only on-prem — `group` was ignored." };
|
|
44
44
|
return { id: (0, resolve_js_1.resolveRef)("scenario group", ref, items).item.id };
|
|
45
45
|
};
|
|
46
|
-
exports.resolveGroup = resolveGroup;
|
|
47
46
|
const latestScenario = async (ctx, ws, id) => ctx.api.getScenario(ws, id);
|
|
48
|
-
// The version of each scenario this session last READ or wrote. update_scenario
|
|
49
|
-
// replaces the whole graph, so without an explicit expectedVersion it checks
|
|
50
|
-
// against what the model actually saw — a newer save from the desktop (or a
|
|
51
|
-
// teammate) then comes back as a conflict instead of being overwritten.
|
|
52
|
-
const seenVersions = new WeakMap();
|
|
53
|
-
const rememberVersion = (ctx, scenario) => {
|
|
54
|
-
if (!scenario.id || typeof scenario.version !== "number")
|
|
55
|
-
return;
|
|
56
|
-
let map = seenVersions.get(ctx);
|
|
57
|
-
if (!map) {
|
|
58
|
-
map = new Map();
|
|
59
|
-
seenVersions.set(ctx, map);
|
|
60
|
-
}
|
|
61
|
-
map.set(scenario.id, scenario.version);
|
|
62
|
-
};
|
|
63
|
-
const seenVersion = (ctx, id) => seenVersions.get(ctx)?.get(id);
|
|
64
|
-
// scenario-ref nodes name the scenario to link (`config.scenario`: name or
|
|
65
|
-
// id); the server copies it in when the snapshot is empty.
|
|
66
|
-
const resolveScenarioLinks = async (ctx, ws, nodes) => {
|
|
67
|
-
const out = [];
|
|
68
|
-
for (const node of nodes) {
|
|
69
|
-
const ref = node.type.trim() === "scenario-ref" && node.config ? node.config.scenario : undefined;
|
|
70
|
-
if (typeof ref !== "string" || !ref.trim()) {
|
|
71
|
-
out.push(node);
|
|
72
|
-
continue;
|
|
73
|
-
}
|
|
74
|
-
const target = await (0, lookups_js_1.resolveScenario)(ctx, ws, ref);
|
|
75
|
-
const { scenario: _ref, ...rest } = node.config;
|
|
76
|
-
void _ref;
|
|
77
|
-
out.push({ ...node, config: { ...rest, referencedScenarioId: target.item.id, nodes: [], edges: [] } });
|
|
78
|
-
}
|
|
79
|
-
return out;
|
|
80
|
-
};
|
|
81
|
-
// Labels must be unique across the whole graph; a linked scenario brings its
|
|
82
|
-
// own nodes' labels, which this tool can only check after the server copied
|
|
83
|
-
// them in.
|
|
84
|
-
const labelClashWarnings = (nodes) => {
|
|
85
|
-
const owners = new Map();
|
|
86
|
-
const clashes = [];
|
|
87
|
-
const walk = (list, container) => {
|
|
88
|
-
for (const node of list) {
|
|
89
|
-
const label = node.data?.label;
|
|
90
|
-
if (typeof label === "string" && label) {
|
|
91
|
-
const where = container ? `${node.id} (inside ${container})` : node.id;
|
|
92
|
-
const first = owners.get(label);
|
|
93
|
-
if (first)
|
|
94
|
-
clashes.push(`"${label}" is used by ${first} and ${where}`);
|
|
95
|
-
else
|
|
96
|
-
owners.set(label, where);
|
|
97
|
-
}
|
|
98
|
-
const inner = node.data?.config?.nodes;
|
|
99
|
-
if (Array.isArray(inner))
|
|
100
|
-
walk(inner, container ?? node.id);
|
|
101
|
-
}
|
|
102
|
-
};
|
|
103
|
-
walk(nodes, null);
|
|
104
|
-
return clashes.length > 0 ? [`Label clash after linking — later nodes read the wrong output until you rename one: ${clashes.join("; ")}.`] : [];
|
|
105
|
-
};
|
|
106
|
-
const hasLink = (graph) => Boolean(graph?.nodes.some((node) => node.type === "scenario-ref" && Array.isArray(node.data.config.nodes) && node.data.config.nodes.length === 0));
|
|
107
47
|
const registerScenarioTools = (server, ctx) => {
|
|
108
48
|
server.registerTool("list_scenarios", {
|
|
109
49
|
title: "List scenarios",
|
|
@@ -152,7 +92,6 @@ const registerScenarioTools = (server, ctx) => {
|
|
|
152
92
|
const ws = await ctx.resolveWorkspaceOrNull(workspace);
|
|
153
93
|
const resolved = await (0, lookups_js_1.resolveScenario)(ctx, ws?.id ?? null, scenario);
|
|
154
94
|
const fresh = resolved.matched === "id" && !reveal ? resolved.item : await ctx.api.getScenario(ws?.id ?? null, resolved.item.id, reveal ?? false);
|
|
155
|
-
rememberVersion(ctx, fresh);
|
|
156
95
|
if (node) {
|
|
157
96
|
const found = (0, summarize_js_1.scenarioNodeView)(fresh, node, { reveal });
|
|
158
97
|
if (!found) {
|
|
@@ -165,7 +104,7 @@ const registerScenarioTools = (server, ctx) => {
|
|
|
165
104
|
}));
|
|
166
105
|
server.registerTool("get_scenario_report", {
|
|
167
106
|
title: "Get a scenario run report",
|
|
168
|
-
description: "The result of a scenario run: status, summary counts, an error outside any node (unexpectedError), a per-node timeline and every failing node expanded (failed tests, assertion checks with expected vs actual, failed contracts, script error with line, the input as resolved at run time, response, logs). `node` returns one node's result in that detail. Defaults to the latest run; `list: true` lists recent runs instead.
|
|
107
|
+
description: "The result of a scenario run: status, summary counts, an error outside any node (unexpectedError), a per-node timeline and every failing node expanded (failed tests, assertion checks with expected vs actual, failed contracts, script error with line, the input as resolved at run time, response, logs). `node` returns one node's result in that detail. Defaults to the latest run; `list: true` lists recent runs instead.",
|
|
169
108
|
inputSchema: {
|
|
170
109
|
workspace: shared_js_1.workspaceArg,
|
|
171
110
|
scenario: (0, shared_js_1.refArg)("Scenario"),
|
|
@@ -186,7 +125,7 @@ const registerScenarioTools = (server, ctx) => {
|
|
|
186
125
|
const runs = await ctx.api.listScenarioReports(ws?.id ?? null, resolved.item.id, 5);
|
|
187
126
|
const latest = runs.items[0];
|
|
188
127
|
if (!latest)
|
|
189
|
-
return (0, shared_js_1.ok)({ scenario: { id: resolved.item.id, name: resolved.item.name }, report: null, note: "
|
|
128
|
+
return (0, shared_js_1.ok)({ scenario: { id: resolved.item.id, name: resolved.item.name }, report: null, note: "This scenario has not been run on the server yet. Use run_scenario." });
|
|
190
129
|
reportId = latest.reportId;
|
|
191
130
|
}
|
|
192
131
|
const detail = await ctx.api.getScenarioReport(ws?.id ?? null, resolved.item.id, reportId);
|
|
@@ -200,7 +139,7 @@ const registerScenarioTools = (server, ctx) => {
|
|
|
200
139
|
}));
|
|
201
140
|
server.registerTool("create_scenario", {
|
|
202
141
|
title: "Create a scenario",
|
|
203
|
-
description: "Create a multi-step API test scenario from compact nodes and edges. READ callman://docs/scenario-nodes first: it lists every node type, its config fields, defaults and which are required. Configs are merged over the type's defaults (send what you set; arrays you send must be complete). Request nodes also accept the request tools' shapes (auth { type: \"bearer\", token }, a JSON body) and are converted. Labels are generated when omitted and must be unique. db/redis/kafka/notification/ai nodes need a connectionId (list_connections). Config keys the server does not know come back as warnings. dryRun: true returns the complete resolved nodes without saving. On-prem: new scenarios start as drafts — submit_scenario sends them for approval; personal-token runs use the approved version.",
|
|
142
|
+
description: "Create a multi-step API test scenario from compact nodes and edges. READ callman://docs/scenario-nodes first: it lists every node type, its config fields, defaults and which are required. Configs are merged over the type's defaults (send what you set; arrays you send must be complete). Request nodes also accept the request tools' shapes (auth { type: \"bearer\", token }, a JSON body) and are converted. Labels are generated when omitted and must be unique. db/redis/kafka/notification/ai/temporal nodes need a connectionId (list_connections). A temporal node runs one Temporal.io operation (start/signal/query/update/await/describe/history/cancel/terminate/list/count/describeTaskQueue) — set `operation` and its required fields; use `expect` rules to assert on the result. Config keys the server does not know come back as warnings. dryRun: true returns the complete resolved nodes without saving. On-prem: new scenarios start as drafts — submit_scenario sends them for approval; personal-token runs use the approved version.",
|
|
204
143
|
inputSchema: {
|
|
205
144
|
workspace: shared_js_1.workspaceArg,
|
|
206
145
|
folder: zod_1.z.string().max(200).optional().describe("Scenario folder id or name"),
|
|
@@ -212,22 +151,14 @@ const registerScenarioTools = (server, ctx) => {
|
|
|
212
151
|
}, (0, shared_js_1.guarded)(async ({ workspace, folder, group, dryRun, ...input }) => {
|
|
213
152
|
const ws = await ctx.resolveWorkspace(workspace);
|
|
214
153
|
const targetFolder = folder ? await (0, lookups_js_1.resolveScenarioFolder)(ctx, ws.id, folder) : null;
|
|
215
|
-
const targetGroup = await
|
|
216
|
-
const
|
|
217
|
-
const { body, graph } = (0, build_js_1.buildScenarioCreateBody)(linkedInput, targetFolder?.item.id ?? null, targetGroup?.id === null ? undefined : targetGroup?.id);
|
|
154
|
+
const targetGroup = await resolveGroup(ctx, ws.id, group);
|
|
155
|
+
const { body, graph } = (0, build_js_1.buildScenarioCreateBody)(input, targetFolder?.item.id ?? null, targetGroup?.id === null ? undefined : targetGroup?.id);
|
|
218
156
|
if (dryRun) {
|
|
219
157
|
return (0, shared_js_1.ok)({ dryRun: true, scenario: { name: body.name, nodes: graph.nodes.map((node) => ({ id: node.id, type: node.type, label: node.data.label, config: node.data.config })), edges: graph.edges }, warnings: graph.warnings });
|
|
220
158
|
}
|
|
221
159
|
const created = await ctx.api.createScenario(ws.id, body);
|
|
222
160
|
ctx.invalidate("scenarios:");
|
|
223
|
-
|
|
224
|
-
const warnings = [
|
|
225
|
-
...graph.warnings,
|
|
226
|
-
...droppedFieldWarnings(graph, created),
|
|
227
|
-
...(created.graph?.warnings ?? []),
|
|
228
|
-
...(targetGroup?.note ? [targetGroup.note] : []),
|
|
229
|
-
...(hasLink(graph) ? labelClashWarnings(created.nodes) : []),
|
|
230
|
-
];
|
|
161
|
+
const warnings = [...graph.warnings, ...droppedFieldWarnings(graph, created), ...(created.graph?.warnings ?? []), ...(targetGroup?.note ? [targetGroup.note] : [])];
|
|
231
162
|
return (0, shared_js_1.ok)({
|
|
232
163
|
scenario: (0, summarize_js_1.scenarioGraphView)(created),
|
|
233
164
|
...(warnings.length > 0 ? { warnings } : {}),
|
|
@@ -295,12 +226,12 @@ const registerScenarioTools = (server, ctx) => {
|
|
|
295
226
|
}
|
|
296
227
|
}
|
|
297
228
|
}
|
|
298
|
-
const graph = (0, build_js_1.buildScenarioGraph)(
|
|
229
|
+
const graph = (0, build_js_1.buildScenarioGraph)([...nodes.values()], edges, { existing: current.nodes });
|
|
299
230
|
return saveGraph(ctx, ws?.id ?? null, current, graph, { expectedVersion, annotation: resolved.annotation ? (0, resolve_js_1.resolvedSummary)(scenario, resolved) : undefined });
|
|
300
231
|
}));
|
|
301
232
|
server.registerTool("update_scenario", {
|
|
302
233
|
title: "Update a scenario",
|
|
303
|
-
description: "Update a scenario's name / description / priority / folder / environments / dataset / dbSettings and/or replace its graph (nodes AND edges together). A node whose id already exists MERGES into the stored node (only the config keys you send change, its position is kept); new ids merge over the type's defaults; nodes you leave out are removed. `environments` replaces the whole list (stored ids are kept by name; a masked value sent back unchanged keeps the stored one). For small edits prefer patch_scenario. Version-checked:
|
|
234
|
+
description: "Update a scenario's name / description / priority / folder / environments / dataset / dbSettings and/or replace its graph (nodes AND edges together). A node whose id already exists MERGES into the stored node (only the config keys you send change, its position is kept); new ids merge over the type's defaults; nodes you leave out are removed. `environments` replaces the whole list (stored ids are kept by name; a masked value sent back unchanged keeps the stored one). For small edits prefer patch_scenario. Version-checked: pass the `version` you read (expectedVersion) or it is fetched first; a conflict comes back structured. On-prem: editing an approved scenario returns it to draft.",
|
|
304
235
|
inputSchema: {
|
|
305
236
|
workspace: shared_js_1.workspaceArg,
|
|
306
237
|
scenario: (0, shared_js_1.refArg)("Scenario"),
|
|
@@ -325,7 +256,7 @@ const registerScenarioTools = (server, ctx) => {
|
|
|
325
256
|
const resolved = await (0, lookups_js_1.resolveScenario)(ctx, ws?.id ?? null, scenario);
|
|
326
257
|
const current = await latestScenario(ctx, ws?.id ?? null, resolved.item.id);
|
|
327
258
|
const targetFolder = folder ? await (0, lookups_js_1.resolveScenarioFolder)(ctx, ws?.id ?? null, folder) : null;
|
|
328
|
-
const graph = nodes && edges ? (0, build_js_1.buildScenarioGraph)(
|
|
259
|
+
const graph = nodes && edges ? (0, build_js_1.buildScenarioGraph)(nodes, edges, { existing: current.nodes }) : null;
|
|
329
260
|
const extra = {
|
|
330
261
|
...(name !== undefined ? { name } : {}),
|
|
331
262
|
...(description !== undefined ? { description } : {}),
|
|
@@ -337,9 +268,7 @@ const registerScenarioTools = (server, ctx) => {
|
|
|
337
268
|
};
|
|
338
269
|
if (!graph && Object.keys(extra).length === 0)
|
|
339
270
|
throw new errors_js_1.ToolInputError("NOTHING_TO_UPDATE", "Pass at least one field to change.");
|
|
340
|
-
|
|
341
|
-
const checkedVersion = expectedVersion ?? (graph ? seenVersion(ctx, current.id) : undefined);
|
|
342
|
-
return saveGraph(ctx, ws?.id ?? null, current, graph, { expectedVersion: checkedVersion, force, extra, annotation: resolved.annotation ? (0, resolve_js_1.resolvedSummary)(scenario, resolved) : undefined });
|
|
271
|
+
return saveGraph(ctx, ws?.id ?? null, current, graph, { expectedVersion, force, extra, annotation: resolved.annotation ? (0, resolve_js_1.resolvedSummary)(scenario, resolved) : undefined });
|
|
343
272
|
}));
|
|
344
273
|
server.registerTool("submit_scenario", {
|
|
345
274
|
title: "Submit a scenario for approval",
|
|
@@ -381,18 +310,17 @@ const registerScenarioTools = (server, ctx) => {
|
|
|
381
310
|
return (0, shared_js_1.ok)({ deleted: { id: resolved.item.id, name: resolved.item.name }, resolved: [(0, resolve_js_1.resolvedSummary)(scenario, resolved)] });
|
|
382
311
|
}));
|
|
383
312
|
server.registerTool("run_scenario", {
|
|
384
|
-
title: "Run a scenario",
|
|
385
|
-
description: "
|
|
313
|
+
title: "Run a scenario on the server",
|
|
314
|
+
description: "Start a server-side run of a scenario (with one of its inline environments, by name or id; the first one when omitted) and wait for the result (default up to 5 minutes, max 30). Returns the report as in get_scenario_report. A personal token runs the scenario's APPROVED version on-prem — the result says when that differs from the version you edited. If it times out you get the reportId to check later.",
|
|
386
315
|
inputSchema: {
|
|
387
316
|
workspace: shared_js_1.workspaceArg,
|
|
388
317
|
scenario: (0, shared_js_1.refArg)("Scenario"),
|
|
389
|
-
target: zod_1.z.enum(["server", "desktop"]).default("server").describe('"server" (default) or "desktop" — the user\'s own desktop app, for what only their machine reaches'),
|
|
390
318
|
environment: zod_1.z.string().max(200).optional().describe("One of the scenario's own environments (name or id)"),
|
|
391
319
|
wait: zod_1.z.boolean().default(true),
|
|
392
320
|
timeoutSec: zod_1.z.number().int().min(5).max(1800).default(300),
|
|
393
321
|
},
|
|
394
322
|
annotations: shared_js_1.RUN,
|
|
395
|
-
}, (0, shared_js_1.guarded)(async ({ workspace, scenario,
|
|
323
|
+
}, (0, shared_js_1.guarded)(async ({ workspace, scenario, environment, wait, timeoutSec }) => {
|
|
396
324
|
const ws = await ctx.resolveWorkspaceOrNull(workspace);
|
|
397
325
|
const resolved = await (0, lookups_js_1.resolveScenario)(ctx, ws?.id ?? null, scenario);
|
|
398
326
|
let environmentId;
|
|
@@ -405,19 +333,9 @@ const registerScenarioTools = (server, ctx) => {
|
|
|
405
333
|
}
|
|
406
334
|
environmentId = picked.id;
|
|
407
335
|
}
|
|
408
|
-
const
|
|
409
|
-
let trigger;
|
|
410
|
-
try {
|
|
411
|
-
trigger = target === "desktop" ? await ctx.api.runScenarioOnDesktop(ws?.id ?? null, resolved.item.id, runBody) : await ctx.api.runScenario(ws?.id ?? null, resolved.item.id, runBody);
|
|
412
|
-
}
|
|
413
|
-
catch (error) {
|
|
414
|
-
if (target === "desktop" && error instanceof errors_js_1.CallmanApiError && error.status === 404 && error.code !== "SCENARIO_NOT_FOUND") {
|
|
415
|
-
throw new errors_js_1.ToolInputError("SCENARIO_DESKTOP_UNSUPPORTED", "This Callman server cannot run scenarios on a desktop yet (update the backend), so only target \"server\" works.");
|
|
416
|
-
}
|
|
417
|
-
throw error;
|
|
418
|
-
}
|
|
336
|
+
const trigger = await ctx.api.runScenario(ws?.id ?? null, resolved.item.id, environmentId ? { environmentId } : {});
|
|
419
337
|
if (!wait)
|
|
420
|
-
return (0, shared_js_1.ok)({ scenario: { id: resolved.item.id, name: resolved.item.name }, reportId: trigger.reportId, status: trigger.status,
|
|
338
|
+
return (0, shared_js_1.ok)({ scenario: { id: resolved.item.id, name: resolved.item.name }, reportId: trigger.reportId, status: trigger.status, note: "Check with get_scenario_report." });
|
|
421
339
|
const deadline = Date.now() + timeoutSec * 1000;
|
|
422
340
|
let polls = 0;
|
|
423
341
|
let last = null;
|
|
@@ -436,15 +354,7 @@ const registerScenarioTools = (server, ctx) => {
|
|
|
436
354
|
break;
|
|
437
355
|
}
|
|
438
356
|
if (!last || !TERMINAL_STATUSES.has(last.status)) {
|
|
439
|
-
return (0, shared_js_1.ok)({
|
|
440
|
-
scenario: { id: resolved.item.id, name: resolved.item.name },
|
|
441
|
-
reportId: trigger.reportId,
|
|
442
|
-
status: last?.status ?? "running",
|
|
443
|
-
timedOut: true,
|
|
444
|
-
note: target === "desktop" && (last?.status ?? "queued") === "queued"
|
|
445
|
-
? `No desktop picked the run up within ${timeoutSec}s — the app must be open with "Let AI tools run scenarios on this computer" on. It is failed automatically after 10 minutes; check with get_scenario_report.`
|
|
446
|
-
: `Still running after ${timeoutSec}s — call get_scenario_report with this reportId later.`,
|
|
447
|
-
});
|
|
357
|
+
return (0, shared_js_1.ok)({ scenario: { id: resolved.item.id, name: resolved.item.name }, reportId: trigger.reportId, status: last?.status ?? "running", timedOut: true, note: `Still running after ${timeoutSec}s — call get_scenario_report with this reportId later.` });
|
|
448
358
|
}
|
|
449
359
|
const warnings = [];
|
|
450
360
|
if (typeof last.scenarioVersion === "number" && last.scenarioVersion !== resolved.item.version) {
|
|
@@ -469,13 +379,7 @@ const saveGraph = async (ctx, ws, current, graph, options) => {
|
|
|
469
379
|
try {
|
|
470
380
|
const updated = await ctx.api.patchScenario(ws, current.id, body);
|
|
471
381
|
ctx.invalidate("scenarios:");
|
|
472
|
-
|
|
473
|
-
const warnings = [
|
|
474
|
-
...(graph?.warnings ?? []),
|
|
475
|
-
...(graph ? droppedFieldWarnings(graph, updated) : []),
|
|
476
|
-
...(updated.graph?.warnings ?? []),
|
|
477
|
-
...(hasLink(graph) ? labelClashWarnings(updated.nodes) : []),
|
|
478
|
-
];
|
|
382
|
+
const warnings = [...(graph?.warnings ?? []), ...(graph ? droppedFieldWarnings(graph, updated) : []), ...(updated.graph?.warnings ?? [])];
|
|
479
383
|
const removed = graph ? current.nodes.filter((node) => !graph.nodes.some((entry) => entry.id === node.id)).map((node) => node.id) : [];
|
|
480
384
|
return (0, shared_js_1.ok)({
|
|
481
385
|
scenario: (0, summarize_js_1.scenarioGraphView)(updated),
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "callman-mcp",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "MCP server for Callman: lets Claude Code, Claude Desktop, Cursor, Codex and Gemini CLI manage collections, requests, environments, test scenarios, UI tests (web, Android, iOS) and
|
|
3
|
+
"version": "0.7.0",
|
|
4
|
+
"description": "MCP server for Callman: lets Claude Code, Claude Desktop, Cursor, Codex and Gemini CLI manage collections, requests, environments, test scenarios, UI tests (web, Android, iOS) and system-design diagrams in your Callman workspace \u2014 cloud or on-prem.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"callman",
|
|
7
7
|
"mcp",
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
},
|
|
63
63
|
"dependencies": {
|
|
64
64
|
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
65
|
-
"callman-core": "^1.
|
|
65
|
+
"callman-core": "^1.37.0",
|
|
66
66
|
"elkjs": "^0.12.0",
|
|
67
67
|
"js-yaml": "^4.1.0",
|
|
68
68
|
"zod": "^3.25.0"
|