@topolo/mcp 0.5.0 → 0.7.0

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
@@ -15814,7 +15814,7 @@ import {
15814
15814
  APPLICATION_REQUIREMENTS,
15815
15815
  APPLICATION_REQUIREMENTS_VERSION,
15816
15816
  APPLICATIONS,
15817
- DEFAULT_SERVICE_URLS,
15817
+ DEFAULT_APP_URLS,
15818
15818
  auditAllApplicationRequirements,
15819
15819
  applicationRequirementScopes,
15820
15820
  requirementsForApplication,
@@ -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,18 +15885,27 @@ 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 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,
@@ -15904,13 +15922,13 @@ var TOOLS = [
15904
15922
  permissions: [...entry.permissions]
15905
15923
  };
15906
15924
  }).sort((left, right) => left.id.localeCompare(right.id));
15907
- return { services };
15925
+ return { applications, page: result.page };
15908
15926
  }
15909
15927
  },
15910
15928
  {
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.",
15929
+ name: "topolo_search_actions",
15930
+ title: "Search Topolo actions the agent can call",
15931
+ description: "Searches one application's credential-scoped actions with a bounded page and continuation cursor.",
15914
15932
  requiredScopes: [],
15915
15933
  destructive: false,
15916
15934
  inputSchema: {
@@ -15918,31 +15936,25 @@ var TOOLS = [
15918
15936
  properties: {
15919
15937
  service: {
15920
15938
  type: "string",
15921
- description: "Optional app id, slug, or name filter."
15922
- }
15939
+ description: "Required app id, slug, or name."
15940
+ },
15941
+ query: { type: "string" },
15942
+ cursor: { type: "string" },
15943
+ limit: { type: "integer", minimum: 1, maximum: 100, default: 25 }
15923
15944
  },
15945
+ required: ["service"],
15924
15946
  additionalProperties: false
15925
15947
  },
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
- })
15948
+ handler: async (topolo, args) => {
15949
+ const service = typeof args["service"] === "string" ? args["service"].trim() : "";
15950
+ if (!service) throw new Error("service is required for bounded action discovery.");
15951
+ return topolo.client.searchActions({
15952
+ service,
15953
+ query: typeof args["query"] === "string" ? args["query"] : void 0,
15954
+ cursor: typeof args["cursor"] === "string" ? args["cursor"] : void 0,
15955
+ limit: typeof args["limit"] === "number" ? args["limit"] : void 0
15956
+ });
15957
+ }
15946
15958
  },
