@topolo/mcp 0.10.0 → 0.10.2

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
@@ -217,6 +217,9 @@ sent.
217
217
  catalog. They do not expose the global generated platform catalog.
218
218
  - **Credential-scoped action discovery.** `topolo_search_actions` reads only one
219
219
  app partition and returns at most 100 permission-filtered actions per page.
220
+ Search, capability discovery, validation, planning, and application audit
221
+ return compact agent guidance by default; pass `detail: true` only when the
222
+ full contracts or findings are needed.
220
223
  - **Audit headers.** Every request sends `X-Topolo-Client: topolo-mcp/<ver>`,
221
224
  `X-Topolo-Agent: <label>`, `X-Topolo-Request-Id: <uuid>`.
222
225
  - **Write-action confirmation.** The SDK refuses mutating HTTP methods unless
package/dist/dispatch.js CHANGED
@@ -7,6 +7,10 @@ import {
7
7
  APPLICATION_REQUIREMENTS_VERSION,
8
8
  auditApplicationEntries,
9
9
  applicationRequirementScopes,
10
+ compactActionCatalogEntry,
11
+ compactActionPlan,
12
+ compactActionValidation,
13
+ compactApplicationAudit,
10
14
  friendlyAppId,
11
15
  listApplicationDirectory,
12
16
  requirementsForApplication,
@@ -78,6 +82,17 @@ function optionalResourceContext(args) {
78
82
  }
79
83
  return { resourceType, resourceId };
80
84
  }
