@topolo/mcp 0.9.11 → 0.10.1
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/README.md +3 -0
- package/dist/dispatch.js +79 -82
- package/dist/http.js +106 -89
- package/dist/index.js +280 -190
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -217,6 +217,9 @@ sent.
|
|
|
217
217
|
catalog. They do not expose the global generated platform catalog.
|
|
218
218
|
- **Credential-scoped action discovery.** `topolo_search_actions` reads only one
|
|
219
219
|
app partition and returns at most 100 permission-filtered actions per page.
|
|
220
|
+
Search, capability discovery, validation, planning, and application audit
|
|
221
|
+
return compact agent guidance by default; pass `detail: true` only when the
|
|
222
|
+
full contracts or findings are needed.
|
|
220
223
|
- **Audit headers.** Every request sends `X-Topolo-Client: topolo-mcp/<ver>`,
|
|
221
224
|
`X-Topolo-Agent: <label>`, `X-Topolo-Request-Id: <uuid>`.
|
|
222
225
|
- **Write-action confirmation.** The SDK refuses mutating HTTP methods unless
|
package/dist/dispatch.js
CHANGED
|
@@ -5,11 +5,16 @@ import { TopoloAuthError, TopoloPermissionError } from "@topolo/sdk";
|
|
|
5
5
|
import {
|
|
6
6
|
APPLICATION_REQUIREMENTS,
|
|
7
7
|
APPLICATION_REQUIREMENTS_VERSION,
|
|
8
|
-
|
|
9
|
-
DEFAULT_APP_URLS,
|
|
10
|
-
auditAllApplicationRequirements,
|
|
8
|
+
auditApplicationEntries,
|
|
11
9
|
applicationRequirementScopes,
|
|
10
|
+
compactActionCatalogEntry,
|
|
11
|
+
compactActionPlan,
|
|
12
|
+
compactActionValidation,
|
|
13
|
+
compactApplicationAudit,
|
|
14
|
+
friendlyAppId,
|
|
15
|
+
listApplicationDirectory,
|
|
12
16
|
requirementsForApplication,
|
|
17
|
+
resolveApplicationDirectoryEntry,
|
|
13
18
|
resolveCatalogServiceUrl
|
|
14
19
|
} from "@topolo/sdk";
|
|
15
20
|
|
|
@@ -62,7 +67,6 @@ function publicMcpErrorMessage(error, fallback) {
|
|
|
62
67
|
}
|
|
63
68
|
|
|
64
69
|
// src/tools.ts
|
|
65
|
-
var APPLICATION_IDS = Object.keys(APPLICATIONS).sort();
|
|
66
70
|
var HTTP_METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE"];
|
|
67
71
|
function requiredString(args, name) {
|
|
68
72
|
const value = typeof args[name] === "string" ? args[name].trim() : "";
|
|
@@ -78,6 +82,20 @@ function optionalResourceContext(args) {
|
|
|
78
82
|
}
|
|
79
83
|
return { resourceType, resourceId };
|
|
80
84
|
}
|
|
85
|
+
function coerceObjectParam(value, name) {
|
|
86
|
+
let candidate = value;
|
|
87
|
+
if (typeof candidate === "string" && candidate.trim().startsWith("{")) {
|
|
88
|
+
try {
|
|
89
|
+
candidate = JSON.parse(candidate);
|
|
90
|
+
} catch {
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
if (candidate === void 0) return {};
|
|
94
|
+
if (!candidate || typeof candidate !== "object" || Array.isArray(candidate)) {
|
|
95
|
+
throw new TopoloMcpPublicError(`${name} must be an object.`);
|
|
96
|
+
}
|
|
97
|
+
return candidate;
|
|
98
|
+
}
|
|
81
99
|
var TOOLS = [
|
|
82
100
|
{
|
|
83
101
|
name: "topolo_whoami",
|
|
@@ -103,7 +121,8 @@ var TOOLS = [
|
|
|
103
121
|
properties: {
|
|
104
122
|
query: { type: "string" },
|
|
105
123
|
cursor: { type: "string" },
|
|
106
|
-
limit: { type: "integer", minimum: 1, maximum: 100, default: 25 }
|
|
124
|
+
limit: { type: "integer", minimum: 1, maximum: 100, default: 25 },
|
|
125
|
+
detail: { type: "boolean", description: "Return full schemas and agent contracts. Defaults to compact action guidance." }
|
|
107
126
|
},
|
|
108
127
|
additionalProperties: false
|
|
109
128
|
},
|
|
@@ -157,12 +176,13 @@ var TOOLS = [
|
|
|
157
176
|
handler: async (topolo, args) => {
|
|
158
177
|
const service = typeof args["service"] === "string" ? args["service"].trim() : "";
|
|
159
178
|
if (!service) throw new TopoloMcpPublicError("service is required for bounded action discovery.");
|
|
160
|
-
|
|
179
|
+
const result = await topolo.client.searchActions({
|
|
161
180
|
service,
|
|
162
181
|
query: typeof args["query"] === "string" ? args["query"] : void 0,
|
|
163
182
|
cursor: typeof args["cursor"] === "string" ? args["cursor"] : void 0,
|
|
164
183
|
limit: typeof args["limit"] === "number" ? args["limit"] : void 0
|
|
165
184
|
});
|
|
185
|
+
return args["detail"] === true ? result : { actions: result.actions.map(compactActionCatalogEntry), page: result.page };
|
|
166
186
|
}
|
|
167
187
|
},
|
|
168
188
|
{
|
|
@@ -228,14 +248,11 @@ var TOOLS = [
|
|
|
228
248
|
handler: async (topolo, args) => {
|
|
229
249
|
const actionId = typeof args["actionId"] === "string" ? args["actionId"].trim() : "";
|
|
230
250
|
if (!actionId) throw new TopoloMcpPublicError("actionId is required.");
|
|
231
|
-
const input = args["input"];
|
|
232
|
-
if (input !== void 0 && (!input || typeof input !== "object" || Array.isArray(input))) {
|
|
233
|
-
throw new TopoloMcpPublicError("input must be an object.");
|
|
234
|
-
}
|
|
251
|
+
const input = coerceObjectParam(args["input"], "input");
|
|
235
252
|
const resource = optionalResourceContext(args);
|
|
236
253
|
return topolo.client.readAction(
|
|
237
254
|
actionId,
|
|
238
|
-
input
|
|
255
|
+
input,
|
|
239
256
|
resource ? { resource } : {}
|
|
240
257
|
);
|
|
241
258
|
}
|
|
@@ -261,14 +278,11 @@ var TOOLS = [
|
|
|
261
278
|
handler: async (topolo, args) => {
|
|
262
279
|
const actionId = typeof args["actionId"] === "string" ? args["actionId"].trim() : "";
|
|
263
280
|
if (!actionId) throw new TopoloMcpPublicError("actionId is required.");
|
|
264
|
-
const input = args["input"];
|
|
265
|
-
if (input !== void 0 && (!input || typeof input !== "object" || Array.isArray(input))) {
|
|
266
|
-
throw new TopoloMcpPublicError("input must be an object.");
|
|
267
|
-
}
|
|
281
|
+
const input = coerceObjectParam(args["input"], "input");
|
|
268
282
|
const resource = optionalResourceContext(args);
|
|
269
283
|
return topolo.client.callAction(
|
|
270
284
|
actionId,
|
|
271
|
-
input
|
|
285
|
+
input,
|
|
272
286
|
{
|
|
273
287
|
confirm: args["confirm"] === true,
|
|
274
288
|
...resource ? { resource } : {}
|
|
@@ -307,23 +321,17 @@ var TOOLS = [
|
|
|
307
321
|
if (!isCanonicalBase64(contentBase64)) throw new TopoloMcpPublicError("contentBase64 must be canonical base64.");
|
|
308
322
|
if (!contentType) throw new TopoloMcpPublicError("contentType is required.");
|
|
309
323
|
if (!fileName) throw new TopoloMcpPublicError("fileName is required.");
|
|
310
|
-
const input = args["input"];
|
|
311
|
-
|
|
312
|
-
throw new TopoloMcpPublicError("input must be an object.");
|
|
313
|
-
}
|
|
314
|
-
const completionInput = args["completionInput"];
|
|
315
|
-
if (completionInput !== void 0 && (!completionInput || typeof completionInput !== "object" || Array.isArray(completionInput))) {
|
|
316
|
-
throw new TopoloMcpPublicError("completionInput must be an object.");
|
|
317
|
-
}
|
|
324
|
+
const input = coerceObjectParam(args["input"], "input");
|
|
325
|
+
const completionInput = coerceObjectParam(args["completionInput"], "completionInput");
|
|
318
326
|
const resource = optionalResourceContext(args);
|
|
319
327
|
return topolo.client.uploadActionBase64(
|
|
320
328
|
actionId,
|
|
321
329
|
contentBase64,
|
|
322
|
-
input
|
|
330
|
+
input,
|
|
323
331
|
{
|
|
324
332
|
fileName,
|
|
325
333
|
contentType,
|
|
326
|
-
completionInput
|
|
334
|
+
completionInput,
|
|
327
335
|
confirm: args["confirm"] === true,
|
|
328
336
|
...resource ? { resource } : {}
|
|
329
337
|
}
|
|
@@ -340,7 +348,8 @@ var TOOLS = [
|
|
|
340
348
|
type: "object",
|
|
341
349
|
properties: {
|
|
342
350
|
actionId: { type: "string", minLength: 1 },
|
|
343
|
-
input: { type: "object", additionalProperties: true }
|
|
351
|
+
input: { type: "object", additionalProperties: true },
|
|
352
|
+
detail: { type: "boolean", description: "Include the full action contract. Defaults to a compact validation result." }
|
|
344
353
|
},
|
|
345
354
|
required: ["actionId"],
|
|
346
355
|
additionalProperties: false
|
|
@@ -348,11 +357,9 @@ var TOOLS = [
|
|
|
348
357
|
handler: async (topolo, args) => {
|
|
349
358
|
const actionId = typeof args["actionId"] === "string" ? args["actionId"].trim() : "";
|
|
350
359
|
if (!actionId) throw new TopoloMcpPublicError("actionId is required.");
|
|
351
|
-
const input = args["input"];
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
}
|
|
355
|
-
return topolo.client.validateActionInput(actionId, input ?? {});
|
|
360
|
+
const input = coerceObjectParam(args["input"], "input");
|
|
361
|
+
const result = await topolo.client.validateActionInput(actionId, input);
|
|
362
|
+
return args["detail"] === true ? result : compactActionValidation(result.action.actionId, result.validation);
|
|
356
363
|
}
|
|
357
364
|
},
|
|
358
365
|
{
|
|
@@ -368,7 +375,8 @@ var TOOLS = [
|
|
|
368
375
|
input: { type: "object", additionalProperties: true },
|
|
369
376
|
resourceType: { type: "string", description: "Optional resource-scoping alias published in the app resource catalog (e.g. workspace, brand, merchant)." },
|
|
370
377
|
resourceId: { type: "string", description: "Resource id. Required when resourceType is provided." },
|
|
371
|
-
confirm: { type: "boolean", description: "Include confirmation in the plan without executing the action." }
|
|
378
|
+
confirm: { type: "boolean", description: "Include confirmation in the plan without executing the action." },
|
|
379
|
+
detail: { type: "boolean", description: "Include the full action contract. Defaults to the executable request and verification plan." }
|
|
372
380
|
},
|
|
373
381
|
required: ["actionId"],
|
|
374
382
|
additionalProperties: false
|
|
@@ -376,19 +384,17 @@ var TOOLS = [
|
|
|
376
384
|
handler: async (topolo, args) => {
|
|
377
385
|
const actionId = typeof args["actionId"] === "string" ? args["actionId"].trim() : "";
|
|
378
386
|
if (!actionId) throw new TopoloMcpPublicError("actionId is required.");
|
|
379
|
-
const input = args["input"];
|
|
380
|
-
if (input !== void 0 && (!input || typeof input !== "object" || Array.isArray(input))) {
|
|
381
|
-
throw new TopoloMcpPublicError("input must be an object.");
|
|
382
|
-
}
|
|
387
|
+
const input = coerceObjectParam(args["input"], "input");
|
|
383
388
|
const resource = optionalResourceContext(args);
|
|
384
|
-
|
|
389
|
+
const plan = await topolo.client.planAction(
|
|
385
390
|
actionId,
|
|
386
|
-
input
|
|
391
|
+
input,
|
|
387
392
|
{
|
|
388
393
|
confirm: args["confirm"] === true,
|
|
389
394
|
...resource ? { resource } : {}
|
|
390
395
|
}
|
|
391
396
|
);
|
|
397
|
+
return args["detail"] === true ? plan : compactActionPlan(plan);
|
|
392
398
|
}
|
|
393
399
|
},
|
|
394
400
|
{
|
|
@@ -422,14 +428,18 @@ var TOOLS = [
|
|
|
422
428
|
destructive: false,
|
|
423
429
|
inputSchema: {
|
|
424
430
|
type: "object",
|
|
425
|
-
properties: {
|
|
431
|
+
properties: {
|
|
432
|
+
service: { type: "string", minLength: 1 },
|
|
433
|
+
detail: { type: "boolean", description: "Return full schemas and agent contracts. Defaults to compact capability guidance." }
|
|
434
|
+
},
|
|
426
435
|
required: ["service"],
|
|
427
436
|
additionalProperties: false
|
|
428
437
|
},
|
|
429
438
|
handler: async (topolo, args) => {
|
|
430
439
|
const service = typeof args["service"] === "string" ? args["service"].trim() : "";
|
|
431
440
|
if (!service) throw new TopoloMcpPublicError("service is required.");
|
|
432
|
-
|
|
441
|
+
const result = await topolo.client.searchActions({ service, limit: 100 });
|
|
442
|
+
return args["detail"] === true ? result : { actions: result.actions.map(compactActionCatalogEntry), page: result.page };
|
|
433
443
|
}
|
|
434
444
|
},
|
|
435
445
|
{
|
|
@@ -560,7 +570,7 @@ var TOOLS = [
|
|
|
560
570
|
},
|
|
561
571
|
additionalProperties: false
|
|
562
572
|
},
|
|
563
|
-
handler: async (
|
|
573
|
+
handler: async (topolo, args) => {
|
|
564
574
|
const application = args["application"];
|
|
565
575
|
if (application === void 0) {
|
|
566
576
|
return {
|
|
@@ -570,12 +580,8 @@ var TOOLS = [
|
|
|
570
580
|
requirements: APPLICATION_REQUIREMENTS
|
|
571
581
|
};
|
|
572
582
|
}
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
`Unknown application "${String(application)}". ${formatKnownValues(APPLICATION_IDS, "applications")}`
|
|
576
|
-
);
|
|
577
|
-
}
|
|
578
|
-
const app = APPLICATIONS[application];
|
|
583
|
+
const resolved = await resolveDirectoryApplication(topolo, application);
|
|
584
|
+
const app = resolved.application;
|
|
579
585
|
return {
|
|
580
586
|
version: APPLICATION_REQUIREMENTS_VERSION,
|
|
581
587
|
application: app,
|
|
@@ -601,11 +607,15 @@ var TOOLS = [
|
|
|
601
607
|
type: "string",
|
|
602
608
|
enum: ["missing", "needs_review", "partial"],
|
|
603
609
|
description: "Optional conformance gate. Returns conformanceGate.passed=false when findings at this severity or worse exist."
|
|
610
|
+
},
|
|
611
|
+
detail: {
|
|
612
|
+
type: "boolean",
|
|
613
|
+
description: "Include every finding and migration item. Defaults to per-app scores and a queue count."
|
|
604
614
|
}
|
|
605
615
|
},
|
|
606
616
|
additionalProperties: false
|
|
607
617
|
},
|
|
608
|
-
handler: async (
|
|
618
|
+
handler: async (topolo, args) => {
|
|
609
619
|
const application = args["application"];
|
|
610
620
|
const failOn = args["failOn"];
|
|
611
621
|
if (failOn !== void 0 && typeof failOn !== "string") {
|
|
@@ -614,16 +624,15 @@ var TOOLS = [
|
|
|
614
624
|
const gate = failOn ? normalizeFailOn(failOn) : null;
|
|
615
625
|
let report;
|
|
616
626
|
if (application === void 0) {
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
throw new TopoloMcpPublicError(
|
|
622
|
-
`Unknown application "${String(application)}". ${formatKnownValues(APPLICATION_IDS, "applications")}`
|
|
623
|
-
);
|
|
627
|
+
const directory = await listApplicationDirectory(topolo.client);
|
|
628
|
+
report = auditApplicationEntries(directory.applications.map((app) => app.application));
|
|
629
|
+
const output2 = args["detail"] === true ? report : compactApplicationAudit(report);
|
|
630
|
+
return gate ? { ...output2, conformanceGate: evaluateApplicationAuditGate(report, gate) } : output2;
|
|
624
631
|
}
|
|
625
|
-
|
|
626
|
-
|
|
632
|
+
const resolved = await resolveDirectoryApplication(topolo, application);
|
|
633
|
+
report = auditApplicationEntries([resolved.application]);
|
|
634
|
+
const output = args["detail"] === true ? report : compactApplicationAudit(report);
|
|
635
|
+
return gate ? { ...output, conformanceGate: evaluateApplicationAuditGate(report, gate) } : output;
|
|
627
636
|
}
|
|
628
637
|
},
|
|
629
638
|
{
|
|
@@ -762,31 +771,19 @@ function statusesAtOrWorse(threshold) {
|
|
|
762
771
|
return ["missing", "needs_review", "partial"];
|
|
763
772
|
}
|
|
764
773
|
function displayAppId(entry) {
|
|
765
|
-
|
|
766
|
-
if (typeof value !== "string" || !value.trim()) continue;
|
|
767
|
-
for (const candidate of appIdCandidates(value)) {
|
|
768
|
-
if (Object.prototype.hasOwnProperty.call(DEFAULT_APP_URLS, candidate)) {
|
|
769
|
-
return candidate;
|
|
770
|
-
}
|
|
771
|
-
}
|
|
772
|
-
}
|
|
773
|
-
return appIdCandidates(entry.slug || entry.appId)[0] || entry.appId;
|
|
774
|
-
}
|
|
775
|
-
function appIdCandidates(value) {
|
|
776
|
-
const normalized = value.trim().toLowerCase().replace(/\s+/g, "-");
|
|
777
|
-
const withoutTopolo = normalized.startsWith("topolo-") ? normalized.slice("topolo-".length) : normalized;
|
|
778
|
-
return [.../* @__PURE__ */ new Set([
|
|
779
|
-
normalized,
|
|
780
|
-
normalized.replace(/-/g, "_"),
|
|
781
|
-
withoutTopolo,
|
|
782
|
-
withoutTopolo.replace(/-/g, "_")
|
|
783
|
-
])].filter(Boolean);
|
|
774
|
+
return friendlyAppId(entry);
|
|
784
775
|
}
|
|
785
|
-
function
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
776
|
+
async function resolveDirectoryApplication(topolo, application) {
|
|
777
|
+
if (typeof application !== "string" || !application.trim()) {
|
|
778
|
+
throw new TopoloMcpPublicError("`application` must be a non-empty string.");
|
|
779
|
+
}
|
|
780
|
+
try {
|
|
781
|
+
return await resolveApplicationDirectoryEntry(topolo.client, application);
|
|
782
|
+
} catch (error) {
|
|
783
|
+
throw new TopoloMcpPublicError(
|
|
784
|
+
error instanceof Error ? error.message : `Unknown application "${application}".`
|
|
785
|
+
);
|
|
786
|
+
}
|
|
790
787
|
}
|
|
791
788
|
|
|
792
789
|
// src/dispatch.ts
|