@topolo/mcp 0.6.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/README.md +43 -22
- package/dist/dispatch.js +143 -106
- package/dist/http.js +144 -107
- package/dist/index.js +382 -167
- package/package.json +9 -2
package/dist/http.js
CHANGED
|
@@ -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: "
|
|
15880
|
-
title: "
|
|
15881
|
-
description: "
|
|
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
|
|
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 {
|
|
15925
|
+
return { applications, page: result.page };
|
|
15908
15926
|
}
|
|
15909
15927
|
},
|
|
15910
15928
|
{
|
|
15911
|
-
name: "
|
|
15912
|
-
title: "
|
|
15913
|
-
description: "
|
|
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: "
|
|
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
|
-
|
|
15928
|
-
|
|
15929
|
-
|
|
15930
|
-
|
|
15931
|
-
|
|
15932
|
-
|
|
15933
|
-
|
|
15934
|
-
|
|
15935
|
-
|
|
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
|
|
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
|
-
|
|
15970
|
-
|
|
15971
|
-
|
|
15972
|
-
|
|
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
|
|
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
|
|
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
|
|
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: {
|
|
@@ -16096,7 +16188,7 @@ var TOOLS = [
|
|
|
16096
16188
|
},
|
|
16097
16189
|
resourceType: {
|
|
16098
16190
|
type: "string",
|
|
16099
|
-
description: "Optional workspace resource alias from
|
|
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
|
|
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
|
|
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
|
-
|
|
16154
|
-
|
|
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
|
-
};
|
|
16240
|
+
void topolo;
|
|
16241
|
+
return filterToolsByScopes(tools, scopes);
|
|
16205
16242
|
}
|
|
16206
16243
|
function evaluateApplicationAuditGate(report, threshold) {
|
|
16207
16244
|
const counts = {
|