@topolo/mcp 0.9.11 → 0.10.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/README.md +3 -0
- package/dist/dispatch.js +79 -82
- package/dist/http.js +106 -89
- package/dist/index.js +280 -190
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -104,57 +104,8 @@ var TopoloHttpError = class extends TopoloSdkError {
|
|
|
104
104
|
}
|
|
105
105
|
};
|
|
106
106
|
var APP_API_URLS = {
|
|
107
|
-
agent: "https://agent.topolo.app",
|
|
108
107
|
auth: "https://auth.topolo.app",
|
|
109
|
-
|
|
110
|
-
blog: "https://blog.topolo.app",
|
|
111
|
-
books: "https://books.topolo.app",
|
|
112
|
-
brand: "https://brand.topolo.app",
|
|
113
|
-
bugfix: "https://bugfix.topolo.app",
|
|
114
|
-
bytes: "https://bytes.topolo.app",
|
|
115
|
-
calendar: "https://calendar.topolo.app",
|
|
116
|
-
campaigns: "https://campaigns.topolo.app",
|
|
117
|
-
capacity: "https://capacity.topolo.app",
|
|
118
|
-
chat: "https://chat.topolo.app",
|
|
119
|
-
commerce: "https://commerce.topolo.app",
|
|
120
|
-
compose: "https://compose.topolo.app",
|
|
121
|
-
consent: "https://consent.topolo.app",
|
|
122
|
-
crm: "https://crm.topolo.app",
|
|
123
|
-
design: "https://design.topolo.app",
|
|
124
|
-
developers: "https://developers.topolo.app",
|
|
125
|
-
director: "https://director.topolo.app",
|
|
126
|
-
feed: "https://feed.topolo.app",
|
|
127
|
-
flow: "https://flow.topolo.app",
|
|
128
|
-
forecast: "https://forecast.topolo.app",
|
|
129
|
-
forms: "https://forms.topolo.app",
|
|
130
|
-
home: "https://home.topolo.app",
|
|
131
|
-
insights: "https://insights.topolo.app",
|
|
132
|
-
inventory: "https://inventory.topolo.app",
|
|
133
|
-
learn: "https://learn.topolo.app",
|
|
134
|
-
localize: "https://localize.topolo.app",
|
|
135
|
-
mail: "https://mail.topolo.app",
|
|
136
|
-
mdm: "https://mdm.topolo.app",
|
|
137
|
-
messages: "https://messages.topolo.app",
|
|
138
|
-
nexus: "https://nexus.topolo.app",
|
|
139
|
-
notify: "https://notify.topolo.app",
|
|
140
|
-
observability_watch: "https://observability-watch.topolo.app",
|
|
141
|
-
one: "https://www.topolo.app",
|
|
142
|
-
p2p: "https://p2p.topolo.app",
|
|
143
|
-
pay: "https://pay.topolo.app",
|
|
144
|
-
people: "https://people.topolo.app",
|
|
145
|
-
"quro.api": "https://api.ol0.me",
|
|
146
|
-
"quro.redirect": "https://ol0.me",
|
|
147
|
-
roadmapper: "https://roadmapper.topolo.app",
|
|
148
|
-
sign: "https://sign.topolo.app",
|
|
149
|
-
social_studio: "https://studio.topolo.app",
|
|
150
|
-
socialize: "https://socialize.topolo.app",
|
|
151
|
-
spaces: "https://spaces.topolo.app",
|
|
152
|
-
status: "https://status.topolo.app",
|
|
153
|
-
success: "https://success.topolo.app",
|
|
154
|
-
support: "https://support.topolo.app",
|
|
155
|
-
survey: "https://survey.topolo.app",
|
|
156
|
-
voice: "https://voice.topolo.app",
|
|
157
|
-
web: "https://web.topolo.app"
|
|
108
|
+
developers: "https://developers.topolo.app"
|
|
158
109
|
};
|
|
159
110
|
var APPLICATIONS = {
|
|
160
111
|
"admin": {
|
|
@@ -1880,7 +1831,145 @@ var APPLICATIONS = {
|
|
|
1880
1831
|
]
|
|
1881
1832
|
}
|
|
1882
1833
|
};
|
|
1883
|
-
|
|
1834
|
+
function friendlyAppId(entry) {
|
|
1835
|
+
for (const value of [entry.slug, entry.name, entry.appId]) {
|
|
1836
|
+
if (typeof value !== "string" || !value.trim()) continue;
|
|
1837
|
+
const normalized = value.trim().toLowerCase().replace(/\s+/g, "-");
|
|
1838
|
+
const withoutPrefix = normalized.replace(/^(?:app[_-])?topolo[-_]+/, "");
|
|
1839
|
+
if (withoutPrefix) return withoutPrefix;
|
|
1840
|
+
}
|
|
1841
|
+
return entry.appId;
|
|
1842
|
+
}
|
|
1843
|
+
function idVariants(value) {
|
|
1844
|
+
const normalized = value.trim().toLowerCase().replace(/\s+/g, "-");
|
|
1845
|
+
return [.../* @__PURE__ */ new Set([
|
|
1846
|
+
normalized,
|
|
1847
|
+
normalized.replace(/-/g, "_"),
|
|
1848
|
+
normalized.replace(/_/g, "-")
|
|
1849
|
+
])].filter(Boolean);
|
|
1850
|
+
}
|
|
1851
|
+
var STATIC_APPLICATIONS = APPLICATIONS;
|
|
1852
|
+
function staticApplicationForId(id) {
|
|
1853
|
+
for (const variant of idVariants(id)) {
|
|
1854
|
+
const entry = STATIC_APPLICATIONS[variant];
|
|
1855
|
+
if (entry) return entry;
|
|
1856
|
+
}
|
|
1857
|
+
return null;
|
|
1858
|
+
}
|
|
1859
|
+
function applicationEntryFromCatalog(live) {
|
|
1860
|
+
const id = friendlyAppId(live);
|
|
1861
|
+
return {
|
|
1862
|
+
id,
|
|
1863
|
+
appDir: "-",
|
|
1864
|
+
name: live.name ?? live.slug ?? live.appId,
|
|
1865
|
+
packageName: null,
|
|
1866
|
+
productionUrl: live.launchUrl ?? live.apiBaseUrl ?? null,
|
|
1867
|
+
services: live.apiBaseUrl ? [id] : [],
|
|
1868
|
+
deployTargets: []
|
|
1869
|
+
};
|
|
1870
|
+
}
|
|
1871
|
+
var DIRECTORY_PAGE_LIMIT = 100;
|
|
1872
|
+
var DIRECTORY_MAX_PAGES = 100;
|
|
1873
|
+
function staticApplicationDirectory() {
|
|
1874
|
+
const applications = Object.entries(STATIC_APPLICATIONS).map(([id, application]) => ({
|
|
1875
|
+
id,
|
|
1876
|
+
application,
|
|
1877
|
+
source: "static",
|
|
1878
|
+
live: null
|
|
1879
|
+
})).sort((left, right) => left.id.localeCompare(right.id));
|
|
1880
|
+
return { source: "static_fallback", applications };
|
|
1881
|
+
}
|
|
1882
|
+
function directoryApplicationFromLive(live) {
|
|
1883
|
+
const id = friendlyAppId(live);
|
|
1884
|
+
return {
|
|
1885
|
+
id,
|
|
1886
|
+
// Prefer the static snapshot's richer repo/deploy metadata when the live
|
|
1887
|
+
// registry confirms the app; synthesize from the live entry otherwise.
|
|
1888
|
+
application: staticApplicationForId(id) ?? applicationEntryFromCatalog(live),
|
|
1889
|
+
source: "live",
|
|
1890
|
+
live
|
|
1891
|
+
};
|
|
1892
|
+
}
|
|
1893
|
+
async function listApplicationDirectory(client) {
|
|
1894
|
+
if (!client) return staticApplicationDirectory();
|
|
1895
|
+
let services;
|
|
1896
|
+
try {
|
|
1897
|
+
services = [];
|
|
1898
|
+
let cursor;
|
|
1899
|
+
for (let page = 0; page < DIRECTORY_MAX_PAGES; page += 1) {
|
|
1900
|
+
const result = await client.searchServices({
|
|
1901
|
+
...cursor ? { cursor } : {},
|
|
1902
|
+
limit: DIRECTORY_PAGE_LIMIT
|
|
1903
|
+
});
|
|
1904
|
+
services.push(...result.services);
|
|
1905
|
+
if (!result.page.nextCursor) break;
|
|
1906
|
+
cursor = result.page.nextCursor;
|
|
1907
|
+
}
|
|
1908
|
+
} catch {
|
|
1909
|
+
return staticApplicationDirectory();
|
|
1910
|
+
}
|
|
1911
|
+
const seen = /* @__PURE__ */ new Map();
|
|
1912
|
+
for (const live of services) {
|
|
1913
|
+
const entry = directoryApplicationFromLive(live);
|
|
1914
|
+
if (!seen.has(entry.id)) seen.set(entry.id, entry);
|
|
1915
|
+
}
|
|
1916
|
+
return {
|
|
1917
|
+
source: "live",
|
|
1918
|
+
applications: [...seen.values()].sort((left, right) => left.id.localeCompare(right.id))
|
|
1919
|
+
};
|
|
1920
|
+
}
|
|
1921
|
+
function matchesDirectoryApplication(app, needle) {
|
|
1922
|
+
const candidates = new Set(idVariants(needle));
|
|
1923
|
+
const keys = [
|
|
1924
|
+
app.id,
|
|
1925
|
+
app.application.id,
|
|
1926
|
+
app.application.name,
|
|
1927
|
+
app.live?.appId,
|
|
1928
|
+
app.live?.slug,
|
|
1929
|
+
app.live?.name
|
|
1930
|
+
];
|
|
1931
|
+
for (const key of keys) {
|
|
1932
|
+
if (typeof key !== "string" || !key.trim()) continue;
|
|
1933
|
+
for (const variant of idVariants(key)) {
|
|
1934
|
+
if (candidates.has(variant)) return true;
|
|
1935
|
+
}
|
|
1936
|
+
for (const variant of idVariants(friendlyAppId({ appId: key }))) {
|
|
1937
|
+
if (candidates.has(variant)) return true;
|
|
1938
|
+
}
|
|
1939
|
+
}
|
|
1940
|
+
return false;
|
|
1941
|
+
}
|
|
1942
|
+
function formatDirectoryApplicationIds(directory) {
|
|
1943
|
+
const ids = directory.applications.map((app) => app.id).sort();
|
|
1944
|
+
const preview = ids.slice(0, 50).join(", ");
|
|
1945
|
+
const suffix = ids.length > 50 ? `, ... +${ids.length - 50} more` : "";
|
|
1946
|
+
const label = directory.source === "live" ? "Applications available to this credential" : "Applications in the bundled static snapshot (live registry unreachable)";
|
|
1947
|
+
return `${label}: ${preview}${suffix}`;
|
|
1948
|
+
}
|
|
1949
|
+
async function resolveApplicationDirectoryEntry(client, application) {
|
|
1950
|
+
const needle = typeof application === "string" ? application.trim() : "";
|
|
1951
|
+
if (!needle) {
|
|
1952
|
+
throw new TopoloSdkError("unknown_application", "application is required");
|
|
1953
|
+
}
|
|
1954
|
+
if (client) {
|
|
1955
|
+
let live = null;
|
|
1956
|
+
try {
|
|
1957
|
+
live = await client.getService(needle);
|
|
1958
|
+
} catch {
|
|
1959
|
+
live = null;
|
|
1960
|
+
}
|
|
1961
|
+
if (live) return directoryApplicationFromLive(live);
|
|
1962
|
+
}
|
|
1963
|
+
const directory = await listApplicationDirectory(client);
|
|
1964
|
+
const match = directory.applications.find((app) => matchesDirectoryApplication(app, needle));
|
|
1965
|
+
if (match) return match;
|
|
1966
|
+
throw new TopoloSdkError(
|
|
1967
|
+
"unknown_application",
|
|
1968
|
+
`Unknown application "${application}". ${formatDirectoryApplicationIds(directory)}`
|
|
1969
|
+
);
|
|
1970
|
+
}
|
|
1971
|
+
var STATIC_APPLICATIONS2 = APPLICATIONS;
|
|
1972
|
+
var APPLICATION_REQUIREMENTS_VERSION = "2026-08-11.1";
|
|
1884
1973
|
var APPLICATION_REQUIREMENTS = [
|
|
1885
1974
|
{
|
|
1886
1975
|
id: "platform-metadata",
|
|
@@ -1890,10 +1979,10 @@ var APPLICATION_REQUIREMENTS = [
|
|
|
1890
1979
|
evidence: [
|
|
1891
1980
|
"topolo.cloudcontrol.json exists for every deployed app surface",
|
|
1892
1981
|
"package.json names the package or app when the repo ships code",
|
|
1893
|
-
"The
|
|
1982
|
+
"The live platform registry exposes the app through topolo apps and MCP discovery"
|
|
1894
1983
|
],
|
|
1895
1984
|
implementation: [
|
|
1896
|
-
"
|
|
1985
|
+
"Register the app in the live platform registry (Auth service catalog) before exposing it to agents",
|
|
1897
1986
|
"Keep production URLs, Worker names, Pages projects, routes, domains, and bindings current in CloudControl metadata",
|
|
1898
1987
|
"Do not leave a new Topolo* app directory without an explicit application ID"
|
|
1899
1988
|
]
|
|
@@ -1968,7 +2057,7 @@ var APPLICATION_REQUIREMENTS = [
|
|
|
1968
2057
|
implementation: [
|
|
1969
2058
|
"Add production Worker api_url metadata and sdk_app_id for every agent-callable API target",
|
|
1970
2059
|
"Mark browser, documentation, and runtime-only Worker targets with agent_callable:false",
|
|
1971
|
-
"Expose stable app IDs through
|
|
2060
|
+
"Expose stable app IDs through live catalog discovery",
|
|
1972
2061
|
"Keep typed SDK/CLI/MCP surfaces in sync when an API contract stabilizes"
|
|
1973
2062
|
]
|
|
1974
2063
|
},
|
|
@@ -2088,15 +2177,24 @@ function applicationRequirementScopes(application) {
|
|
|
2088
2177
|
}
|
|
2089
2178
|
return Array.from(scopes);
|
|
2090
2179
|
}
|
|
2180
|
+
function fallbackApplication(id) {
|
|
2181
|
+
const entry = STATIC_APPLICATIONS2[id];
|
|
2182
|
+
if (!entry) {
|
|
2183
|
+
throw new Error(
|
|
2184
|
+
`Unknown application "${id}" in the static fallback snapshot. Resolve applications from the live registry (resolveApplicationDirectoryEntry) and pass the entry directly.`
|
|
2185
|
+
);
|
|
2186
|
+
}
|
|
2187
|
+
return entry;
|
|
2188
|
+
}
|
|
2091
2189
|
function requirementsForApplication(applicationOrId) {
|
|
2092
|
-
const application = typeof applicationOrId === "string" ?
|
|
2190
|
+
const application = typeof applicationOrId === "string" ? fallbackApplication(applicationOrId) : applicationOrId;
|
|
2093
2191
|
const scopes = new Set(applicationRequirementScopes(application));
|
|
2094
2192
|
return APPLICATION_REQUIREMENTS.filter(
|
|
2095
2193
|
(requirement) => requirement.appliesTo.some((scope) => scopes.has(scope))
|
|
2096
2194
|
);
|
|
2097
2195
|
}
|
|
2098
2196
|
function auditApplicationRequirements(applicationOrId) {
|
|
2099
|
-
const application = typeof applicationOrId === "string" ?
|
|
2197
|
+
const application = typeof applicationOrId === "string" ? fallbackApplication(applicationOrId) : applicationOrId;
|
|
2100
2198
|
const scopes = applicationRequirementScopes(application);
|
|
2101
2199
|
const findings = requirementsForApplication(application).map(
|
|
2102
2200
|
(requirement) => evaluateRequirement(application, requirement)
|
|
@@ -2109,10 +2207,12 @@ function auditApplicationRequirements(applicationOrId) {
|
|
|
2109
2207
|
findings
|
|
2110
2208
|
};
|
|
2111
2209
|
}
|
|
2112
|
-
function
|
|
2113
|
-
|
|
2114
|
-
(
|
|
2210
|
+
function auditApplicationEntries(applications) {
|
|
2211
|
+
return buildAuditReport(
|
|
2212
|
+
applications.map((application) => auditApplicationRequirements(application))
|
|
2115
2213
|
);
|
|
2214
|
+
}
|
|
2215
|
+
function buildAuditReport(applications) {
|
|
2116
2216
|
const migrationQueue = applications.flatMap(
|
|
2117
2217
|
(audit) => audit.findings.filter((finding2) => finding2.status !== "met").map((finding2) => ({
|
|
2118
2218
|
applicationId: audit.application.id,
|
|
@@ -3415,8 +3515,9 @@ var TopoloClient = class _TopoloClient {
|
|
|
3415
3515
|
});
|
|
3416
3516
|
}
|
|
3417
3517
|
/**
|
|
3418
|
-
*
|
|
3419
|
-
*
|
|
3518
|
+
* @deprecated Static fallback snapshot only. Use `searchServices()` (the
|
|
3519
|
+
* live credential-scoped registry) for anything that decides behavior; this
|
|
3520
|
+
* exists for offline packaging audits when the registry is unreachable.
|
|
3420
3521
|
*/
|
|
3421
3522
|
listBundledServices() {
|
|
3422
3523
|
const apps = Object.values(APPLICATIONS);
|
|
@@ -3807,6 +3908,52 @@ function mergeSignals(a, b) {
|
|
|
3807
3908
|
b.addEventListener("abort", onAbort, { once: true });
|
|
3808
3909
|
return controller.signal;
|
|
3809
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
|
+
}
|
|
3810
3957
|
var CrmModule = class {
|
|
3811
3958
|
constructor(client) {
|
|
3812
3959
|
this.client = client;
|
|
@@ -3995,57 +4142,8 @@ var TopoloHttpError2 = class extends TopoloSdkError2 {
|
|
|
3995
4142
|
}
|
|
3996
4143
|
};
|
|
3997
4144
|
var APP_API_URLS2 = {
|
|
3998
|
-
agent: "https://agent.topolo.app",
|
|
3999
4145
|
auth: "https://auth.topolo.app",
|
|
4000
|
-
|
|
4001
|
-
blog: "https://blog.topolo.app",
|
|
4002
|
-
books: "https://books.topolo.app",
|
|
4003
|
-
brand: "https://brand.topolo.app",
|
|
4004
|
-
bugfix: "https://bugfix.topolo.app",
|
|
4005
|
-
bytes: "https://bytes.topolo.app",
|
|
4006
|
-
calendar: "https://calendar.topolo.app",
|
|
4007
|
-
campaigns: "https://campaigns.topolo.app",
|
|
4008
|
-
capacity: "https://capacity.topolo.app",
|
|
4009
|
-
chat: "https://chat.topolo.app",
|
|
4010
|
-
commerce: "https://commerce.topolo.app",
|
|
4011
|
-
compose: "https://compose.topolo.app",
|
|
4012
|
-
consent: "https://consent.topolo.app",
|
|
4013
|
-
crm: "https://crm.topolo.app",
|
|
4014
|
-
design: "https://design.topolo.app",
|
|
4015
|
-
developers: "https://developers.topolo.app",
|
|
4016
|
-
director: "https://director.topolo.app",
|
|
4017
|
-
feed: "https://feed.topolo.app",
|
|
4018
|
-
flow: "https://flow.topolo.app",
|
|
4019
|
-
forecast: "https://forecast.topolo.app",
|
|
4020
|
-
forms: "https://forms.topolo.app",
|
|
4021
|
-
home: "https://home.topolo.app",
|
|
4022
|
-
insights: "https://insights.topolo.app",
|
|
4023
|
-
inventory: "https://inventory.topolo.app",
|
|
4024
|
-
learn: "https://learn.topolo.app",
|
|
4025
|
-
localize: "https://localize.topolo.app",
|
|
4026
|
-
mail: "https://mail.topolo.app",
|
|
4027
|
-
mdm: "https://mdm.topolo.app",
|
|
4028
|
-
messages: "https://messages.topolo.app",
|
|
4029
|
-
nexus: "https://nexus.topolo.app",
|
|
4030
|
-
notify: "https://notify.topolo.app",
|
|
4031
|
-
observability_watch: "https://observability-watch.topolo.app",
|
|
4032
|
-
one: "https://www.topolo.app",
|
|
4033
|
-
p2p: "https://p2p.topolo.app",
|
|
4034
|
-
pay: "https://pay.topolo.app",
|
|
4035
|
-
people: "https://people.topolo.app",
|
|
4036
|
-
"quro.api": "https://api.ol0.me",
|
|
4037
|
-
"quro.redirect": "https://ol0.me",
|
|
4038
|
-
roadmapper: "https://roadmapper.topolo.app",
|
|
4039
|
-
sign: "https://sign.topolo.app",
|
|
4040
|
-
social_studio: "https://studio.topolo.app",
|
|
4041
|
-
socialize: "https://socialize.topolo.app",
|
|
4042
|
-
spaces: "https://spaces.topolo.app",
|
|
4043
|
-
status: "https://status.topolo.app",
|
|
4044
|
-
success: "https://success.topolo.app",
|
|
4045
|
-
support: "https://support.topolo.app",
|
|
4046
|
-
survey: "https://survey.topolo.app",
|
|
4047
|
-
voice: "https://voice.topolo.app",
|
|
4048
|
-
web: "https://web.topolo.app"
|
|
4146
|
+
developers: "https://developers.topolo.app"
|
|
4049
4147
|
};
|
|
4050
4148
|
var DEFAULT_APP_URLS2 = APP_API_URLS2;
|
|
4051
4149
|
function resolveServiceUrl2(service, overrides) {
|
|
@@ -4412,7 +4510,6 @@ function publicMcpErrorMessage(error, fallback) {
|
|
|
4412
4510
|
}
|
|
4413
4511
|
|
|
4414
4512
|
// src/tools.ts
|
|
4415
|
-
var APPLICATION_IDS = Object.keys(APPLICATIONS).sort();
|
|
4416
4513
|
var HTTP_METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE"];
|
|
4417
4514
|
function requiredString(args, name) {
|
|
4418
4515
|
const value = typeof args[name] === "string" ? args[name].trim() : "";
|
|
@@ -4428,6 +4525,20 @@ function optionalResourceContext(args) {
|
|
|
4428
4525
|
}
|
|
4429
4526
|
return { resourceType, resourceId };
|
|
4430
4527
|
}
|
|
4528
|
+
function coerceObjectParam(value, name) {
|
|
4529
|
+
let candidate = value;
|
|
4530
|
+
if (typeof candidate === "string" && candidate.trim().startsWith("{")) {
|
|
4531
|
+
try {
|
|
4532
|
+
candidate = JSON.parse(candidate);
|
|
4533
|
+
} catch {
|
|
4534
|
+
}
|
|
4535
|
+
}
|
|
4536
|
+
if (candidate === void 0) return {};
|
|
4537
|
+
if (!candidate || typeof candidate !== "object" || Array.isArray(candidate)) {
|
|
4538
|
+
throw new TopoloMcpPublicError(`${name} must be an object.`);
|
|
4539
|
+
}
|
|
4540
|
+
return candidate;
|
|
4541
|
+
}
|
|
4431
4542
|
var TOOLS = [
|
|
4432
4543
|
{
|
|
4433
4544
|
name: "topolo_whoami",
|
|
@@ -4453,7 +4564,8 @@ var TOOLS = [
|
|
|
4453
4564
|
properties: {
|
|
4454
4565
|
query: { type: "string" },
|
|
4455
4566
|
cursor: { type: "string" },
|
|
4456
|
-
limit: { type: "integer", minimum: 1, maximum: 100, default: 25 }
|
|
4567
|
+
limit: { type: "integer", minimum: 1, maximum: 100, default: 25 },
|
|
4568
|
+
detail: { type: "boolean", description: "Return full schemas and agent contracts. Defaults to compact action guidance." }
|
|
4457
4569
|
},
|
|
4458
4570
|
additionalProperties: false
|
|
4459
4571
|
},
|
|
@@ -4507,12 +4619,13 @@ var TOOLS = [
|
|
|
4507
4619
|
handler: async (topolo, args) => {
|
|
4508
4620
|
const service = typeof args["service"] === "string" ? args["service"].trim() : "";
|
|
4509
4621
|
if (!service) throw new TopoloMcpPublicError("service is required for bounded action discovery.");
|
|
4510
|
-
|
|
4622
|
+
const result = await topolo.client.searchActions({
|
|
4511
4623
|
service,
|
|
4512
4624
|
query: typeof args["query"] === "string" ? args["query"] : void 0,
|
|
4513
4625
|
cursor: typeof args["cursor"] === "string" ? args["cursor"] : void 0,
|
|
4514
4626
|
limit: typeof args["limit"] === "number" ? args["limit"] : void 0
|
|
4515
4627
|
});
|
|
4628
|
+
return args["detail"] === true ? result : { actions: result.actions.map(compactActionCatalogEntry), page: result.page };
|
|
4516
4629
|
}
|
|
4517
4630
|
},
|
|
4518
4631
|
{
|
|
@@ -4578,14 +4691,11 @@ var TOOLS = [
|
|
|
4578
4691
|
handler: async (topolo, args) => {
|
|
4579
4692
|
const actionId = typeof args["actionId"] === "string" ? args["actionId"].trim() : "";
|
|
4580
4693
|
if (!actionId) throw new TopoloMcpPublicError("actionId is required.");
|
|
4581
|
-
const input = args["input"];
|
|
4582
|
-
if (input !== void 0 && (!input || typeof input !== "object" || Array.isArray(input))) {
|
|
4583
|
-
throw new TopoloMcpPublicError("input must be an object.");
|
|
4584
|
-
}
|
|
4694
|
+
const input = coerceObjectParam(args["input"], "input");
|
|
4585
4695
|
const resource = optionalResourceContext(args);
|
|
4586
4696
|
return topolo.client.readAction(
|
|
4587
4697
|
actionId,
|
|
4588
|
-
input
|
|
4698
|
+
input,
|
|
4589
4699
|
resource ? { resource } : {}
|
|
4590
4700
|
);
|
|
4591
4701
|
}
|
|
@@ -4611,14 +4721,11 @@ var TOOLS = [
|
|
|
4611
4721
|
handler: async (topolo, args) => {
|
|
4612
4722
|
const actionId = typeof args["actionId"] === "string" ? args["actionId"].trim() : "";
|
|
4613
4723
|
if (!actionId) throw new TopoloMcpPublicError("actionId is required.");
|
|
4614
|
-
const input = args["input"];
|
|
4615
|
-
if (input !== void 0 && (!input || typeof input !== "object" || Array.isArray(input))) {
|
|
4616
|
-
throw new TopoloMcpPublicError("input must be an object.");
|
|
4617
|
-
}
|
|
4724
|
+
const input = coerceObjectParam(args["input"], "input");
|
|
4618
4725
|
const resource = optionalResourceContext(args);
|
|
4619
4726
|
return topolo.client.callAction(
|
|
4620
4727
|
actionId,
|
|
4621
|
-
input
|
|
4728
|
+
input,
|
|
4622
4729
|
{
|
|
4623
4730
|
confirm: args["confirm"] === true,
|
|
4624
4731
|
...resource ? { resource } : {}
|
|
@@ -4657,23 +4764,17 @@ var TOOLS = [
|
|
|
4657
4764
|
if (!isCanonicalBase642(contentBase64)) throw new TopoloMcpPublicError("contentBase64 must be canonical base64.");
|
|
4658
4765
|
if (!contentType) throw new TopoloMcpPublicError("contentType is required.");
|
|
4659
4766
|
if (!fileName) throw new TopoloMcpPublicError("fileName is required.");
|
|
4660
|
-
const input = args["input"];
|
|
4661
|
-
|
|
4662
|
-
throw new TopoloMcpPublicError("input must be an object.");
|
|
4663
|
-
}
|
|
4664
|
-
const completionInput = args["completionInput"];
|
|
4665
|
-
if (completionInput !== void 0 && (!completionInput || typeof completionInput !== "object" || Array.isArray(completionInput))) {
|
|
4666
|
-
throw new TopoloMcpPublicError("completionInput must be an object.");
|
|
4667
|
-
}
|
|
4767
|
+
const input = coerceObjectParam(args["input"], "input");
|
|
4768
|
+
const completionInput = coerceObjectParam(args["completionInput"], "completionInput");
|
|
4668
4769
|
const resource = optionalResourceContext(args);
|
|
4669
4770
|
return topolo.client.uploadActionBase64(
|
|
4670
4771
|
actionId,
|
|
4671
4772
|
contentBase64,
|
|
4672
|
-
input
|
|
4773
|
+
input,
|
|
4673
4774
|
{
|
|
4674
4775
|
fileName,
|
|
4675
4776
|
contentType,
|
|
4676
|
-
completionInput
|
|
4777
|
+
completionInput,
|
|
4677
4778
|
confirm: args["confirm"] === true,
|
|
4678
4779
|
...resource ? { resource } : {}
|
|
4679
4780
|
}
|
|
@@ -4690,7 +4791,8 @@ var TOOLS = [
|
|
|
4690
4791
|
type: "object",
|
|
4691
4792
|
properties: {
|
|
4692
4793
|
actionId: { type: "string", minLength: 1 },
|
|
4693
|
-
input: { type: "object", additionalProperties: true }
|
|
4794
|
+
input: { type: "object", additionalProperties: true },
|
|
4795
|
+
detail: { type: "boolean", description: "Include the full action contract. Defaults to a compact validation result." }
|
|
4694
4796
|
},
|
|
4695
4797
|
required: ["actionId"],
|
|
4696
4798
|
additionalProperties: false
|
|
@@ -4698,11 +4800,9 @@ var TOOLS = [
|
|
|
4698
4800
|
handler: async (topolo, args) => {
|
|
4699
4801
|
const actionId = typeof args["actionId"] === "string" ? args["actionId"].trim() : "";
|
|
4700
4802
|
if (!actionId) throw new TopoloMcpPublicError("actionId is required.");
|
|
4701
|
-
const input = args["input"];
|
|
4702
|
-
|
|
4703
|
-
|
|
4704
|
-
}
|
|
4705
|
-
return topolo.client.validateActionInput(actionId, input ?? {});
|
|
4803
|
+
const input = coerceObjectParam(args["input"], "input");
|
|
4804
|
+
const result = await topolo.client.validateActionInput(actionId, input);
|
|
4805
|
+
return args["detail"] === true ? result : compactActionValidation(result.action.actionId, result.validation);
|
|
4706
4806
|
}
|
|
4707
4807
|
},
|
|
4708
4808
|
{
|
|
@@ -4718,7 +4818,8 @@ var TOOLS = [
|
|
|
4718
4818
|
input: { type: "object", additionalProperties: true },
|
|
4719
4819
|
resourceType: { type: "string", description: "Optional resource-scoping alias published in the app resource catalog (e.g. workspace, brand, merchant)." },
|
|
4720
4820
|
resourceId: { type: "string", description: "Resource id. Required when resourceType is provided." },
|
|
4721
|
-
confirm: { type: "boolean", description: "Include confirmation in the plan without executing the action." }
|
|
4821
|
+
confirm: { type: "boolean", description: "Include confirmation in the plan without executing the action." },
|
|
4822
|
+
detail: { type: "boolean", description: "Include the full action contract. Defaults to the executable request and verification plan." }
|
|
4722
4823
|
},
|
|
4723
4824
|
required: ["actionId"],
|
|
4724
4825
|
additionalProperties: false
|
|
@@ -4726,19 +4827,17 @@ var TOOLS = [
|
|
|
4726
4827
|
handler: async (topolo, args) => {
|
|
4727
4828
|
const actionId = typeof args["actionId"] === "string" ? args["actionId"].trim() : "";
|
|
4728
4829
|
if (!actionId) throw new TopoloMcpPublicError("actionId is required.");
|
|
4729
|
-
const input = args["input"];
|
|
4730
|
-
if (input !== void 0 && (!input || typeof input !== "object" || Array.isArray(input))) {
|
|
4731
|
-
throw new TopoloMcpPublicError("input must be an object.");
|
|
4732
|
-
}
|
|
4830
|
+
const input = coerceObjectParam(args["input"], "input");
|
|
4733
4831
|
const resource = optionalResourceContext(args);
|
|
4734
|
-
|
|
4832
|
+
const plan = await topolo.client.planAction(
|
|
4735
4833
|
actionId,
|
|
4736
|
-
input
|
|
4834
|
+
input,
|
|
4737
4835
|
{
|
|
4738
4836
|
confirm: args["confirm"] === true,
|
|
4739
4837
|
...resource ? { resource } : {}
|
|
4740
4838
|
}
|
|
4741
4839
|
);
|
|
4840
|
+
return args["detail"] === true ? plan : compactActionPlan(plan);
|
|
4742
4841
|
}
|
|
4743
4842
|
},
|
|
4744
4843
|
{
|
|
@@ -4772,14 +4871,18 @@ var TOOLS = [
|
|
|
4772
4871
|
destructive: false,
|
|
4773
4872
|
inputSchema: {
|
|
4774
4873
|
type: "object",
|
|
4775
|
-
properties: {
|
|
4874
|
+
properties: {
|
|
4875
|
+
service: { type: "string", minLength: 1 },
|
|
4876
|
+
detail: { type: "boolean", description: "Return full schemas and agent contracts. Defaults to compact capability guidance." }
|
|
4877
|
+
},
|
|
4776
4878
|
required: ["service"],
|
|
4777
4879
|
additionalProperties: false
|
|
4778
4880
|
},
|
|
4779
4881
|
handler: async (topolo, args) => {
|
|
4780
4882
|
const service = typeof args["service"] === "string" ? args["service"].trim() : "";
|
|
4781
4883
|
if (!service) throw new TopoloMcpPublicError("service is required.");
|
|
4782
|
-
|
|
4884
|
+
const result = await topolo.client.searchActions({ service, limit: 100 });
|
|
4885
|
+
return args["detail"] === true ? result : { actions: result.actions.map(compactActionCatalogEntry), page: result.page };
|
|
4783
4886
|
}
|
|
4784
4887
|
},
|
|
4785
4888
|
{
|
|
@@ -4910,7 +5013,7 @@ var TOOLS = [
|
|
|
4910
5013
|
},
|
|
4911
5014
|
additionalProperties: false
|
|
4912
5015
|
},
|
|
4913
|
-
handler: async (
|
|
5016
|
+
handler: async (topolo, args) => {
|
|
4914
5017
|
const application = args["application"];
|
|
4915
5018
|
if (application === void 0) {
|
|
4916
5019
|
return {
|
|
@@ -4920,12 +5023,8 @@ var TOOLS = [
|
|
|
4920
5023
|
requirements: APPLICATION_REQUIREMENTS
|
|
4921
5024
|
};
|
|
4922
5025
|
}
|
|
4923
|
-
|
|
4924
|
-
|
|
4925
|
-
`Unknown application "${String(application)}". ${formatKnownValues(APPLICATION_IDS, "applications")}`
|
|
4926
|
-
);
|
|
4927
|
-
}
|
|
4928
|
-
const app = APPLICATIONS[application];
|
|
5026
|
+
const resolved = await resolveDirectoryApplication(topolo, application);
|
|
5027
|
+
const app = resolved.application;
|
|
4929
5028
|
return {
|
|
4930
5029
|
version: APPLICATION_REQUIREMENTS_VERSION,
|
|
4931
5030
|
application: app,
|
|
@@ -4951,11 +5050,15 @@ var TOOLS = [
|
|
|
4951
5050
|
type: "string",
|
|
4952
5051
|
enum: ["missing", "needs_review", "partial"],
|
|
4953
5052
|
description: "Optional conformance gate. Returns conformanceGate.passed=false when findings at this severity or worse exist."
|
|
5053
|
+
},
|
|
5054
|
+
detail: {
|
|
5055
|
+
type: "boolean",
|
|
5056
|
+
description: "Include every finding and migration item. Defaults to per-app scores and a queue count."
|
|
4954
5057
|
}
|
|
4955
5058
|
},
|
|
4956
5059
|
additionalProperties: false
|
|
4957
5060
|
},
|
|
4958
|
-
handler: async (
|
|
5061
|
+
handler: async (topolo, args) => {
|
|
4959
5062
|
const application = args["application"];
|
|
4960
5063
|
const failOn = args["failOn"];
|
|
4961
5064
|
if (failOn !== void 0 && typeof failOn !== "string") {
|
|
@@ -4964,16 +5067,15 @@ var TOOLS = [
|
|
|
4964
5067
|
const gate = failOn ? normalizeFailOn(failOn) : null;
|
|
4965
5068
|
let report;
|
|
4966
5069
|
if (application === void 0) {
|
|
4967
|
-
|
|
4968
|
-
|
|
5070
|
+
const directory = await listApplicationDirectory(topolo.client);
|
|
5071
|
+
report = auditApplicationEntries(directory.applications.map((app) => app.application));
|
|
5072
|
+
const output2 = args["detail"] === true ? report : compactApplicationAudit(report);
|
|
5073
|
+
return gate ? { ...output2, conformanceGate: evaluateApplicationAuditGate(report, gate) } : output2;
|
|
4969
5074
|
}
|
|
4970
|
-
|
|
4971
|
-
|
|
4972
|
-
|
|
4973
|
-
|
|
4974
|
-
}
|
|
4975
|
-
report = auditAllApplicationRequirements([application]);
|
|
4976
|
-
return gate ? { ...report, conformanceGate: evaluateApplicationAuditGate(report, gate) } : report;
|
|
5075
|
+
const resolved = await resolveDirectoryApplication(topolo, application);
|
|
5076
|
+
report = auditApplicationEntries([resolved.application]);
|
|
5077
|
+
const output = args["detail"] === true ? report : compactApplicationAudit(report);
|
|
5078
|
+
return gate ? { ...output, conformanceGate: evaluateApplicationAuditGate(report, gate) } : output;
|
|
4977
5079
|
}
|
|
4978
5080
|
},
|
|
4979
5081
|
{
|
|
@@ -5112,31 +5214,19 @@ function statusesAtOrWorse(threshold) {
|
|
|
5112
5214
|
return ["missing", "needs_review", "partial"];
|
|
5113
5215
|
}
|
|
5114
5216
|
function displayAppId(entry) {
|
|
5115
|
-
|
|
5116
|
-
if (typeof value !== "string" || !value.trim()) continue;
|
|
5117
|
-
for (const candidate of appIdCandidates(value)) {
|
|
5118
|
-
if (Object.prototype.hasOwnProperty.call(DEFAULT_APP_URLS, candidate)) {
|
|
5119
|
-
return candidate;
|
|
5120
|
-
}
|
|
5121
|
-
}
|
|
5122
|
-
}
|
|
5123
|
-
return appIdCandidates(entry.slug || entry.appId)[0] || entry.appId;
|
|
5217
|
+
return friendlyAppId(entry);
|
|
5124
5218
|
}
|
|
5125
|
-
function
|
|
5126
|
-
|
|
5127
|
-
|
|
5128
|
-
|
|
5129
|
-
|
|
5130
|
-
|
|
5131
|
-
|
|
5132
|
-
|
|
5133
|
-
|
|
5134
|
-
|
|
5135
|
-
|
|
5136
|
-
const sorted = [...values].sort();
|
|
5137
|
-
const preview = sorted.slice(0, 25).join(", ");
|
|
5138
|
-
const suffix = sorted.length > 25 ? `, ... +${sorted.length - 25} more` : "";
|
|
5139
|
-
return `Run discovery for the full ${label} list. Known snapshot sample: ${preview}${suffix}`;
|
|
5219
|
+
async function resolveDirectoryApplication(topolo, application) {
|
|
5220
|
+
if (typeof application !== "string" || !application.trim()) {
|
|
5221
|
+
throw new TopoloMcpPublicError("`application` must be a non-empty string.");
|
|
5222
|
+
}
|
|
5223
|
+
try {
|
|
5224
|
+
return await resolveApplicationDirectoryEntry(topolo.client, application);
|
|
5225
|
+
} catch (error) {
|
|
5226
|
+
throw new TopoloMcpPublicError(
|
|
5227
|
+
error instanceof Error ? error.message : `Unknown application "${application}".`
|
|
5228
|
+
);
|
|
5229
|
+
}
|
|
5140
5230
|
}
|
|
5141
5231
|
|
|
5142
5232
|
// src/version.ts
|