@topolo/mcp 0.9.11 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dispatch.js +50 -73
- package/dist/http.js +50 -73
- package/dist/index.js +209 -181
- package/package.json +3 -3
package/dist/dispatch.js
CHANGED
|
@@ -5,11 +5,12 @@ 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
|
+
friendlyAppId,
|
|
11
|
+
listApplicationDirectory,
|
|
12
12
|
requirementsForApplication,
|
|
13
|
+
resolveApplicationDirectoryEntry,
|
|
13
14
|
resolveCatalogServiceUrl
|
|
14
15
|
} from "@topolo/sdk";
|
|
15
16
|
|
|
@@ -62,7 +63,6 @@ function publicMcpErrorMessage(error, fallback) {
|
|
|
62
63
|
}
|
|
63
64
|
|
|
64
65
|
// src/tools.ts
|
|
65
|
-
var APPLICATION_IDS = Object.keys(APPLICATIONS).sort();
|
|
66
66
|
var HTTP_METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE"];
|
|
67
67
|
function requiredString(args, name) {
|
|
68
68
|
const value = typeof args[name] === "string" ? args[name].trim() : "";
|
|
@@ -78,6 +78,20 @@ function optionalResourceContext(args) {
|
|
|
78
78
|
}
|
|
79
79
|
return { resourceType, resourceId };
|
|
80
80
|
}
|
|
81
|
+
function coerceObjectParam(value, name) {
|
|
82
|
+
let candidate = value;
|
|
83
|
+
if (typeof candidate === "string" && candidate.trim().startsWith("{")) {
|
|
84
|
+
try {
|
|
85
|
+
candidate = JSON.parse(candidate);
|
|
86
|
+
} catch {
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (candidate === void 0) return {};
|
|
90
|
+
if (!candidate || typeof candidate !== "object" || Array.isArray(candidate)) {
|
|
91
|
+
throw new TopoloMcpPublicError(`${name} must be an object.`);
|
|
92
|
+
}
|
|
93
|
+
return candidate;
|
|
94
|
+
}
|
|
81
95
|
var TOOLS = [
|
|
82
96
|
{
|
|
83
97
|
name: "topolo_whoami",
|
|
@@ -228,14 +242,11 @@ var TOOLS = [
|
|
|
228
242
|
handler: async (topolo, args) => {
|
|
229
243
|
const actionId = typeof args["actionId"] === "string" ? args["actionId"].trim() : "";
|
|
230
244
|
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
|
-
}
|
|
245
|
+
const input = coerceObjectParam(args["input"], "input");
|
|
235
246
|
const resource = optionalResourceContext(args);
|
|
236
247
|
return topolo.client.readAction(
|
|
237
248
|
actionId,
|
|
238
|
-
input
|
|
249
|
+
input,
|
|
239
250
|
resource ? { resource } : {}
|
|
240
251
|
);
|
|
241
252
|
}
|
|
@@ -261,14 +272,11 @@ var TOOLS = [
|
|
|
261
272
|
handler: async (topolo, args) => {
|
|
262
273
|
const actionId = typeof args["actionId"] === "string" ? args["actionId"].trim() : "";
|
|
263
274
|
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
|
-
}
|
|
275
|
+
const input = coerceObjectParam(args["input"], "input");
|
|
268
276
|
const resource = optionalResourceContext(args);
|
|
269
277
|
return topolo.client.callAction(
|
|
270
278
|
actionId,
|
|
271
|
-
input
|
|
279
|
+
input,
|
|
272
280
|
{
|
|
273
281
|
confirm: args["confirm"] === true,
|
|
274
282
|
...resource ? { resource } : {}
|
|
@@ -307,23 +315,17 @@ var TOOLS = [
|
|
|
307
315
|
if (!isCanonicalBase64(contentBase64)) throw new TopoloMcpPublicError("contentBase64 must be canonical base64.");
|
|
308
316
|
if (!contentType) throw new TopoloMcpPublicError("contentType is required.");
|
|
309
317
|
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
|
-
}
|
|
318
|
+
const input = coerceObjectParam(args["input"], "input");
|
|
319
|
+
const completionInput = coerceObjectParam(args["completionInput"], "completionInput");
|
|
318
320
|
const resource = optionalResourceContext(args);
|
|
319
321
|
return topolo.client.uploadActionBase64(
|
|
320
322
|
actionId,
|
|
321
323
|
contentBase64,
|
|
322
|
-
input
|
|
324
|
+
input,
|
|
323
325
|
{
|
|
324
326
|
fileName,
|
|
325
327
|
contentType,
|
|
326
|
-
completionInput
|
|
328
|
+
completionInput,
|
|
327
329
|
confirm: args["confirm"] === true,
|
|
328
330
|
...resource ? { resource } : {}
|
|
329
331
|
}
|
|
@@ -348,11 +350,8 @@ var TOOLS = [
|
|
|
348
350
|
handler: async (topolo, args) => {
|
|
349
351
|
const actionId = typeof args["actionId"] === "string" ? args["actionId"].trim() : "";
|
|
350
352
|
if (!actionId) throw new TopoloMcpPublicError("actionId is required.");
|
|
351
|
-
const input = args["input"];
|
|
352
|
-
|
|
353
|
-
throw new TopoloMcpPublicError("input must be an object.");
|
|
354
|
-
}
|
|
355
|
-
return topolo.client.validateActionInput(actionId, input ?? {});
|
|
353
|
+
const input = coerceObjectParam(args["input"], "input");
|
|
354
|
+
return topolo.client.validateActionInput(actionId, input);
|
|
356
355
|
}
|
|
357
356
|
},
|
|
358
357
|
{
|
|
@@ -376,14 +375,11 @@ var TOOLS = [
|
|
|
376
375
|
handler: async (topolo, args) => {
|
|
377
376
|
const actionId = typeof args["actionId"] === "string" ? args["actionId"].trim() : "";
|
|
378
377
|
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
|
-
}
|
|
378
|
+
const input = coerceObjectParam(args["input"], "input");
|
|
383
379
|
const resource = optionalResourceContext(args);
|
|
384
380
|
return topolo.client.planAction(
|
|
385
381
|
actionId,
|
|
386
|
-
input
|
|
382
|
+
input,
|
|
387
383
|
{
|
|
388
384
|
confirm: args["confirm"] === true,
|
|
389
385
|
...resource ? { resource } : {}
|
|
@@ -560,7 +556,7 @@ var TOOLS = [
|
|
|
560
556
|
},
|
|
561
557
|
additionalProperties: false
|
|
562
558
|
},
|
|
563
|
-
handler: async (
|
|
559
|
+
handler: async (topolo, args) => {
|
|
564
560
|
const application = args["application"];
|
|
565
561
|
if (application === void 0) {
|
|
566
562
|
return {
|
|
@@ -570,12 +566,8 @@ var TOOLS = [
|
|
|
570
566
|
requirements: APPLICATION_REQUIREMENTS
|
|
571
567
|
};
|
|
572
568
|
}
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
`Unknown application "${String(application)}". ${formatKnownValues(APPLICATION_IDS, "applications")}`
|
|
576
|
-
);
|
|
577
|
-
}
|
|
578
|
-
const app = APPLICATIONS[application];
|
|
569
|
+
const resolved = await resolveDirectoryApplication(topolo, application);
|
|
570
|
+
const app = resolved.application;
|
|
579
571
|
return {
|
|
580
572
|
version: APPLICATION_REQUIREMENTS_VERSION,
|
|
581
573
|
application: app,
|
|
@@ -605,7 +597,7 @@ var TOOLS = [
|
|
|
605
597
|
},
|
|
606
598
|
additionalProperties: false
|
|
607
599
|
},
|
|
608
|
-
handler: async (
|
|
600
|
+
handler: async (topolo, args) => {
|
|
609
601
|
const application = args["application"];
|
|
610
602
|
const failOn = args["failOn"];
|
|
611
603
|
if (failOn !== void 0 && typeof failOn !== "string") {
|
|
@@ -614,15 +606,12 @@ var TOOLS = [
|
|
|
614
606
|
const gate = failOn ? normalizeFailOn(failOn) : null;
|
|
615
607
|
let report;
|
|
616
608
|
if (application === void 0) {
|
|
617
|
-
|
|
609
|
+
const directory = await listApplicationDirectory(topolo.client);
|
|
610
|
+
report = auditApplicationEntries(directory.applications.map((app) => app.application));
|
|
618
611
|
return gate ? { ...report, conformanceGate: evaluateApplicationAuditGate(report, gate) } : report;
|
|
619
612
|
}
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
`Unknown application "${String(application)}". ${formatKnownValues(APPLICATION_IDS, "applications")}`
|
|
623
|
-
);
|
|
624
|
-
}
|
|
625
|
-
report = auditAllApplicationRequirements([application]);
|
|
613
|
+
const resolved = await resolveDirectoryApplication(topolo, application);
|
|
614
|
+
report = auditApplicationEntries([resolved.application]);
|
|
626
615
|
return gate ? { ...report, conformanceGate: evaluateApplicationAuditGate(report, gate) } : report;
|
|
627
616
|
}
|
|
628
617
|
},
|
|
@@ -762,31 +751,19 @@ function statusesAtOrWorse(threshold) {
|
|
|
762
751
|
return ["missing", "needs_review", "partial"];
|
|
763
752
|
}
|
|
764
753
|
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);
|
|
754
|
+
return friendlyAppId(entry);
|
|
784
755
|
}
|
|
785
|
-
function
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
756
|
+
async function resolveDirectoryApplication(topolo, application) {
|
|
757
|
+
if (typeof application !== "string" || !application.trim()) {
|
|
758
|
+
throw new TopoloMcpPublicError("`application` must be a non-empty string.");
|
|
759
|
+
}
|
|
760
|
+
try {
|
|
761
|
+
return await resolveApplicationDirectoryEntry(topolo.client, application);
|
|
762
|
+
} catch (error) {
|
|
763
|
+
throw new TopoloMcpPublicError(
|
|
764
|
+
error instanceof Error ? error.message : `Unknown application "${application}".`
|
|
765
|
+
);
|
|
766
|
+
}
|
|
790
767
|
}
|
|
791
768
|
|
|
792
769
|
// src/dispatch.ts
|
package/dist/http.js
CHANGED
|
@@ -15830,11 +15830,12 @@ import { TopoloAuthError, TopoloHttpError, TopoloPermissionError } from "@topolo
|
|
|
15830
15830
|
import {
|
|
15831
15831
|
APPLICATION_REQUIREMENTS,
|
|
15832
15832
|
APPLICATION_REQUIREMENTS_VERSION,
|
|
15833
|
-
|
|
15834
|
-
DEFAULT_APP_URLS,
|
|
15835
|
-
auditAllApplicationRequirements,
|
|
15833
|
+
auditApplicationEntries,
|
|
15836
15834
|
applicationRequirementScopes,
|
|
15835
|
+
friendlyAppId,
|
|
15836
|
+
listApplicationDirectory,
|
|
15837
15837
|
requirementsForApplication,
|
|
15838
|
+
resolveApplicationDirectoryEntry,
|
|
15838
15839
|
resolveCatalogServiceUrl
|
|
15839
15840
|
} from "@topolo/sdk";
|
|
15840
15841
|
|
|
@@ -15876,7 +15877,6 @@ function splitService(servicePart) {
|
|
|
15876
15877
|
}
|
|
15877
15878
|
|
|
15878
15879
|
// src/tools.ts
|
|
15879
|
-
var APPLICATION_IDS = Object.keys(APPLICATIONS).sort();
|
|
15880
15880
|
var HTTP_METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE"];
|
|
15881
15881
|
function requiredString(args, name) {
|
|
15882
15882
|
const value = typeof args[name] === "string" ? args[name].trim() : "";
|
|
@@ -15892,6 +15892,20 @@ function optionalResourceContext(args) {
|
|
|
15892
15892
|
}
|
|
15893
15893
|
return { resourceType, resourceId };
|
|
15894
15894
|
}
|
|
15895
|
+
function coerceObjectParam(value, name) {
|
|
15896
|
+
let candidate = value;
|
|
15897
|
+
if (typeof candidate === "string" && candidate.trim().startsWith("{")) {
|
|
15898
|
+
try {
|
|
15899
|
+
candidate = JSON.parse(candidate);
|
|
15900
|
+
} catch {
|
|
15901
|
+
}
|
|
15902
|
+
}
|
|
15903
|
+
if (candidate === void 0) return {};
|
|
15904
|
+
if (!candidate || typeof candidate !== "object" || Array.isArray(candidate)) {
|
|
15905
|
+
throw new TopoloMcpPublicError(`${name} must be an object.`);
|
|
15906
|
+
}
|
|
15907
|
+
return candidate;
|
|
15908
|
+
}
|
|
15895
15909
|
var TOOLS = [
|
|
15896
15910
|
{
|
|
15897
15911
|
name: "topolo_whoami",
|
|
@@ -16042,14 +16056,11 @@ var TOOLS = [
|
|
|
16042
16056
|
handler: async (topolo, args) => {
|
|
16043
16057
|
const actionId = typeof args["actionId"] === "string" ? args["actionId"].trim() : "";
|
|
16044
16058
|
if (!actionId) throw new TopoloMcpPublicError("actionId is required.");
|
|
16045
|
-
const input = args["input"];
|
|
16046
|
-
if (input !== void 0 && (!input || typeof input !== "object" || Array.isArray(input))) {
|
|
16047
|
-
throw new TopoloMcpPublicError("input must be an object.");
|
|
16048
|
-
}
|
|
16059
|
+
const input = coerceObjectParam(args["input"], "input");
|
|
16049
16060
|
const resource = optionalResourceContext(args);
|
|
16050
16061
|
return topolo.client.readAction(
|
|
16051
16062
|
actionId,
|
|
16052
|
-
input
|
|
16063
|
+
input,
|
|
16053
16064
|
resource ? { resource } : {}
|
|
16054
16065
|
);
|
|
16055
16066
|
}
|
|
@@ -16075,14 +16086,11 @@ var TOOLS = [
|
|
|
16075
16086
|
handler: async (topolo, args) => {
|
|
16076
16087
|
const actionId = typeof args["actionId"] === "string" ? args["actionId"].trim() : "";
|
|
16077
16088
|
if (!actionId) throw new TopoloMcpPublicError("actionId is required.");
|
|
16078
|
-
const input = args["input"];
|
|
16079
|
-
if (input !== void 0 && (!input || typeof input !== "object" || Array.isArray(input))) {
|
|
16080
|
-
throw new TopoloMcpPublicError("input must be an object.");
|
|
16081
|
-
}
|
|
16089
|
+
const input = coerceObjectParam(args["input"], "input");
|
|
16082
16090
|
const resource = optionalResourceContext(args);
|
|
16083
16091
|
return topolo.client.callAction(
|
|
16084
16092
|
actionId,
|
|
16085
|
-
input
|
|
16093
|
+
input,
|
|
16086
16094
|
{
|
|
16087
16095
|
confirm: args["confirm"] === true,
|
|
16088
16096
|
...resource ? { resource } : {}
|
|
@@ -16121,23 +16129,17 @@ var TOOLS = [
|
|
|
16121
16129
|
if (!isCanonicalBase64(contentBase64)) throw new TopoloMcpPublicError("contentBase64 must be canonical base64.");
|
|
16122
16130
|
if (!contentType) throw new TopoloMcpPublicError("contentType is required.");
|
|
16123
16131
|
if (!fileName) throw new TopoloMcpPublicError("fileName is required.");
|
|
16124
|
-
const input = args["input"];
|
|
16125
|
-
|
|
16126
|
-
throw new TopoloMcpPublicError("input must be an object.");
|
|
16127
|
-
}
|
|
16128
|
-
const completionInput = args["completionInput"];
|
|
16129
|
-
if (completionInput !== void 0 && (!completionInput || typeof completionInput !== "object" || Array.isArray(completionInput))) {
|
|
16130
|
-
throw new TopoloMcpPublicError("completionInput must be an object.");
|
|
16131
|
-
}
|
|
16132
|
+
const input = coerceObjectParam(args["input"], "input");
|
|
16133
|
+
const completionInput = coerceObjectParam(args["completionInput"], "completionInput");
|
|
16132
16134
|
const resource = optionalResourceContext(args);
|
|
16133
16135
|
return topolo.client.uploadActionBase64(
|
|
16134
16136
|
actionId,
|
|
16135
16137
|
contentBase64,
|
|
16136
|
-
input
|
|
16138
|
+
input,
|
|
16137
16139
|
{
|
|
16138
16140
|
fileName,
|
|
16139
16141
|
contentType,
|
|
16140
|
-
completionInput
|
|
16142
|
+
completionInput,
|
|
16141
16143
|
confirm: args["confirm"] === true,
|
|
16142
16144
|
...resource ? { resource } : {}
|
|
16143
16145
|
}
|
|
@@ -16162,11 +16164,8 @@ var TOOLS = [
|
|
|
16162
16164
|
handler: async (topolo, args) => {
|
|
16163
16165
|
const actionId = typeof args["actionId"] === "string" ? args["actionId"].trim() : "";
|
|
16164
16166
|
if (!actionId) throw new TopoloMcpPublicError("actionId is required.");
|
|
16165
|
-
const input = args["input"];
|
|
16166
|
-
|
|
16167
|
-
throw new TopoloMcpPublicError("input must be an object.");
|
|
16168
|
-
}
|
|
16169
|
-
return topolo.client.validateActionInput(actionId, input ?? {});
|
|
16167
|
+
const input = coerceObjectParam(args["input"], "input");
|
|
16168
|
+
return topolo.client.validateActionInput(actionId, input);
|
|
16170
16169
|
}
|
|
16171
16170
|
},
|
|
16172
16171
|
{
|
|
@@ -16190,14 +16189,11 @@ var TOOLS = [
|
|
|
16190
16189
|
handler: async (topolo, args) => {
|
|
16191
16190
|
const actionId = typeof args["actionId"] === "string" ? args["actionId"].trim() : "";
|
|
16192
16191
|
if (!actionId) throw new TopoloMcpPublicError("actionId is required.");
|
|
16193
|
-
const input = args["input"];
|
|
16194
|
-
if (input !== void 0 && (!input || typeof input !== "object" || Array.isArray(input))) {
|
|
16195
|
-
throw new TopoloMcpPublicError("input must be an object.");
|
|
16196
|
-
}
|
|
16192
|
+
const input = coerceObjectParam(args["input"], "input");
|
|
16197
16193
|
const resource = optionalResourceContext(args);
|
|
16198
16194
|
return topolo.client.planAction(
|
|
16199
16195
|
actionId,
|
|
16200
|
-
input
|
|
16196
|
+
input,
|
|
16201
16197
|
{
|
|
16202
16198
|
confirm: args["confirm"] === true,
|
|
16203
16199
|
...resource ? { resource } : {}
|
|
@@ -16374,7 +16370,7 @@ var TOOLS = [
|
|
|
16374
16370
|
},
|
|
16375
16371
|
additionalProperties: false
|
|
16376
16372
|
},
|
|
16377
|
-
handler: async (
|
|
16373
|
+
handler: async (topolo, args) => {
|
|
16378
16374
|
const application = args["application"];
|
|
16379
16375
|
if (application === void 0) {
|
|
16380
16376
|
return {
|
|
@@ -16384,12 +16380,8 @@ var TOOLS = [
|
|
|
16384
16380
|
requirements: APPLICATION_REQUIREMENTS
|
|
16385
16381
|
};
|
|
16386
16382
|
}
|
|
16387
|
-
|
|
16388
|
-
|
|
16389
|
-
`Unknown application "${String(application)}". ${formatKnownValues(APPLICATION_IDS, "applications")}`
|
|
16390
|
-
);
|
|
16391
|
-
}
|
|
16392
|
-
const app = APPLICATIONS[application];
|
|
16383
|
+
const resolved = await resolveDirectoryApplication(topolo, application);
|
|
16384
|
+
const app = resolved.application;
|
|
16393
16385
|
return {
|
|
16394
16386
|
version: APPLICATION_REQUIREMENTS_VERSION,
|
|
16395
16387
|
application: app,
|
|
@@ -16419,7 +16411,7 @@ var TOOLS = [
|
|
|
16419
16411
|
},
|
|
16420
16412
|
additionalProperties: false
|
|
16421
16413
|
},
|
|
16422
|
-
handler: async (
|
|
16414
|
+
handler: async (topolo, args) => {
|
|
16423
16415
|
const application = args["application"];
|
|
16424
16416
|
const failOn = args["failOn"];
|
|
16425
16417
|
if (failOn !== void 0 && typeof failOn !== "string") {
|
|
@@ -16428,15 +16420,12 @@ var TOOLS = [
|
|
|
16428
16420
|
const gate = failOn ? normalizeFailOn(failOn) : null;
|
|
16429
16421
|
let report;
|
|
16430
16422
|
if (application === void 0) {
|
|
16431
|
-
|
|
16423
|
+
const directory = await listApplicationDirectory(topolo.client);
|
|
16424
|
+
report = auditApplicationEntries(directory.applications.map((app) => app.application));
|
|
16432
16425
|
return gate ? { ...report, conformanceGate: evaluateApplicationAuditGate(report, gate) } : report;
|
|
16433
16426
|
}
|
|
16434
|
-
|
|
16435
|
-
|
|
16436
|
-
`Unknown application "${String(application)}". ${formatKnownValues(APPLICATION_IDS, "applications")}`
|
|
16437
|
-
);
|
|
16438
|
-
}
|
|
16439
|
-
report = auditAllApplicationRequirements([application]);
|
|
16427
|
+
const resolved = await resolveDirectoryApplication(topolo, application);
|
|
16428
|
+
report = auditApplicationEntries([resolved.application]);
|
|
16440
16429
|
return gate ? { ...report, conformanceGate: evaluateApplicationAuditGate(report, gate) } : report;
|
|
16441
16430
|
}
|
|
16442
16431
|
},
|
|
@@ -16576,31 +16565,19 @@ function statusesAtOrWorse(threshold) {
|
|
|
16576
16565
|
return ["missing", "needs_review", "partial"];
|
|
16577
16566
|
}
|
|
16578
16567
|
function displayAppId(entry) {
|
|
16579
|
-
|
|
16580
|
-
if (typeof value !== "string" || !value.trim()) continue;
|
|
16581
|
-
for (const candidate of appIdCandidates(value)) {
|
|
16582
|
-
if (Object.prototype.hasOwnProperty.call(DEFAULT_APP_URLS, candidate)) {
|
|
16583
|
-
return candidate;
|
|
16584
|
-
}
|
|
16585
|
-
}
|
|
16586
|
-
}
|
|
16587
|
-
return appIdCandidates(entry.slug || entry.appId)[0] || entry.appId;
|
|
16568
|
+
return friendlyAppId(entry);
|
|
16588
16569
|
}
|
|
16589
|
-
function
|
|
16590
|
-
|
|
16591
|
-
|
|
16592
|
-
|
|
16593
|
-
|
|
16594
|
-
|
|
16595
|
-
|
|
16596
|
-
|
|
16597
|
-
|
|
16598
|
-
|
|
16599
|
-
|
|
16600
|
-
const sorted = [...values].sort();
|
|
16601
|
-
const preview = sorted.slice(0, 25).join(", ");
|
|
16602
|
-
const suffix = sorted.length > 25 ? `, ... +${sorted.length - 25} more` : "";
|
|
16603
|
-
return `Run discovery for the full ${label} list. Known snapshot sample: ${preview}${suffix}`;
|
|
16570
|
+
async function resolveDirectoryApplication(topolo, application) {
|
|
16571
|
+
if (typeof application !== "string" || !application.trim()) {
|
|
16572
|
+
throw new TopoloMcpPublicError("`application` must be a non-empty string.");
|
|
16573
|
+
}
|
|
16574
|
+
try {
|
|
16575
|
+
return await resolveApplicationDirectoryEntry(topolo.client, application);
|
|
16576
|
+
} catch (error2) {
|
|
16577
|
+
throw new TopoloMcpPublicError(
|
|
16578
|
+
error2 instanceof Error ? error2.message : `Unknown application "${application}".`
|
|
16579
|
+
);
|
|
16580
|
+
}
|
|
16604
16581
|
}
|
|
16605
16582
|
|
|
16606
16583
|
// src/version.ts
|
package/dist/index.js
CHANGED
|
@@ -104,57 +104,8 @@ var TopoloHttpError = class extends TopoloSdkError {
|
|
|
104
104
|
}
|
|
105
105
|
};
|
|
106
106
|
var APP_API_URLS = {
|
|
107
|
-
agent: "https://agent.topolo.app",
|
|
108
107
|
auth: "https://auth.topolo.app",
|
|
109
|
-
|
|
110
|
-
blog: "https://blog.topolo.app",
|
|
111
|
-
books: "https://books.topolo.app",
|
|
112
|
-
brand: "https://brand.topolo.app",
|
|
113
|
-
bugfix: "https://bugfix.topolo.app",
|
|
114
|
-
bytes: "https://bytes.topolo.app",
|
|
115
|
-
calendar: "https://calendar.topolo.app",
|
|
116
|
-
campaigns: "https://campaigns.topolo.app",
|
|
117
|
-
capacity: "https://capacity.topolo.app",
|
|
118
|
-
chat: "https://chat.topolo.app",
|
|
119
|
-
commerce: "https://commerce.topolo.app",
|
|
120
|
-
compose: "https://compose.topolo.app",
|
|
121
|
-
consent: "https://consent.topolo.app",
|
|
122
|
-
crm: "https://crm.topolo.app",
|
|
123
|
-
design: "https://design.topolo.app",
|
|
124
|
-
developers: "https://developers.topolo.app",
|
|
125
|
-
director: "https://director.topolo.app",
|
|
126
|
-
feed: "https://feed.topolo.app",
|
|
127
|
-
flow: "https://flow.topolo.app",
|
|
128
|
-
forecast: "https://forecast.topolo.app",
|
|
129
|
-
forms: "https://forms.topolo.app",
|
|
130
|
-
home: "https://home.topolo.app",
|
|
131
|
-
insights: "https://insights.topolo.app",
|
|
132
|
-
inventory: "https://inventory.topolo.app",
|
|
133
|
-
learn: "https://learn.topolo.app",
|
|
134
|
-
localize: "https://localize.topolo.app",
|
|
135
|
-
mail: "https://mail.topolo.app",
|
|
136
|
-
mdm: "https://mdm.topolo.app",
|
|
137
|
-
messages: "https://messages.topolo.app",
|
|
138
|
-
nexus: "https://nexus.topolo.app",
|
|
139
|
-
notify: "https://notify.topolo.app",
|
|
140
|
-
observability_watch: "https://observability-watch.topolo.app",
|
|
141
|
-
one: "https://www.topolo.app",
|
|
142
|
-
p2p: "https://p2p.topolo.app",
|
|
143
|
-
pay: "https://pay.topolo.app",
|
|
144
|
-
people: "https://people.topolo.app",
|
|
145
|
-
"quro.api": "https://api.ol0.me",
|
|
146
|
-
"quro.redirect": "https://ol0.me",
|
|
147
|
-
roadmapper: "https://roadmapper.topolo.app",
|
|
148
|
-
sign: "https://sign.topolo.app",
|
|
149
|
-
social_studio: "https://studio.topolo.app",
|
|
150
|
-
socialize: "https://socialize.topolo.app",
|
|
151
|
-
spaces: "https://spaces.topolo.app",
|
|
152
|
-
status: "https://status.topolo.app",
|
|
153
|
-
success: "https://success.topolo.app",
|
|
154
|
-
support: "https://support.topolo.app",
|
|
155
|
-
survey: "https://survey.topolo.app",
|
|
156
|
-
voice: "https://voice.topolo.app",
|
|
157
|
-
web: "https://web.topolo.app"
|
|
108
|
+
developers: "https://developers.topolo.app"
|
|
158
109
|
};
|
|
159
110
|
var APPLICATIONS = {
|
|
160
111
|
"admin": {
|
|
@@ -1880,7 +1831,145 @@ var APPLICATIONS = {
|
|
|
1880
1831
|
]
|
|
1881
1832
|
}
|
|
1882
1833
|
};
|
|
1883
|
-
|
|
1834
|
+
function friendlyAppId(entry) {
|
|
1835
|
+
for (const value of [entry.slug, entry.name, entry.appId]) {
|
|
1836
|
+
if (typeof value !== "string" || !value.trim()) continue;
|
|
1837
|
+
const normalized = value.trim().toLowerCase().replace(/\s+/g, "-");
|
|
1838
|
+
const withoutPrefix = normalized.replace(/^(?:app[_-])?topolo[-_]+/, "");
|
|
1839
|
+
if (withoutPrefix) return withoutPrefix;
|
|
1840
|
+
}
|
|
1841
|
+
return entry.appId;
|
|
1842
|
+
}
|
|
1843
|
+
function idVariants(value) {
|
|
1844
|
+
const normalized = value.trim().toLowerCase().replace(/\s+/g, "-");
|
|
1845
|
+
return [.../* @__PURE__ */ new Set([
|
|
1846
|
+
normalized,
|
|
1847
|
+
normalized.replace(/-/g, "_"),
|
|
1848
|
+
normalized.replace(/_/g, "-")
|
|
1849
|
+
])].filter(Boolean);
|
|
1850
|
+
}
|
|
1851
|
+
var STATIC_APPLICATIONS = APPLICATIONS;
|
|
1852
|
+
function staticApplicationForId(id) {
|
|
1853
|
+
for (const variant of idVariants(id)) {
|
|
1854
|
+
const entry = STATIC_APPLICATIONS[variant];
|
|
1855
|
+
if (entry) return entry;
|
|
1856
|
+
}
|
|
1857
|
+
return null;
|
|
1858
|
+
}
|
|
1859
|
+
function applicationEntryFromCatalog(live) {
|
|
1860
|
+
const id = friendlyAppId(live);
|
|
1861
|
+
return {
|
|
1862
|
+
id,
|
|
1863
|
+
appDir: "-",
|
|
1864
|
+
name: live.name ?? live.slug ?? live.appId,
|
|
1865
|
+
packageName: null,
|
|
1866
|
+
productionUrl: live.launchUrl ?? live.apiBaseUrl ?? null,
|
|
1867
|
+
services: live.apiBaseUrl ? [id] : [],
|
|
1868
|
+
deployTargets: []
|
|
1869
|
+
};
|
|
1870
|
+
}
|
|
1871
|
+
var DIRECTORY_PAGE_LIMIT = 100;
|
|
1872
|
+
var DIRECTORY_MAX_PAGES = 100;
|
|
1873
|
+
function staticApplicationDirectory() {
|
|
1874
|
+
const applications = Object.entries(STATIC_APPLICATIONS).map(([id, application]) => ({
|
|
1875
|
+
id,
|
|
1876
|
+
application,
|
|
1877
|
+
source: "static",
|
|
1878
|
+
live: null
|
|
1879
|
+
})).sort((left, right) => left.id.localeCompare(right.id));
|
|
1880
|
+
return { source: "static_fallback", applications };
|
|
1881
|
+
}
|
|
1882
|
+
function directoryApplicationFromLive(live) {
|
|
1883
|
+
const id = friendlyAppId(live);
|
|
1884
|
+
return {
|
|
1885
|
+
id,
|
|
1886
|
+
// Prefer the static snapshot's richer repo/deploy metadata when the live
|
|
1887
|
+
// registry confirms the app; synthesize from the live entry otherwise.
|
|
1888
|
+
application: staticApplicationForId(id) ?? applicationEntryFromCatalog(live),
|
|
1889
|
+
source: "live",
|
|
1890
|
+
live
|
|
1891
|
+
};
|
|
1892
|
+
}
|
|
1893
|
+
async function listApplicationDirectory(client) {
|
|
1894
|
+
if (!client) return staticApplicationDirectory();
|
|
1895
|
+
let services;
|
|
1896
|
+
try {
|
|
1897
|
+
services = [];
|
|
1898
|
+
let cursor;
|
|
1899
|
+
for (let page = 0; page < DIRECTORY_MAX_PAGES; page += 1) {
|
|
1900
|
+
const result = await client.searchServices({
|
|
1901
|
+
...cursor ? { cursor } : {},
|
|
1902
|
+
limit: DIRECTORY_PAGE_LIMIT
|
|
1903
|
+
});
|
|
1904
|
+
services.push(...result.services);
|
|
1905
|
+
if (!result.page.nextCursor) break;
|
|
1906
|
+
cursor = result.page.nextCursor;
|
|
1907
|
+
}
|
|
1908
|
+
} catch {
|
|
1909
|
+
return staticApplicationDirectory();
|
|
1910
|
+
}
|
|
1911
|
+
const seen = /* @__PURE__ */ new Map();
|
|
1912
|
+
for (const live of services) {
|
|
1913
|
+
const entry = directoryApplicationFromLive(live);
|
|
1914
|
+
if (!seen.has(entry.id)) seen.set(entry.id, entry);
|
|
1915
|
+
}
|
|
1916
|
+
return {
|
|
1917
|
+
source: "live",
|
|
1918
|
+
applications: [...seen.values()].sort((left, right) => left.id.localeCompare(right.id))
|
|
1919
|
+
};
|
|
1920
|
+
}
|
|
1921
|
+
function matchesDirectoryApplication(app, needle) {
|
|
1922
|
+
const candidates = new Set(idVariants(needle));
|
|
1923
|
+
const keys = [
|
|
1924
|
+
app.id,
|
|
1925
|
+
app.application.id,
|
|
1926
|
+
app.application.name,
|
|
1927
|
+
app.live?.appId,
|
|
1928
|
+
app.live?.slug,
|
|
1929
|
+
app.live?.name
|
|
1930
|
+
];
|
|
1931
|
+
for (const key of keys) {
|
|
1932
|
+
if (typeof key !== "string" || !key.trim()) continue;
|
|
1933
|
+
for (const variant of idVariants(key)) {
|
|
1934
|
+
if (candidates.has(variant)) return true;
|
|
1935
|
+
}
|
|
1936
|
+
for (const variant of idVariants(friendlyAppId({ appId: key }))) {
|
|
1937
|
+
if (candidates.has(variant)) return true;
|
|
1938
|
+
}
|
|
1939
|
+
}
|
|
1940
|
+
return false;
|
|
1941
|
+
}
|
|
1942
|
+
function formatDirectoryApplicationIds(directory) {
|
|
1943
|
+
const ids = directory.applications.map((app) => app.id).sort();
|
|
1944
|
+
const preview = ids.slice(0, 50).join(", ");
|
|
1945
|
+
const suffix = ids.length > 50 ? `, ... +${ids.length - 50} more` : "";
|
|
1946
|
+
const label = directory.source === "live" ? "Applications available to this credential" : "Applications in the bundled static snapshot (live registry unreachable)";
|
|
1947
|
+
return `${label}: ${preview}${suffix}`;
|
|
1948
|
+
}
|
|
1949
|
+
async function resolveApplicationDirectoryEntry(client, application) {
|
|
1950
|
+
const needle = typeof application === "string" ? application.trim() : "";
|
|
1951
|
+
if (!needle) {
|
|
1952
|
+
throw new TopoloSdkError("unknown_application", "application is required");
|
|
1953
|
+
}
|
|
1954
|
+
if (client) {
|
|
1955
|
+
let live = null;
|
|
1956
|
+
try {
|
|
1957
|
+
live = await client.getService(needle);
|
|
1958
|
+
} catch {
|
|
1959
|
+
live = null;
|
|
1960
|
+
}
|
|
1961
|
+
if (live) return directoryApplicationFromLive(live);
|
|
1962
|
+
}
|
|
1963
|
+
const directory = await listApplicationDirectory(client);
|
|
1964
|
+
const match = directory.applications.find((app) => matchesDirectoryApplication(app, needle));
|
|
1965
|
+
if (match) return match;
|
|
1966
|
+
throw new TopoloSdkError(
|
|
1967
|
+
"unknown_application",
|
|
1968
|
+
`Unknown application "${application}". ${formatDirectoryApplicationIds(directory)}`
|
|
1969
|
+
);
|
|
1970
|
+
}
|
|
1971
|
+
var STATIC_APPLICATIONS2 = APPLICATIONS;
|
|
1972
|
+
var APPLICATION_REQUIREMENTS_VERSION = "2026-08-11.1";
|
|
1884
1973
|
var APPLICATION_REQUIREMENTS = [
|
|
1885
1974
|
{
|
|
1886
1975
|
id: "platform-metadata",
|
|
@@ -1890,10 +1979,10 @@ var APPLICATION_REQUIREMENTS = [
|
|
|
1890
1979
|
evidence: [
|
|
1891
1980
|
"topolo.cloudcontrol.json exists for every deployed app surface",
|
|
1892
1981
|
"package.json names the package or app when the repo ships code",
|
|
1893
|
-
"The
|
|
1982
|
+
"The live platform registry exposes the app through topolo apps and MCP discovery"
|
|
1894
1983
|
],
|
|
1895
1984
|
implementation: [
|
|
1896
|
-
"
|
|
1985
|
+
"Register the app in the live platform registry (Auth service catalog) before exposing it to agents",
|
|
1897
1986
|
"Keep production URLs, Worker names, Pages projects, routes, domains, and bindings current in CloudControl metadata",
|
|
1898
1987
|
"Do not leave a new Topolo* app directory without an explicit application ID"
|
|
1899
1988
|
]
|
|
@@ -1968,7 +2057,7 @@ var APPLICATION_REQUIREMENTS = [
|
|
|
1968
2057
|
implementation: [
|
|
1969
2058
|
"Add production Worker api_url metadata and sdk_app_id for every agent-callable API target",
|
|
1970
2059
|
"Mark browser, documentation, and runtime-only Worker targets with agent_callable:false",
|
|
1971
|
-
"Expose stable app IDs through
|
|
2060
|
+
"Expose stable app IDs through live catalog discovery",
|
|
1972
2061
|
"Keep typed SDK/CLI/MCP surfaces in sync when an API contract stabilizes"
|
|
1973
2062
|
]
|
|
1974
2063
|
},
|
|
@@ -2088,15 +2177,24 @@ function applicationRequirementScopes(application) {
|
|
|
2088
2177
|
}
|
|
2089
2178
|
return Array.from(scopes);
|
|
2090
2179
|
}
|
|
2180
|
+
function fallbackApplication(id) {
|
|
2181
|
+
const entry = STATIC_APPLICATIONS2[id];
|
|
2182
|
+
if (!entry) {
|
|
2183
|
+
throw new Error(
|
|
2184
|
+
`Unknown application "${id}" in the static fallback snapshot. Resolve applications from the live registry (resolveApplicationDirectoryEntry) and pass the entry directly.`
|
|
2185
|
+
);
|
|
2186
|
+
}
|
|
2187
|
+
return entry;
|
|
2188
|
+
}
|
|
2091
2189
|
function requirementsForApplication(applicationOrId) {
|
|
2092
|
-
const application = typeof applicationOrId === "string" ?
|
|
2190
|
+
const application = typeof applicationOrId === "string" ? fallbackApplication(applicationOrId) : applicationOrId;
|
|
2093
2191
|
const scopes = new Set(applicationRequirementScopes(application));
|
|
2094
2192
|
return APPLICATION_REQUIREMENTS.filter(
|
|
2095
2193
|
(requirement) => requirement.appliesTo.some((scope) => scopes.has(scope))
|
|
2096
2194
|
);
|
|
2097
2195
|
}
|
|
2098
2196
|
function auditApplicationRequirements(applicationOrId) {
|
|
2099
|
-
const application = typeof applicationOrId === "string" ?
|
|
2197
|
+
const application = typeof applicationOrId === "string" ? fallbackApplication(applicationOrId) : applicationOrId;
|
|
2100
2198
|
const scopes = applicationRequirementScopes(application);
|
|
2101
2199
|
const findings = requirementsForApplication(application).map(
|
|
2102
2200
|
(requirement) => evaluateRequirement(application, requirement)
|
|
@@ -2109,10 +2207,12 @@ function auditApplicationRequirements(applicationOrId) {
|
|
|
2109
2207
|
findings
|
|
2110
2208
|
};
|
|
2111
2209
|
}
|
|
2112
|
-
function
|
|
2113
|
-
|
|
2114
|
-
(
|
|
2210
|
+
function auditApplicationEntries(applications) {
|
|
2211
|
+
return buildAuditReport(
|
|
2212
|
+
applications.map((application) => auditApplicationRequirements(application))
|
|
2115
2213
|
);
|
|
2214
|
+
}
|
|
2215
|
+
function buildAuditReport(applications) {
|
|
2116
2216
|
const migrationQueue = applications.flatMap(
|
|
2117
2217
|
(audit) => audit.findings.filter((finding2) => finding2.status !== "met").map((finding2) => ({
|
|
2118
2218
|
applicationId: audit.application.id,
|
|
@@ -3415,8 +3515,9 @@ var TopoloClient = class _TopoloClient {
|
|
|
3415
3515
|
});
|
|
3416
3516
|
}
|
|
3417
3517
|
/**
|
|
3418
|
-
*
|
|
3419
|
-
*
|
|
3518
|
+
* @deprecated Static fallback snapshot only. Use `searchServices()` (the
|
|
3519
|
+
* live credential-scoped registry) for anything that decides behavior; this
|
|
3520
|
+
* exists for offline packaging audits when the registry is unreachable.
|
|
3420
3521
|
*/
|
|
3421
3522
|
listBundledServices() {
|
|
3422
3523
|
const apps = Object.values(APPLICATIONS);
|
|
@@ -3995,57 +4096,8 @@ var TopoloHttpError2 = class extends TopoloSdkError2 {
|
|
|
3995
4096
|
}
|
|
3996
4097
|
};
|
|
3997
4098
|
var APP_API_URLS2 = {
|
|
3998
|
-
agent: "https://agent.topolo.app",
|
|
3999
4099
|
auth: "https://auth.topolo.app",
|
|
4000
|
-
|
|
4001
|
-
blog: "https://blog.topolo.app",
|
|
4002
|
-
books: "https://books.topolo.app",
|
|
4003
|
-
brand: "https://brand.topolo.app",
|
|
4004
|
-
bugfix: "https://bugfix.topolo.app",
|
|
4005
|
-
bytes: "https://bytes.topolo.app",
|
|
4006
|
-
calendar: "https://calendar.topolo.app",
|
|
4007
|
-
campaigns: "https://campaigns.topolo.app",
|
|
4008
|
-
capacity: "https://capacity.topolo.app",
|
|
4009
|
-
chat: "https://chat.topolo.app",
|
|
4010
|
-
commerce: "https://commerce.topolo.app",
|
|
4011
|
-
compose: "https://compose.topolo.app",
|
|
4012
|
-
consent: "https://consent.topolo.app",
|
|
4013
|
-
crm: "https://crm.topolo.app",
|
|
4014
|
-
design: "https://design.topolo.app",
|
|
4015
|
-
developers: "https://developers.topolo.app",
|
|
4016
|
-
director: "https://director.topolo.app",
|
|
4017
|
-
feed: "https://feed.topolo.app",
|
|
4018
|
-
flow: "https://flow.topolo.app",
|
|
4019
|
-
forecast: "https://forecast.topolo.app",
|
|
4020
|
-
forms: "https://forms.topolo.app",
|
|
4021
|
-
home: "https://home.topolo.app",
|
|
4022
|
-
insights: "https://insights.topolo.app",
|
|
4023
|
-
inventory: "https://inventory.topolo.app",
|
|
4024
|
-
learn: "https://learn.topolo.app",
|
|
4025
|
-
localize: "https://localize.topolo.app",
|
|
4026
|
-
mail: "https://mail.topolo.app",
|
|
4027
|
-
mdm: "https://mdm.topolo.app",
|
|
4028
|
-
messages: "https://messages.topolo.app",
|
|
4029
|
-
nexus: "https://nexus.topolo.app",
|
|
4030
|
-
notify: "https://notify.topolo.app",
|
|
4031
|
-
observability_watch: "https://observability-watch.topolo.app",
|
|
4032
|
-
one: "https://www.topolo.app",
|
|
4033
|
-
p2p: "https://p2p.topolo.app",
|
|
4034
|
-
pay: "https://pay.topolo.app",
|
|
4035
|
-
people: "https://people.topolo.app",
|
|
4036
|
-
"quro.api": "https://api.ol0.me",
|
|
4037
|
-
"quro.redirect": "https://ol0.me",
|
|
4038
|
-
roadmapper: "https://roadmapper.topolo.app",
|
|
4039
|
-
sign: "https://sign.topolo.app",
|
|
4040
|
-
social_studio: "https://studio.topolo.app",
|
|
4041
|
-
socialize: "https://socialize.topolo.app",
|
|
4042
|
-
spaces: "https://spaces.topolo.app",
|
|
4043
|
-
status: "https://status.topolo.app",
|
|
4044
|
-
success: "https://success.topolo.app",
|
|
4045
|
-
support: "https://support.topolo.app",
|
|
4046
|
-
survey: "https://survey.topolo.app",
|
|
4047
|
-
voice: "https://voice.topolo.app",
|
|
4048
|
-
web: "https://web.topolo.app"
|
|
4100
|
+
developers: "https://developers.topolo.app"
|
|
4049
4101
|
};
|
|
4050
4102
|
var DEFAULT_APP_URLS2 = APP_API_URLS2;
|
|
4051
4103
|
function resolveServiceUrl2(service, overrides) {
|
|
@@ -4412,7 +4464,6 @@ function publicMcpErrorMessage(error, fallback) {
|
|
|
4412
4464
|
}
|
|
4413
4465
|
|
|
4414
4466
|
// src/tools.ts
|
|
4415
|
-
var APPLICATION_IDS = Object.keys(APPLICATIONS).sort();
|
|
4416
4467
|
var HTTP_METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE"];
|
|
4417
4468
|
function requiredString(args, name) {
|
|
4418
4469
|
const value = typeof args[name] === "string" ? args[name].trim() : "";
|
|
@@ -4428,6 +4479,20 @@ function optionalResourceContext(args) {
|
|
|
4428
4479
|
}
|
|
4429
4480
|
return { resourceType, resourceId };
|
|
4430
4481
|
}
|
|
4482
|
+
function coerceObjectParam(value, name) {
|
|
4483
|
+
let candidate = value;
|
|
4484
|
+
if (typeof candidate === "string" && candidate.trim().startsWith("{")) {
|
|
4485
|
+
try {
|
|
4486
|
+
candidate = JSON.parse(candidate);
|
|
4487
|
+
} catch {
|
|
4488
|
+
}
|
|
4489
|
+
}
|
|
4490
|
+
if (candidate === void 0) return {};
|
|
4491
|
+
if (!candidate || typeof candidate !== "object" || Array.isArray(candidate)) {
|
|
4492
|
+
throw new TopoloMcpPublicError(`${name} must be an object.`);
|
|
4493
|
+
}
|
|
4494
|
+
return candidate;
|
|
4495
|
+
}
|
|
4431
4496
|
var TOOLS = [
|
|
4432
4497
|
{
|
|
4433
4498
|
name: "topolo_whoami",
|
|
@@ -4578,14 +4643,11 @@ var TOOLS = [
|
|
|
4578
4643
|
handler: async (topolo, args) => {
|
|
4579
4644
|
const actionId = typeof args["actionId"] === "string" ? args["actionId"].trim() : "";
|
|
4580
4645
|
if (!actionId) throw new TopoloMcpPublicError("actionId is required.");
|
|
4581
|
-
const input = args["input"];
|
|
4582
|
-
if (input !== void 0 && (!input || typeof input !== "object" || Array.isArray(input))) {
|
|
4583
|
-
throw new TopoloMcpPublicError("input must be an object.");
|
|
4584
|
-
}
|
|
4646
|
+
const input = coerceObjectParam(args["input"], "input");
|
|
4585
4647
|
const resource = optionalResourceContext(args);
|
|
4586
4648
|
return topolo.client.readAction(
|
|
4587
4649
|
actionId,
|
|
4588
|
-
input
|
|
4650
|
+
input,
|
|
4589
4651
|
resource ? { resource } : {}
|
|
4590
4652
|
);
|
|
4591
4653
|
}
|
|
@@ -4611,14 +4673,11 @@ var TOOLS = [
|
|
|
4611
4673
|
handler: async (topolo, args) => {
|
|
4612
4674
|
const actionId = typeof args["actionId"] === "string" ? args["actionId"].trim() : "";
|
|
4613
4675
|
if (!actionId) throw new TopoloMcpPublicError("actionId is required.");
|
|
4614
|
-
const input = args["input"];
|
|
4615
|
-
if (input !== void 0 && (!input || typeof input !== "object" || Array.isArray(input))) {
|
|
4616
|
-
throw new TopoloMcpPublicError("input must be an object.");
|
|
4617
|
-
}
|
|
4676
|
+
const input = coerceObjectParam(args["input"], "input");
|
|
4618
4677
|
const resource = optionalResourceContext(args);
|
|
4619
4678
|
return topolo.client.callAction(
|
|
4620
4679
|
actionId,
|
|
4621
|
-
input
|
|
4680
|
+
input,
|
|
4622
4681
|
{
|
|
4623
4682
|
confirm: args["confirm"] === true,
|
|
4624
4683
|
...resource ? { resource } : {}
|
|
@@ -4657,23 +4716,17 @@ var TOOLS = [
|
|
|
4657
4716
|
if (!isCanonicalBase642(contentBase64)) throw new TopoloMcpPublicError("contentBase64 must be canonical base64.");
|
|
4658
4717
|
if (!contentType) throw new TopoloMcpPublicError("contentType is required.");
|
|
4659
4718
|
if (!fileName) throw new TopoloMcpPublicError("fileName is required.");
|
|
4660
|
-
const input = args["input"];
|
|
4661
|
-
|
|
4662
|
-
throw new TopoloMcpPublicError("input must be an object.");
|
|
4663
|
-
}
|
|
4664
|
-
const completionInput = args["completionInput"];
|
|
4665
|
-
if (completionInput !== void 0 && (!completionInput || typeof completionInput !== "object" || Array.isArray(completionInput))) {
|
|
4666
|
-
throw new TopoloMcpPublicError("completionInput must be an object.");
|
|
4667
|
-
}
|
|
4719
|
+
const input = coerceObjectParam(args["input"], "input");
|
|
4720
|
+
const completionInput = coerceObjectParam(args["completionInput"], "completionInput");
|
|
4668
4721
|
const resource = optionalResourceContext(args);
|
|
4669
4722
|
return topolo.client.uploadActionBase64(
|
|
4670
4723
|
actionId,
|
|
4671
4724
|
contentBase64,
|
|
4672
|
-
input
|
|
4725
|
+
input,
|
|
4673
4726
|
{
|
|
4674
4727
|
fileName,
|
|
4675
4728
|
contentType,
|
|
4676
|
-
completionInput
|
|
4729
|
+
completionInput,
|
|
4677
4730
|
confirm: args["confirm"] === true,
|
|
4678
4731
|
...resource ? { resource } : {}
|
|
4679
4732
|
}
|
|
@@ -4698,11 +4751,8 @@ var TOOLS = [
|
|
|
4698
4751
|
handler: async (topolo, args) => {
|
|
4699
4752
|
const actionId = typeof args["actionId"] === "string" ? args["actionId"].trim() : "";
|
|
4700
4753
|
if (!actionId) throw new TopoloMcpPublicError("actionId is required.");
|
|
4701
|
-
const input = args["input"];
|
|
4702
|
-
|
|
4703
|
-
throw new TopoloMcpPublicError("input must be an object.");
|
|
4704
|
-
}
|
|
4705
|
-
return topolo.client.validateActionInput(actionId, input ?? {});
|
|
4754
|
+
const input = coerceObjectParam(args["input"], "input");
|
|
4755
|
+
return topolo.client.validateActionInput(actionId, input);
|
|
4706
4756
|
}
|
|
4707
4757
|
},
|
|
4708
4758
|
{
|
|
@@ -4726,14 +4776,11 @@ var TOOLS = [
|
|
|
4726
4776
|
handler: async (topolo, args) => {
|
|
4727
4777
|
const actionId = typeof args["actionId"] === "string" ? args["actionId"].trim() : "";
|
|
4728
4778
|
if (!actionId) throw new TopoloMcpPublicError("actionId is required.");
|
|
4729
|
-
const input = args["input"];
|
|
4730
|
-
if (input !== void 0 && (!input || typeof input !== "object" || Array.isArray(input))) {
|
|
4731
|
-
throw new TopoloMcpPublicError("input must be an object.");
|
|
4732
|
-
}
|
|
4779
|
+
const input = coerceObjectParam(args["input"], "input");
|
|
4733
4780
|
const resource = optionalResourceContext(args);
|
|
4734
4781
|
return topolo.client.planAction(
|
|
4735
4782
|
actionId,
|
|
4736
|
-
input
|
|
4783
|
+
input,
|
|
4737
4784
|
{
|
|
4738
4785
|
confirm: args["confirm"] === true,
|
|
4739
4786
|
...resource ? { resource } : {}
|
|
@@ -4910,7 +4957,7 @@ var TOOLS = [
|
|
|
4910
4957
|
},
|
|
4911
4958
|
additionalProperties: false
|
|
4912
4959
|
},
|
|
4913
|
-
handler: async (
|
|
4960
|
+
handler: async (topolo, args) => {
|
|
4914
4961
|
const application = args["application"];
|
|
4915
4962
|
if (application === void 0) {
|
|
4916
4963
|
return {
|
|
@@ -4920,12 +4967,8 @@ var TOOLS = [
|
|
|
4920
4967
|
requirements: APPLICATION_REQUIREMENTS
|
|
4921
4968
|
};
|
|
4922
4969
|
}
|
|
4923
|
-
|
|
4924
|
-
|
|
4925
|
-
`Unknown application "${String(application)}". ${formatKnownValues(APPLICATION_IDS, "applications")}`
|
|
4926
|
-
);
|
|
4927
|
-
}
|
|
4928
|
-
const app = APPLICATIONS[application];
|
|
4970
|
+
const resolved = await resolveDirectoryApplication(topolo, application);
|
|
4971
|
+
const app = resolved.application;
|
|
4929
4972
|
return {
|
|
4930
4973
|
version: APPLICATION_REQUIREMENTS_VERSION,
|
|
4931
4974
|
application: app,
|
|
@@ -4955,7 +4998,7 @@ var TOOLS = [
|
|
|
4955
4998
|
},
|
|
4956
4999
|
additionalProperties: false
|
|
4957
5000
|
},
|
|
4958
|
-
handler: async (
|
|
5001
|
+
handler: async (topolo, args) => {
|
|
4959
5002
|
const application = args["application"];
|
|
4960
5003
|
const failOn = args["failOn"];
|
|
4961
5004
|
if (failOn !== void 0 && typeof failOn !== "string") {
|
|
@@ -4964,15 +5007,12 @@ var TOOLS = [
|
|
|
4964
5007
|
const gate = failOn ? normalizeFailOn(failOn) : null;
|
|
4965
5008
|
let report;
|
|
4966
5009
|
if (application === void 0) {
|
|
4967
|
-
|
|
5010
|
+
const directory = await listApplicationDirectory(topolo.client);
|
|
5011
|
+
report = auditApplicationEntries(directory.applications.map((app) => app.application));
|
|
4968
5012
|
return gate ? { ...report, conformanceGate: evaluateApplicationAuditGate(report, gate) } : report;
|
|
4969
5013
|
}
|
|
4970
|
-
|
|
4971
|
-
|
|
4972
|
-
`Unknown application "${String(application)}". ${formatKnownValues(APPLICATION_IDS, "applications")}`
|
|
4973
|
-
);
|
|
4974
|
-
}
|
|
4975
|
-
report = auditAllApplicationRequirements([application]);
|
|
5014
|
+
const resolved = await resolveDirectoryApplication(topolo, application);
|
|
5015
|
+
report = auditApplicationEntries([resolved.application]);
|
|
4976
5016
|
return gate ? { ...report, conformanceGate: evaluateApplicationAuditGate(report, gate) } : report;
|
|
4977
5017
|
}
|
|
4978
5018
|
},
|
|
@@ -5112,31 +5152,19 @@ function statusesAtOrWorse(threshold) {
|
|
|
5112
5152
|
return ["missing", "needs_review", "partial"];
|
|
5113
5153
|
}
|
|
5114
5154
|
function displayAppId(entry) {
|
|
5115
|
-
|
|
5116
|
-
if (typeof value !== "string" || !value.trim()) continue;
|
|
5117
|
-
for (const candidate of appIdCandidates(value)) {
|
|
5118
|
-
if (Object.prototype.hasOwnProperty.call(DEFAULT_APP_URLS, candidate)) {
|
|
5119
|
-
return candidate;
|
|
5120
|
-
}
|
|
5121
|
-
}
|
|
5122
|
-
}
|
|
5123
|
-
return appIdCandidates(entry.slug || entry.appId)[0] || entry.appId;
|
|
5124
|
-
}
|
|
5125
|
-
function appIdCandidates(value) {
|
|
5126
|
-
const normalized = value.trim().toLowerCase().replace(/\s+/g, "-");
|
|
5127
|
-
const withoutTopolo = normalized.startsWith("topolo-") ? normalized.slice("topolo-".length) : normalized;
|
|
5128
|
-
return [.../* @__PURE__ */ new Set([
|
|
5129
|
-
normalized,
|
|
5130
|
-
normalized.replace(/-/g, "_"),
|
|
5131
|
-
withoutTopolo,
|
|
5132
|
-
withoutTopolo.replace(/-/g, "_")
|
|
5133
|
-
])].filter(Boolean);
|
|
5155
|
+
return friendlyAppId(entry);
|
|
5134
5156
|
}
|
|
5135
|
-
function
|
|
5136
|
-
|
|
5137
|
-
|
|
5138
|
-
|
|
5139
|
-
|
|
5157
|
+
async function resolveDirectoryApplication(topolo, application) {
|
|
5158
|
+
if (typeof application !== "string" || !application.trim()) {
|
|
5159
|
+
throw new TopoloMcpPublicError("`application` must be a non-empty string.");
|
|
5160
|
+
}
|
|
5161
|
+
try {
|
|
5162
|
+
return await resolveApplicationDirectoryEntry(topolo.client, application);
|
|
5163
|
+
} catch (error) {
|
|
5164
|
+
throw new TopoloMcpPublicError(
|
|
5165
|
+
error instanceof Error ? error.message : `Unknown application "${application}".`
|
|
5166
|
+
);
|
|
5167
|
+
}
|
|
5140
5168
|
}
|
|
5141
5169
|
|
|
5142
5170
|
// src/version.ts
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@topolo/mcp",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"topoloPublishedVersion": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
|
+
"topoloPublishedVersion": "0.10.0",
|
|
5
5
|
"description": "Model Context Protocol server for the Topolo platform. Exposes scope-gated tools that third-party agents (Claude, Codex, etc.) can call natively.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"@modelcontextprotocol/sdk": "^1.0.0"
|
|
38
38
|
},
|
|
39
39
|
"peerDependencies": {
|
|
40
|
-
"@topolo/sdk": "^0.
|
|
40
|
+
"@topolo/sdk": "^0.10.0"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@topolo/sdk": "file:../topolo-sdk",
|