@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/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
- backup: "https://backup.topolo.app",
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
- var APPLICATION_REQUIREMENTS_VERSION = "2026-06-07.1";
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 SDK application catalog exposes the app through topolo apps and MCP discovery"
1982
+ "The live platform registry exposes the app through topolo apps and MCP discovery"
1894
1983
  ],
1895
1984
  implementation: [
1896
- "Add the app to the SDK application catalog generator before exposing it to agents",
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 generated DEFAULT_APP_URLS and live catalog discovery",
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" ? APPLICATIONS[applicationOrId] : applicationOrId;
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" ? APPLICATIONS[applicationOrId] : applicationOrId;
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 auditAllApplicationRequirements(applicationIds = Object.keys(APPLICATIONS).sort()) {
2113
- const applications = applicationIds.map(
2114
- (applicationId) => auditApplicationRequirements(applicationId)
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
- * Bundled generated registry for tooling that audits platform packaging, not
3419
- * for deciding what the current credential may use.
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
- backup: "https://backup.topolo.app",
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
- return topolo.client.searchActions({
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
- if (input !== void 0 && (!input || typeof input !== "object" || Array.isArray(input))) {
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: 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
- if (input !== void 0 && (!input || typeof input !== "object" || Array.isArray(input))) {
4703
- throw new TopoloMcpPublicError("input must be an object.");
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
- return topolo.client.planAction(
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: { service: { type: "string", minLength: 1 } },
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
- return topolo.client.searchActions({ service, limit: 100 });
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 (_topolo, args) => {
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
- if (typeof application !== "string" || !APPLICATION_IDS.includes(application)) {
4924
- throw new TopoloMcpPublicError(
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 (_topolo, args) => {
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
- report = auditAllApplicationRequirements();
4968
- return gate ? { ...report, conformanceGate: evaluateApplicationAuditGate(report, gate) } : report;
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
- if (typeof application !== "string" || !APPLICATION_IDS.includes(application)) {
4971
- throw new TopoloMcpPublicError(
4972
- `Unknown application "${String(application)}". ${formatKnownValues(APPLICATION_IDS, "applications")}`
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
- for (const value of [entry.slug, entry.name, entry.appId]) {
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 appIdCandidates(value) {
5126
- const normalized = value.trim().toLowerCase().replace(/\s+/g, "-");
5127
- const withoutTopolo = normalized.startsWith("topolo-") ? normalized.slice("topolo-".length) : normalized;
5128
- return [.../* @__PURE__ */ new Set([
5129
- normalized,
5130
- normalized.replace(/-/g, "_"),
5131
- withoutTopolo,
5132
- withoutTopolo.replace(/-/g, "_")
5133
- ])].filter(Boolean);
5134
- }
5135
- function formatKnownValues(values, label) {
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