15947
15959
  {
15948
15960
  name: "topolo_get_application",
@@ -15955,7 +15967,7 @@ var TOOLS = [
15955
15967
  properties: {
15956
15968
  application: {
15957
15969
  type: "string",
15958
- description: "Application identifier: app id, slug, or name from topolo_list_applications."
15970
+ description: "Application identifier: app id, slug, or name from topolo_search_applications."
15959
15971
  }
15960
15972
  },
15961
15973
  required: ["application"],
@@ -15966,18 +15978,98 @@ var TOOLS = [
15966
15978
  if (typeof application !== "string" || !application.trim()) {
15967
15979
  throw new Error("`application` must be a non-empty string.");
15968
15980
  }
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
15981
+ return { application: await topolo.client.getService(application) };
15982
+ }
15983
+ },
15984
+ {
15985
+ name: "topolo_get_action",
15986
+ title: "Describe one Topolo action",
15987
+ description: "Returns one credential-scoped action by exact action id.",
15988
+ requiredScopes: [],
15989
+ destructive: false,
15990
+ inputSchema: {
15991
+ type: "object",
15992
+ properties: { actionId: { type: "string", minLength: 1 } },
15993
+ required: ["actionId"],
15994
+ additionalProperties: false
15995
+ },
15996
+ handler: async (topolo, args) => {
15997
+ const actionId = typeof args["actionId"] === "string" ? args["actionId"].trim() : "";
15998
+ if (!actionId) throw new Error("actionId is required.");
15999
+ return { action: await topolo.client.getAction(actionId) };
16000
+ }
16001
+ },
16002
+ {
16003
+ name: "topolo_read_action",
16004
+ title: "Call one read-only Topolo action",
16005
+ description: "Calls one exact action id only when its published contract is read-only and needs no confirmation.",
16006
+ requiredScopes: [],
16007
+ destructive: false,
16008
+ inputSchema: {
16009
+ type: "object",
16010
+ properties: {
16011
+ actionId: { type: "string", minLength: 1 },
16012
+ input: { type: "object", additionalProperties: true },
16013
+ resourceType: { type: "string", description: "Optional app-local resource alias, such as workspace." },
16014
+ resourceId: { type: "string", description: "Resource id. Required when resourceType is provided." }
16015
+ },
16016
+ required: ["actionId"],
16017
+ additionalProperties: false
16018
+ },
16019
+ handler: async (topolo, args) => {
16020
+ const actionId = typeof args["actionId"] === "string" ? args["actionId"].trim() : "";
16021
+ if (!actionId) throw new Error("actionId is required.");
16022
+ const input = args["input"];
16023
+ if (input !== void 0 && (!input || typeof input !== "object" || Array.isArray(input))) {
16024
+ throw new Error("input must be an object.");
16025
+ }
16026
+ const action = await topolo.client.getAction(actionId);
16027
+ const agentAccess = action.agentAccess ?? (action.destructive ? "off" : action.readOnly && !action.requiresConfirmation ? "auto" : "confirm");
16028
+ if (action.method !== "GET" || !action.readOnly || action.destructive || action.requiresConfirmation || agentAccess !== "auto") {
16029
+ throw new Error(`Action "${actionId}" is not an automatic read-only action. Use topolo_call_action with confirmation.`);
16030
+ }
16031
+ const resource = optionalResourceContext(args);
16032
+ return topolo.client.callAction(
16033
+ actionId,
16034
+ input ?? {},
16035
+ resource ? { resource } : {}
16036
+ );
16037
+ }
16038
+ },
16039
+ {
16040
+ name: "topolo_call_action",
16041
+ title: "Call one Topolo action",
16042
+ description: "Calls one exact action id. Mutating actions require confirm:true.",
16043
+ requiredScopes: [],
16044
+ destructive: true,
16045
+ inputSchema: {
16046
+ type: "object",
16047
+ properties: {
16048
+ actionId: { type: "string", minLength: 1 },
16049
+ input: { type: "object", additionalProperties: true },
16050
+ resourceType: { type: "string", description: "Optional app-local resource alias, such as workspace." },
16051
+ resourceId: { type: "string", description: "Resource id. Required when resourceType is provided." },
16052
+ confirm: { type: "boolean" }
16053
+ },
16054
+ required: ["actionId"],
16055
+ additionalProperties: false
16056
+ },
16057
+ handler: async (topolo, args) => {
16058
+ const actionId = typeof args["actionId"] === "string" ? args["actionId"].trim() : "";
16059
+ if (!actionId) throw new Error("actionId is required.");
16060
+ const input = args["input"];
16061
+ if (input !== void 0 && (!input || typeof input !== "object" || Array.isArray(input))) {
16062
+ throw new Error("input must be an object.");
16063
+ }
16064
+ const resource = optionalResourceContext(args);
16065
+ return topolo.client.callAction(
16066
+ actionId,
16067
+ input ?? {},
16068
+ {
16069
+ confirm: args["confirm"] === true,
16070
+ ...resource ? { resource } : {}
16071
+ }
15973
16072
  );
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
16073
  }
15982
16074
  },
15983
16075
  {
@@ -15991,7 +16083,7 @@ var TOOLS = [
15991
16083
  properties: {
15992
16084
  application: {
15993
16085
  type: "string",
15994
- description: "Optional application ID from topolo_list_applications."
16086
+ description: "Optional application ID from topolo_search_applications."
15995
16087
  }
15996
16088
  },
15997
16089
  additionalProperties: false
@@ -16031,7 +16123,7 @@ var TOOLS = [
16031
16123
  properties: {
16032
16124
  application: {
16033
16125
  type: "string",
16034
- description: "Optional application ID from topolo_list_applications."
16126
+ description: "Optional application ID from topolo_search_applications."
16035
16127
  },
16036
16128
  failOn: {
16037
16129
  type: "string",
@@ -16065,7 +16157,7 @@ var TOOLS = [
16065
16157
  {
16066
16158
  name: "topolo_api_call",
16067
16159
  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 service IDs; the SDK can also resolve live Auth-catalog service ids/slugs for newly registered API surfaces.",
16160
+ 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
16161
  requiredScopes: [],
16070
16162
  destructive: true,
16071
16163
  inputSchema: {
@@ -16073,7 +16165,7 @@ var TOOLS = [
16073
16165
  properties: {
16074
16166
  service: {
16075
16167
  type: "string",
16076
- description: "Target service ID from the platform registry."
16168
+ description: "Target app ID from the platform registry."
16077
16169
  },
16078
16170
  method: {
16079
16171
  type: "string",
@@ -16096,7 +16188,7 @@ var TOOLS = [
16096
16188
  },
16097
16189
  resourceType: {
16098
16190
  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."
16191
+ 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
16192
  },
16101
16193
  resourceId: {
16102
16194
  type: "string",
@@ -16114,7 +16206,7 @@ var TOOLS = [
16114
16206
  const service = args["service"];
16115
16207
  const path = args["path"];
16116
16208
  if (typeof service !== "string" || !service.trim()) {
16117
- throw new Error("service is required. Call topolo_list_services first to discover callable services.");
16209
+ throw new Error("service is required. Call topolo_search_applications first to discover callable services.");
16118
16210
  }
16119
16211
  if (typeof path !== "string" || !path) {
16120
16212
  throw new Error("path is required");
@@ -16128,12 +16220,7 @@ var TOOLS = [
16128
16220
  const normalisedQuery = query && typeof query === "object" && !Array.isArray(query) ? Object.fromEntries(
16129
16221
  Object.entries(query).map(([k, v]) => [k, String(v)])
16130
16222
  ) : 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;
16223
+ const resource = optionalResourceContext(args);
16137
16224
  return topolo.client.request({
16138
16225
  service: service.trim(),
16139
16226
  method,
@@ -16150,58 +16237,8 @@ function filterToolsByScopes(tools, scopes) {
16150
16237
  return tools.filter((t) => hasAnyScope(scopes, t.requiredScopes));
16151
16238
  }
16152
16239
  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.serviceSlug || 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
- };
16240
+ void topolo;
16241
+ return filterToolsByScopes(tools, scopes);
16205
16242
  }
16206
16243
  function evaluateApplicationAuditGate(report, threshold) {
16207
16244
  const counts = {
@@ -16243,7 +16280,7 @@ function displayAppId(entry) {
16243
16280
  for (const value of [entry.slug, entry.name, entry.appId]) {
16244
16281
  if (typeof value !== "string" || !value.trim()) continue;
16245
16282
  for (const candidate of appIdCandidates(value)) {
16246
- if (Object.prototype.hasOwnProperty.call(DEFAULT_SERVICE_URLS, candidate)) {
16283
+ if (Object.prototype.hasOwnProperty.call(DEFAULT_APP_URLS, candidate)) {
16247
16284
  return candidate;
16248
16285
  }
16249
16286
  }