@topolo/mcp 0.4.0 → 0.4.1

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 CHANGED
@@ -112,7 +112,10 @@ clients surface that as a failed server launch.
112
112
  `topolo_api_call` is the escape hatch for endpoints without typed MCP tools
113
113
  yet. GET requests work without confirmation; mutating HTTP methods must pass
114
114
  `confirm: true` or the SDK rejects the call. Backing services still enforce
115
- permissions for every request.
115
+ permissions for every request. The tool schema intentionally does not embed a
116
+ large service enum; agents should call `topolo_list_services` first, then pass a
117
+ service ID/slug. The SDK can resolve live Auth-catalog API/technical service
118
+ surfaces for newly registered services before the next MCP package release.
116
119
 
117
120
  ## Safety rails
118
121
 
@@ -159,11 +162,12 @@ waiting for JSON-RPC on stdin. To drive it manually, use the MCP Inspector:
159
162
  npx @modelcontextprotocol/inspector node dist/index.js
160
163
  ```
161
164
 
162
- ## Release flow
165
+ ## Release Flow
163
166
 
164
- Pushing a `v<x.y.z>` tag to `main` triggers GitHub Actions to typecheck, test,
165
- build, verify the tag matches `package.json`, and publish to npm via the
166
- `NPM_TOKEN` secret. No developer-machine credentials involved.
167
+ Preferred flow: push a `v<x.y.z>` tag to `main`; GitHub Actions typechecks,
168
+ tests, builds, verifies the tag matches `package.json`, and publishes to npm via
169
+ the `NPM_TOKEN` secret. Operators may publish directly with an npm token only
170
+ after running the same package checks and `npm pack --dry-run`.
167
171
 
168
172
  ## Phase 2 (planned)
169
173
 
package/dist/dispatch.js CHANGED
@@ -52,7 +52,6 @@ function splitService(servicePart) {
52
52
 
53
53
  // src/tools.ts
54
54
  var APPLICATION_IDS = Object.keys(APPLICATIONS).sort();
55
- var SERVICE_IDS = Object.keys(DEFAULT_SERVICE_URLS).sort();
56
55
  var HTTP_METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE"];
57
56
  var TOOLS = [
58
57
  {
@@ -131,9 +130,9 @@ var TOOLS = [
131
130
  (e) => e.serviceId.toLowerCase() === needle || e.slug && e.slug.toLowerCase() === needle || e.name && e.name.toLowerCase() === needle
132
131
  );
133
132
  if (!match) {
134
- const known = catalog.map((e) => e.slug || e.serviceId).sort().join(", ");
133
+ const known = catalog.map((e) => e.slug || e.serviceId).sort().filter((value) => typeof value === "string" && value.length > 0);
135
134
  throw new Error(
136
- `Unknown application "${application}". Known: ${known}`
135
+ `Unknown application "${application}". ${formatKnownValues(known, "applications")}`
137
136
  );
138
137
  }
139
138
  return { application: match };
@@ -150,7 +149,6 @@ var TOOLS = [
150
149
  properties: {
151
150
  application: {
152
151
  type: "string",
153
- enum: APPLICATION_IDS,
154
152
  description: "Optional application ID from topolo_list_applications."
155
153
  }
156
154
  },
@@ -168,7 +166,7 @@ var TOOLS = [
168
166
  }
169
167
  if (typeof application !== "string" || !APPLICATION_IDS.includes(application)) {
170
168
  throw new Error(
171
- `Unknown application "${String(application)}". Known: ${APPLICATION_IDS.join(", ")}`
169
+ `Unknown application "${String(application)}". ${formatKnownValues(APPLICATION_IDS, "applications")}`
172
170
  );
173
171
  }
174
172
  const app = APPLICATIONS[application];
@@ -191,7 +189,6 @@ var TOOLS = [
191
189
  properties: {
192
190
  application: {
193
191
  type: "string",
194
- enum: APPLICATION_IDS,
195
192
  description: "Optional application ID from topolo_list_applications."
196
193
  },
197
194
  failOn: {
@@ -216,7 +213,7 @@ var TOOLS = [
216
213
  }
217
214
  if (typeof application !== "string" || !APPLICATION_IDS.includes(application)) {
218
215
  throw new Error(
219
- `Unknown application "${String(application)}". Known: ${APPLICATION_IDS.join(", ")}`
216
+ `Unknown application "${String(application)}". ${formatKnownValues(APPLICATION_IDS, "applications")}`
220
217
  );
221
218
  }
222
219
  report = auditAllApplicationRequirements([application]);
@@ -249,7 +246,7 @@ var TOOLS = [
249
246
  {
250
247
  name: "topolo_api_call",
251
248
  title: "Call any Topolo platform service",
252
- 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. Known services: ${SERVICE_IDS.join(", ")}.`,
249
+ 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 service IDs; the SDK can also resolve live Auth-catalog service ids/slugs for newly registered API surfaces.",
253
250
  requiredScopes: [],
254
251
  destructive: true,
255
252
  inputSchema: {
@@ -257,7 +254,6 @@ var TOOLS = [
257
254
  properties: {
258
255
  service: {
259
256
  type: "string",
260
- enum: SERVICE_IDS,
261
257
  description: "Target service ID from the platform registry."
262
258
  },
263
259
  method: {
@@ -290,8 +286,8 @@ var TOOLS = [
290
286
  handler: async (topolo, args) => {
291
287
  const service = args["service"];
292
288
  const path = args["path"];
293
- if (typeof service !== "string" || !SERVICE_IDS.includes(service)) {
294
- throw new Error(`Unknown service "${String(service)}". Known: ${SERVICE_IDS.join(", ")}`);
289
+ if (typeof service !== "string" || !service.trim()) {
290
+ throw new Error("service is required. Call topolo_list_services first to discover callable services.");
295
291
  }
296
292
  if (typeof path !== "string" || !path) {
297
293
  throw new Error("path is required");
@@ -306,7 +302,7 @@ var TOOLS = [
306
302
  Object.entries(query).map(([k, v]) => [k, String(v)])
307
303
  ) : void 0;
308
304
  return topolo.client.request({
309
- service,
305
+ service: service.trim(),
310
306
  method,
311
307
  path,
312
308
  body: args["body"],
@@ -379,6 +375,12 @@ function statusesAtOrWorse(threshold) {
379
375
  if (threshold === "needs_review") return ["missing", "needs_review"];
380
376
  return ["missing", "needs_review", "partial"];
381
377
  }
378
+ function formatKnownValues(values, label) {
379
+ const sorted = [...values].sort();
380
+ const preview = sorted.slice(0, 25).join(", ");
381
+ const suffix = sorted.length > 25 ? `, ... +${sorted.length - 25} more` : "";
382
+ return `Run discovery for the full ${label} list. Known snapshot sample: ${preview}${suffix}`;
383
+ }
382
384
 
383
385
  // src/dispatch.ts
384
386
  function listAvailableTopoloTools(scopes, tools = TOOLS) {