@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 CHANGED
@@ -10,7 +10,7 @@ import {
10
10
  auditAllApplicationRequirements,
11
11
  applicationRequirementScopes,
12
12
  requirementsForApplication,
13
- resolveServiceUrl
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 base URL. Use this to discover what `topolo_api_call` can address. This is not the global platform catalog.",
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
- baseUrl: entry.baseUrl,
90
- effectiveUrl: entry.baseUrl || resolveServiceUrl(id),
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, base URL, status). Accepts the service id, slug, or name. Resolved against the live registry so newly-registered apps work without a client rebuild.",
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": "mail"
922
+ "serviceId": null
923
923
  },
924
924
  {
925
925
  "name": "topolo-mail-api",
926
926
  "kind": "worker",
927
- "apiUrl": null,
928
- "domains": [],
927
+ "apiUrl": "https://mail-api.topolo.app",
928
+ "domains": [
929
+ "mail-api.topolo.app"
930
+ ],
929
931
  "routes": [],
930
- "serviceId": null
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 = overrides?.[service];
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?.baseUrl || !isCallableCatalogEntry(match)) return null;
2220
- return { serviceKey, baseUrl: match.baseUrl };
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
- baseUrl: typeof s.base_url === "string" ? s.base_url : null,
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
- baseUrl: app.productionUrl ?? null,
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 serviceKeyCandidates(slug)) {
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 serviceKeyCandidates(slug)) {
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 serviceKeyCandidates(slug) {
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 serviceKeyCandidates(normalized)) {
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 base URL. Use this to discover what `topolo_api_call` can address. This is not the global platform catalog.",
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
- baseUrl: entry.baseUrl,
2784
- effectiveUrl: entry.baseUrl || resolveServiceUrl(id),
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, base URL, status). Accepts the service id, slug, or name. Resolved against the live registry so newly-registered apps work without a client rebuild.",
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@topolo/mcp",
3
- "version": "0.4.4",
3
+ "version": "0.4.6",
4
4
  "description": "Model Context Protocol server for the Topolo platform. Exposes scope-gated tools that third-party agents (Claude, Codex, etc.) can call natively.",
5
5
  "type": "module",
6
6
  "bin": {