@topolo/mcp 0.4.10 → 0.6.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/README.md +1 -1
- package/dist/dispatch.js +21 -21
- package/dist/http.d.ts +2 -2
- package/dist/http.js +22 -22
- package/dist/index.js +529 -190
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -123,7 +123,7 @@ yet. GET requests work without confirmation; mutating HTTP methods must pass
|
|
|
123
123
|
`confirm: true` or the SDK rejects the call. Backing services still enforce
|
|
124
124
|
permissions for every request. The tool schema intentionally does not embed a
|
|
125
125
|
large service enum; agents should call `topolo_list_services` first, then pass a
|
|
126
|
-
|
|
126
|
+
app ID/slug from that credential-scoped result. New services become callable
|
|
127
127
|
without an MCP release once Auth grants the organization and credential the
|
|
128
128
|
relevant permissions, and new actions become typed tools without an MCP release
|
|
129
129
|
once the application publishes them.
|
package/dist/dispatch.js
CHANGED
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
APPLICATION_REQUIREMENTS,
|
|
7
7
|
APPLICATION_REQUIREMENTS_VERSION,
|
|
8
8
|
APPLICATIONS,
|
|
9
|
-
|
|
9
|
+
DEFAULT_APP_URLS,
|
|
10
10
|
auditAllApplicationRequirements,
|
|
11
11
|
applicationRequirementScopes,
|
|
12
12
|
requirementsForApplication,
|
|
@@ -22,13 +22,13 @@ function hasScope(set, required) {
|
|
|
22
22
|
if (set.permissions.includes("*")) return true;
|
|
23
23
|
const [servicePart, actionPart] = splitPermission(required);
|
|
24
24
|
if (!servicePart) return set.permissions.includes(required);
|
|
25
|
-
const [
|
|
25
|
+
const [appId, resource] = splitService(servicePart);
|
|
26
26
|
const candidates = new Set([
|
|
27
27
|
required,
|
|
28
28
|
"*",
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
appId ? `${appId}.*` : null,
|
|
30
|
+
appId && resource && actionPart ? `${appId}.${resource}:*` : null,
|
|
31
|
+
appId && resource && actionPart ? `${appId}.${resource}.${actionPart}` : null,
|
|
32
32
|
resource && actionPart ? `${resource}:*` : null,
|
|
33
33
|
resource && actionPart ? `${resource}.${actionPart}` : null,
|
|
34
34
|
resource && actionPart ? `${resource}:${actionPart}` : null
|
|
@@ -80,10 +80,10 @@ var TOOLS = [
|
|
|
80
80
|
},
|
|
81
81
|
handler: async (topolo) => {
|
|
82
82
|
const services = (await topolo.client.listServices()).map((entry) => {
|
|
83
|
-
const id =
|
|
83
|
+
const id = displayAppId(entry);
|
|
84
84
|
return {
|
|
85
85
|
id,
|
|
86
|
-
|
|
86
|
+
appId: entry.appId,
|
|
87
87
|
slug: entry.slug,
|
|
88
88
|
name: entry.name,
|
|
89
89
|
apiBaseUrl: entry.apiBaseUrl,
|
|
@@ -110,7 +110,7 @@ var TOOLS = [
|
|
|
110
110
|
properties: {
|
|
111
111
|
service: {
|
|
112
112
|
type: "string",
|
|
113
|
-
description: "Optional
|
|
113
|
+
description: "Optional app id, slug, or name filter."
|
|
114
114
|
}
|
|
115
115
|
},
|
|
116
116
|
additionalProperties: false
|
|
@@ -139,7 +139,7 @@ var TOOLS = [
|
|
|
139
139
|
{
|
|
140
140
|
name: "topolo_get_application",
|
|
141
141
|
title: "Describe one Topolo platform application",
|
|
142
|
-
description: "Returns one live application catalog entry (
|
|
142
|
+
description: "Returns one live application catalog entry (app id, slug, name, API URL, launch URL, status). Accepts the app id, slug, or name. Resolved against the live registry so newly-registered apps work without a client rebuild.",
|
|
143
143
|
requiredScopes: [],
|
|
144
144
|
destructive: false,
|
|
145
145
|
inputSchema: {
|
|
@@ -147,7 +147,7 @@ var TOOLS = [
|
|
|
147
147
|
properties: {
|
|
148
148
|
application: {
|
|
149
149
|
type: "string",
|
|
150
|
-
description: "Application identifier:
|
|
150
|
+
description: "Application identifier: app id, slug, or name from topolo_list_applications."
|
|
151
151
|
}
|
|
152
152
|
},
|
|
153
153
|
required: ["application"],
|
|
@@ -161,10 +161,10 @@ var TOOLS = [
|
|
|
161
161
|
const needle = application.trim().toLowerCase();
|
|
162
162
|
const catalog = await topolo.client.listServices();
|
|
163
163
|
const match = catalog.find(
|
|
164
|
-
(e) => e.
|
|
164
|
+
(e) => e.appId.toLowerCase() === needle || e.slug && e.slug.toLowerCase() === needle || e.name && e.name.toLowerCase() === needle
|
|
165
165
|
);
|
|
166
166
|
if (!match) {
|
|
167
|
-
const known = catalog.map((e) => e.slug || e.
|
|
167
|
+
const known = catalog.map((e) => e.slug || e.appId).sort().filter((value) => typeof value === "string" && value.length > 0);
|
|
168
168
|
throw new Error(
|
|
169
169
|
`Unknown application "${application}". ${formatKnownValues(known, "applications")}`
|
|
170
170
|
);
|
|
@@ -257,7 +257,7 @@ var TOOLS = [
|
|
|
257
257
|
{
|
|
258
258
|
name: "topolo_api_call",
|
|
259
259
|
title: "Call any Topolo platform service",
|
|
260
|
-
description: "Low-level passthrough to any Topolo service. Use when no domain-specific tool exists for the operation you need. The request is signed with the current credential and scoped to the caller's organization \u2014 the target service will return 403 if your scopes do not permit the operation, even though this tool is advertised. Mutating calls (non-GET methods) require confirm:true. Call topolo_list_services first to discover callable
|
|
260
|
+
description: "Low-level passthrough to any Topolo service. Use when no domain-specific tool exists for the operation you need. The request is signed with the current credential and scoped to the caller's organization \u2014 the target service will return 403 if your scopes do not permit the operation, even though this tool is advertised. Mutating calls (non-GET methods) require confirm:true. Call topolo_list_services first to discover callable app IDs; the SDK can also resolve live Auth-catalog app ids/slugs for newly registered API surfaces.",
|
|
261
261
|
requiredScopes: [],
|
|
262
262
|
destructive: true,
|
|
263
263
|
inputSchema: {
|
|
@@ -265,7 +265,7 @@ var TOOLS = [
|
|
|
265
265
|
properties: {
|
|
266
266
|
service: {
|
|
267
267
|
type: "string",
|
|
268
|
-
description: "Target
|
|
268
|
+
description: "Target app ID from the platform registry."
|
|
269
269
|
},
|
|
270
270
|
method: {
|
|
271
271
|
type: "string",
|
|
@@ -370,7 +370,7 @@ function actionsToToolDefs(actions) {
|
|
|
370
370
|
}));
|
|
371
371
|
}
|
|
372
372
|
function toolNameForAction(action) {
|
|
373
|
-
const service = (action.
|
|
373
|
+
const service = (action.appSlug || action.appId || "service").replace(/^topolo-/, "").toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
|
|
374
374
|
const name = action.name.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
|
|
375
375
|
return ["topolo", service, name].filter(Boolean).join("_").slice(0, 96);
|
|
376
376
|
}
|
|
@@ -431,18 +431,18 @@ function statusesAtOrWorse(threshold) {
|
|
|
431
431
|
if (threshold === "needs_review") return ["missing", "needs_review"];
|
|
432
432
|
return ["missing", "needs_review", "partial"];
|
|
433
433
|
}
|
|
434
|
-
function
|
|
435
|
-
for (const value of [entry.slug, entry.name, entry.
|
|
434
|
+
function displayAppId(entry) {
|
|
435
|
+
for (const value of [entry.slug, entry.name, entry.appId]) {
|
|
436
436
|
if (typeof value !== "string" || !value.trim()) continue;
|
|
437
|
-
for (const candidate of
|
|
438
|
-
if (Object.prototype.hasOwnProperty.call(
|
|
437
|
+
for (const candidate of appIdCandidates(value)) {
|
|
438
|
+
if (Object.prototype.hasOwnProperty.call(DEFAULT_APP_URLS, candidate)) {
|
|
439
439
|
return candidate;
|
|
440
440
|
}
|
|
441
441
|
}
|
|
442
442
|
}
|
|
443
|
-
return
|
|
443
|
+
return appIdCandidates(entry.slug || entry.appId)[0] || entry.appId;
|
|
444
444
|
}
|
|
445
|
-
function
|
|
445
|
+
function appIdCandidates(value) {
|
|
446
446
|
const normalized = value.trim().toLowerCase().replace(/\s+/g, "-");
|
|
447
447
|
const withoutTopolo = normalized.startsWith("topolo-") ? normalized.slice("topolo-".length) : normalized;
|
|
448
448
|
return [.../* @__PURE__ */ new Set([
|
package/dist/http.d.ts
CHANGED
|
@@ -23,8 +23,8 @@ interface TopoloMcpHttpOptions {
|
|
|
23
23
|
path?: string;
|
|
24
24
|
/** Per-service URL overrides (e.g. staging). Passed through to createTopolo. */
|
|
25
25
|
serviceUrls?: Record<string, string>;
|
|
26
|
-
/** Per-service TopoloAuth
|
|
27
|
-
|
|
26
|
+
/** Per-service TopoloAuth app-id overrides. Passed through to createTopolo. */
|
|
27
|
+
appIds?: Record<string, string>;
|
|
28
28
|
/** Human-readable agent label for audit logs (forwarded to the SDK). */
|
|
29
29
|
agentName?: string;
|
|
30
30
|
/**
|
package/dist/http.js
CHANGED
|
@@ -15814,7 +15814,7 @@ import {
|
|
|
15814
15814
|
APPLICATION_REQUIREMENTS,
|
|
15815
15815
|
APPLICATION_REQUIREMENTS_VERSION,
|
|
15816
15816
|
APPLICATIONS,
|
|
15817
|
-
|
|
15817
|
+
DEFAULT_APP_URLS,
|
|
15818
15818
|
auditAllApplicationRequirements,
|
|
15819
15819
|
applicationRequirementScopes,
|
|
15820
15820
|
requirementsForApplication,
|
|
@@ -15830,13 +15830,13 @@ function hasScope(set, required2) {
|
|
|
15830
15830
|
if (set.permissions.includes("*")) return true;
|
|
15831
15831
|
const [servicePart, actionPart] = splitPermission(required2);
|
|
15832
15832
|
if (!servicePart) return set.permissions.includes(required2);
|
|
15833
|
-
const [
|
|
15833
|
+
const [appId, resource] = splitService(servicePart);
|
|
15834
15834
|
const candidates = new Set([
|
|
15835
15835
|
required2,
|
|
15836
15836
|
"*",
|
|
15837
|
-
|
|
15838
|
-
|
|
15839
|
-
|
|
15837
|
+
appId ? `${appId}.*` : null,
|
|
15838
|
+
appId && resource && actionPart ? `${appId}.${resource}:*` : null,
|
|
15839
|
+
appId && resource && actionPart ? `${appId}.${resource}.${actionPart}` : null,
|
|
15840
15840
|
resource && actionPart ? `${resource}:*` : null,
|
|
15841
15841
|
resource && actionPart ? `${resource}.${actionPart}` : null,
|
|
15842
15842
|
resource && actionPart ? `${resource}:${actionPart}` : null
|
|
@@ -15888,10 +15888,10 @@ var TOOLS = [
|
|
|
15888
15888
|
},
|
|
15889
15889
|
handler: async (topolo) => {
|
|
15890
15890
|
const services = (await topolo.client.listServices()).map((entry) => {
|
|
15891
|
-
const id =
|
|
15891
|
+
const id = displayAppId(entry);
|
|
15892
15892
|
return {
|
|
15893
15893
|
id,
|
|
15894
|
-
|
|
15894
|
+
appId: entry.appId,
|
|
15895
15895
|
slug: entry.slug,
|
|
15896
15896
|
name: entry.name,
|
|
15897
15897
|
apiBaseUrl: entry.apiBaseUrl,
|
|
@@ -15918,7 +15918,7 @@ var TOOLS = [
|
|
|
15918
15918
|
properties: {
|
|
15919
15919
|
service: {
|
|
15920
15920
|
type: "string",
|
|
15921
|
-
description: "Optional
|
|
15921
|
+
description: "Optional app id, slug, or name filter."
|
|
15922
15922
|
}
|
|
15923
15923
|
},
|
|
15924
15924
|
additionalProperties: false
|
|
@@ -15947,7 +15947,7 @@ var TOOLS = [
|
|
|
15947
15947
|
{
|
|
15948
15948
|
name: "topolo_get_application",
|
|
15949
15949
|
title: "Describe one Topolo platform application",
|
|
15950
|
-
description: "Returns one live application catalog entry (
|
|
15950
|
+
description: "Returns one live application catalog entry (app id, slug, name, API URL, launch URL, status). Accepts the app id, slug, or name. Resolved against the live registry so newly-registered apps work without a client rebuild.",
|
|
15951
15951
|
requiredScopes: [],
|
|
15952
15952
|
destructive: false,
|
|
15953
15953
|
inputSchema: {
|
|
@@ -15955,7 +15955,7 @@ var TOOLS = [
|
|
|
15955
15955
|
properties: {
|
|
15956
15956
|
application: {
|
|
15957
15957
|
type: "string",
|
|
15958
|
-
description: "Application identifier:
|
|
15958
|
+
description: "Application identifier: app id, slug, or name from topolo_list_applications."
|
|
15959
15959
|
}
|
|
15960
15960
|
},
|
|
15961
15961
|
required: ["application"],
|
|
@@ -15969,10 +15969,10 @@ var TOOLS = [
|
|
|
15969
15969
|
const needle = application.trim().toLowerCase();
|
|
15970
15970
|
const catalog = await topolo.client.listServices();
|
|
15971
15971
|
const match = catalog.find(
|
|
15972
|
-
(e) => e.
|
|
15972
|
+
(e) => e.appId.toLowerCase() === needle || e.slug && e.slug.toLowerCase() === needle || e.name && e.name.toLowerCase() === needle
|
|
15973
15973
|
);
|
|
15974
15974
|
if (!match) {
|
|
15975
|
-
const known = catalog.map((e) => e.slug || e.
|
|
15975
|
+
const known = catalog.map((e) => e.slug || e.appId).sort().filter((value) => typeof value === "string" && value.length > 0);
|
|
15976
15976
|
throw new Error(
|
|
15977
15977
|
`Unknown application "${application}". ${formatKnownValues(known, "applications")}`
|
|
15978
15978
|
);
|
|
@@ -16065,7 +16065,7 @@ var TOOLS = [
|
|
|
16065
16065
|
{
|
|
16066
16066
|
name: "topolo_api_call",
|
|
16067
16067
|
title: "Call any Topolo platform service",
|
|
16068
|
-
description: "Low-level passthrough to any Topolo service. Use when no domain-specific tool exists for the operation you need. The request is signed with the current credential and scoped to the caller's organization \u2014 the target service will return 403 if your scopes do not permit the operation, even though this tool is advertised. Mutating calls (non-GET methods) require confirm:true. Call topolo_list_services first to discover callable
|
|
16068
|
+
description: "Low-level passthrough to any Topolo service. Use when no domain-specific tool exists for the operation you need. The request is signed with the current credential and scoped to the caller's organization \u2014 the target service will return 403 if your scopes do not permit the operation, even though this tool is advertised. Mutating calls (non-GET methods) require confirm:true. Call topolo_list_services first to discover callable app IDs; the SDK can also resolve live Auth-catalog app ids/slugs for newly registered API surfaces.",
|
|
16069
16069
|
requiredScopes: [],
|
|
16070
16070
|
destructive: true,
|
|
16071
16071
|
inputSchema: {
|
|
@@ -16073,7 +16073,7 @@ var TOOLS = [
|
|
|
16073
16073
|
properties: {
|
|
16074
16074
|
service: {
|
|
16075
16075
|
type: "string",
|
|
16076
|
-
description: "Target
|
|
16076
|
+
description: "Target app ID from the platform registry."
|
|
16077
16077
|
},
|
|
16078
16078
|
method: {
|
|
16079
16079
|
type: "string",
|
|
@@ -16178,7 +16178,7 @@ function actionsToToolDefs(actions) {
|
|
|
16178
16178
|
}));
|
|
16179
16179
|
}
|
|
16180
16180
|
function toolNameForAction(action) {
|
|
16181
|
-
const service = (action.
|
|
16181
|
+
const service = (action.appSlug || action.appId || "service").replace(/^topolo-/, "").toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
|
|
16182
16182
|
const name = action.name.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
|
|
16183
16183
|
return ["topolo", service, name].filter(Boolean).join("_").slice(0, 96);
|
|
16184
16184
|
}
|
|
@@ -16239,18 +16239,18 @@ function statusesAtOrWorse(threshold) {
|
|
|
16239
16239
|
if (threshold === "needs_review") return ["missing", "needs_review"];
|
|
16240
16240
|
return ["missing", "needs_review", "partial"];
|
|
16241
16241
|
}
|
|
16242
|
-
function
|
|
16243
|
-
for (const value of [entry.slug, entry.name, entry.
|
|
16242
|
+
function displayAppId(entry) {
|
|
16243
|
+
for (const value of [entry.slug, entry.name, entry.appId]) {
|
|
16244
16244
|
if (typeof value !== "string" || !value.trim()) continue;
|
|
16245
|
-
for (const candidate of
|
|
16246
|
-
if (Object.prototype.hasOwnProperty.call(
|
|
16245
|
+
for (const candidate of appIdCandidates(value)) {
|
|
16246
|
+
if (Object.prototype.hasOwnProperty.call(DEFAULT_APP_URLS, candidate)) {
|
|
16247
16247
|
return candidate;
|
|
16248
16248
|
}
|
|
16249
16249
|
}
|
|
16250
16250
|
}
|
|
16251
|
-
return
|
|
16251
|
+
return appIdCandidates(entry.slug || entry.appId)[0] || entry.appId;
|
|
16252
16252
|
}
|
|
16253
|
-
function
|
|
16253
|
+
function appIdCandidates(value) {
|
|
16254
16254
|
const normalized = value.trim().toLowerCase().replace(/\s+/g, "-");
|
|
16255
16255
|
const withoutTopolo = normalized.startsWith("topolo-") ? normalized.slice("topolo-".length) : normalized;
|
|
16256
16256
|
return [.../* @__PURE__ */ new Set([
|
|
@@ -16383,7 +16383,7 @@ function createTopoloMcpHttpHandler(options = {}) {
|
|
|
16383
16383
|
...options.agentName ? { agentName: options.agentName } : {}
|
|
16384
16384
|
},
|
|
16385
16385
|
serviceUrls: options.serviceUrls,
|
|
16386
|
-
|
|
16386
|
+
appIds: options.appIds,
|
|
16387
16387
|
...options.fetch ? { fetch: options.fetch } : {},
|
|
16388
16388
|
// Hosted writes still go through the SDK's confirm gate: the tool layer
|
|
16389
16389
|
// sets { confirm } per-call based on each tool's requiresConfirmation.
|