@topolo/mcp 0.4.4 → 0.4.6
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 +6 -5
- package/dist/index.js +82 -28
- package/package.json +1 -1
package/dist/dispatch.js
CHANGED
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
auditAllApplicationRequirements,
|
|
11
11
|
applicationRequirementScopes,
|
|
12
12
|
requirementsForApplication,
|
|
13
|
-
|
|
13
|
+
resolveCatalogServiceUrl
|
|
14
14
|
} from "@topolo/sdk";
|
|
15
15
|
|
|
16
16
|
// src/gating.ts
|
|
@@ -70,7 +70,7 @@ var TOOLS = [
|
|
|
70
70
|
{
|
|
71
71
|
name: "topolo_list_services",
|
|
72
72
|
title: "List every Topolo service the agent can reach",
|
|
73
|
-
description: "Returns the credential-scoped service registry: one entry per platform service the current credential can use in its organization, with granted permissions and
|
|
73
|
+
description: "Returns the credential-scoped service registry: one entry per platform service the current credential can use in its organization, with granted permissions, API URL, and launch URL. Use this to discover what `topolo_api_call` can address. This is not the global platform catalog.",
|
|
74
74
|
requiredScopes: [],
|
|
75
75
|
destructive: false,
|
|
76
76
|
inputSchema: {
|
|
@@ -86,8 +86,9 @@ var TOOLS = [
|
|
|
86
86
|
serviceId: entry.serviceId,
|
|
87
87
|
slug: entry.slug,
|
|
88
88
|
name: entry.name,
|
|
89
|
-
|
|
90
|
-
|
|
89
|
+
apiBaseUrl: entry.apiBaseUrl,
|
|
90
|
+
launchUrl: entry.launchUrl,
|
|
91
|
+
effectiveUrl: resolveCatalogServiceUrl(entry, { serviceKey: id }),
|
|
91
92
|
surfaceKind: entry.surfaceKind,
|
|
92
93
|
launchable: entry.launchable,
|
|
93
94
|
permissions: [...entry.permissions]
|
|
@@ -136,7 +137,7 @@ var TOOLS = [
|
|
|
136
137
|
{
|
|
137
138
|
name: "topolo_get_application",
|
|
138
139
|
title: "Describe one Topolo platform application",
|
|
139
|
-
description: "Returns one live application catalog entry (service id, slug, name,
|
|
140
|
+
description: "Returns one live application catalog entry (service id, slug, name, API URL, launch URL, status). Accepts the service id, slug, or name. Resolved against the live registry so newly-registered apps work without a client rebuild.",
|
|
140
141
|
requiredScopes: [],
|
|
141
142
|
destructive: false,
|
|
142
143
|
inputSchema: {
|
package/dist/index.js
CHANGED
|
@@ -83,7 +83,7 @@ var SERVICES = {
|
|
|
83
83
|
inventory: "https://inventory.topolo.app",
|
|
84
84
|
learn: "https://learn-api.topolo.app",
|
|
85
85
|
localize: "https://localize.topolo.app",
|
|
86
|
-
mail: "https://mail.topolo.app",
|
|
86
|
+
mail: "https://mail-api.topolo.app",
|
|
87
87
|
mdm: "https://mdm-api.topolo.app",
|
|
88
88
|
messages: "https://messages.topolo.app",
|
|
89
89
|
nexus: "https://nexus-api.topolo.app",
|
|
@@ -919,15 +919,17 @@ var APPLICATIONS = {
|
|
|
919
919
|
"mail.topolo.app"
|
|
920
920
|
],
|
|
921
921
|
"routes": [],
|
|
922
|
-
"serviceId":
|
|
922
|
+
"serviceId": null
|
|
923
923
|
},
|
|
924
924
|
{
|
|
925
925
|
"name": "topolo-mail-api",
|
|
926
926
|
"kind": "worker",
|
|
927
|
-
"apiUrl":
|
|
928
|
-
"domains": [
|
|
927
|
+
"apiUrl": "https://mail-api.topolo.app",
|
|
928
|
+
"domains": [
|
|
929
|
+
"mail-api.topolo.app"
|
|
930
|
+
],
|
|
929
931
|
"routes": [],
|
|
930
|
-
"serviceId":
|
|
932
|
+
"serviceId": "mail"
|
|
931
933
|
}
|
|
932
934
|
]
|
|
933
935
|
},
|
|
@@ -2040,15 +2042,63 @@ function statusRank(status) {
|
|
|
2040
2042
|
return 2;
|
|
2041
2043
|
}
|
|
2042
2044
|
var DEFAULT_SERVICE_URLS = SERVICES;
|
|
2045
|
+
function resolveCatalogServiceUrl(entry, options = {}) {
|
|
2046
|
+
const keys = catalogServiceKeyCandidates(entry, options.serviceKey);
|
|
2047
|
+
const override = resolveServiceUrlOverride(keys, options.overrides);
|
|
2048
|
+
if (override) return override;
|
|
2049
|
+
const apiBaseUrl = firstString(entry.apiBaseUrl, entry.api_base_url);
|
|
2050
|
+
if (apiBaseUrl) return apiBaseUrl;
|
|
2051
|
+
return null;
|
|
2052
|
+
}
|
|
2043
2053
|
function resolveServiceUrl(service, overrides) {
|
|
2044
|
-
const override =
|
|
2054
|
+
const override = resolveServiceUrlOverride([service], overrides);
|
|
2045
2055
|
if (override) return override;
|
|
2046
|
-
const envKey = `TOPOLO_SERVICE_URL_${service.replace(/\./g, "_").toUpperCase()}`;
|
|
2047
|
-
const envValue = typeof process !== "undefined" ? process.env?.[envKey] : void 0;
|
|
2048
|
-
if (envValue) return envValue;
|
|
2049
2056
|
return DEFAULT_SERVICE_URLS[service];
|
|
2050
2057
|
}
|
|
2058
|
+
function catalogServiceKeyCandidates(entry, preferred) {
|
|
2059
|
+
const values = [preferred, entry.slug, entry.name, entry.serviceId].filter(
|
|
2060
|
+
(value) => typeof value === "string" && value.trim().length > 0
|
|
2061
|
+
);
|
|
2062
|
+
const keys = /* @__PURE__ */ new Set();
|
|
2063
|
+
for (const value of values) {
|
|
2064
|
+
for (const candidate of serviceKeyCandidates(value)) keys.add(candidate);
|
|
2065
|
+
}
|
|
2066
|
+
return [...keys];
|
|
2067
|
+
}
|
|
2068
|
+
function serviceKeyCandidates(value) {
|
|
2069
|
+
const normalized = value.trim().toLowerCase().replace(/\s+/g, "-");
|
|
2070
|
+
const withoutTopolo = normalized.startsWith("topolo-") ? normalized.slice("topolo-".length) : normalized;
|
|
2071
|
+
return [.../* @__PURE__ */ new Set([
|
|
2072
|
+
normalized,
|
|
2073
|
+
normalized.replace(/-/g, "_"),
|
|
2074
|
+
withoutTopolo,
|
|
2075
|
+
withoutTopolo.replace(/-/g, "_")
|
|
2076
|
+
])].filter(Boolean);
|
|
2077
|
+
}
|
|
2078
|
+
function resolveServiceUrlOverride(keys, overrides) {
|
|
2079
|
+
for (const key of keys) {
|
|
2080
|
+
const direct = overrides?.[key];
|
|
2081
|
+
if (direct) return direct;
|
|
2082
|
+
const envStyleKey = key.replace(/\./g, "_");
|
|
2083
|
+
const envStyle = overrides?.[envStyleKey];
|
|
2084
|
+
if (envStyle) return envStyle;
|
|
2085
|
+
}
|
|
2086
|
+
for (const key of keys) {
|
|
2087
|
+
const envKey = `TOPOLO_SERVICE_URL_${key.replace(/\./g, "_").toUpperCase()}`;
|
|
2088
|
+
const envValue = typeof process !== "undefined" ? process.env?.[envKey] : void 0;
|
|
2089
|
+
if (envValue) return envValue;
|
|
2090
|
+
}
|
|
2091
|
+
return null;
|
|
2092
|
+
}
|
|
2093
|
+
function firstString(...values) {
|
|
2094
|
+
for (const value of values) {
|
|
2095
|
+
if (typeof value === "string" && value.trim()) return value.trim();
|
|
2096
|
+
}
|
|
2097
|
+
return null;
|
|
2098
|
+
}
|
|
2051
2099
|
var WRITE_METHODS = /* @__PURE__ */ new Set(["POST", "PUT", "PATCH", "DELETE"]);
|
|
2100
|
+
var TOPOLO_ACTION_ID_HEADER = "X-Topolo-Action-Id";
|
|
2101
|
+
var TOPOLO_ACTION_NAME_HEADER = "X-Topolo-Action-Name";
|
|
2052
2102
|
var POSITIVE_CACHE_TTL_MS = 5 * 60 * 1e3;
|
|
2053
2103
|
var NEGATIVE_CACHE_TTL_MS = 60 * 1e3;
|
|
2054
2104
|
var CATALOG_CACHE_TTL_MS = 60 * 1e3;
|
|
@@ -2216,8 +2266,12 @@ var TopoloClient = class _TopoloClient {
|
|
|
2216
2266
|
async resolveLiveCallableService(serviceKey) {
|
|
2217
2267
|
const catalog = await this.listServices();
|
|
2218
2268
|
const match = catalog.find((entry) => catalogEntryMatches(entry, serviceKey));
|
|
2219
|
-
if (!match
|
|
2220
|
-
|
|
2269
|
+
if (!match) return null;
|
|
2270
|
+
const baseUrl = resolveCatalogServiceUrl(match, {
|
|
2271
|
+
serviceKey,
|
|
2272
|
+
overrides: this.serviceUrls
|
|
2273
|
+
});
|
|
2274
|
+
return baseUrl ? { serviceKey, baseUrl } : null;
|
|
2221
2275
|
}
|
|
2222
2276
|
/**
|
|
2223
2277
|
* Resolve a service-slug → opaque service-id via caller config or TopoloAuth.
|
|
@@ -2310,7 +2364,8 @@ var TopoloClient = class _TopoloClient {
|
|
|
2310
2364
|
slug: typeof s.app_slug === "string" ? s.app_slug : null,
|
|
2311
2365
|
name: typeof s.name === "string" ? s.name : null,
|
|
2312
2366
|
description: typeof s.description === "string" ? s.description : null,
|
|
2313
|
-
|
|
2367
|
+
apiBaseUrl: typeof s.api_base_url === "string" ? s.api_base_url : typeof s.apiBaseUrl === "string" ? s.apiBaseUrl : null,
|
|
2368
|
+
launchUrl: typeof s.launch_url === "string" ? s.launch_url : typeof s.launchUrl === "string" ? s.launchUrl : null,
|
|
2314
2369
|
status: typeof s.status === "string" ? s.status : null,
|
|
2315
2370
|
surfaceKind: typeof s.surface_kind === "string" ? s.surface_kind : null,
|
|
2316
2371
|
launchable: s.launchable === true,
|
|
@@ -2377,6 +2432,10 @@ var TopoloClient = class _TopoloClient {
|
|
|
2377
2432
|
path: mapped.path,
|
|
2378
2433
|
...mapped.query ? { query: mapped.query } : {},
|
|
2379
2434
|
...mapped.body !== void 0 ? { body: mapped.body } : {},
|
|
2435
|
+
headers: {
|
|
2436
|
+
[TOPOLO_ACTION_ID_HEADER]: entry.actionId,
|
|
2437
|
+
[TOPOLO_ACTION_NAME_HEADER]: entry.name
|
|
2438
|
+
},
|
|
2380
2439
|
confirm: options.confirm === true
|
|
2381
2440
|
});
|
|
2382
2441
|
}
|
|
@@ -2391,7 +2450,8 @@ var TopoloClient = class _TopoloClient {
|
|
|
2391
2450
|
slug: app.id,
|
|
2392
2451
|
name: app.name ?? app.id,
|
|
2393
2452
|
description: null,
|
|
2394
|
-
|
|
2453
|
+
apiBaseUrl: null,
|
|
2454
|
+
launchUrl: app.productionUrl ?? null,
|
|
2395
2455
|
status: "bundled",
|
|
2396
2456
|
surfaceKind: "application",
|
|
2397
2457
|
launchable: Boolean(app.productionUrl),
|
|
@@ -2435,7 +2495,7 @@ var TopoloClient = class _TopoloClient {
|
|
|
2435
2495
|
}
|
|
2436
2496
|
};
|
|
2437
2497
|
function resolveConfiguredServiceId(slug, serviceIds) {
|
|
2438
|
-
for (const serviceKey of
|
|
2498
|
+
for (const serviceKey of serviceKeyCandidates2(slug)) {
|
|
2439
2499
|
const configured = serviceIds?.[serviceKey];
|
|
2440
2500
|
if (typeof configured === "string" && configured.trim()) return configured.trim();
|
|
2441
2501
|
const envKey = `TOPOLO_SERVICE_ID_${serviceKey.replace(/\./g, "_").toUpperCase()}`;
|
|
@@ -2445,7 +2505,7 @@ function resolveConfiguredServiceId(slug, serviceIds) {
|
|
|
2445
2505
|
return null;
|
|
2446
2506
|
}
|
|
2447
2507
|
function resolveConfiguredServiceUrl(slug, serviceUrls) {
|
|
2448
|
-
for (const serviceKey of
|
|
2508
|
+
for (const serviceKey of serviceKeyCandidates2(slug)) {
|
|
2449
2509
|
const configured = serviceUrls?.[serviceKey];
|
|
2450
2510
|
if (typeof configured === "string" && configured.trim()) return configured.trim();
|
|
2451
2511
|
const envKey = `TOPOLO_SERVICE_URL_${serviceKey.replace(/\./g, "_").toUpperCase()}`;
|
|
@@ -2454,7 +2514,7 @@ function resolveConfiguredServiceUrl(slug, serviceUrls) {
|
|
|
2454
2514
|
}
|
|
2455
2515
|
return null;
|
|
2456
2516
|
}
|
|
2457
|
-
function
|
|
2517
|
+
function serviceKeyCandidates2(slug) {
|
|
2458
2518
|
const normalized = normalizeLookupKey(slug);
|
|
2459
2519
|
const withoutTopolo = normalized.startsWith("topolo-") ? normalized.slice("topolo-".length) : normalized;
|
|
2460
2520
|
return [.../* @__PURE__ */ new Set([
|
|
@@ -2476,19 +2536,12 @@ function catalogEntryLookupKeys(entry) {
|
|
|
2476
2536
|
for (const value of values) {
|
|
2477
2537
|
const normalized = normalizeLookupKey(value);
|
|
2478
2538
|
if (!normalized) continue;
|
|
2479
|
-
for (const candidate of
|
|
2539
|
+
for (const candidate of serviceKeyCandidates2(normalized)) {
|
|
2480
2540
|
keys.add(candidate);
|
|
2481
2541
|
}
|
|
2482
2542
|
}
|
|
2483
2543
|
return [...keys];
|
|
2484
2544
|
}
|
|
2485
|
-
function isCallableCatalogEntry(entry) {
|
|
2486
|
-
const kind = normalizeLookupKey(entry.surfaceKind || "");
|
|
2487
|
-
if (kind === "api" || kind === "technical_service" || kind === "service") return true;
|
|
2488
|
-
return Boolean(
|
|
2489
|
-
entry.baseUrl && catalogEntryLookupKeys(entry).some((key) => Object.prototype.hasOwnProperty.call(DEFAULT_SERVICE_URLS, key))
|
|
2490
|
-
);
|
|
2491
|
-
}
|
|
2492
2545
|
function normalizeActionCatalogEntry(item) {
|
|
2493
2546
|
if (!item || typeof item !== "object" || Array.isArray(item)) return null;
|
|
2494
2547
|
const a = item;
|
|
@@ -2764,7 +2817,7 @@ var TOOLS = [
|
|
|
2764
2817
|
{
|
|
2765
2818
|
name: "topolo_list_services",
|
|
2766
2819
|
title: "List every Topolo service the agent can reach",
|
|
2767
|
-
description: "Returns the credential-scoped service registry: one entry per platform service the current credential can use in its organization, with granted permissions and
|
|
2820
|
+
description: "Returns the credential-scoped service registry: one entry per platform service the current credential can use in its organization, with granted permissions, API URL, and launch URL. Use this to discover what `topolo_api_call` can address. This is not the global platform catalog.",
|
|
2768
2821
|
requiredScopes: [],
|
|
2769
2822
|
destructive: false,
|
|
2770
2823
|
inputSchema: {
|
|
@@ -2780,8 +2833,9 @@ var TOOLS = [
|
|
|
2780
2833
|
serviceId: entry.serviceId,
|
|
2781
2834
|
slug: entry.slug,
|
|
2782
2835
|
name: entry.name,
|
|
2783
|
-
|
|
2784
|
-
|
|
2836
|
+
apiBaseUrl: entry.apiBaseUrl,
|
|
2837
|
+
launchUrl: entry.launchUrl,
|
|
2838
|
+
effectiveUrl: resolveCatalogServiceUrl(entry, { serviceKey: id }),
|
|
2785
2839
|
surfaceKind: entry.surfaceKind,
|
|
2786
2840
|
launchable: entry.launchable,
|
|
2787
2841
|
permissions: [...entry.permissions]
|
|
@@ -2830,7 +2884,7 @@ var TOOLS = [
|
|
|
2830
2884
|
{
|
|
2831
2885
|
name: "topolo_get_application",
|
|
2832
2886
|
title: "Describe one Topolo platform application",
|
|
2833
|
-
description: "Returns one live application catalog entry (service id, slug, name,
|
|
2887
|
+
description: "Returns one live application catalog entry (service id, slug, name, API URL, launch URL, status). Accepts the service id, slug, or name. Resolved against the live registry so newly-registered apps work without a client rebuild.",
|
|
2834
2888
|
requiredScopes: [],
|
|
2835
2889
|
destructive: false,
|
|
2836
2890
|
inputSchema: {
|
package/package.json
CHANGED