85
+ function summarizeActionCapabilities(service, actions) {
86
+ return {
87
+ service,
88
+ total: actions.length,
89
+ readOnly: actions.filter((action) => action.readOnly).length,
90
+ mutating: actions.filter((action) => !action.readOnly).length,
91
+ destructive: actions.filter((action) => action.destructive).length,
92
+ confirmationRequired: actions.filter((action) => action.requiresConfirmation).length,
93
+ resourceTypes: [...new Set(actions.map((action) => action.agentContract?.resource?.kind).filter(Boolean))].sort()
94
+ };
95
+ }
81
96
  function coerceObjectParam(value, name) {
82
97
  let candidate = value;
83
98
  if (typeof candidate === "string" && candidate.trim().startsWith("{")) {
@@ -117,7 +132,8 @@ var TOOLS = [
117
132
  properties: {
118
133
  query: { type: "string" },
119
134
  cursor: { type: "string" },
120
- limit: { type: "integer", minimum: 1, maximum: 100, default: 25 }
135
+ limit: { type: "integer", minimum: 1, maximum: 100, default: 25 },
136
+ detail: { type: "boolean", description: "Return full schemas and agent contracts. Defaults to compact action guidance." }
121
137
  },
122
138
  additionalProperties: false
123
139
  },
@@ -171,12 +187,13 @@ var TOOLS = [
171
187
  handler: async (topolo, args) => {
172
188
  const service = typeof args["service"] === "string" ? args["service"].trim() : "";
173
189
  if (!service) throw new TopoloMcpPublicError("service is required for bounded action discovery.");
174
- return topolo.client.searchActions({
190
+ const result = await topolo.client.searchActions({
175
191
  service,
176
192
  query: typeof args["query"] === "string" ? args["query"] : void 0,
177
193
  cursor: typeof args["cursor"] === "string" ? args["cursor"] : void 0,
178
194
  limit: typeof args["limit"] === "number" ? args["limit"] : void 0
179
195
  });
196
+ return args["detail"] === true ? result : { actions: result.actions.map(compactActionCatalogEntry), page: result.page };
180
197
  }
181
198
  },
182
199
  {
@@ -342,7 +359,8 @@ var TOOLS = [
342
359
  type: "object",
343
360
  properties: {
344
361
  actionId: { type: "string", minLength: 1 },
345
- input: { type: "object", additionalProperties: true }
362
+ input: { type: "object", additionalProperties: true },
363
+ detail: { type: "boolean", description: "Include the full action contract. Defaults to a compact validation result." }
346
364
  },
347
365
  required: ["actionId"],
348
366
  additionalProperties: false
@@ -351,7 +369,8 @@ var TOOLS = [
351
369
  const actionId = typeof args["actionId"] === "string" ? args["actionId"].trim() : "";
352
370
  if (!actionId) throw new TopoloMcpPublicError("actionId is required.");
353
371
  const input = coerceObjectParam(args["input"], "input");
354
- return topolo.client.validateActionInput(actionId, input);
372
+ const result = await topolo.client.validateActionInput(actionId, input);
373
+ return args["detail"] === true ? result : compactActionValidation(result.action.actionId, result.validation);
355
374
  }
356
375
  },
357
376
  {
@@ -367,7 +386,8 @@ var TOOLS = [
367
386
  input: { type: "object", additionalProperties: true },
368
387
  resourceType: { type: "string", description: "Optional resource-scoping alias published in the app resource catalog (e.g. workspace, brand, merchant)." },
369
388
  resourceId: { type: "string", description: "Resource id. Required when resourceType is provided." },
370
- confirm: { type: "boolean", description: "Include confirmation in the plan without executing the action." }
389
+ confirm: { type: "boolean", description: "Include confirmation in the plan without executing the action." },
390
+ detail: { type: "boolean", description: "Include the full action contract. Defaults to the executable request and verification plan." }
371
391
  },
372
392
  required: ["actionId"],
373
393
  additionalProperties: false
@@ -377,7 +397,7 @@ var TOOLS = [
377
397
  if (!actionId) throw new TopoloMcpPublicError("actionId is required.");
378
398
  const input = coerceObjectParam(args["input"], "input");
379
399
  const resource = optionalResourceContext(args);
380
- return topolo.client.planAction(
400
+ const plan = await topolo.client.planAction(
381
401
  actionId,
382
402
  input,
383
403
  {
@@ -385,6 +405,7 @@ var TOOLS = [
385
405
  ...resource ? { resource } : {}
386
406
  }
387
407
  );
408
+ return args["detail"] === true ? plan : compactActionPlan(plan);
388
409
  }
389
410
  },
390
411
  {
@@ -413,19 +434,42 @@ var TOOLS = [
413
434
  {
414
435
  name: "topolo_discover_capabilities",
415
436
  title: "Discover one Topolo application capability contract",
416
- description: "Lists every action published by one application \u2014 its full capability contract, straight from the registry-canonical catalog. Use the actionService value returned by topolo_search_applications as service. Follow page.nextCursor via topolo_search_actions when the contract exceeds one page.",
437
+ description: "Lists every action published by one application \u2014 its full capability contract, straight from the registry-canonical catalog. Use the actionService value returned by topolo_search_applications as service.",
417
438
  requiredScopes: [],
418
439
  destructive: false,
419
440
  inputSchema: {
420
441
  type: "object",
421
- properties: { service: { type: "string", minLength: 1 } },
442
+ properties: {
443
+ service: { type: "string", minLength: 1 },
444
+ summary: { type: "boolean", description: "Return compact counts without action rows." },
445
+ detail: { type: "boolean", description: "Return full schemas and agent contracts. Defaults to compact capability guidance." }
446
+ },
422
447
  required: ["service"],
423
448
  additionalProperties: false
424
449
  },
425
450
  handler: async (topolo, args) => {
426
451
  const service = typeof args["service"] === "string" ? args["service"].trim() : "";
427
452
  if (!service) throw new TopoloMcpPublicError("service is required.");
428
- return topolo.client.searchActions({ service, limit: 100 });
453
+ if (args["summary"] === true && args["detail"] === true) {
454
+ throw new TopoloMcpPublicError("summary cannot be combined with detail.");
455
+ }
456
+ const actions = [];
457
+ const seenCursors = /* @__PURE__ */ new Set();
458
+ let cursor;
459
+ for (; ; ) {
460
+ const page = await topolo.client.searchActions({ service, limit: 100, ...cursor ? { cursor } : {} });
461
+ actions.push(...page.actions);
462
+ if (!page.page.hasMore) break;
463
+ const nextCursor = page.page.nextCursor?.trim();
464
+ if (!nextCursor || seenCursors.has(nextCursor)) {
465
+ throw new TopoloMcpPublicError("Capability discovery returned an invalid continuation cursor.");
466
+ }
467
+ seenCursors.add(nextCursor);
468
+ cursor = nextCursor;
469
+ }
470
+ if (args["summary"] === true) return summarizeActionCapabilities(service, actions);
471
+ const result = { actions, page: { nextCursor: null, hasMore: false } };
472
+ return args["detail"] === true ? result : { actions: actions.map(compactActionCatalogEntry), page: result.page };
429
473
  }
430
474
  },
431
475
  {
@@ -593,6 +637,10 @@ var TOOLS = [
593
637
  type: "string",
594
638
  enum: ["missing", "needs_review", "partial"],
595
639
  description: "Optional conformance gate. Returns conformanceGate.passed=false when findings at this severity or worse exist."
640
+ },
641
+ detail: {
642
+ type: "boolean",
643
+ description: "Include every finding and migration item. Defaults to per-app scores and a queue count."
596
644
  }
597
645
  },
598
646
  additionalProperties: false
@@ -608,11 +656,13 @@ var TOOLS = [
608
656
  if (application === void 0) {
609
657
  const directory = await listApplicationDirectory(topolo.client);
610
658
  report = auditApplicationEntries(directory.applications.map((app) => app.application));
611
- return gate ? { ...report, conformanceGate: evaluateApplicationAuditGate(report, gate) } : report;
659
+ const output2 = args["detail"] === true ? report : compactApplicationAudit(report);
660
+ return gate ? { ...output2, conformanceGate: evaluateApplicationAuditGate(report, gate) } : output2;
612
661
  }
613
662
  const resolved = await resolveDirectoryApplication(topolo, application);
614
663
  report = auditApplicationEntries([resolved.application]);
615
- return gate ? { ...report, conformanceGate: evaluateApplicationAuditGate(report, gate) } : report;
664
+ const output = args["detail"] === true ? report : compactApplicationAudit(report);
665
+ return gate ? { ...output, conformanceGate: evaluateApplicationAuditGate(report, gate) } : output;
616
666
  }
617
667
  },
618
668
  {
package/dist/http.js CHANGED
@@ -3098,9 +3098,9 @@ var require_data = __commonJS({
3098
3098
  }
3099
3099
  });
3100
3100
 
3101
- // ../../node_modules/.pnpm/fast-uri@3.1.4/node_modules/fast-uri/lib/utils.js
3101
+ // ../../node_modules/.pnpm/fast-uri@3.1.5/node_modules/fast-uri/lib/utils.js
3102
3102
  var require_utils = __commonJS({
3103
- "../../node_modules/.pnpm/fast-uri@3.1.4/node_modules/fast-uri/lib/utils.js"(exports, module) {
3103
+ "../../node_modules/.pnpm/fast-uri@3.1.5/node_modules/fast-uri/lib/utils.js"(exports, module) {
3104
3104
  "use strict";
3105
3105
  var isUUID = RegExp.prototype.test.bind(/^[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}$/iu);
3106
3106
  var isIPv4 = RegExp.prototype.test.bind(/^(?:(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)$/u);
@@ -3411,9 +3411,9 @@ var require_utils = __commonJS({
3411
3411
  }
3412
3412
  });
3413
3413
 
3414
- // ../../node_modules/.pnpm/fast-uri@3.1.4/node_modules/fast-uri/lib/schemes.js
3414
+ // ../../node_modules/.pnpm/fast-uri@3.1.5/node_modules/fast-uri/lib/schemes.js
3415
3415
  var require_schemes = __commonJS({
3416
- "../../node_modules/.pnpm/fast-uri@3.1.4/node_modules/fast-uri/lib/schemes.js"(exports, module) {
3416
+ "../../node_modules/.pnpm/fast-uri@3.1.5/node_modules/fast-uri/lib/schemes.js"(exports, module) {
3417
3417
  "use strict";
3418
3418
  var { isUUID } = require_utils();
3419
3419
  var URN_REG = /([\da-z][\d\-a-z]{0,31}):((?:[\w!$'()*+,\-.:;=@]|%[\da-f]{2})+)/iu;
@@ -3621,9 +3621,9 @@ var require_schemes = __commonJS({
3621
3621
  }
3622
3622
  });
3623
3623
 
3624
- // ../../node_modules/.pnpm/fast-uri@3.1.4/node_modules/fast-uri/index.js
3624
+ // ../../node_modules/.pnpm/fast-uri@3.1.5/node_modules/fast-uri/index.js
3625
3625
  var require_fast_uri = __commonJS({
3626
- "../../node_modules/.pnpm/fast-uri@3.1.4/node_modules/fast-uri/index.js"(exports, module) {
3626
+ "../../node_modules/.pnpm/fast-uri@3.1.5/node_modules/fast-uri/index.js"(exports, module) {
3627
3627
  "use strict";
3628
3628
  var { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizePercentEncoding, normalizePathEncoding, escapePreservingEscapes, reescapeHostDelimiters, isIPv4, nonSimpleDomain } = require_utils();
3629
3629
  var { SCHEMES, getSchemeHandler } = require_schemes();
@@ -3639,7 +3639,12 @@ var require_fast_uri = __commonJS({
3639
3639
  }
3640
3640
  function resolve(baseURI, relativeURI, options) {
3641
3641
  const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
3642
- const resolved = resolveComponent(parse3(baseURI, schemelessOptions), parse3(relativeURI, schemelessOptions), schemelessOptions, true);
3642
+ const { parsed: baseParsed, malformedAuthorityOrPort: baseMalformed } = parseWithStatus(baseURI, schemelessOptions);
3643
+ const { parsed: relativeParsed, malformedAuthorityOrPort: relativeMalformed } = parseWithStatus(relativeURI, schemelessOptions);
3644
+ if (baseMalformed || relativeMalformed) {
3645
+ throw new Error(baseParsed.error || relativeParsed.error || "URI is malformed.");
3646
+ }
3647
+ const resolved = resolveComponent(baseParsed, relativeParsed, schemelessOptions, true);
3643
3648
  schemelessOptions.skipEscape = true;
3644
3649
  return serialize(resolved, schemelessOptions);
3645
3650
  }
@@ -3765,6 +3770,7 @@ var require_fast_uri = __commonJS({
3765
3770
  }
3766
3771
  var URI_PARSE = /^(?:([^#/:?]+):)?(?:\/\/((?:([^#/?@]*)@)?(\[[^#/?\]]+\]|[^#/:?]*)(?::(\d*))?))?([^#?]*)(?:\?([^#]*))?(?:#((?:.|[\n\r])*))?/u;
3767
3772
  var AUTHORITY_PREFIX = /^(?:[^#/:?]+:)?\/\/([^/?#]*)/;
3773
+ var AUTHORITY_INTRODUCER_REGION = /^(?:[^#/:?]+:)?([/\\\t\n\r]*)/;
3768
3774
  function getParseError(parsed, matches) {
3769
3775
  if (matches[2] !== void 0 && parsed.path && parsed.path[0] !== "/") {
3770
3776
  return 'URI path must start with "/" when authority is present.';
@@ -3799,6 +3805,20 @@ var require_fast_uri = __commonJS({
3799
3805
  parsed.error = "URI authority must not contain a literal backslash.";
3800
3806
  malformedAuthorityOrPort = true;
3801
3807
  }
3808
+ const introducerMatch = uri.match(AUTHORITY_INTRODUCER_REGION);
3809
+ if (introducerMatch !== null) {
3810
+ const region = introducerMatch[1];
3811
+ const normalizedRegion = region.replace(/[\t\n\r]/g, "");
3812
+ if (normalizedRegion.length >= 2) {
3813
+ if (normalizedRegion.slice(0, 2) !== "//") {
3814
+ parsed.error = parsed.error || "URI authority must not contain a literal backslash.";
3815
+ malformedAuthorityOrPort = true;
3816
+ } else if (region.length !== normalizedRegion.length) {
3817
+ parsed.error = parsed.error || "URI authority introducer must not contain whitespace.";
3818
+ malformedAuthorityOrPort = true;
3819
+ }
3820
+ }
3821
+ }
3802
3822
  const matches = uri.match(URI_PARSE);
3803
3823
  if (matches) {
3804
3824
  parsed.scheme = matches[1];
@@ -15832,6 +15852,10 @@ import {
15832
15852
  APPLICATION_REQUIREMENTS_VERSION,
15833
15853
  auditApplicationEntries,
15834
15854
  applicationRequirementScopes,
15855
+ compactActionCatalogEntry,
15856
+ compactActionPlan,
15857
+ compactActionValidation,
15858
+ compactApplicationAudit,
15835
15859
  friendlyAppId,
15836
15860
  listApplicationDirectory,
15837
15861
  requirementsForApplication,
@@ -15892,6 +15916,17 @@ function optionalResourceContext(args) {
15892
15916
  }
15893
15917
  return { resourceType, resourceId };
15894
15918
  }
15919
+ function summarizeActionCapabilities(service, actions) {
15920
+ return {
15921
+ service,
15922
+ total: actions.length,
15923
+ readOnly: actions.filter((action) => action.readOnly).length,
15924
+ mutating: actions.filter((action) => !action.readOnly).length,
15925
+ destructive: actions.filter((action) => action.destructive).length,
15926
+ confirmationRequired: actions.filter((action) => action.requiresConfirmation).length,
15927
+ resourceTypes: [...new Set(actions.map((action) => action.agentContract?.resource?.kind).filter(Boolean))].sort()
15928
+ };
15929
+ }
15895
15930
  function coerceObjectParam(value, name) {
15896
15931
  let candidate = value;
15897
15932
  if (typeof candidate === "string" && candidate.trim().startsWith("{")) {
@@ -15931,7 +15966,8 @@ var TOOLS = [
15931
15966
  properties: {
15932
15967
  query: { type: "string" },
15933
15968
  cursor: { type: "string" },
15934
- limit: { type: "integer", minimum: 1, maximum: 100, default: 25 }
15969
+ limit: { type: "integer", minimum: 1, maximum: 100, default: 25 },
15970
+ detail: { type: "boolean", description: "Return full schemas and agent contracts. Defaults to compact action guidance." }
15935
15971
  },
15936
15972
  additionalProperties: false
15937
15973
  },
@@ -15985,12 +16021,13 @@ var TOOLS = [
15985
16021
  handler: async (topolo, args) => {
15986
16022
  const service = typeof args["service"] === "string" ? args["service"].trim() : "";
15987
16023
  if (!service) throw new TopoloMcpPublicError("service is required for bounded action discovery.");
15988
- return topolo.client.searchActions({
16024
+ const result = await topolo.client.searchActions({
15989
16025
  service,
15990
16026
  query: typeof args["query"] === "string" ? args["query"] : void 0,
15991
16027
  cursor: typeof args["cursor"] === "string" ? args["cursor"] : void 0,
15992
16028
  limit: typeof args["limit"] === "number" ? args["limit"] : void 0
15993
16029
  });
16030
+ return args["detail"] === true ? result : { actions: result.actions.map(compactActionCatalogEntry), page: result.page };
15994
16031
  }
15995
16032
  },
15996
16033
  {
@@ -16156,7 +16193,8 @@ var TOOLS = [
16156
16193
  type: "object",
16157
16194
  properties: {
16158
16195
  actionId: { type: "string", minLength: 1 },
16159
- input: { type: "object", additionalProperties: true }
16196
+ input: { type: "object", additionalProperties: true },
16197
+ detail: { type: "boolean", description: "Include the full action contract. Defaults to a compact validation result." }
16160
16198
  },
16161
16199
  required: ["actionId"],
16162
16200
  additionalProperties: false
@@ -16165,7 +16203,8 @@ var TOOLS = [
16165
16203
  const actionId = typeof args["actionId"] === "string" ? args["actionId"].trim() : "";
16166
16204
  if (!actionId) throw new TopoloMcpPublicError("actionId is required.");
16167
16205
  const input = coerceObjectParam(args["input"], "input");
16168
- return topolo.client.validateActionInput(actionId, input);
16206
+ const result = await topolo.client.validateActionInput(actionId, input);
16207
+ return args["detail"] === true ? result : compactActionValidation(result.action.actionId, result.validation);
16169
16208
  }
16170
16209
  },
16171
16210
  {
@@ -16181,7 +16220,8 @@ var TOOLS = [
16181
16220
  input: { type: "object", additionalProperties: true },
16182
16221
  resourceType: { type: "string", description: "Optional resource-scoping alias published in the app resource catalog (e.g. workspace, brand, merchant)." },
16183
16222
  resourceId: { type: "string", description: "Resource id. Required when resourceType is provided." },
16184
- confirm: { type: "boolean", description: "Include confirmation in the plan without executing the action." }
16223
+ confirm: { type: "boolean", description: "Include confirmation in the plan without executing the action." },
16224
+ detail: { type: "boolean", description: "Include the full action contract. Defaults to the executable request and verification plan." }
16185
16225
  },
16186
16226
  required: ["actionId"],
16187
16227
  additionalProperties: false
@@ -16191,7 +16231,7 @@ var TOOLS = [
16191
16231
  if (!actionId) throw new TopoloMcpPublicError("actionId is required.");
16192
16232
  const input = coerceObjectParam(args["input"], "input");
16193
16233
  const resource = optionalResourceContext(args);
16194
- return topolo.client.planAction(
16234
+ const plan = await topolo.client.planAction(
16195
16235
  actionId,
16196
16236
  input,
16197
16237
  {
@@ -16199,6 +16239,7 @@ var TOOLS = [
16199
16239
  ...resource ? { resource } : {}
16200
16240
  }
16201
16241
  );
16242
+ return args["detail"] === true ? plan : compactActionPlan(plan);
16202
16243
  }
16203
16244
  },
16204
16245
  {
@@ -16227,19 +16268,42 @@ var TOOLS = [
16227
16268
  {
16228
16269
  name: "topolo_discover_capabilities",
16229
16270
  title: "Discover one Topolo application capability contract",
16230
- description: "Lists every action published by one application \u2014 its full capability contract, straight from the registry-canonical catalog. Use the actionService value returned by topolo_search_applications as service. Follow page.nextCursor via topolo_search_actions when the contract exceeds one page.",
16271
+ description: "Lists every action published by one application \u2014 its full capability contract, straight from the registry-canonical catalog. Use the actionService value returned by topolo_search_applications as service.",
16231
16272
  requiredScopes: [],
16232
16273
  destructive: false,
16233
16274
  inputSchema: {
16234
16275
  type: "object",
16235
- properties: { service: { type: "string", minLength: 1 } },
16276
+ properties: {
16277
+ service: { type: "string", minLength: 1 },
16278
+ summary: { type: "boolean", description: "Return compact counts without action rows." },
16279
+ detail: { type: "boolean", description: "Return full schemas and agent contracts. Defaults to compact capability guidance." }
16280
+ },
16236
16281
  required: ["service"],
16237
16282
  additionalProperties: false
16238
16283
  },
16239
16284
  handler: async (topolo, args) => {
16240
16285
  const service = typeof args["service"] === "string" ? args["service"].trim() : "";
16241
16286
  if (!service) throw new TopoloMcpPublicError("service is required.");
16242
- return topolo.client.searchActions({ service, limit: 100 });
16287
+ if (args["summary"] === true && args["detail"] === true) {
16288
+ throw new TopoloMcpPublicError("summary cannot be combined with detail.");
16289
+ }
16290
+ const actions = [];
16291
+ const seenCursors = /* @__PURE__ */ new Set();
16292
+ let cursor;
16293
+ for (; ; ) {
16294
+ const page = await topolo.client.searchActions({ service, limit: 100, ...cursor ? { cursor } : {} });
16295
+ actions.push(...page.actions);
16296
+ if (!page.page.hasMore) break;
16297
+ const nextCursor = page.page.nextCursor?.trim();
16298
+ if (!nextCursor || seenCursors.has(nextCursor)) {
16299
+ throw new TopoloMcpPublicError("Capability discovery returned an invalid continuation cursor.");
16300
+ }
16301
+ seenCursors.add(nextCursor);
16302
+ cursor = nextCursor;
16303
+ }
16304
+ if (args["summary"] === true) return summarizeActionCapabilities(service, actions);
16305
+ const result = { actions, page: { nextCursor: null, hasMore: false } };
16306
+ return args["detail"] === true ? result : { actions: actions.map(compactActionCatalogEntry), page: result.page };
16243
16307
  }
16244
16308
  },
16245
16309
  {
@@ -16407,6 +16471,10 @@ var TOOLS = [
16407
16471
  type: "string",
16408
16472
  enum: ["missing", "needs_review", "partial"],
16409
16473
  description: "Optional conformance gate. Returns conformanceGate.passed=false when findings at this severity or worse exist."
16474
+ },
16475
+ detail: {
16476
+ type: "boolean",
16477
+ description: "Include every finding and migration item. Defaults to per-app scores and a queue count."
16410
16478
  }
16411
16479
  },
16412
16480
  additionalProperties: false
@@ -16422,11 +16490,13 @@ var TOOLS = [
16422
16490
  if (application === void 0) {
16423
16491
  const directory = await listApplicationDirectory(topolo.client);
16424
16492
  report = auditApplicationEntries(directory.applications.map((app) => app.application));
16425
- return gate ? { ...report, conformanceGate: evaluateApplicationAuditGate(report, gate) } : report;
16493
+ const output2 = args["detail"] === true ? report : compactApplicationAudit(report);
16494
+ return gate ? { ...output2, conformanceGate: evaluateApplicationAuditGate(report, gate) } : output2;
16426
16495
  }
16427
16496
  const resolved = await resolveDirectoryApplication(topolo, application);
16428
16497
  report = auditApplicationEntries([resolved.application]);
16429
- return gate ? { ...report, conformanceGate: evaluateApplicationAuditGate(report, gate) } : report;
16498
+ const output = args["detail"] === true ? report : compactApplicationAudit(report);
16499
+ return gate ? { ...output, conformanceGate: evaluateApplicationAuditGate(report, gate) } : output;
16430
16500
  }
16431
16501
  },
16432
16502
  {
package/dist/index.js CHANGED
@@ -3908,6 +3908,52 @@ function mergeSignals(a, b) {
3908
3908
  b.addEventListener("abort", onAbort, { once: true });
3909
3909
  return controller.signal;
3910
3910
  }
3911
+ function compactActionCatalogEntry(action) {
3912
+ const required = Array.isArray(action.inputSchema["required"]) ? action.inputSchema["required"].filter((value) => typeof value === "string") : [];
3913
+ const examples = action.agentContract?.examples ?? [];
3914
+ return {
3915
+ actionId: action.actionId,
3916
+ title: action.title,
3917
+ description: action.description,
3918
+ method: action.method,
3919
+ readOnly: action.readOnly,
3920
+ requiresConfirmation: action.requiresConfirmation,
3921
+ agentAccess: action.agentAccess ?? (action.requiresConfirmation ? "confirm" : action.readOnly ? "auto" : "confirm"),
3922
+ requiredPermission: action.requiredPermission,
3923
+ requiredInput: required,
3924
+ resourceType: action.agentContract?.resource?.kind ?? null,
3925
+ exampleInput: examples[0]?.input ?? null,
3926
+ docsUrl: action.agentContract?.docsUrl ?? null
3927
+ };
3928
+ }
3929
+ function compactActionValidation(actionId, validation) {
3930
+ return { actionId, valid: validation.valid, errors: validation.errors };
3931
+ }
3932
+ function compactActionPlan(plan) {
3933
+ return {
3934
+ actionId: plan.action.actionId,
3935
+ valid: plan.validation.valid,
3936
+ errors: plan.validation.errors,
3937
+ executable: plan.executable,
3938
+ confirmationRequired: plan.confirmationRequired,
3939
+ confirmationProvided: plan.confirmationProvided,
3940
+ request: plan.request,
3941
+ verification: plan.verification,
3942
+ rollbackActionId: plan.rollbackActionId,
3943
+ nextActionIds: plan.nextActionIds
3944
+ };
3945
+ }
3946
+ function compactApplicationAudit(report) {
3947
+ return {
3948
+ version: report.version,
3949
+ applications: report.applications.map((audit) => ({
3950
+ applicationId: audit.application.id,
3951
+ applicationName: audit.application.name,
3952
+ score: audit.score
3953
+ })),
3954
+ migrationQueueCount: report.migrationQueue.length
3955
+ };
3956
+ }
3911
3957
  var CrmModule = class {
3912
3958
  constructor(client) {
3913
3959
  this.client = client;
@@ -4479,6 +4525,17 @@ function optionalResourceContext(args) {
4479
4525
  }
4480
4526
  return { resourceType, resourceId };
4481
4527
  }
4528
+ function summarizeActionCapabilities(service, actions) {
4529
+ return {
4530
+ service,
4531
+ total: actions.length,
4532
+ readOnly: actions.filter((action) => action.readOnly).length,
4533
+ mutating: actions.filter((action) => !action.readOnly).length,
4534
+ destructive: actions.filter((action) => action.destructive).length,
4535
+ confirmationRequired: actions.filter((action) => action.requiresConfirmation).length,
4536
+ resourceTypes: [...new Set(actions.map((action) => action.agentContract?.resource?.kind).filter(Boolean))].sort()
4537
+ };
4538
+ }
4482
4539
  function coerceObjectParam(value, name) {
4483
4540
  let candidate = value;
4484
4541
  if (typeof candidate === "string" && candidate.trim().startsWith("{")) {
@@ -4518,7 +4575,8 @@ var TOOLS = [
4518
4575
  properties: {
4519
4576
  query: { type: "string" },
4520
4577
  cursor: { type: "string" },
4521
- limit: { type: "integer", minimum: 1, maximum: 100, default: 25 }
4578
+ limit: { type: "integer", minimum: 1, maximum: 100, default: 25 },
4579
+ detail: { type: "boolean", description: "Return full schemas and agent contracts. Defaults to compact action guidance." }
4522
4580
  },
4523
4581
  additionalProperties: false
4524
4582
  },
@@ -4572,12 +4630,13 @@ var TOOLS = [
4572
4630
  handler: async (topolo, args) => {
4573
4631
  const service = typeof args["service"] === "string" ? args["service"].trim() : "";
4574
4632
  if (!service) throw new TopoloMcpPublicError("service is required for bounded action discovery.");
4575
- return topolo.client.searchActions({
4633
+ const result = await topolo.client.searchActions({
4576
4634
  service,
4577
4635
  query: typeof args["query"] === "string" ? args["query"] : void 0,
4578
4636
  cursor: typeof args["cursor"] === "string" ? args["cursor"] : void 0,
4579
4637
  limit: typeof args["limit"] === "number" ? args["limit"] : void 0
4580
4638
  });
4639
+ return args["detail"] === true ? result : { actions: result.actions.map(compactActionCatalogEntry), page: result.page };
4581
4640
  }
4582
4641
  },
4583
4642
  {
@@ -4743,7 +4802,8 @@ var TOOLS = [
4743
4802
  type: "object",
4744
4803
  properties: {
4745
4804
  actionId: { type: "string", minLength: 1 },
4746
- input: { type: "object", additionalProperties: true }
4805
+ input: { type: "object", additionalProperties: true },
4806
+ detail: { type: "boolean", description: "Include the full action contract. Defaults to a compact validation result." }
4747
4807
  },
4748
4808
  required: ["actionId"],
4749
4809
  additionalProperties: false
@@ -4752,7 +4812,8 @@ var TOOLS = [
4752
4812
  const actionId = typeof args["actionId"] === "string" ? args["actionId"].trim() : "";
4753
4813
  if (!actionId) throw new TopoloMcpPublicError("actionId is required.");
4754
4814
  const input = coerceObjectParam(args["input"], "input");
4755
- return topolo.client.validateActionInput(actionId, input);
4815
+ const result = await topolo.client.validateActionInput(actionId, input);
4816
+ return args["detail"] === true ? result : compactActionValidation(result.action.actionId, result.validation);
4756
4817
  }
4757
4818
  },
4758
4819
  {
@@ -4768,7 +4829,8 @@ var TOOLS = [
4768
4829
  input: { type: "object", additionalProperties: true },
4769
4830
  resourceType: { type: "string", description: "Optional resource-scoping alias published in the app resource catalog (e.g. workspace, brand, merchant)." },
4770
4831
  resourceId: { type: "string", description: "Resource id. Required when resourceType is provided." },
4771
- confirm: { type: "boolean", description: "Include confirmation in the plan without executing the action." }
4832
+ confirm: { type: "boolean", description: "Include confirmation in the plan without executing the action." },
4833
+ detail: { type: "boolean", description: "Include the full action contract. Defaults to the executable request and verification plan." }
4772
4834
  },
4773
4835
  required: ["actionId"],
4774
4836
  additionalProperties: false
@@ -4778,7 +4840,7 @@ var TOOLS = [
4778
4840
  if (!actionId) throw new TopoloMcpPublicError("actionId is required.");
4779
4841
  const input = coerceObjectParam(args["input"], "input");
4780
4842
  const resource = optionalResourceContext(args);
4781
- return topolo.client.planAction(
4843
+ const plan = await topolo.client.planAction(
4782
4844
  actionId,
4783
4845
  input,
4784
4846
  {
@@ -4786,6 +4848,7 @@ var TOOLS = [
4786
4848
  ...resource ? { resource } : {}
4787
4849
  }
4788
4850
  );
4851
+ return args["detail"] === true ? plan : compactActionPlan(plan);
4789
4852
  }
4790
4853
  },
4791
4854
  {
@@ -4814,19 +4877,42 @@ var TOOLS = [
4814
4877
  {
4815
4878
  name: "topolo_discover_capabilities",
4816
4879
  title: "Discover one Topolo application capability contract",
4817
- description: "Lists every action published by one application \u2014 its full capability contract, straight from the registry-canonical catalog. Use the actionService value returned by topolo_search_applications as service. Follow page.nextCursor via topolo_search_actions when the contract exceeds one page.",
4880
+ description: "Lists every action published by one application \u2014 its full capability contract, straight from the registry-canonical catalog. Use the actionService value returned by topolo_search_applications as service.",
4818
4881
  requiredScopes: [],
4819
4882
  destructive: false,
4820
4883
  inputSchema: {
4821
4884
  type: "object",
4822
- properties: { service: { type: "string", minLength: 1 } },
4885
+ properties: {
4886
+ service: { type: "string", minLength: 1 },
4887
+ summary: { type: "boolean", description: "Return compact counts without action rows." },
4888
+ detail: { type: "boolean", description: "Return full schemas and agent contracts. Defaults to compact capability guidance." }
4889
+ },
4823
4890
  required: ["service"],
4824
4891
  additionalProperties: false
4825
4892
  },
4826
4893
  handler: async (topolo, args) => {
4827
4894
  const service = typeof args["service"] === "string" ? args["service"].trim() : "";
4828
4895
  if (!service) throw new TopoloMcpPublicError("service is required.");
4829
- return topolo.client.searchActions({ service, limit: 100 });
4896
+ if (args["summary"] === true && args["detail"] === true) {
4897
+ throw new TopoloMcpPublicError("summary cannot be combined with detail.");
4898
+ }
4899
+ const actions = [];
4900
+ const seenCursors = /* @__PURE__ */ new Set();
4901
+ let cursor;
4902
+ for (; ; ) {
4903
+ const page = await topolo.client.searchActions({ service, limit: 100, ...cursor ? { cursor } : {} });
4904
+ actions.push(...page.actions);
4905
+ if (!page.page.hasMore) break;
4906
+ const nextCursor = page.page.nextCursor?.trim();
4907
+ if (!nextCursor || seenCursors.has(nextCursor)) {
4908
+ throw new TopoloMcpPublicError("Capability discovery returned an invalid continuation cursor.");
4909
+ }
4910
+ seenCursors.add(nextCursor);
4911
+ cursor = nextCursor;
4912
+ }
4913
+ if (args["summary"] === true) return summarizeActionCapabilities(service, actions);
4914
+ const result = { actions, page: { nextCursor: null, hasMore: false } };
4915
+ return args["detail"] === true ? result : { actions: actions.map(compactActionCatalogEntry), page: result.page };
4830
4916
  }
4831
4917
  },
4832
4918
  {
@@ -4994,6 +5080,10 @@ var TOOLS = [
4994
5080
  type: "string",
4995
5081
  enum: ["missing", "needs_review", "partial"],
4996
5082
  description: "Optional conformance gate. Returns conformanceGate.passed=false when findings at this severity or worse exist."
5083
+ },
5084
+ detail: {
5085
+ type: "boolean",
5086
+ description: "Include every finding and migration item. Defaults to per-app scores and a queue count."
4997
5087
  }
4998
5088
  },
4999
5089
  additionalProperties: false
@@ -5009,11 +5099,13 @@ var TOOLS = [
5009
5099
  if (application === void 0) {
5010
5100
  const directory = await listApplicationDirectory(topolo.client);
5011
5101
  report = auditApplicationEntries(directory.applications.map((app) => app.application));
5012
- return gate ? { ...report, conformanceGate: evaluateApplicationAuditGate(report, gate) } : report;
5102
+ const output2 = args["detail"] === true ? report : compactApplicationAudit(report);
5103
+ return gate ? { ...output2, conformanceGate: evaluateApplicationAuditGate(report, gate) } : output2;
5013
5104
  }
5014
5105
  const resolved = await resolveDirectoryApplication(topolo, application);
5015
5106
  report = auditApplicationEntries([resolved.application]);
5016
- return gate ? { ...report, conformanceGate: evaluateApplicationAuditGate(report, gate) } : report;
5107
+ const output = args["detail"] === true ? report : compactApplicationAudit(report);
5108
+ return gate ? { ...output, conformanceGate: evaluateApplicationAuditGate(report, gate) } : output;
5017
5109
  }
5018
5110
  },
5019
5111
  {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@topolo/mcp",
3
- "version": "0.10.0",
4
- "topoloPublishedVersion": "0.10.0",
3
+ "version": "0.10.2",
4
+ "topoloPublishedVersion": "0.10.2",
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
  "type": "module",
7
7
  "bin": {