@topolo/mcp 0.11.11 → 0.11.12
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 +1 -1
- package/dist/http.js +2373 -1128
- package/dist/index.js +100 -13
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -80,6 +80,7 @@ var ERROR_CODE_PATTERN = /^[a-z][a-z0-9_]{0,63}$/;
|
|
|
80
80
|
var TOPOLO_REQUEST_ID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
81
81
|
var CLOUDFLARE_RAY_ID_PATTERN = /^[0-9a-f]{16}-[A-Z]{3}$/;
|
|
82
82
|
var PERMISSION_PATTERN = /^[a-z][a-z0-9_-]{0,63}(?:\.[a-z][a-z0-9_-]{0,63})*:(?:[a-z][a-z0-9_-]{0,63}|\*)$/;
|
|
83
|
+
var PUBLIC_FIELD_PATH_PATTERN = /^[$.a-z0-9_[\]-]{1,160}$/i;
|
|
83
84
|
var RETRY_AFTER_DATE_PATTERN = /^(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun), \d{2} (?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) \d{4} \d{2}:\d{2}:\d{2} GMT$/;
|
|
84
85
|
var PUBLIC_DETAIL_SOURCES = /* @__PURE__ */ new Set([
|
|
85
86
|
"api_key_introspection",
|
|
@@ -192,7 +193,11 @@ function extractTopoloServiceErrorDetails(body) {
|
|
|
192
193
|
if (candidate === void 0) candidate = nestedRecord.details ?? nestedRecord;
|
|
193
194
|
}
|
|
194
195
|
if (candidate === void 0) candidate = record;
|
|
195
|
-
if (
|
|
196
|
+
if (Array.isArray(candidate)) {
|
|
197
|
+
const paths = canonicalTopoloValidationPaths(candidate);
|
|
198
|
+
return paths.length ? { paths } : void 0;
|
|
199
|
+
}
|
|
200
|
+
if (!candidate || typeof candidate !== "object") return void 0;
|
|
196
201
|
const source = candidate;
|
|
197
202
|
const safe = {};
|
|
198
203
|
for (const [key, value] of Object.entries(source)) {
|
|
@@ -229,12 +234,42 @@ function extractTopoloServiceErrorDetails(body) {
|
|
|
229
234
|
continue;
|
|
230
235
|
}
|
|
231
236
|
if (["missingFields", "fields", "paths"].includes(key) && Array.isArray(value)) {
|
|
232
|
-
const paths = value.filter((item) => typeof item === "string" &&
|
|
237
|
+
const paths = value.filter((item) => typeof item === "string" && PUBLIC_FIELD_PATH_PATTERN.test(item));
|
|
233
238
|
if (paths.length) safe[key] = paths;
|
|
234
239
|
}
|
|
235
240
|
}
|
|
236
241
|
return Object.keys(safe).length ? safe : void 0;
|
|
237
242
|
}
|
|
243
|
+
function canonicalTopoloValidationPaths(issues) {
|
|
244
|
+
const paths = [];
|
|
245
|
+
for (const issue of issues) {
|
|
246
|
+
if (!issue || typeof issue !== "object" || Array.isArray(issue)) continue;
|
|
247
|
+
const record = issue;
|
|
248
|
+
const path = canonicalTopoloValidationPath(record.field) ?? canonicalTopoloValidationPath(record.path);
|
|
249
|
+
if (path && !paths.includes(path)) paths.push(path);
|
|
250
|
+
if (paths.length === 32) break;
|
|
251
|
+
}
|
|
252
|
+
return paths;
|
|
253
|
+
}
|
|
254
|
+
function canonicalTopoloValidationPath(value) {
|
|
255
|
+
if (typeof value === "string") {
|
|
256
|
+
const path2 = value.trim();
|
|
257
|
+
return PUBLIC_FIELD_PATH_PATTERN.test(path2) ? path2 : void 0;
|
|
258
|
+
}
|
|
259
|
+
if (!Array.isArray(value) || value.length === 0 || value.length > 32) return void 0;
|
|
260
|
+
const segments = value.map((segment) => {
|
|
261
|
+
if (typeof segment === "number" && Number.isSafeInteger(segment) && segment >= 0) {
|
|
262
|
+
return String(segment);
|
|
263
|
+
}
|
|
264
|
+
if (typeof segment === "string" && /^[a-z0-9_$-]{1,80}$/i.test(segment)) {
|
|
265
|
+
return segment;
|
|
266
|
+
}
|
|
267
|
+
return null;
|
|
268
|
+
});
|
|
269
|
+
if (segments.includes(null)) return void 0;
|
|
270
|
+
const path = segments.join(".");
|
|
271
|
+
return PUBLIC_FIELD_PATH_PATTERN.test(path) ? path : void 0;
|
|
272
|
+
}
|
|
238
273
|
function publicTopoloErrorMessage(error) {
|
|
239
274
|
const code = canonicalTopoloErrorCode(
|
|
240
275
|
typeof error === "string" ? error : error.code ?? extractTopoloServiceErrorCode(error.body)
|
|
@@ -1011,16 +1046,29 @@ var TopoloClient = class _TopoloClient {
|
|
|
1011
1046
|
clearTimeout(timeoutId);
|
|
1012
1047
|
}
|
|
1013
1048
|
};
|
|
1049
|
+
const fetchWithReadRetry = async () => {
|
|
1050
|
+
const maxAttempts = method === "GET" ? 2 : 1;
|
|
1051
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
|
|
1052
|
+
try {
|
|
1053
|
+
return await fetchOnce();
|
|
1054
|
+
} catch (error) {
|
|
1055
|
+
const transportFailure = !(error instanceof TopoloSdkError) && !opts.signal?.aborted;
|
|
1056
|
+
if (!transportFailure || attempt === maxAttempts) throw error;
|
|
1057
|
+
await new Promise((resolve2) => setTimeout(resolve2, 250));
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
throw new TopoloSdkError("network_error", "Topolo read retry loop exhausted.");
|
|
1061
|
+
};
|
|
1014
1062
|
let res;
|
|
1015
1063
|
try {
|
|
1016
1064
|
const attemptedCredential = this.credential;
|
|
1017
|
-
res = await
|
|
1065
|
+
res = await fetchWithReadRetry();
|
|
1018
1066
|
if (res.status === 401 && attemptedCredential.kind === "access_token" && this.refreshCredential) {
|
|
1019
1067
|
await res.body?.cancel().catch(() => void 0);
|
|
1020
1068
|
const refreshed = await this.refreshRejectedAccessToken(attemptedCredential.accessToken);
|
|
1021
1069
|
if (refreshed) {
|
|
1022
1070
|
applyAuthHeaders(headers, refreshed);
|
|
1023
|
-
res = await
|
|
1071
|
+
res = await fetchWithReadRetry();
|
|
1024
1072
|
}
|
|
1025
1073
|
}
|
|
1026
1074
|
} catch (err) {
|
|
@@ -1672,26 +1720,29 @@ var TopoloClient = class _TopoloClient {
|
|
|
1672
1720
|
};
|
|
1673
1721
|
function validateActionResource(entry, resource) {
|
|
1674
1722
|
const permissionName = entry.permissionName || entry.requiredPermission.split(".").at(-1) || "";
|
|
1675
|
-
|
|
1723
|
+
const declaredContext = entry.agentContract?.resourceContext;
|
|
1724
|
+
const declaredKind = typeof declaredContext?.kind === "string" ? declaredContext.kind.trim() : "";
|
|
1725
|
+
const expectedType = declaredKind || (permissionName.startsWith("workspace:") ? "workspace" : "");
|
|
1726
|
+
if (!expectedType || declaredContext?.required === false && !permissionName.startsWith("workspace:")) return null;
|
|
1676
1727
|
if (!resource) {
|
|
1677
1728
|
return {
|
|
1678
1729
|
path: "$.resource",
|
|
1679
1730
|
code: "required",
|
|
1680
|
-
message:
|
|
1731
|
+
message: `Select resourceType "${expectedType}" with the application resource catalog before planning or calling this action.`
|
|
1681
1732
|
};
|
|
1682
1733
|
}
|
|
1683
|
-
if (resource.resourceType !==
|
|
1734
|
+
if (resource.resourceType !== expectedType) {
|
|
1684
1735
|
return {
|
|
1685
1736
|
path: "$.resource.resourceType",
|
|
1686
1737
|
code: "const",
|
|
1687
|
-
message:
|
|
1738
|
+
message: `This action requires resourceType "${expectedType}".`
|
|
1688
1739
|
};
|
|
1689
1740
|
}
|
|
1690
1741
|
if (!resource.resourceId.trim()) {
|
|
1691
1742
|
return {
|
|
1692
1743
|
path: "$.resource.resourceId",
|
|
1693
1744
|
code: "required",
|
|
1694
|
-
message:
|
|
1745
|
+
message: `This action requires a ${expectedType} resourceId.`
|
|
1695
1746
|
};
|
|
1696
1747
|
}
|
|
1697
1748
|
return null;
|
|
@@ -2063,7 +2114,8 @@ function compactActionCatalogEntry(action) {
|
|
|
2063
2114
|
agentAccess: action.agentAccess ?? (action.requiresConfirmation ? "confirm" : action.readOnly ? "auto" : "confirm"),
|
|
2064
2115
|
requiredPermission: action.requiredPermission,
|
|
2065
2116
|
requiredInput: required,
|
|
2066
|
-
resourceType: action.agentContract?.
|
|
2117
|
+
resourceType: action.agentContract?.resourceContext?.kind ?? (action.permissionName.startsWith("workspace:") ? "workspace" : null),
|
|
2118
|
+
resultResourceType: action.agentContract?.resource?.kind ?? null,
|
|
2067
2119
|
exampleInput: example.value,
|
|
2068
2120
|
exampleInputAvailable: example.available,
|
|
2069
2121
|
docsUrl: action.agentContract?.docsUrl ?? null
|
|
@@ -2411,6 +2463,7 @@ var ERROR_CODE_PATTERN2 = /^[a-z][a-z0-9_]{0,63}$/;
|
|
|
2411
2463
|
var TOPOLO_REQUEST_ID_PATTERN2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
2412
2464
|
var CLOUDFLARE_RAY_ID_PATTERN2 = /^[0-9a-f]{16}-[A-Z]{3}$/;
|
|
2413
2465
|
var PERMISSION_PATTERN2 = /^[a-z][a-z0-9_-]{0,63}(?:\.[a-z][a-z0-9_-]{0,63})*:(?:[a-z][a-z0-9_-]{0,63}|\*)$/;
|
|
2466
|
+
var PUBLIC_FIELD_PATH_PATTERN2 = /^[$.a-z0-9_[\]-]{1,160}$/i;
|
|
2414
2467
|
var RETRY_AFTER_DATE_PATTERN2 = /^(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun), \d{2} (?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) \d{4} \d{2}:\d{2}:\d{2} GMT$/;
|
|
2415
2468
|
var PUBLIC_DETAIL_SOURCES2 = /* @__PURE__ */ new Set([
|
|
2416
2469
|
"api_key_introspection",
|
|
@@ -2496,7 +2549,11 @@ function extractTopoloServiceErrorDetails2(body) {
|
|
|
2496
2549
|
if (candidate === void 0) candidate = nestedRecord.details ?? nestedRecord;
|
|
2497
2550
|
}
|
|
2498
2551
|
if (candidate === void 0) candidate = record;
|
|
2499
|
-
if (
|
|
2552
|
+
if (Array.isArray(candidate)) {
|
|
2553
|
+
const paths = canonicalTopoloValidationPaths2(candidate);
|
|
2554
|
+
return paths.length ? { paths } : void 0;
|
|
2555
|
+
}
|
|
2556
|
+
if (!candidate || typeof candidate !== "object") return void 0;
|
|
2500
2557
|
const source = candidate;
|
|
2501
2558
|
const safe = {};
|
|
2502
2559
|
for (const [key, value] of Object.entries(source)) {
|
|
@@ -2533,12 +2590,42 @@ function extractTopoloServiceErrorDetails2(body) {
|
|
|
2533
2590
|
continue;
|
|
2534
2591
|
}
|
|
2535
2592
|
if (["missingFields", "fields", "paths"].includes(key) && Array.isArray(value)) {
|
|
2536
|
-
const paths = value.filter((item) => typeof item === "string" &&
|
|
2593
|
+
const paths = value.filter((item) => typeof item === "string" && PUBLIC_FIELD_PATH_PATTERN2.test(item));
|
|
2537
2594
|
if (paths.length) safe[key] = paths;
|
|
2538
2595
|
}
|
|
2539
2596
|
}
|
|
2540
2597
|
return Object.keys(safe).length ? safe : void 0;
|
|
2541
2598
|
}
|
|
2599
|
+
function canonicalTopoloValidationPaths2(issues) {
|
|
2600
|
+
const paths = [];
|
|
2601
|
+
for (const issue of issues) {
|
|
2602
|
+
if (!issue || typeof issue !== "object" || Array.isArray(issue)) continue;
|
|
2603
|
+
const record = issue;
|
|
2604
|
+
const path = canonicalTopoloValidationPath2(record.field) ?? canonicalTopoloValidationPath2(record.path);
|
|
2605
|
+
if (path && !paths.includes(path)) paths.push(path);
|
|
2606
|
+
if (paths.length === 32) break;
|
|
2607
|
+
}
|
|
2608
|
+
return paths;
|
|
2609
|
+
}
|
|
2610
|
+
function canonicalTopoloValidationPath2(value) {
|
|
2611
|
+
if (typeof value === "string") {
|
|
2612
|
+
const path2 = value.trim();
|
|
2613
|
+
return PUBLIC_FIELD_PATH_PATTERN2.test(path2) ? path2 : void 0;
|
|
2614
|
+
}
|
|
2615
|
+
if (!Array.isArray(value) || value.length === 0 || value.length > 32) return void 0;
|
|
2616
|
+
const segments = value.map((segment) => {
|
|
2617
|
+
if (typeof segment === "number" && Number.isSafeInteger(segment) && segment >= 0) {
|
|
2618
|
+
return String(segment);
|
|
2619
|
+
}
|
|
2620
|
+
if (typeof segment === "string" && /^[a-z0-9_$-]{1,80}$/i.test(segment)) {
|
|
2621
|
+
return segment;
|
|
2622
|
+
}
|
|
2623
|
+
return null;
|
|
2624
|
+
});
|
|
2625
|
+
if (segments.includes(null)) return void 0;
|
|
2626
|
+
const path = segments.join(".");
|
|
2627
|
+
return PUBLIC_FIELD_PATH_PATTERN2.test(path) ? path : void 0;
|
|
2628
|
+
}
|
|
2542
2629
|
var TopoloHttpError2 = class extends TopoloSdkError2 {
|
|
2543
2630
|
status;
|
|
2544
2631
|
body;
|
|
@@ -3047,7 +3134,7 @@ function summarizeActionCapabilities(service, actions) {
|
|
|
3047
3134
|
mutating: actions.filter((action) => !action.readOnly).length,
|
|
3048
3135
|
destructive: actions.filter((action) => action.destructive).length,
|
|
3049
3136
|
confirmationRequired: actions.filter((action) => action.requiresConfirmation).length,
|
|
3050
|
-
resourceTypes: [...new Set(actions.map((action) => action.agentContract?.
|
|
3137
|
+
resourceTypes: [...new Set(actions.map((action) => action.agentContract?.resourceContext?.kind ?? (action.permissionName.startsWith("workspace:") ? "workspace" : null)).filter(Boolean))].sort()
|
|
3051
3138
|
};
|
|
3052
3139
|
}
|
|
3053
3140
|
function coerceObjectParam(value, name) {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@topolo/mcp",
|
|
3
|
-
"version": "0.11.
|
|
4
|
-
"topoloPublishedVersion": "0.11.
|
|
3
|
+
"version": "0.11.12",
|
|
4
|
+
"topoloPublishedVersion": "0.11.12",
|
|
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
|
"license": "UNLICENSED",
|
|
7
7
|
"author": "Topolo",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
38
|
-
"@topolo/sdk": "0.
|
|
38
|
+
"@topolo/sdk": "0.14.2"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
41
|
"@types/node": "^20.12.0",
|