@topolo/mcp 0.10.1 → 0.10.3

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.
@@ -75,6 +75,11 @@ type ToolDispatchResult = {
75
75
  reason: ToolDispatchFailureReason;
76
76
  durationMs: number;
77
77
  requiredScopes?: string[];
78
+ code?: string;
79
+ status?: number;
80
+ requestId?: string;
81
+ details?: unknown;
82
+ hint?: string;
78
83
  };
79
84
  interface ToolAdvertisement {
80
85
  name: string;
package/dist/dispatch.js CHANGED
@@ -1,5 +1,11 @@
1
1
  // src/dispatch.ts
2
- import { TopoloAuthError, TopoloPermissionError } from "@topolo/sdk";
2
+ import {
3
+ TopoloAuthError,
4
+ TopoloHttpError,
5
+ TopoloPermissionError,
6
+ publicTopoloErrorMessage,
7
+ topoloErrorHint
8
+ } from "@topolo/sdk";
3
9
 
4
10
  // src/tools.ts
5
11
  import {
@@ -8,6 +14,7 @@ import {
8
14
  auditApplicationEntries,
9
15
  applicationRequirementScopes,
10
16
  compactActionCatalogEntry,
17
+ compactActionPreparation,
11
18
  compactActionPlan,
12
19
  compactActionValidation,
13
20
  compactApplicationAudit,
@@ -82,6 +89,17 @@ function optionalResourceContext(args) {
82
89
  }
83
90
  return { resourceType, resourceId };
84
91
  }
92
+ function summarizeActionCapabilities(service, actions) {
93
+ return {
94
+ service,
95
+ total: actions.length,
96
+ readOnly: actions.filter((action) => action.readOnly).length,
97
+ mutating: actions.filter((action) => !action.readOnly).length,
98
+ destructive: actions.filter((action) => action.destructive).length,
99
+ confirmationRequired: actions.filter((action) => action.requiresConfirmation).length,
100
+ resourceTypes: [...new Set(actions.map((action) => action.agentContract?.resource?.kind).filter(Boolean))].sort()
101
+ };
102
+ }
85
103
  function coerceObjectParam(value, name) {
86
104
  let candidate = value;
87
105
  if (typeof candidate === "string" && candidate.trim().startsWith("{")) {
@@ -362,6 +380,38 @@ var TOOLS = [
362
380
  return args["detail"] === true ? result : compactActionValidation(result.action.actionId, result.validation);
363
381
  }
364
382
  },
383
+ {
384
+ name: "topolo_prepare_action",
385
+ title: "Prepare one Topolo action",
386
+ description: "Fetches one exact live action contract once and returns one valid published example, missing fields, exact request, confirmation state, verification, and rollback without executing it.",
387
+ requiredScopes: [],
388
+ destructive: false,
389
+ inputSchema: {
390
+ type: "object",
391
+ properties: {
392
+ actionId: { type: "string", minLength: 1 },
393
+ input: { type: "object", additionalProperties: true },
394
+ resourceType: { type: "string" },
395
+ resourceId: { type: "string" },
396
+ confirm: { type: "boolean", description: "Include confirmation in the plan without executing the action." }
397
+ },
398
+ required: ["actionId"],
399
+ additionalProperties: false
400
+ },
401
+ handler: async (topolo, args) => {
402
+ const actionId = requiredString(args, "actionId");
403
+ const resource = optionalResourceContext(args);
404
+ const preparation = await topolo.client.prepareAction(
405
+ actionId,
406
+ args["input"] === void 0 ? void 0 : coerceObjectParam(args["input"], "input"),
407
+ {
408
+ confirm: args["confirm"] === true,
409
+ ...resource ? { resource } : {}
410
+ }
411
+ );
412
+ return compactActionPreparation(preparation);
413
+ }
414
+ },
365
415
  {
366
416
  name: "topolo_plan_action",
367
417
  title: "Plan one Topolo action",
@@ -423,13 +473,14 @@ var TOOLS = [
423
473
  {
424
474
  name: "topolo_discover_capabilities",
425
475
  title: "Discover one Topolo application capability contract",
426
- 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.",
476
+ 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.",
427
477
  requiredScopes: [],
428
478
  destructive: false,
429
479
  inputSchema: {
430
480
  type: "object",
431
481
  properties: {
432
482
  service: { type: "string", minLength: 1 },
483
+ summary: { type: "boolean", description: "Return compact counts without action rows." },
433
484
  detail: { type: "boolean", description: "Return full schemas and agent contracts. Defaults to compact capability guidance." }
434
485
  },
435
486
  required: ["service"],
@@ -438,8 +489,26 @@ var TOOLS = [
438
489
  handler: async (topolo, args) => {
439
490
  const service = typeof args["service"] === "string" ? args["service"].trim() : "";
440
491
  if (!service) throw new TopoloMcpPublicError("service is required.");
441
- const result = await topolo.client.searchActions({ service, limit: 100 });
442
- return args["detail"] === true ? result : { actions: result.actions.map(compactActionCatalogEntry), page: result.page };
492
+ if (args["summary"] === true && args["detail"] === true) {
493
+ throw new TopoloMcpPublicError("summary cannot be combined with detail.");
494
+ }
495
+ const actions = [];
496
+ const seenCursors = /* @__PURE__ */ new Set();
497
+ let cursor;
498
+ for (; ; ) {
499
+ const page = await topolo.client.searchActions({ service, limit: 100, ...cursor ? { cursor } : {} });
500
+ actions.push(...page.actions);
501
+ if (!page.page.hasMore) break;
502
+ const nextCursor = page.page.nextCursor?.trim();
503
+ if (!nextCursor || seenCursors.has(nextCursor)) {
504
+ throw new TopoloMcpPublicError("Capability discovery returned an invalid continuation cursor.");
505
+ }
506
+ seenCursors.add(nextCursor);
507
+ cursor = nextCursor;
508
+ }
509
+ if (args["summary"] === true) return summarizeActionCapabilities(service, actions);
510
+ const result = { actions, page: { nextCursor: null, hasMore: false } };
511
+ return args["detail"] === true ? result : { actions: actions.map(compactActionCatalogEntry), page: result.page };
443
512
  }
444
513
  },
445
514
  {
@@ -837,8 +906,13 @@ async function dispatchTopoloTool(input) {
837
906
  return {
838
907
  ok: false,
839
908
  reason: "permission",
840
- error: `Permission denied. Required: ${err.required.join(", ") || "(unknown)"}`,
909
+ error: publicTopoloErrorMessage(err),
841
910
  requiredScopes: err.required,
911
+ code: err.code,
912
+ status: err.status,
913
+ requestId: err.requestId,
914
+ details: err.details,
915
+ hint: topoloErrorHint(err),
842
916
  durationMs: Date.now() - started
843
917
  };
844
918
  }
@@ -847,6 +921,24 @@ async function dispatchTopoloTool(input) {
847
921
  ok: false,
848
922
  reason: "auth",
849
923
  error: "Authentication failed.",
924
+ code: err.code,
925
+ status: err.status,
926
+ requestId: err.requestId,
927
+ details: err.details,
928
+ hint: topoloErrorHint(err),
929
+ durationMs: Date.now() - started
930
+ };
931
+ }
932
+ if (err instanceof TopoloHttpError) {
933
+ return {
934
+ ok: false,
935
+ reason: "handler",
936
+ error: publicTopoloErrorMessage(err),
937
+ code: err.code,
938
+ status: err.status,
939
+ requestId: err.requestId,
940
+ details: err.details,
941
+ hint: topoloErrorHint(err),
850
942
  durationMs: Date.now() - started
851
943
  };
852
944
  }
package/dist/http.d.ts CHANGED
@@ -1,5 +1,5 @@
1
+ import { TopoloRuntimeEnvironment, TopoloCredential, Topolo } from '@topolo/sdk';
1
2
  import { WebStandardStreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js';
2
- import { TopoloCredential, Topolo } from '@topolo/sdk';
3
3
 
4
4
  /**
5
5
  * Hosted, multi-tenant MCP Streamable HTTP transport for the Topolo platform.
@@ -18,9 +18,11 @@ import { TopoloCredential, Topolo } from '@topolo/sdk';
18
18
  * Mcp-Session-Id continuity, GET SSE stream, DELETE to terminate) over pure
19
19
  * Web-Standard Request/Response — so it runs unchanged in a Cloudflare Worker.
20
20
  */
21
- interface TopoloMcpHttpOptions {
21
+ interface TopoloMcpHttpInternalOptions {
22
22
  /** Path the MCP endpoint is mounted at. Defaults to '/mcp'. */
23
23
  path?: string;
24
+ /** Effective Topolo environment. Defaults to production and is always surfaced to the MCP client. */
25
+ environment?: TopoloRuntimeEnvironment;
24
26
  /** Per-service URL overrides (e.g. staging). Passed through to createTopolo. */
25
27
  serviceUrls?: Record<string, string>;
26
28
  /** Per-service TopoloAuth app-id overrides. Passed through to createTopolo. */
@@ -52,12 +54,33 @@ interface McpSession {
52
54
  * const handler = createTopoloMcpHttpHandler();
53
55
  * export default { fetch: handler.fetch };
54
56
  */
55
- declare function createTopoloMcpHttpHandler(options?: TopoloMcpHttpOptions): {
57
+ declare function createTopoloMcpHttpHandlerInternal(options?: TopoloMcpHttpInternalOptions): {
56
58
  /** Cloudflare Worker / fetch-compatible entrypoint. */
57
59
  fetch: (request: Request) => Promise<Response>;
58
60
  /** Exposed for tests/introspection. */
59
61
  sessions: Map<string, McpSession>;
60
62
  };
63
+ type TopoloMcpHttpHandlerInternal = ReturnType<typeof createTopoloMcpHttpHandlerInternal>;
64
+
65
+ interface TopoloMcpHttpOptions {
66
+ /** Path the MCP endpoint is mounted at. Defaults to '/mcp'. */
67
+ path?: string;
68
+ /** Effective Topolo environment. Defaults to production and is always surfaced to the MCP client. */
69
+ environment?: TopoloRuntimeEnvironment;
70
+ /** Per-service URL overrides (e.g. staging). Passed through to createTopolo. */
71
+ serviceUrls?: Record<string, string>;
72
+ /** Per-service TopoloAuth app-id overrides. Passed through to createTopolo. */
73
+ appIds?: Record<string, string>;
74
+ /** Human-readable agent label for audit logs (forwarded to the SDK). */
75
+ agentName?: string;
76
+ /** Validated network transport for the SDK client. Defaults to global fetch. */
77
+ fetch?: typeof fetch;
78
+ }
79
+ /**
80
+ * Create the public hosted MCP handler. The SDK client is always constructed
81
+ * here from the validated effective environment and per-request credential.
82
+ */
83
+ declare function createTopoloMcpHttpHandler(options?: TopoloMcpHttpOptions): TopoloMcpHttpHandlerInternal;
61
84
  type TopoloMcpHttpHandler = ReturnType<typeof createTopoloMcpHttpHandler>;
62
85
 
63
86
  export { type TopoloMcpHttpHandler, type TopoloMcpHttpOptions, createTopoloMcpHttpHandler };