@topolo/mcp 0.6.0 → 0.7.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/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.2/node_modules/fast-uri/lib/utils.js
3101
+ // ../../node_modules/.pnpm/fast-uri@3.1.3/node_modules/fast-uri/lib/utils.js
3102
3102
  var require_utils = __commonJS({
3103
- "../../node_modules/.pnpm/fast-uri@3.1.2/node_modules/fast-uri/lib/utils.js"(exports, module) {
3103
+ "../../node_modules/.pnpm/fast-uri@3.1.3/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.2/node_modules/fast-uri/lib/schemes.js
3414
+ // ../../node_modules/.pnpm/fast-uri@3.1.3/node_modules/fast-uri/lib/schemes.js
3415
3415
  var require_schemes = __commonJS({
3416
- "../../node_modules/.pnpm/fast-uri@3.1.2/node_modules/fast-uri/lib/schemes.js"(exports, module) {
3416
+ "../../node_modules/.pnpm/fast-uri@3.1.3/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.2/node_modules/fast-uri/index.js
3624
+ // ../../node_modules/.pnpm/fast-uri@3.1.3/node_modules/fast-uri/index.js
3625
3625
  var require_fast_uri = __commonJS({
3626
- "../../node_modules/.pnpm/fast-uri@3.1.2/node_modules/fast-uri/index.js"(exports, module) {
3626
+ "../../node_modules/.pnpm/fast-uri@3.1.3/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();
@@ -3836,7 +3836,7 @@ var require_fast_uri = __commonJS({
3836
3836
  if (!options.unicodeSupport && (!schemeHandler || !schemeHandler.unicodeSupport)) {
3837
3837
  if (parsed.host && (options.domainHost || schemeHandler && schemeHandler.domainHost) && isIP === false && nonSimpleDomain(parsed.host)) {
3838
3838
  try {
3839
- parsed.host = URL.domainToASCII(parsed.host.toLowerCase());
3839
+ parsed.host = new URL("http://" + parsed.host).hostname;
3840
3840
  } catch (e) {
3841
3841
  parsed.error = parsed.error || "Host's domain name can not be converted to ASCII: " + e;
3842
3842
  }
@@ -15861,6 +15861,15 @@ function splitService(servicePart) {
15861
15861
  // src/tools.ts
15862
15862
  var APPLICATION_IDS = Object.keys(APPLICATIONS).sort();
15863
15863
  var HTTP_METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE"];
15864
+ function optionalResourceContext(args) {
15865
+ const resourceType = typeof args["resourceType"] === "string" ? args["resourceType"].trim() : "";
15866
+ const resourceId = typeof args["resourceId"] === "string" ? args["resourceId"].trim() : "";
15867
+ if (!resourceType && !resourceId) return void 0;
15868
+ if (!resourceType || !resourceId) {
15869
+ throw new Error("resourceType and resourceId must be provided together.");
15870
+ }
15871
+ return { resourceType, resourceId };
15872
+ }
15864
15873
  var TOOLS = [
15865
15874
  {
15866
15875
  name: "topolo_whoami",
@@ -15876,22 +15885,32 @@ var TOOLS = [
15876
15885
  handler: async (topolo) => topolo.identity.whoami()
15877
15886
  },
15878
15887
  {
15879
- name: "topolo_list_services",
15880
- title: "List every Topolo service the agent can reach",
15881
- 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.",
15888
+ name: "topolo_search_applications",
15889
+ title: "Search Topolo applications the agent can reach",
15890
+ description: "Searches the credential-scoped application registry with a bounded page and continuation cursor. Returns actionService as the canonical selector for topolo_search_actions, plus granted permissions, API URL, and launch URL without loading the global platform catalog.",
15882
15891
  requiredScopes: [],
15883
15892
  destructive: false,
15884
15893
  inputSchema: {
15885
15894
  type: "object",
15886
- properties: {},
15895
+ properties: {
15896
+ query: { type: "string" },
15897
+ cursor: { type: "string" },
15898
+ limit: { type: "integer", minimum: 1, maximum: 100, default: 25 }
15899
+ },
15887
15900
  additionalProperties: false
15888
15901
  },
15889
- handler: async (topolo) => {
15890
- const services = (await topolo.client.listServices()).map((entry) => {
15902
+ handler: async (topolo, args) => {
15903
+ const result = await topolo.client.searchServices({
15904
+ query: typeof args["query"] === "string" ? args["query"] : void 0,
15905
+ cursor: typeof args["cursor"] === "string" ? args["cursor"] : void 0,
15906
+ limit: typeof args["limit"] === "number" ? args["limit"] : void 0
15907
+ });
15908
+ const applications = result.services.map((entry) => {
15891
15909
  const id = displayAppId(entry);
15892
15910
  return {
15893
15911
  id,
15894
15912
  appId: entry.appId,
15913
+ actionService: entry.appId,
15895
15914
  slug: entry.slug,
15896
15915
  name: entry.name,
15897
15916
  apiBaseUrl: entry.apiBaseUrl,
@@ -15904,13 +15923,13 @@ var TOOLS = [
15904
15923
  permissions: [...entry.permissions]
15905
15924
  };
15906
15925
  }).sort((left, right) => left.id.localeCompare(right.id));
15907
- return { services };
15926
+ return { applications, page: result.page };
15908
15927
  }
15909
15928
  },
15910
15929
  {
15911
- name: "topolo_list_actions",
15912
- title: "List every Topolo action the agent can call",
15913
- description: "Returns the credential-scoped callable action catalog. Actions are published by applications through TopoloDevelopers and filtered by TopoloAuth against the current organization and effective permissions.",
15930
+ name: "topolo_search_actions",
15931
+ title: "Search Topolo actions the agent can call",
15932
+ description: "Searches one application's credential-scoped actions with a bounded page and continuation cursor.",
15914
15933
  requiredScopes: [],
15915
15934
  destructive: false,
15916
15935
  inputSchema: {
@@ -15918,31 +15937,25 @@ var TOOLS = [
15918
15937
  properties: {
15919
15938
  service: {
15920
15939
  type: "string",
15921
- description: "Optional app id, slug, or name filter."
15922
- }
15940
+ description: "Required application selector. Prefer actionService from topolo_search_applications; canonical app id, slug, and name are also accepted."
15941
+ },
15942
+ query: { type: "string" },
15943
+ cursor: { type: "string" },
15944
+ limit: { type: "integer", minimum: 1, maximum: 100, default: 25 }
15923
15945
  },
15946
+ required: ["service"],
15924
15947
  additionalProperties: false
15925
15948
  },
15926
- handler: async (topolo, args) => ({
15927
- actions: await topolo.client.listActions({
15928
- service: typeof args["service"] === "string" ? args["service"] : void 0
15929
- })
15930
- })
15931
- },
15932
- {
15933
- name: "topolo_list_applications",
15934
- title: "List every Topolo platform application",
15935
- description: "Returns the live Topolo application catalog from the platform registry. Reflects apps as they are registered/removed with no client rebuild. Authenticated callers in an entitled org also see the developer_only apps their role permits. Falls back to a bundled snapshot only if the registry is unreachable.",
15936
- requiredScopes: [],
15937
- destructive: false,
15938
- inputSchema: {
15939
- type: "object",
15940
- properties: {},
15941
- additionalProperties: false
15942
- },
15943
- handler: async (topolo) => ({
15944
- applications: await topolo.client.listServices()
15945
- })
15949
+ handler: async (topolo, args) => {
15950
+ const service = typeof args["service"] === "string" ? args["service"].trim() : "";
15951
+ if (!service) throw new Error("service is required for bounded action discovery.");
15952
+ return topolo.client.searchActions({
15953
+ service,
15954
+ query: typeof args["query"] === "string" ? args["query"] : void 0,
15955
+ cursor: typeof args["cursor"] === "string" ? args["cursor"] : void 0,
15956
+ limit: typeof args["limit"] === "number" ? args["limit"] : void 0
15957
+ });
15958
+ }
15946
15959
  },
15947
15960
  {
15948
15961
  name: "topolo_get_application",
@@ -15955,7 +15968,7 @@ var TOOLS = [
15955
15968
  properties: {
15956
15969
  application: {
15957
15970
  type: "string",
15958
- description: "Application identifier: app id, slug, or name from topolo_list_applications."
15971
+ description: "Application identifier: app id, slug, or name from topolo_search_applications."
15959
15972
  }
15960
15973
  },
15961
15974
  required: ["application"],
@@ -15966,18 +15979,98 @@ var TOOLS = [
15966
15979
  if (typeof application !== "string" || !application.trim()) {
15967
15980
  throw new Error("`application` must be a non-empty string.");
15968
15981
  }
15969
- const needle = application.trim().toLowerCase();
15970
- const catalog = await topolo.client.listServices();
15971
- const match = catalog.find(
15972
- (e) => e.appId.toLowerCase() === needle || e.slug && e.slug.toLowerCase() === needle || e.name && e.name.toLowerCase() === needle
15982
+ return { application: await topolo.client.getService(application) };
15983
+ }
15984
+ },
15985
+ {
15986
+ name: "topolo_get_action",
15987
+ title: "Describe one Topolo action",
15988
+ description: "Returns one credential-scoped action by exact action id.",
15989
+ requiredScopes: [],
15990
+ destructive: false,
15991
+ inputSchema: {
15992
+ type: "object",
15993
+ properties: { actionId: { type: "string", minLength: 1 } },
15994
+ required: ["actionId"],
15995
+ additionalProperties: false
15996
+ },
15997
+ handler: async (topolo, args) => {
15998
+ const actionId = typeof args["actionId"] === "string" ? args["actionId"].trim() : "";
15999
+ if (!actionId) throw new Error("actionId is required.");
16000
+ return { action: await topolo.client.getAction(actionId) };
16001
+ }
16002
+ },
16003
+ {
16004
+ name: "topolo_read_action",
16005
+ title: "Call one read-only Topolo action",
16006
+ description: "Calls one exact action id only when its published contract is read-only and needs no confirmation.",
16007
+ requiredScopes: [],
16008
+ destructive: false,
16009
+ inputSchema: {
16010
+ type: "object",
16011
+ properties: {
16012
+ actionId: { type: "string", minLength: 1 },
16013
+ input: { type: "object", additionalProperties: true },
16014
+ resourceType: { type: "string", description: "Optional app-local resource alias, such as workspace." },
16015
+ resourceId: { type: "string", description: "Resource id. Required when resourceType is provided." }
16016
+ },
16017
+ required: ["actionId"],
16018
+ additionalProperties: false
16019
+ },
16020
+ handler: async (topolo, args) => {
16021
+ const actionId = typeof args["actionId"] === "string" ? args["actionId"].trim() : "";
16022
+ if (!actionId) throw new Error("actionId is required.");
16023
+ const input = args["input"];
16024
+ if (input !== void 0 && (!input || typeof input !== "object" || Array.isArray(input))) {
16025
+ throw new Error("input must be an object.");
16026
+ }
16027
+ const action = await topolo.client.getAction(actionId);
16028
+ const agentAccess = action.agentAccess ?? (action.destructive ? "off" : action.readOnly && !action.requiresConfirmation ? "auto" : "confirm");
16029
+ if (action.method !== "GET" || !action.readOnly || action.destructive || action.requiresConfirmation || agentAccess !== "auto") {
16030
+ throw new Error(`Action "${actionId}" is not an automatic read-only action. Use topolo_call_action with confirmation.`);
16031
+ }
16032
+ const resource = optionalResourceContext(args);
16033
+ return topolo.client.callAction(
16034
+ actionId,
16035
+ input ?? {},
16036
+ resource ? { resource } : {}
16037
+ );
16038
+ }
16039
+ },
16040
+ {
16041
+ name: "topolo_call_action",
16042
+ title: "Call one Topolo action",
16043
+ description: "Calls one exact action id. Mutating actions require confirm:true.",
16044
+ requiredScopes: [],
16045
+ destructive: true,
16046
+ inputSchema: {
16047
+ type: "object",
16048
+ properties: {
16049
+ actionId: { type: "string", minLength: 1 },
16050
+ input: { type: "object", additionalProperties: true },
16051
+ resourceType: { type: "string", description: "Optional app-local resource alias, such as workspace." },
16052
+ resourceId: { type: "string", description: "Resource id. Required when resourceType is provided." },
16053
+ confirm: { type: "boolean" }
16054
+ },
16055
+ required: ["actionId"],
16056
+ additionalProperties: false
16057
+ },
16058
+ handler: async (topolo, args) => {
16059
+ const actionId = typeof args["actionId"] === "string" ? args["actionId"].trim() : "";
16060
+ if (!actionId) throw new Error("actionId is required.");
16061
+ const input = args["input"];
16062
+ if (input !== void 0 && (!input || typeof input !== "object" || Array.isArray(input))) {
16063
+ throw new Error("input must be an object.");
16064
+ }
16065
+ const resource = optionalResourceContext(args);
16066
+ return topolo.client.callAction(
16067
+ actionId,
16068
+ input ?? {},
16069
+ {
16070
+ confirm: args["confirm"] === true,
16071
+ ...resource ? { resource } : {}
16072
+ }
15973
16073
  );
15974
- if (!match) {
15975
- const known = catalog.map((e) => e.slug || e.appId).sort().filter((value) => typeof value === "string" && value.length > 0);
15976
- throw new Error(
15977
- `Unknown application "${application}". ${formatKnownValues(known, "applications")}`
15978
- );
15979
- }
15980
- return { application: match };
15981
16074
  }
15982
16075
  },
15983
16076
  {
@@ -15991,7 +16084,7 @@ var TOOLS = [
15991
16084
  properties: {
15992
16085
  application: {
15993
16086
  type: "string",
15994
- description: "Optional application ID from topolo_list_applications."
16087
+ description: "Optional application ID from topolo_search_applications."
15995
16088
  }
15996
16089
  },
15997
16090
  additionalProperties: false
@@ -16031,7 +16124,7 @@ var TOOLS = [
16031
16124
  properties: {
16032
16125
  application: {
16033
16126
  type: "string",
16034
- description: "Optional application ID from topolo_list_applications."
16127
+ description: "Optional application ID from topolo_search_applications."
16035
16128
  },
16036
16129
  failOn: {
16037
16130
  type: "string",
@@ -16065,7 +16158,7 @@ var TOOLS = [
16065
16158
  {
16066
16159
  name: "topolo_api_call",
16067
16160
  title: "Call any Topolo platform service",
16068
- 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 app IDs; the SDK can also resolve live Auth-catalog app ids/slugs for newly registered API surfaces.",
16161
+ 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_search_applications first to discover callable app IDs; the SDK can also resolve live Auth-catalog app ids/slugs for newly registered API surfaces.",
16069
16162
  requiredScopes: [],
16070
16163
  destructive: true,
16071
16164
  inputSchema: {
@@ -16096,7 +16189,7 @@ var TOOLS = [
16096
16189
  },
16097
16190
  resourceType: {
16098
16191
  type: "string",
16099
- description: "Optional workspace resource alias from topolo_list_services apiKeyResources. Aliases are app-defined, e.g. brand, mailbox, venue, merchant, or any other cataloged alias."
16192
+ description: "Optional workspace resource alias from topolo_search_applications apiKeyResources. Aliases are app-defined, e.g. brand, mailbox, venue, merchant, or any other cataloged alias."
16100
16193
  },
16101
16194
  resourceId: {
16102
16195
  type: "string",
@@ -16114,7 +16207,7 @@ var TOOLS = [
16114
16207
  const service = args["service"];
16115
16208
  const path = args["path"];
16116
16209
  if (typeof service !== "string" || !service.trim()) {
16117
- throw new Error("service is required. Call topolo_list_services first to discover callable services.");
16210
+ throw new Error("service is required. Call topolo_search_applications first to discover callable services.");
16118
16211
  }
16119
16212
  if (typeof path !== "string" || !path) {
16120
16213
  throw new Error("path is required");
@@ -16128,12 +16221,7 @@ var TOOLS = [
16128
16221
  const normalisedQuery = query && typeof query === "object" && !Array.isArray(query) ? Object.fromEntries(
16129
16222
  Object.entries(query).map(([k, v]) => [k, String(v)])
16130
16223
  ) : void 0;
16131
- const resourceType = typeof args["resourceType"] === "string" ? args["resourceType"].trim() : "";
16132
- const resourceId = typeof args["resourceId"] === "string" ? args["resourceId"].trim() : "";
16133
- if (resourceType && !resourceId || !resourceType && resourceId) {
16134
- throw new Error("resourceType and resourceId must be provided together.");
16135
- }
16136
- const resource = resourceType && resourceId ? { resourceType, resourceId } : void 0;
16224
+ const resource = optionalResourceContext(args);
16137
16225
  return topolo.client.request({
16138
16226
  service: service.trim(),
16139
16227
  method,
@@ -16150,58 +16238,8 @@ function filterToolsByScopes(tools, scopes) {
16150
16238
  return tools.filter((t) => hasAnyScope(scopes, t.requiredScopes));
16151
16239
  }
16152
16240
  async function buildTopoloTools(topolo, scopes, tools = TOOLS) {
16153
- const baseTools = filterToolsByScopes(tools, scopes);
16154
- const actions = await topolo.client.listActions().catch(() => []);
16155
- const actionTools = actionsToToolDefs(actions);
16156
- return filterToolsByScopes([...baseTools, ...actionTools], scopes);
16157
- }
16158
- function effectiveAgentAccess(a) {
16159
- if (a.agentAccess) return a.agentAccess;
16160
- if (a.destructive) return "off";
16161
- if (a.readOnly && !a.requiresConfirmation) return "auto";
16162
- return "confirm";
16163
- }
16164
- function actionsToToolDefs(actions) {
16165
- return actions.map((action) => ({ action, access: effectiveAgentAccess(action) })).filter(({ access }) => access !== "off").map(({ action, access }) => ({
16166
- name: action.toolName || toolNameForAction(action),
16167
- title: action.title,
16168
- description: action.description,
16169
- requiredScopes: action.requiredPermission ? [action.requiredPermission] : [],
16170
- destructive: access === "confirm",
16171
- inputSchema: actionInputSchema(action, access),
16172
- handler: async (topolo, args) => {
16173
- const confirm = Boolean(args["confirm"]);
16174
- const input = { ...args };
16175
- delete input["confirm"];
16176
- return topolo.client.callAction(action.actionId, input, { confirm });
16177
- }
16178
- }));
16179
- }
16180
- function toolNameForAction(action) {
16181
- const service = (action.appSlug || action.appId || "service").replace(/^topolo-/, "").toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
16182
- const name = action.name.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
16183
- return ["topolo", service, name].filter(Boolean).join("_").slice(0, 96);
16184
- }
16185
- function actionInputSchema(action, access = "auto") {
16186
- const schema = {
16187
- type: "object",
16188
- properties: {},
16189
- additionalProperties: false,
16190
- ...action.inputSchema
16191
- };
16192
- const properties = schema.properties && typeof schema.properties === "object" && !Array.isArray(schema.properties) ? { ...schema.properties } : {};
16193
- if (access === "confirm") {
16194
- properties.confirm = {
16195
- type: "boolean",
16196
- description: "Required for mutating actions. Explicit human-in-the-loop acknowledgement."
16197
- };
16198
- }
16199
- return {
16200
- ...schema,
16201
- type: "object",
16202
- properties,
16203
- additionalProperties: schema.additionalProperties ?? false
16204
- };
16241
+ void topolo;
16242
+ return filterToolsByScopes(tools, scopes);
16205
16243
  }
16206
16244
  function evaluateApplicationAuditGate(report, threshold) {
16207
16245
  const counts = {