@tool-bridge/server 0.22.1 → 0.24.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.
Files changed (110) hide show
  1. package/dist/admin.js +2 -2
  2. package/dist/{airtable-ML2GIGCH.js → airtable-Z6KEL3MA.js} +6 -6
  3. package/dist/{alt_text_generator_ai-FGYQAF2A.js → alt_text_generator_ai-RM2GHSNM.js} +5 -5
  4. package/dist/{amap-G7V65NGK.js → amap-YEJLGIKY.js} +5 -5
  5. package/dist/{anthropic-6ZK24TBB.js → anthropic-62M4MUVQ.js} +6 -6
  6. package/dist/{apify-VDGYHP6W.js → apify-AHRNDBCB.js} +6 -6
  7. package/dist/{brave_search-TAATLZOS.js → brave_search-JAHWOMQC.js} +6 -6
  8. package/dist/{chunk-HA4BGL6C.js → chunk-7MUNQNXG.js} +486 -450
  9. package/dist/{chunk-RTW5VRTK.js → chunk-FZV7CF7L.js} +3 -3
  10. package/dist/{chunk-7ISGFRC6.js → chunk-GQ4O7NK5.js} +1 -1
  11. package/dist/{chunk-RMAWSG7E.js → chunk-LD7KQRQ3.js} +372 -554
  12. package/dist/{chunk-BNMLA2RC.js → chunk-NG4C7YB3.js} +3 -3
  13. package/dist/{chunk-X7ZUTKHR.js → chunk-SU6Q4RAY.js} +2 -2
  14. package/dist/{chunk-UY6ANCOY.js → chunk-TH3H5YAG.js} +1 -1
  15. package/dist/{chunk-2IAI3XQM.js → chunk-U2UGFSOX.js} +2 -2
  16. package/dist/{circleci-BQ2UWXL2.js → circleci-UJUYBIAO.js} +6 -6
  17. package/dist/{clerk-2JYWQNOI.js → clerk-FCFM3WJK.js} +6 -6
  18. package/dist/{cohere-6MI7AQM4.js → cohere-OTSYSMPC.js} +6 -6
  19. package/dist/{confluence-6Y6GDETF.js → confluence-LPANSCGT.js} +6 -6
  20. package/dist/{convertapi-HBZCSWOX.js → convertapi-AJZOVUHT.js} +4 -4
  21. package/dist/{currencyapi-337U5TGI.js → currencyapi-HGK5FSGO.js} +6 -6
  22. package/dist/{deepseek-OSPASO7O.js → deepseek-7HMTFJRV.js} +6 -6
  23. package/dist/{docker_hub-3ATQOY5L.js → docker_hub-FCNVKJZW.js} +5 -5
  24. package/dist/{dropbox-LSA4GM2Y.js → dropbox-2XVKCQZE.js} +6 -6
  25. package/dist/{dub-VZPJSPI6.js → dub-CTUKPX2A.js} +6 -6
  26. package/dist/{e2b-6SDYQZL2.js → e2b-ULEWTRKI.js} +6 -6
  27. package/dist/{exa-B6EUYDVP.js → exa-QENFV3AU.js} +6 -6
  28. package/dist/{fal_ai-K4Q27IME.js → fal_ai-TQYUBBAF.js} +6 -6
  29. package/dist/{feishu-4TKXG4SU.js → feishu-OYCWDSHD.js} +3 -3
  30. package/dist/{feishu_custom_bot-7CTEAKRB.js → feishu_custom_bot-VYQ7A3PU.js} +4 -4
  31. package/dist/{figma-OUKSZLD5.js → figma-5DLOKAQQ.js} +6 -6
  32. package/dist/{firehydrant-7MOYL7QH.js → firehydrant-X4MGP2OI.js} +6 -6
  33. package/dist/{fixer-H2BV2NO4.js → fixer-LMIWM3ZX.js} +5 -5
  34. package/dist/{fly-PXKY6PNH.js → fly-J5HN5L2I.js} +6 -6
  35. package/dist/{front-UZYIV5DW.js → front-E3SMBQW3.js} +6 -6
  36. package/dist/{geocodio-NSYO7TFP.js → geocodio-AOINRPLA.js} +5 -5
  37. package/dist/{ghost-QBKKQQMF.js → ghost-E4CBGZWJ.js} +5 -5
  38. package/dist/{github-ENLSJ4CL.js → github-PGR6U3FC.js} +6 -6
  39. package/dist/{gmail-KQSDEB47.js → gmail-XNQHMQ6F.js} +6 -6
  40. package/dist/{googlecalendar-5YCX4SZF.js → googlecalendar-RE6DGG7L.js} +6 -6
  41. package/dist/{googledocs-SSWIVFKA.js → googledocs-CX2BZDQH.js} +4 -4
  42. package/dist/{grafana-TF2LXDQA.js → grafana-GX75ZA5X.js} +6 -6
  43. package/dist/{graphhopper-CURBVHYK.js → graphhopper-XMUYLWHS.js} +5 -5
  44. package/dist/index.js +5 -5
  45. package/dist/{ip2proxy-YNVMTZEM.js → ip2proxy-ZGIRBAG5.js} +5 -5
  46. package/dist/{ipgeolocation_io-NAU7VJ4J.js → ipgeolocation_io-MAP27QMO.js} +5 -5
  47. package/dist/{ipqualityscore-OT63L4TI.js → ipqualityscore-6IIUUAQ2.js} +5 -5
  48. package/dist/{jina_ai-6WBMBGWM.js → jina_ai-GGH77RQH.js} +6 -6
  49. package/dist/{jira-DVDVTHNO.js → jira-7GPZW6HZ.js} +6 -6
  50. package/dist/{langsmith-IM5N4YAU.js → langsmith-CJXYE7WM.js} +6 -6
  51. package/dist/{lemlist-277SHUQF.js → lemlist-OYPOX6GN.js} +6 -6
  52. package/dist/{linear-AEPH7B5V.js → linear-TPQ6X4XZ.js} +4 -4
  53. package/dist/{logsnag-VEWRAGBG.js → logsnag-HT2PRLIV.js} +6 -6
  54. package/dist/main.js +5 -5
  55. package/dist/{mattermost-Q3A2BIZA.js → mattermost-6IYTWTM5.js} +6 -6
  56. package/dist/{mem0-AXS7GZGI.js → mem0-7AVGBGOX.js} +6 -6
  57. package/dist/{memos-7TXG4ZTU.js → memos-CTOXWZ6X.js} +6 -6
  58. package/dist/{metabase-NSVACWQM.js → metabase-AFJXQ5SQ.js} +6 -6
  59. package/dist/{mistral_ai-YZ52RGD4.js → mistral_ai-QDKM4N3R.js} +6 -6
  60. package/dist/{mother_duck-XLLL6FVL.js → mother_duck-XSKR4GVL.js} +6 -6
  61. package/dist/{ngrok-4O4W3WZW.js → ngrok-NQMLM24P.js} +6 -6
  62. package/dist/{notes-YTB3TJOO.js → notes-ZWMVZQWJ.js} +2 -2
  63. package/dist/{notion-4W4O7J7V.js → notion-6544KSMM.js} +6 -6
  64. package/dist/{open_exchange_rates-23QJXVO5.js → open_exchange_rates-4CLN7O2N.js} +5 -5
  65. package/dist/{openai-ZS7GLSLH.js → openai-HLFGPVI5.js} +6 -6
  66. package/dist/{opengraph_io-PMVH7OYI.js → opengraph_io-57JDHT3M.js} +5 -5
  67. package/dist/{openrouter-ONRGFNB6.js → openrouter-WDAVB2OP.js} +6 -6
  68. package/dist/{outline-UCUYZZ7J.js → outline-A6MDLZVH.js} +6 -6
  69. package/dist/{paddle-35HTKTUL.js → paddle-WX5ULOPP.js} +6 -6
  70. package/dist/{perplexity-NVOBYN24.js → perplexity-LYTWWWCZ.js} +6 -6
  71. package/dist/{pinecone-55CJY73C.js → pinecone-7KAF3S7U.js} +6 -6
  72. package/dist/{pipedrive-WMCAKS72.js → pipedrive-YQY243G7.js} +6 -6
  73. package/dist/{polar-SM4ZM53B.js → polar-A5HKXSQY.js} +6 -6
  74. package/dist/{posthog-NWCXVXNJ.js → posthog-CF2LHLS4.js} +6 -6
  75. package/dist/{postmark-QJV5PHUQ.js → postmark-W756TMJM.js} +6 -6
  76. package/dist/{prerender-2W7UT4SC.js → prerender-ZYM4UQ5R.js} +5 -5
  77. package/dist/{pubmed-VVV7XYLU.js → pubmed-QXTUQCTQ.js} +4 -4
  78. package/dist/{railway-KGI57S3O.js → railway-F4MOZ3LQ.js} +4 -4
  79. package/dist/{readwise-AGHTQB42.js → readwise-S7MF5SR5.js} +6 -6
  80. package/dist/{render-O4HBROCK.js → render-D7EIVDUA.js} +6 -6
  81. package/dist/{replicate-KWBOMX7D.js → replicate-ABNKPZR7.js} +6 -6
  82. package/dist/{resend-DRH6Y6I4.js → resend-7VJEY4KC.js} +6 -6
  83. package/dist/{rootly-XGCUDW6X.js → rootly-UMFJOKXC.js} +6 -6
  84. package/dist/{scrapfly-OIQ3OY6L.js → scrapfly-UDT4KNFL.js} +5 -5
  85. package/dist/{scrapingbee-OCZO4FHX.js → scrapingbee-XTFD54NB.js} +5 -5
  86. package/dist/{screenshot_fyi-CUNGFZOC.js → screenshot_fyi-5GTW3SFY.js} +5 -5
  87. package/dist/{semantic_scholar-3UJRLKES.js → semantic_scholar-Y6WK2MST.js} +6 -6
  88. package/dist/{sentry-5BWVZFJV.js → sentry-ZFPGDA6C.js} +6 -6
  89. package/dist/{shodan-HI37CTEW.js → shodan-3SCDBOQ3.js} +5 -5
  90. package/dist/{shopify-LJ2EV2HH.js → shopify-LMTBS2I2.js} +6 -6
  91. package/dist/{stripe-3LHMV55K.js → stripe-4JQJ2CUG.js} +4 -4
  92. package/dist/{supabase-H2KPX3Q2.js → supabase-7HA3BEFK.js} +6 -6
  93. package/dist/{tavily-FBEWGH3Z.js → tavily-H34ZBPGC.js} +6 -6
  94. package/dist/{telegram-MYYO3JND.js → telegram-CRX4YWQ3.js} +5 -5
  95. package/dist/{telnyx-H4ALEGAX.js → telnyx-TIKGEU34.js} +6 -6
  96. package/dist/{todoist-OBWICA5Q.js → todoist-LU563DGZ.js} +6 -6
  97. package/dist/{trello-GUFUJRWO.js → trello-NTRGEROX.js} +5 -5
  98. package/dist/{turso-NIAK4UMS.js → turso-EY3CNVPZ.js} +6 -6
  99. package/dist/{twilio-K6SLK2CX.js → twilio-ICX3WRQH.js} +4 -4
  100. package/dist/{umami-42RS2EPS.js → umami-NPMRVI3M.js} +6 -6
  101. package/dist/{unsplash-V7TOTETT.js → unsplash-TIHBZFIM.js} +6 -6
  102. package/dist/{upstash_redis-AWQMB6Y3.js → upstash_redis-2DO6EHCN.js} +6 -6
  103. package/dist/{uptimerobot-AZC2DHOT.js → uptimerobot-BGYOCKGI.js} +4 -4
  104. package/dist/{v2ex-4TVRNMLS.js → v2ex-GOWDPGGA.js} +6 -6
  105. package/dist/{vercel-DPHTJ3XR.js → vercel-G33RXVBI.js} +6 -6
  106. package/dist/{wolfram_alpha_api-XAG7IXBW.js → wolfram_alpha_api-IRZSMD3P.js} +5 -5
  107. package/dist/{wordpress-KMPKVGUX.js → wordpress-ATWGGUC3.js} +6 -6
  108. package/dist/{workos-PKB2YR7S.js → workos-LHJDETBX.js} +6 -6
  109. package/dist/{zhihu-Y4H4XYPB.js → zhihu-IAH53YPP.js} +6 -6
  110. package/package.json +3 -3
@@ -10,15 +10,14 @@ import {
10
10
  import {
11
11
  BootstrapStateStore,
12
12
  package_default
13
- } from "./chunk-2IAI3XQM.js";
13
+ } from "./chunk-U2UGFSOX.js";
14
14
  import {
15
15
  createGuardedFetch
16
- } from "./chunk-7ISGFRC6.js";
16
+ } from "./chunk-GQ4O7NK5.js";
17
17
  import {
18
18
  AnnotationStore,
19
19
  CONTEXT_CAPABILITIES,
20
20
  CONTEXT_DIRECT_UPLOAD_CAPABILITY,
21
- DEFAULT_MAX_NODES,
22
21
  DEVICE_CALL_TIMEOUT_MS,
23
22
  DeviceGatewaySession,
24
23
  DeviceMailboxService,
@@ -35,6 +34,7 @@ import {
35
34
  MAX_TREE_DEPTH,
36
35
  NodeRegistryStore,
37
36
  OAUTH_CLIENT_FIELDS,
37
+ OperationRegistry,
38
38
  PG_SEARCH_INSERT_ROWS_MAX,
39
39
  PG_SEARCH_SCHEMA_STATEMENTS,
40
40
  PG_SEARCH_SNAPSHOTS_COLUMNS,
@@ -72,6 +72,7 @@ import {
72
72
  buildHttpRequest,
73
73
  buildTokenRequest,
74
74
  buildTree,
75
+ canonicalizePath,
75
76
  catalogSetDigest,
76
77
  check,
77
78
  checkAllowlist,
@@ -99,6 +100,7 @@ import {
99
100
  deploymentSettingsSchema,
100
101
  derivePresence,
101
102
  deviceDirectoryHelpModel,
103
+ deviceEnvironmentSchema,
102
104
  deviceFsHelpModel,
103
105
  deviceOperationClaimRequestSchema,
104
106
  deviceOperationClaimResponseSchema,
@@ -109,6 +111,7 @@ import {
109
111
  deviceOperationListResponseSchema,
110
112
  deviceOperationRenewRequestSchema,
111
113
  deviceOperationRenewResponseSchema,
114
+ deviceOperationStateSchema,
112
115
  deviceOperationSummarySchema,
113
116
  deviceShellHelpModel,
114
117
  dispatchContextCmd,
@@ -176,6 +179,7 @@ import {
176
179
  storeUri,
177
180
  tbErrorBodySchema,
178
181
  toolHelpModel,
182
+ toolSearchOptionsSchema,
179
183
  toolSearchPageSchema,
180
184
  toolSearchRelevanceSchema,
181
185
  toolSearchRequestSchema,
@@ -188,7 +192,7 @@ import {
188
192
  validatePath,
189
193
  validateStoreTokenKeyring,
190
194
  virtualizeTools
191
- } from "./chunk-HA4BGL6C.js";
195
+ } from "./chunk-7MUNQNXG.js";
192
196
 
193
197
  // src/config.ts
194
198
  function runtimeAppSettings(settings, instanceId) {
@@ -216,7 +220,7 @@ function runtimeAppSettings(settings, instanceId) {
216
220
  // ../app/package.json
217
221
  var package_default2 = {
218
222
  name: "@tool-bridge/app",
219
- version: "0.21.0",
223
+ version: "0.23.0",
220
224
  description: "Host-neutral HTBP application: assemble the tool-bridge tree on any runtime by injecting state, object, secret, device-channel and search adapters",
221
225
  type: "module",
222
226
  license: "MIT",
@@ -254,7 +258,8 @@ var package_default2 = {
254
258
  "@modelcontextprotocol/client": "catalog:",
255
259
  "@modelcontextprotocol/core": "catalog:",
256
260
  "@modelcontextprotocol/server": "catalog:",
257
- hono: "catalog:"
261
+ hono: "catalog:",
262
+ zod: "catalog:"
258
263
  },
259
264
  devDependencies: {
260
265
  "@modelcontextprotocol/sdk": "catalog:",
@@ -262,8 +267,7 @@ var package_default2 = {
262
267
  "@tool-bridge/plugins": "workspace:*",
263
268
  tsup: "catalog:",
264
269
  typescript: "catalog:",
265
- vitest: "catalog:",
266
- zod: "catalog:"
270
+ vitest: "catalog:"
267
271
  },
268
272
  repository: {
269
273
  type: "git",
@@ -13607,8 +13611,8 @@ var require_utils = /* @__PURE__ */ __commonJSMin2(((exports, module) => {
13607
13611
  }
13608
13612
  function consumeHextets(buffer, address, output) {
13609
13613
  if (buffer.length) {
13610
- const hex2 = stringArrayToHexStripped(buffer);
13611
- if (hex2 !== "") address.push(hex2);
13614
+ const hex = stringArrayToHexStripped(buffer);
13615
+ if (hex !== "") address.push(hex);
13612
13616
  else {
13613
13617
  output.error = true;
13614
13618
  return false;
@@ -19302,6 +19306,10 @@ async function processDeviceHello(opts) {
19302
19306
  throw new TBError("permission_denied", `no scope grants 'register' on '${mountPath}'`);
19303
19307
  }
19304
19308
  if (hello.expose.fs !== void 0) assertFsRoots(hello.expose.fs.roots);
19309
+ const environment = hello.expose.environment === void 0 ? void 0 : deviceEnvironmentSchema.safeParse(hello.expose.environment);
19310
+ if (environment !== void 0 && !environment.success) {
19311
+ throw new TBError("invalid_argument", "device environment contains invalid or unsupported fields");
19312
+ }
19305
19313
  const inputs = nodesForHello(mountPath, hello.deviceId, hello.expose);
19306
19314
  const registry = new NodeRegistryStore(store);
19307
19315
  for (const input of inputs) {
@@ -19320,7 +19328,12 @@ async function processDeviceHello(opts) {
19320
19328
  input,
19321
19329
  authCtx.keyId,
19322
19330
  now,
19323
- input.path === mountPath ? { deviceId: hello.deviceId, online: true, lastSeenAt: now } : {}
19331
+ input.path === mountPath ? {
19332
+ deviceId: hello.deviceId,
19333
+ online: true,
19334
+ lastSeenAt: now,
19335
+ ...environment === void 0 ? {} : { deviceEnvironment: environment.data, deviceReportedAt: now }
19336
+ } : {}
19324
19337
  );
19325
19338
  } catch (error) {
19326
19339
  await searchSync?.abort(marker);
@@ -24524,8 +24537,8 @@ function syntheticElicitationId() {
24524
24537
  webCrypto.getRandomValues(bytes);
24525
24538
  bytes[6] = bytes[6] & 15 | 64;
24526
24539
  bytes[8] = bytes[8] & 63 | 128;
24527
- const hex2 = [...bytes].map((byte) => byte.toString(16).padStart(2, "0")).join("");
24528
- return `${hex2.slice(0, 8)}-${hex2.slice(8, 12)}-${hex2.slice(12, 16)}-${hex2.slice(16, 20)}-${hex2.slice(20)}`;
24540
+ const hex = [...bytes].map((byte) => byte.toString(16).padStart(2, "0")).join("");
24541
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
24529
24542
  }
24530
24543
  function legacyShimFailure(method, message) {
24531
24544
  if (method === "tools/call") return {
@@ -27003,24 +27016,6 @@ function createMcpHandler(factory, options = {}) {
27003
27016
  }
27004
27017
 
27005
27018
  // ../app/src/mcpServer.ts
27006
- function hex(bytes) {
27007
- return [...bytes].map((byte) => byte.toString(16).padStart(2, "0")).join("");
27008
- }
27009
- function mcpToolIdentity(invokePath, toolName) {
27010
- return JSON.stringify([invokePath, toolName]);
27011
- }
27012
- async function mcpToolName(identity2) {
27013
- const encoded = [...new TextEncoder().encode(identity2)].map((byte) => {
27014
- const char = String.fromCharCode(byte);
27015
- if (/[A-Za-z0-9.-]/.test(char)) return char;
27016
- if (char === "_") return "__";
27017
- return `_${byte.toString(16).padStart(2, "0")}`;
27018
- }).join("");
27019
- const prefixed = `tb_${encoded}`;
27020
- if (prefixed.length <= 128) return prefixed;
27021
- const digest = new Uint8Array(await crypto.subtle.digest("SHA-256", new TextEncoder().encode(identity2)));
27022
- return `tb_${encoded.slice(0, 60)}_${hex(digest)}`;
27023
- }
27024
27019
  var SUBSCHEMA_KEYS = [
27025
27020
  "additionalProperties",
27026
27021
  "contains",
@@ -27050,7 +27045,10 @@ function assertSchemaShape(value, path, depth = 0) {
27050
27045
  if (depth >= MAX_SCHEMA_DEPTH) throw new Error(`JSON Schema nested too deeply at '${path}'`);
27051
27046
  const schema = value;
27052
27047
  for (const key of SUBSCHEMA_KEYS) {
27053
- if (schema[key] !== void 0) assertSchemaShape(schema[key], `${path}/${key}`, depth + 1);
27048
+ const sub = schema[key];
27049
+ if (key === "items" && Array.isArray(sub)) {
27050
+ sub.forEach((item, i) => assertSchemaShape(item, `${path}/items/${i}`, depth + 1));
27051
+ } else if (sub !== void 0) assertSchemaShape(sub, `${path}/${key}`, depth + 1);
27054
27052
  }
27055
27053
  for (const key of SUBSCHEMA_MAP_KEYS) {
27056
27054
  const map = schema[key];
@@ -27069,9 +27067,9 @@ function assertSchemaShape(value, path, depth = 0) {
27069
27067
  list.forEach((sub, i) => assertSchemaShape(sub, `${path}/${key}/${i}`, depth + 1));
27070
27068
  }
27071
27069
  }
27072
- function inputSchemaOf(raw, delivery) {
27073
- if (raw === void 0 && delivery === void 0) return { type: "object", properties: {} };
27074
- const source = raw ?? { type: "object", properties: {} };
27070
+ function inputSchemaOf(raw) {
27071
+ if (raw === void 0) return { type: "object", properties: {} };
27072
+ const source = raw;
27075
27073
  if (source === null || typeof source !== "object" || Array.isArray(source)) {
27076
27074
  throw new Error("MCP tool inputSchema must be a JSON Schema object");
27077
27075
  }
@@ -27080,23 +27078,21 @@ function inputSchemaOf(raw, delivery) {
27080
27078
  throw new Error("MCP tool inputSchema root type must be object");
27081
27079
  }
27082
27080
  assertSchemaShape(schema, "inputSchema");
27083
- if (delivery !== "mailbox" && delivery !== "both") {
27084
- return { ...schema, type: "object" };
27081
+ return { ...schema, type: "object" };
27082
+ }
27083
+ function inputValidator(raw, path) {
27084
+ try {
27085
+ return new ToolJsonSchemaValidator().getValidator(
27086
+ inputSchemaOf(raw)
27087
+ );
27088
+ } catch {
27089
+ throw new ProtocolError3(ProtocolErrorCode2.InternalError, `invalid input schema for '${path}'`);
27085
27090
  }
27086
- const properties = schema.properties;
27087
- if (properties !== void 0 && (properties === null || typeof properties !== "object" || Array.isArray(properties))) throw new Error("MCP tool inputSchema properties must be an object");
27088
- return {
27089
- ...schema,
27090
- type: "object",
27091
- properties: {
27092
- ...properties ?? {},
27093
- "~delivery": {
27094
- type: "string",
27095
- enum: delivery === "both" ? ["realtime", "mailbox", "fallback"] : ["mailbox", "fallback"],
27096
- description: "Tool Bridge delivery policy; fallback prefers realtime and queues only when dispatch definitely did not occur."
27097
- }
27098
- }
27099
- };
27091
+ }
27092
+ function validateMcpArguments(raw, args, path) {
27093
+ const validate = inputValidator(raw, path);
27094
+ const result = validate(args);
27095
+ if (!result.valid) throw new ProtocolError3(ProtocolErrorCode2.InvalidParams, result.errorMessage);
27100
27096
  }
27101
27097
  function annotationsOf(tool) {
27102
27098
  const annotations = {};
@@ -27105,69 +27101,26 @@ function annotationsOf(tool) {
27105
27101
  if (tool.effect === "destructive" || tool.confirm === true) annotations.destructiveHint = true;
27106
27102
  return Object.keys(annotations).length > 0 ? annotations : void 0;
27107
27103
  }
27108
- async function projectTools(source, validator) {
27109
- const unique = /* @__PURE__ */ new Map();
27110
- for (const tool of source) {
27111
- if (unique.has(tool.identity)) {
27112
- throw new ProtocolError3(ProtocolErrorCode2.InternalError, "duplicate HTBP tool identity");
27113
- }
27114
- unique.set(tool.identity, tool);
27115
- }
27116
- const projected = await Promise.all(
27117
- [...unique.values()].map(async (bridge) => {
27118
- const name = bridge.mcpName ?? await mcpToolName(bridge.identity);
27119
- const annotations = annotationsOf(bridge);
27120
- const description = bridge.description === void 0 ? `HTBP ${bridge.invokePath}` : `${bridge.description}
27121
-
27122
- HTBP ${bridge.invokePath}`;
27123
- let inputSchema;
27124
- try {
27125
- inputSchema = inputSchemaOf(bridge.inputSchema, bridge.delivery);
27126
- } catch {
27127
- throw new ProtocolError3(
27128
- ProtocolErrorCode2.InternalError,
27129
- `invalid input schema for '${bridge.sourcePath}/${bridge.toolName}'`
27130
- );
27131
- }
27132
- const candidate = {
27133
- name,
27134
- description,
27135
- inputSchema,
27136
- _meta: {
27137
- "io.tool-bridge/path": bridge.sourcePath,
27138
- "io.tool-bridge/command": bridge.toolName
27139
- },
27140
- ...annotations !== void 0 ? { annotations } : {}
27141
- };
27142
- const parsed = ToolSchema.safeParse(candidate);
27143
- if (!parsed.success) {
27144
- throw new ProtocolError3(
27145
- ProtocolErrorCode2.InternalError,
27146
- `invalid tool metadata for '${bridge.sourcePath}/${bridge.toolName}'`
27147
- );
27148
- }
27149
- let validateInput;
27150
- try {
27151
- validateInput = validator.getValidator(
27152
- parsed.data.inputSchema
27153
- );
27154
- } catch {
27155
- throw new ProtocolError3(
27156
- ProtocolErrorCode2.InternalError,
27157
- `invalid input schema for '${bridge.sourcePath}/${bridge.toolName}'`
27158
- );
27159
- }
27160
- return { bridge, tool: parsed.data, validateInput };
27161
- })
27162
- );
27104
+ function projectTools(source) {
27163
27105
  const names = /* @__PURE__ */ new Set();
27164
- for (const item of projected) {
27165
- if (names.has(item.tool.name)) {
27106
+ return source.map((bridge) => {
27107
+ if (names.has(bridge.name)) {
27166
27108
  throw new ProtocolError3(ProtocolErrorCode2.InternalError, "MCP tool name collision");
27167
27109
  }
27168
- names.add(item.tool.name);
27169
- }
27170
- return projected.sort((a, b) => a.tool.name.localeCompare(b.tool.name));
27110
+ names.add(bridge.name);
27111
+ const annotations = annotationsOf(bridge);
27112
+ const validateInput = inputValidator(bridge.inputSchema, bridge.name);
27113
+ const parsed = ToolSchema.safeParse({
27114
+ name: bridge.name,
27115
+ description: bridge.description,
27116
+ inputSchema: inputSchemaOf(bridge.inputSchema),
27117
+ ...annotations === void 0 ? {} : { annotations }
27118
+ });
27119
+ if (!parsed.success) {
27120
+ throw new ProtocolError3(ProtocolErrorCode2.InternalError, `invalid tool metadata for '${bridge.name}'`);
27121
+ }
27122
+ return { bridge, tool: parsed.data, validateInput };
27123
+ }).sort((a, b) => a.tool.name.localeCompare(b.tool.name));
27171
27124
  }
27172
27125
  function contentOf(value) {
27173
27126
  if (Array.isArray(value)) {
@@ -27188,12 +27141,13 @@ function buildMcpServer(version, bridge, listTtlMs) {
27188
27141
  cacheHints: { "tools/list": { ttlMs: listTtlMs, cacheScope: "private" } }
27189
27142
  }
27190
27143
  );
27144
+ let projected;
27145
+ const tools = () => projected ??= bridge.list().then(projectTools);
27191
27146
  server.setRequestHandler("tools/list", async () => ({
27192
- tools: (await projectTools(await bridge.list(), validator)).map((item) => item.tool)
27147
+ tools: (await tools()).map((item) => item.tool)
27193
27148
  }));
27194
27149
  server.setRequestHandler("tools/call", async (rpc) => {
27195
- const projected = await projectTools(await bridge.list(), validator);
27196
- const selected = projected.find((item) => item.tool.name === rpc.params.name);
27150
+ const selected = (await tools()).find((item) => item.tool.name === rpc.params.name);
27197
27151
  if (selected === void 0) {
27198
27152
  throw new ProtocolError3(ProtocolErrorCode2.InvalidParams, "tool not found");
27199
27153
  }
@@ -27202,9 +27156,15 @@ function buildMcpServer(version, bridge, listTtlMs) {
27202
27156
  if (!validation.valid) {
27203
27157
  throw new ProtocolError3(ProtocolErrorCode2.InvalidParams, validation.errorMessage);
27204
27158
  }
27205
- const result = await bridge.call(selected.bridge, args);
27159
+ let result;
27160
+ try {
27161
+ result = await bridge.call(selected.bridge, args);
27162
+ } catch (error) {
27163
+ if (!isTBError(error)) throw error;
27164
+ result = { content: error.toJSON(), isError: true };
27165
+ }
27206
27166
  const candidate = {
27207
- content: contentOf(result.content),
27167
+ content: contentOf(result.contentBlocks ?? result.content),
27208
27168
  ...result.isError === true ? { isError: true } : {},
27209
27169
  ...result.structuredContent !== void 0 ? { structuredContent: result.structuredContent } : result.content !== null && typeof result.content === "object" && !Array.isArray(result.content) ? { structuredContent: result.content } : {}
27210
27170
  };
@@ -28444,6 +28404,7 @@ var RemotePathProjector = class {
28444
28404
  node: { ...help.node, path: nodePath },
28445
28405
  cmds,
28446
28406
  ...children === void 0 ? {} : { children },
28407
+ ...help.deviceContext === void 0 ? {} : { deviceContext: help.deviceContext },
28447
28408
  ...help.feedback === void 0 ? {} : { feedback: help.feedback },
28448
28409
  ...help.hint === void 0 ? {} : { hint: help.hint },
28449
28410
  ...help.note === void 0 ? {} : { note: help.note }
@@ -30676,6 +30637,9 @@ function registerSearchRoute(app, env) {
30676
30637
  );
30677
30638
  }
30678
30639
 
30640
+ // ../app/src/routes/mcp.ts
30641
+ import { z as z5 } from "zod/v4";
30642
+
30679
30643
  // ../app/src/helpModel.ts
30680
30644
  async function helpModelFor(node, registry, ctx, builtins, deps, opts) {
30681
30645
  const index = opts.schemas !== true;
@@ -30696,7 +30660,13 @@ async function helpModelFor(node, registry, ctx, builtins, deps, opts) {
30696
30660
  now: opts.now
30697
30661
  });
30698
30662
  return deviceDirectoryHelpModel(
30699
- { path: node.path, description: node.description, presence },
30663
+ {
30664
+ path: node.path,
30665
+ description: node.description,
30666
+ presence,
30667
+ ...node.deviceEnvironment === void 0 ? {} : { environment: node.deviceEnvironment },
30668
+ ...node.deviceReportedAt === void 0 ? {} : { reportedAt: node.deviceReportedAt }
30669
+ },
30700
30670
  children.map((n) => ({ path: n.path, kind: n.kind, description: n.description }))
30701
30671
  );
30702
30672
  }
@@ -30799,362 +30769,210 @@ async function commandHelpModelFor(registry, ctx, builtins, deps, path, opts) {
30799
30769
  };
30800
30770
  }
30801
30771
 
30802
- // ../app/src/routes/mcp.ts
30803
- var MCP_REMOTE_MAX_REQUESTS = 32;
30804
- var mcpCommand = (nodePath, nodeDescription, command) => {
30805
- const modelPath = nodePath.replace(/^\/+|\/+$/g, "");
30806
- const commandPath = command.path.replace(/^\/+|\/+$/g, "");
30807
- if (!commandPath.startsWith(`${modelPath}/`)) {
30808
- throw new TBError("internal", `command path '${command.path}' escapes node '${nodePath}'`);
30809
- }
30810
- const invokePath = `/${commandPath}`;
30811
- return {
30812
- identity: mcpToolIdentity(invokePath, command.name),
30813
- sourcePath: nodePath,
30814
- toolName: command.name,
30815
- invokePath,
30816
- description: command.h ?? nodeDescription,
30817
- ...command.inputSchema !== void 0 ? { inputSchema: command.inputSchema } : {},
30818
- ...command.delivery !== void 0 ? { delivery: command.delivery } : {},
30819
- ...command.effect !== void 0 ? { effect: command.effect } : {},
30820
- ...command.confirm === true ? { confirm: true } : {}
30821
- };
30822
- };
30823
- var toolSpecCommand = (node, tool, providerBacked = false) => {
30824
- const invokePath = `/${node.path}/${tool.name}`;
30825
- return {
30826
- identity: mcpToolIdentity(invokePath, tool.name),
30827
- sourcePath: node.path,
30828
- toolName: tool.name,
30829
- invokePath,
30830
- ...providerBacked ? { providerBacked: true } : {},
30831
- description: tool.description ?? node.description,
30832
- ...tool.inputSchema !== void 0 ? { inputSchema: tool.inputSchema } : {},
30833
- ...tool.delivery !== void 0 ? { delivery: tool.delivery } : {},
30834
- ...tool.effect !== void 0 ? { effect: tool.effect } : {},
30835
- ...tool.confirm === true ? { confirm: true } : {}
30836
- };
30837
- };
30838
- function mcpBridgeFor(c, env, app) {
30839
- const { builtinsOf, deps, globalSearchCapabilities, searchSync } = env;
30772
+ // ../app/src/mcpInvoke.ts
30773
+ function mcpPath(path, allowRoot = false) {
30774
+ const error = validatePath(path, { allowRoot });
30775
+ if (error !== null) throw error;
30776
+ return canonicalizePath(path).split("/").map(encodeURIComponent).join("/");
30777
+ }
30778
+ function mcpRequest(c, app, path, body, extraHeaders) {
30779
+ return Promise.resolve(app.request(new Request(new URL(path, c.req.url), {
30780
+ method: body === void 0 ? "GET" : "POST",
30781
+ headers: {
30782
+ "authorization": c.req.header("authorization") ?? "",
30783
+ "accept": "application/json",
30784
+ "content-type": "application/json",
30785
+ ...extraHeaders
30786
+ },
30787
+ ...body === void 0 ? {} : { body: JSON.stringify(body) },
30788
+ signal: c.req.raw.signal
30789
+ })));
30790
+ }
30791
+ async function mcpResponse(response) {
30792
+ const text = await response.text();
30793
+ let content = text;
30794
+ try {
30795
+ content = JSON.parse(text);
30796
+ } catch {
30797
+ }
30798
+ return { content, ...response.ok ? {} : { isError: true } };
30799
+ }
30800
+ async function invokeMcpTarget(c, env, app, input) {
30801
+ const encoded = mcpPath(input.path);
30802
+ const path = canonicalizePath(input.path);
30803
+ const args = { ...input.args };
30804
+ if (input.delivery !== void 0 && Object.hasOwn(args, "~delivery")) {
30805
+ throw new TBError("invalid_argument", "delivery and args.~delivery cannot both be provided");
30806
+ }
30807
+ const delivery = input.delivery ?? args["~delivery"];
30808
+ delete args["~delivery"];
30809
+ if (Object.keys(args).some((key) => key.startsWith("~"))) {
30810
+ throw new TBError("invalid_argument", "unknown invocation control in args");
30811
+ }
30812
+ if (delivery !== void 0 && delivery !== "realtime" && delivery !== "mailbox" && delivery !== "fallback") {
30813
+ throw new TBError("invalid_argument", "delivery must be realtime, mailbox or fallback");
30814
+ }
30815
+ if ((input.ttlSeconds !== void 0 || input.idempotencyKey !== void 0) && input.delivery !== "mailbox" && input.delivery !== "fallback") {
30816
+ throw new TBError("invalid_argument", "ttlSeconds and idempotencyKey require mailbox or fallback delivery");
30817
+ }
30818
+ const { deps, searchSync } = env;
30840
30819
  const ctx = c.get("ctx");
30841
30820
  const registry = new NodeRegistryStore(c.get("store"));
30842
- let remoteRequests = 0;
30843
- const controlTools = () => [
30844
- ...globalSearchCapabilities().includes("search") ? [{
30845
- identity: JSON.stringify(["control", "search"]),
30846
- sourcePath: "",
30847
- toolName: "Search",
30848
- invokePath: "/~search",
30849
- mcpName: "tb_search",
30850
- operation: "search",
30851
- description: "Search visible tools across the Tool Bridge tree (compact by default).",
30852
- effect: "read",
30853
- inputSchema: {
30854
- type: "object",
30855
- additionalProperties: false,
30856
- properties: {
30857
- query: { type: "string", minLength: 1 },
30858
- mode: { type: "string", enum: ["keyword"] },
30859
- limit: { type: "integer", minimum: 1, maximum: 200 },
30860
- cursor: { type: "string", minLength: 1 },
30861
- detail: { type: "string", enum: ["compact", "full"], default: "compact" },
30862
- effects: {
30863
- type: "array",
30864
- minItems: 1,
30865
- items: {
30866
- type: "string",
30867
- enum: ["read", "write", "destructive", "unknown"]
30868
- }
30869
- },
30870
- federation: { type: "string", enum: ["local", "recursive"] },
30871
- matching: { type: "string", enum: ["best", "all"] },
30872
- minCoverage: { type: "number", exclusiveMinimum: 0, maximum: 1 },
30873
- pathPrefix: { type: "string", minLength: 1 }
30874
- },
30875
- required: ["query"]
30876
- }
30877
- }] : [],
30878
- {
30879
- identity: JSON.stringify(["control", "help"]),
30880
- sourcePath: "",
30881
- toolName: "Help",
30882
- invokePath: "/~help",
30883
- mcpName: "tb_help",
30884
- operation: "help",
30885
- description: "Describe a visible Tool Bridge node or one of its tools.",
30886
- effect: "read",
30887
- inputSchema: {
30888
- type: "object",
30889
- additionalProperties: false,
30890
- properties: {
30891
- path: { type: "string" },
30892
- tool: { type: "string", minLength: 1, pattern: "^[^/]+$" },
30893
- format: { type: "string", enum: ["json", "markdown", "dsl"] }
30894
- }
30895
- }
30896
- },
30897
- {
30898
- identity: JSON.stringify(["control", "list-nodes"]),
30899
- sourcePath: "",
30900
- toolName: "List",
30901
- invokePath: "/~tree",
30902
- mcpName: "tb_list_nodes",
30903
- operation: "listNodes",
30904
- description: "List the visible Tool Bridge node tree from a path.",
30905
- effect: "read",
30906
- inputSchema: {
30907
- type: "object",
30908
- additionalProperties: false,
30909
- properties: {
30910
- path: { type: "string" },
30911
- depth: { type: "integer", minimum: 0, maximum: MAX_TREE_DEPTH }
30912
- }
30913
- }
30914
- }
30915
- ];
30916
- const takeRemoteRequest = () => {
30917
- remoteRequests += 1;
30918
- if (remoteRequests > MCP_REMOTE_MAX_REQUESTS) {
30919
- throw new TBError("unavailable", "remote MCP discovery request budget exceeded", {
30920
- retryable: false
30921
- });
30922
- }
30923
- };
30924
- const remoteHelp = async (path) => {
30925
- takeRemoteRequest();
30926
- const projector = await remotePathProjectorIfMatch(registry, path);
30927
- if (projector === null) {
30928
- throw remoteProtocolError(`remote ~help path '${path}' lost its mount owner`);
30929
- }
30930
- const headers = new Headers(c.req.raw.headers);
30931
- headers.set("accept", "application/json");
30932
- const response = await remotePassthroughIfMatch(
30933
- c,
30934
- ctx,
30935
- registry,
30936
- path,
30937
- "~help",
30938
- deps,
30939
- headers
30940
- );
30941
- if (response === null || !response.ok) {
30942
- throw new TBError("unavailable", `remote ~help failed for '${path}'`, { retryable: true });
30943
- }
30944
- const parsed = helpJsonSchema.safeParse(await response.json().catch(() => null));
30945
- if (!parsed.success) {
30946
- throw new TBError("unavailable", `remote ~help returned invalid JSON for '${path}'`);
30821
+ const resolved = await registry.resolve(path).catch(() => null);
30822
+ if (resolved === null) throw TBError.notFound("not found");
30823
+ const { node, rest: command } = resolved;
30824
+ if (node.kind === "remote") {
30825
+ if (!check(ctx, path, "read").allow) throw TBError.notFound("not found");
30826
+ if (!check(ctx, path, "call").allow) {
30827
+ throw new TBError("permission_denied", `no scope grants 'call' on '${path}'`);
30828
+ }
30829
+ const response2 = await mcpRequest(c, app, `/${encoded}/~help`);
30830
+ if (!response2.ok) return mcpResponse(response2);
30831
+ const model = helpJsonSchema.safeParse(await response2.json().catch(() => null));
30832
+ if (!model.success) throw new TBError("unavailable", "remote command help returned invalid JSON");
30833
+ const selected = model.data.cmds.find((cmd) => canonicalizePath(cmd.path) === path);
30834
+ if (selected === void 0) throw TBError.notFound("not found");
30835
+ validateMcpArguments(selected.inputSchema, args, path);
30836
+ } else {
30837
+ if (command === "" || command.includes("/") || !check(ctx, node.path, "read").allow) {
30838
+ throw TBError.notFound("not found");
30947
30839
  }
30948
- return projector.projectHelp(parsed.data, path, ctx);
30949
- };
30950
- const remotePaths = async (root) => {
30951
- const found = [];
30952
- const seen = /* @__PURE__ */ new Set();
30953
- const pending = [{ depth: 0, path: root }];
30954
- while (pending.length > 0) {
30955
- const current = pending.shift();
30956
- if (current === void 0 || seen.has(current.path)) continue;
30957
- const { depth, path } = current;
30958
- seen.add(path);
30959
- if (!check(ctx, path, "read").allow || !check(ctx, path, "call").allow) continue;
30960
- const owner = await registry.resolve(path).catch(() => null);
30961
- if (owner?.node.path !== root || owner.node.kind !== "remote") continue;
30962
- if (found.length >= DEFAULT_MAX_NODES) {
30963
- throw new TBError("unavailable", "remote MCP discovery node budget exceeded", {
30964
- retryable: false
30965
- });
30840
+ const marker = deviceToolMarker(node);
30841
+ if (marker === null && (node.kind === "mcp" || node.kind === "http" || node.kind === "tool")) {
30842
+ if (!check(ctx, node.path, "call").allow) {
30843
+ throw new TBError("permission_denied", `no scope grants 'call' on '${node.path}'`);
30966
30844
  }
30967
- found.push(path);
30968
- takeRemoteRequest();
30969
- const children = await remoteTreeChildren(c, ctx, registry, path, deps);
30970
- if (children.length > 0 && depth >= MAX_TREE_DEPTH) {
30971
- throw new TBError("unavailable", "remote MCP discovery depth exceeded", {
30972
- retryable: false
30973
- });
30974
- }
30975
- for (const child of children) {
30976
- if (child.path.startsWith(`${root}/`) && !seen.has(child.path)) {
30977
- pending.push({ path: child.path, depth: depth + 1 });
30978
- }
30845
+ if (delivery !== void 0) {
30846
+ throw new TBError("invalid_argument", "delivery is only supported by device-backed tool commands");
30979
30847
  }
30848
+ const provider = await providerFor(node, ctx, deps);
30849
+ const raw = await upstreamTools(node, provider, deps, false, (/* @__PURE__ */ new Date()).toISOString(), searchSync);
30850
+ const selected = virtualizeTools(node.virtualize, raw).exposed.find((tool) => tool.name === command);
30851
+ if (selected === void 0) throw TBError.notFound("not found");
30852
+ validateMcpArguments(selected.inputSchema, args, path);
30853
+ return provider.call(resolveUpstreamTool(node.virtualize, raw, command), args);
30980
30854
  }
30981
- return found;
30982
- };
30983
- const list = async () => {
30984
- const now = (/* @__PURE__ */ new Date()).toISOString();
30985
- const nodes = await pruneExpiredContext(await registry.subtree(""), registry);
30986
- const result = controlTools();
30987
- for (const node of nodes) {
30988
- if (node.kind === "directory") continue;
30989
- if (!check(ctx, node.path, "read").allow) continue;
30990
- if (node.kind === "remote") {
30991
- for (const path of await remotePaths(node.path)) {
30992
- const model2 = await remoteHelp(path);
30993
- for (const command of model2.cmds) {
30994
- if (check(ctx, path, command.scope).allow) {
30995
- let detailed = command;
30996
- if (command.inputSchema === void 0 && command.path !== `/${model2.node.path}`) {
30997
- const detail = await remoteHelp(command.path.replace(/^\/+/, ""));
30998
- detailed = detail.cmds.find((item) => item.name === command.name) ?? command;
30999
- }
31000
- result.push(mcpCommand(path, model2.node.description, detailed));
31001
- }
31002
- }
31003
- }
31004
- continue;
31005
- }
31006
- const marker = deviceToolMarker(node);
31007
- if (marker !== null) {
31008
- if (check(ctx, node.path, "call").allow) {
31009
- result.push(...(marker.cmds ?? []).map((tool) => toolSpecCommand(node, tool)));
31010
- }
31011
- continue;
31012
- }
31013
- if ((node.kind === "mcp" || node.kind === "http" || node.kind === "tool") && node.config !== void 0) {
31014
- if (!check(ctx, node.path, "call").allow) continue;
31015
- const provider = await providerFor(node, ctx, deps);
31016
- const raw = await upstreamTools(node, provider, deps, false, now, searchSync);
31017
- const { exposed } = virtualizeTools(node.virtualize, raw);
31018
- result.push(...exposed.map((tool) => toolSpecCommand(node, tool, true)));
31019
- continue;
30855
+ if (marker !== null && marker.cmds === void 0) {
30856
+ if (!check(ctx, node.path, "call").allow) {
30857
+ throw new TBError("permission_denied", `no scope grants 'call' on '${node.path}'`);
31020
30858
  }
31021
- const model = await helpModelFor(node, registry, ctx, builtinsOf(c.get("store")), deps, {
30859
+ } else {
30860
+ const model = await helpModelFor(node, registry, ctx, env.builtinsOf(c.get("store")), deps, {
31022
30861
  includeDirectUpload: check(ctx, node.path, "write").allow,
30862
+ now: (/* @__PURE__ */ new Date()).toISOString(),
31023
30863
  refresh: false,
31024
- now,
30864
+ schemas: true,
31025
30865
  searchSync
31026
30866
  });
31027
- for (const command of model.cmds) {
31028
- if (check(ctx, node.path, command.scope).allow) {
31029
- result.push(mcpCommand(node.path, node.description, command));
31030
- }
30867
+ const selected = model.cmds.find((cmd) => canonicalizePath(cmd.path) === path);
30868
+ if (selected === void 0) throw TBError.notFound("not found");
30869
+ if (!check(ctx, node.path, selected.scope).allow) {
30870
+ throw new TBError("permission_denied", `no scope grants '${selected.scope}' on '${node.path}'`);
31031
30871
  }
30872
+ validateMcpArguments(selected.inputSchema, args, path);
31032
30873
  }
31033
- return result;
31034
- };
30874
+ }
30875
+ const query = input.ttlSeconds === void 0 ? "" : `?ttlSeconds=${input.ttlSeconds}`;
30876
+ const response = await mcpRequest(c, app, `/${encoded}${query}`, {
30877
+ ...args,
30878
+ ...delivery === void 0 ? {} : { "~delivery": delivery }
30879
+ }, input.idempotencyKey === void 0 ? void 0 : { "x-tb-idempotency-key": input.idempotencyKey });
30880
+ const result = await mcpResponse(response);
30881
+ if (delivery !== void 0 && response.ok) {
30882
+ return {
30883
+ content: response.status === 202 ? { delivery: "mailbox", operation: result.content } : { delivery: "realtime", result: result.content }
30884
+ };
30885
+ }
30886
+ return result;
30887
+ }
30888
+
30889
+ // ../app/src/routes/mcp.ts
30890
+ var callInput = z5.strictObject({
30891
+ path: z5.string().min(1).describe("Complete command path returned by tb_help or tb_search; the same path as tb call."),
30892
+ args: z5.record(z5.string(), z5.unknown()).optional().describe("The command arguments object. Defaults to {}."),
30893
+ delivery: z5.enum(["realtime", "mailbox", "fallback"]).optional(),
30894
+ ttlSeconds: z5.number().int().positive().optional(),
30895
+ idempotencyKey: z5.string().min(1).optional()
30896
+ });
30897
+ var operationIdentity = {
30898
+ deviceId: z5.string().min(1),
30899
+ operationId: z5.string().min(1)
30900
+ };
30901
+ var deviceOperationInput = z5.discriminatedUnion("action", [
30902
+ z5.strictObject({
30903
+ action: z5.literal("list"),
30904
+ deviceId: z5.string().min(1),
30905
+ cursor: z5.string().min(1).optional(),
30906
+ limit: z5.number().int().positive().optional(),
30907
+ states: z5.array(deviceOperationStateSchema).min(1).optional()
30908
+ }),
30909
+ z5.strictObject({ action: z5.literal("get"), ...operationIdentity }),
30910
+ z5.strictObject({ action: z5.literal("cancel"), ...operationIdentity })
30911
+ ]);
30912
+ function mcpBridgeFor(c, env, app) {
30913
+ const operations = new OperationRegistry();
30914
+ const request = async (path, body) => mcpResponse(await mcpRequest(c, app, path, body));
30915
+ if (env.globalSearchCapabilities().includes("search")) {
30916
+ operations.register("tb_search", {
30917
+ description: 'Search visible Tool Bridge tools, compact by default. Use tb_help on a selected command path for its full schema, then tb_call. Use detail="full" to include schemas in this response.',
30918
+ effect: "read",
30919
+ inputSchema: toolSearchOptionsSchema.extend({ query: z5.string().trim().min(1) })
30920
+ }, async ({ query, ...opts }) => request("/~search", { query, opts }));
30921
+ }
30922
+ operations.register("tb_help", {
30923
+ description: "Describe a visible node or complete command path, including input schema, permissions, effects and device delivery. Root help browses available nodes. Equivalent to tb help.",
30924
+ effect: "read",
30925
+ inputSchema: z5.strictObject({
30926
+ path: z5.string().optional(),
30927
+ tool: z5.string().min(1).regex(/^[^/]+$/).optional(),
30928
+ format: z5.enum(["json", "markdown", "dsl"]).optional(),
30929
+ schemas: z5.boolean().optional()
30930
+ })
30931
+ }, async ({ path = "", tool, format = "json", schemas: schemas2 }) => {
30932
+ const prefix = mcpPath(path, true);
30933
+ if (tool !== void 0 && prefix === "") {
30934
+ throw new TBError("invalid_argument", "tool detail requires a node path");
30935
+ }
30936
+ const command = tool === void 0 ? prefix : `${prefix}/${mcpPath(tool)}`;
30937
+ const response = await mcpRequest(c, app, `/${command ? `${command}/` : ""}~help${schemas2 ? "?schemas=1" : ""}`, void 0, {
30938
+ accept: format === "json" ? "application/json" : format === "dsl" ? "text/plain" : "text/markdown"
30939
+ });
30940
+ return mcpResponse(response);
30941
+ });
30942
+ operations.register("tb_list_nodes", {
30943
+ description: "Browse visible Tool Bridge nodes at a bounded depth. Use tb_help to inspect one node or command. Equivalent to tb ls / tb tree; works without search.",
30944
+ effect: "read",
30945
+ inputSchema: z5.strictObject({
30946
+ path: z5.string().optional(),
30947
+ depth: z5.number().int().min(0).max(MAX_TREE_DEPTH).optional()
30948
+ })
30949
+ }, async ({ path = "", depth = 1 }) => {
30950
+ const prefix = mcpPath(path, true);
30951
+ return request(`/${prefix ? `${prefix}/` : ""}~tree?depth=${depth}`);
30952
+ });
30953
+ operations.register("tb_call", {
30954
+ description: "Invoke one Tool Bridge command by its complete path and arguments, equivalent to tb call. Discover unknown commands with tb_search / tb_help; check the target effect and confirm before writes. Supports tools, Context, Skill and system commands. Device delivery may return a mailbox operation; inspect it with tb_device_operations. Never retry a write merely because the result is unknown.",
30955
+ effect: "destructive",
30956
+ confirm: true,
30957
+ inputSchema: callInput
30958
+ }, async (input) => invokeMcpTarget(c, env, app, input));
30959
+ operations.register("tb_device_operations", {
30960
+ description: "List, inspect or cancel device mailbox operations, equivalent to tb device op. Use the original deviceId and operationId. Cancellation of a claimed operation is cooperative; result_unknown and expired with executionMayHaveOccurred do not establish that a retry is safe.",
30961
+ effect: "destructive",
30962
+ confirm: true,
30963
+ inputSchema: deviceOperationInput
30964
+ }, async (input) => {
30965
+ const { action, deviceId } = input;
30966
+ const body = action === "list" ? { deviceId, opts: { cursor: input.cursor, limit: input.limit, states: input.states } } : { deviceId, operationId: input.operationId };
30967
+ return request(`/~device/operations/${action}`, body);
30968
+ });
31035
30969
  return {
31036
- list,
31037
- call: async (tool, args) => {
31038
- const resultFromResponse = async (response2) => {
31039
- const text = await response2.text();
31040
- let value = text;
31041
- try {
31042
- value = JSON.parse(text);
31043
- } catch {
31044
- }
31045
- return { content: value, ...response2.ok ? {} : { isError: true } };
31046
- };
31047
- if (tool.operation !== void 0) {
31048
- const rawPath = args.path ?? "";
31049
- if (typeof rawPath !== "string") {
31050
- throw new TBError("invalid_argument", "path must be a string");
31051
- }
31052
- const path = rawPath.replace(/^\/+|\/+$/g, "");
31053
- const pathError = validatePath(path, { allowRoot: true });
31054
- if (pathError !== null) throw pathError;
31055
- const segments = path === "" ? [] : path.split("/");
31056
- if (segments.some((segment) => segment === "." || segment === "..")) {
31057
- throw new TBError("invalid_argument", "path contains a dot segment");
31058
- }
31059
- const encoded = segments.map((segment) => encodeURIComponent(segment));
31060
- const headers2 = new Headers({
31061
- authorization: c.req.header("authorization") ?? ""
31062
- });
31063
- if (tool.operation === "search") {
31064
- headers2.set("accept", "application/json");
31065
- headers2.set("content-type", "application/json");
31066
- const opts = {
31067
- detail: args.detail ?? "compact",
31068
- ...Object.fromEntries(
31069
- [
31070
- "mode",
31071
- "limit",
31072
- "cursor",
31073
- "effects",
31074
- "federation",
31075
- "matching",
31076
- "minCoverage",
31077
- "pathPrefix"
31078
- ].filter((key) => args[key] !== void 0).map((key) => [key, args[key]])
31079
- )
31080
- };
31081
- const response2 = await app.request(new Request(new URL("/~search", c.req.url), {
31082
- method: "POST",
31083
- headers: headers2,
31084
- body: JSON.stringify({
31085
- query: args.query,
31086
- opts
31087
- })
31088
- }));
31089
- return await resultFromResponse(response2);
31090
- }
31091
- if (tool.operation === "help") {
31092
- const detail = args.tool;
31093
- if (detail !== void 0) {
31094
- if (path === "" || typeof detail !== "string" || detail.includes("/")) {
31095
- throw new TBError("invalid_argument", "tool detail requires a node path and one segment");
31096
- }
31097
- encoded.push(encodeURIComponent(detail));
31098
- }
31099
- const format = args.format ?? "json";
31100
- headers2.set("accept", format === "json" ? "application/json" : format === "dsl" ? "text/plain" : "text/markdown");
31101
- const prefix2 = encoded.length === 0 ? "" : `/${encoded.join("/")}`;
31102
- return await resultFromResponse(await app.request(new Request(
31103
- new URL(`${prefix2}/~help`, c.req.url),
31104
- { headers: headers2 }
31105
- )));
31106
- }
31107
- headers2.set("accept", "application/json");
31108
- const prefix = encoded.length === 0 ? "" : `/${encoded.join("/")}`;
31109
- const url5 = new URL(`${prefix}/~tree`, c.req.url);
31110
- if (args.depth !== void 0) url5.searchParams.set("depth", String(args.depth));
31111
- return await resultFromResponse(await app.request(new Request(url5, { headers: headers2 })));
31112
- }
31113
- if (tool.providerBacked === true) {
31114
- let node;
31115
- try {
31116
- node = await registry.get(tool.sourcePath);
31117
- } catch {
31118
- throw TBError.notFound("not found");
31119
- }
31120
- if (!check(ctx, node.path, "read").allow) throw TBError.notFound("not found");
31121
- if (!check(ctx, node.path, "call").allow) {
31122
- throw new TBError("permission_denied", `no scope grants 'call' on '${node.path}'`);
31123
- }
31124
- if (node.kind !== "mcp" && node.kind !== "http" && node.kind !== "tool" || node.config === void 0) {
31125
- throw TBError.notFound("not found");
31126
- }
31127
- const provider = await providerFor(node, ctx, deps);
31128
- const raw = await upstreamTools(node, provider, deps, false, (/* @__PURE__ */ new Date()).toISOString(), searchSync);
31129
- const upstreamName = resolveUpstreamTool(node.virtualize, raw, tool.toolName);
31130
- const result2 = await provider.call(upstreamName, args);
31131
- return {
31132
- content: result2.contentBlocks ?? result2.content,
31133
- ...result2.isError === true ? { isError: true } : {},
31134
- ...result2.structuredContent !== void 0 ? { structuredContent: result2.structuredContent } : {}
31135
- };
31136
- }
31137
- const url4 = new URL(tool.invokePath, c.req.url);
31138
- const headers = new Headers({
31139
- "accept": "application/json",
31140
- "authorization": c.req.header("authorization") ?? "",
31141
- "content-type": "application/json"
31142
- });
31143
- const response = await app.request(
31144
- new Request(url4, { method: "POST", headers, body: JSON.stringify(args) })
31145
- );
31146
- const result = await resultFromResponse(response);
31147
- if (args["~delivery"] !== void 0 && response.ok) {
31148
- return {
31149
- content: response.status === 202 ? { delivery: "mailbox", operation: result.content } : { delivery: "realtime", result: result.content }
31150
- };
31151
- }
31152
- return result;
31153
- }
30970
+ list: async () => operations.list(),
30971
+ call: async (tool, args) => operations.call(tool.name, args, void 0)
31154
30972
  };
31155
30973
  }
31156
30974
  function registerMcpRoute(app, env) {
31157
- app.all("/~mcp", (c) => runHandler(async () => await handleMcpRequest(
30975
+ app.all("/~mcp", (c) => runHandler(async () => handleMcpRequest(
31158
30976
  c.req.raw,
31159
30977
  env.deps.version,
31160
30978
  mcpBridgeFor(c, env, app),
@@ -35371,104 +35189,104 @@ function createTbServer(config) {
35371
35189
 
35372
35190
  // ../plugins/src/registry.generated.ts
35373
35191
  var BUILTIN_PLUGIN_LOADERS = {
35374
- airtable: () => import("./airtable-ML2GIGCH.js"),
35375
- alt_text_generator_ai: () => import("./alt_text_generator_ai-FGYQAF2A.js"),
35376
- amap: () => import("./amap-G7V65NGK.js"),
35377
- anthropic: () => import("./anthropic-6ZK24TBB.js"),
35378
- apify: () => import("./apify-VDGYHP6W.js"),
35379
- brave_search: () => import("./brave_search-TAATLZOS.js"),
35380
- circleci: () => import("./circleci-BQ2UWXL2.js"),
35381
- clerk: () => import("./clerk-2JYWQNOI.js"),
35382
- cohere: () => import("./cohere-6MI7AQM4.js"),
35383
- confluence: () => import("./confluence-6Y6GDETF.js"),
35384
- convertapi: () => import("./convertapi-HBZCSWOX.js"),
35385
- currencyapi: () => import("./currencyapi-337U5TGI.js"),
35386
- deepseek: () => import("./deepseek-OSPASO7O.js"),
35387
- docker_hub: () => import("./docker_hub-3ATQOY5L.js"),
35388
- dropbox: () => import("./dropbox-LSA4GM2Y.js"),
35389
- dub: () => import("./dub-VZPJSPI6.js"),
35390
- e2b: () => import("./e2b-6SDYQZL2.js"),
35391
- exa: () => import("./exa-B6EUYDVP.js"),
35392
- fal_ai: () => import("./fal_ai-K4Q27IME.js"),
35393
- feishu: () => import("./feishu-4TKXG4SU.js"),
35394
- feishu_custom_bot: () => import("./feishu_custom_bot-7CTEAKRB.js"),
35395
- figma: () => import("./figma-OUKSZLD5.js"),
35396
- firehydrant: () => import("./firehydrant-7MOYL7QH.js"),
35397
- fixer: () => import("./fixer-H2BV2NO4.js"),
35398
- fly: () => import("./fly-PXKY6PNH.js"),
35399
- front: () => import("./front-UZYIV5DW.js"),
35400
- geocodio: () => import("./geocodio-NSYO7TFP.js"),
35401
- ghost: () => import("./ghost-QBKKQQMF.js"),
35402
- github: () => import("./github-ENLSJ4CL.js"),
35403
- gmail: () => import("./gmail-KQSDEB47.js"),
35404
- googlecalendar: () => import("./googlecalendar-5YCX4SZF.js"),
35405
- googledocs: () => import("./googledocs-SSWIVFKA.js"),
35406
- grafana: () => import("./grafana-TF2LXDQA.js"),
35407
- graphhopper: () => import("./graphhopper-CURBVHYK.js"),
35408
- ip2proxy: () => import("./ip2proxy-YNVMTZEM.js"),
35409
- ipgeolocation_io: () => import("./ipgeolocation_io-NAU7VJ4J.js"),
35410
- ipqualityscore: () => import("./ipqualityscore-OT63L4TI.js"),
35411
- jina_ai: () => import("./jina_ai-6WBMBGWM.js"),
35412
- jira: () => import("./jira-DVDVTHNO.js"),
35413
- langsmith: () => import("./langsmith-IM5N4YAU.js"),
35414
- lemlist: () => import("./lemlist-277SHUQF.js"),
35415
- linear: () => import("./linear-AEPH7B5V.js"),
35416
- logsnag: () => import("./logsnag-VEWRAGBG.js"),
35417
- mattermost: () => import("./mattermost-Q3A2BIZA.js"),
35418
- mem0: () => import("./mem0-AXS7GZGI.js"),
35419
- memos: () => import("./memos-7TXG4ZTU.js"),
35420
- metabase: () => import("./metabase-NSVACWQM.js"),
35421
- mistral_ai: () => import("./mistral_ai-YZ52RGD4.js"),
35422
- mother_duck: () => import("./mother_duck-XLLL6FVL.js"),
35423
- ngrok: () => import("./ngrok-4O4W3WZW.js"),
35424
- notes: () => import("./notes-YTB3TJOO.js"),
35425
- notion: () => import("./notion-4W4O7J7V.js"),
35426
- open_exchange_rates: () => import("./open_exchange_rates-23QJXVO5.js"),
35427
- openai: () => import("./openai-ZS7GLSLH.js"),
35428
- opengraph_io: () => import("./opengraph_io-PMVH7OYI.js"),
35429
- openrouter: () => import("./openrouter-ONRGFNB6.js"),
35430
- outline: () => import("./outline-UCUYZZ7J.js"),
35431
- paddle: () => import("./paddle-35HTKTUL.js"),
35432
- perplexity: () => import("./perplexity-NVOBYN24.js"),
35433
- pinecone: () => import("./pinecone-55CJY73C.js"),
35434
- pipedrive: () => import("./pipedrive-WMCAKS72.js"),
35435
- polar: () => import("./polar-SM4ZM53B.js"),
35436
- posthog: () => import("./posthog-NWCXVXNJ.js"),
35437
- postmark: () => import("./postmark-QJV5PHUQ.js"),
35438
- prerender: () => import("./prerender-2W7UT4SC.js"),
35439
- pubmed: () => import("./pubmed-VVV7XYLU.js"),
35440
- railway: () => import("./railway-KGI57S3O.js"),
35441
- readwise: () => import("./readwise-AGHTQB42.js"),
35442
- render: () => import("./render-O4HBROCK.js"),
35443
- replicate: () => import("./replicate-KWBOMX7D.js"),
35444
- resend: () => import("./resend-DRH6Y6I4.js"),
35445
- rootly: () => import("./rootly-XGCUDW6X.js"),
35446
- scrapfly: () => import("./scrapfly-OIQ3OY6L.js"),
35447
- scrapingbee: () => import("./scrapingbee-OCZO4FHX.js"),
35448
- screenshot_fyi: () => import("./screenshot_fyi-CUNGFZOC.js"),
35449
- semantic_scholar: () => import("./semantic_scholar-3UJRLKES.js"),
35450
- sentry: () => import("./sentry-5BWVZFJV.js"),
35451
- shodan: () => import("./shodan-HI37CTEW.js"),
35452
- shopify: () => import("./shopify-LJ2EV2HH.js"),
35453
- stripe: () => import("./stripe-3LHMV55K.js"),
35454
- supabase: () => import("./supabase-H2KPX3Q2.js"),
35455
- tavily: () => import("./tavily-FBEWGH3Z.js"),
35456
- telegram: () => import("./telegram-MYYO3JND.js"),
35457
- telnyx: () => import("./telnyx-H4ALEGAX.js"),
35458
- todoist: () => import("./todoist-OBWICA5Q.js"),
35459
- trello: () => import("./trello-GUFUJRWO.js"),
35460
- turso: () => import("./turso-NIAK4UMS.js"),
35461
- twilio: () => import("./twilio-K6SLK2CX.js"),
35462
- umami: () => import("./umami-42RS2EPS.js"),
35463
- unsplash: () => import("./unsplash-V7TOTETT.js"),
35464
- upstash_redis: () => import("./upstash_redis-AWQMB6Y3.js"),
35465
- uptimerobot: () => import("./uptimerobot-AZC2DHOT.js"),
35466
- v2ex: () => import("./v2ex-4TVRNMLS.js"),
35467
- vercel: () => import("./vercel-DPHTJ3XR.js"),
35468
- wolfram_alpha_api: () => import("./wolfram_alpha_api-XAG7IXBW.js"),
35469
- wordpress: () => import("./wordpress-KMPKVGUX.js"),
35470
- workos: () => import("./workos-PKB2YR7S.js"),
35471
- zhihu: () => import("./zhihu-Y4H4XYPB.js")
35192
+ airtable: () => import("./airtable-Z6KEL3MA.js"),
35193
+ alt_text_generator_ai: () => import("./alt_text_generator_ai-RM2GHSNM.js"),
35194
+ amap: () => import("./amap-YEJLGIKY.js"),
35195
+ anthropic: () => import("./anthropic-62M4MUVQ.js"),
35196
+ apify: () => import("./apify-AHRNDBCB.js"),
35197
+ brave_search: () => import("./brave_search-JAHWOMQC.js"),
35198
+ circleci: () => import("./circleci-UJUYBIAO.js"),
35199
+ clerk: () => import("./clerk-FCFM3WJK.js"),
35200
+ cohere: () => import("./cohere-OTSYSMPC.js"),
35201
+ confluence: () => import("./confluence-LPANSCGT.js"),
35202
+ convertapi: () => import("./convertapi-AJZOVUHT.js"),
35203
+ currencyapi: () => import("./currencyapi-HGK5FSGO.js"),
35204
+ deepseek: () => import("./deepseek-7HMTFJRV.js"),
35205
+ docker_hub: () => import("./docker_hub-FCNVKJZW.js"),
35206
+ dropbox: () => import("./dropbox-2XVKCQZE.js"),
35207
+ dub: () => import("./dub-CTUKPX2A.js"),
35208
+ e2b: () => import("./e2b-ULEWTRKI.js"),
35209
+ exa: () => import("./exa-QENFV3AU.js"),
35210
+ fal_ai: () => import("./fal_ai-TQYUBBAF.js"),
35211
+ feishu: () => import("./feishu-OYCWDSHD.js"),
35212
+ feishu_custom_bot: () => import("./feishu_custom_bot-VYQ7A3PU.js"),
35213
+ figma: () => import("./figma-5DLOKAQQ.js"),
35214
+ firehydrant: () => import("./firehydrant-X4MGP2OI.js"),
35215
+ fixer: () => import("./fixer-LMIWM3ZX.js"),
35216
+ fly: () => import("./fly-J5HN5L2I.js"),
35217
+ front: () => import("./front-E3SMBQW3.js"),
35218
+ geocodio: () => import("./geocodio-AOINRPLA.js"),
35219
+ ghost: () => import("./ghost-E4CBGZWJ.js"),
35220
+ github: () => import("./github-PGR6U3FC.js"),
35221
+ gmail: () => import("./gmail-XNQHMQ6F.js"),
35222
+ googlecalendar: () => import("./googlecalendar-RE6DGG7L.js"),
35223
+ googledocs: () => import("./googledocs-CX2BZDQH.js"),
35224
+ grafana: () => import("./grafana-GX75ZA5X.js"),
35225
+ graphhopper: () => import("./graphhopper-XMUYLWHS.js"),
35226
+ ip2proxy: () => import("./ip2proxy-ZGIRBAG5.js"),
35227
+ ipgeolocation_io: () => import("./ipgeolocation_io-MAP27QMO.js"),
35228
+ ipqualityscore: () => import("./ipqualityscore-6IIUUAQ2.js"),
35229
+ jina_ai: () => import("./jina_ai-GGH77RQH.js"),
35230
+ jira: () => import("./jira-7GPZW6HZ.js"),
35231
+ langsmith: () => import("./langsmith-CJXYE7WM.js"),
35232
+ lemlist: () => import("./lemlist-OYPOX6GN.js"),
35233
+ linear: () => import("./linear-TPQ6X4XZ.js"),
35234
+ logsnag: () => import("./logsnag-HT2PRLIV.js"),
35235
+ mattermost: () => import("./mattermost-6IYTWTM5.js"),
35236
+ mem0: () => import("./mem0-7AVGBGOX.js"),
35237
+ memos: () => import("./memos-CTOXWZ6X.js"),
35238
+ metabase: () => import("./metabase-AFJXQ5SQ.js"),
35239
+ mistral_ai: () => import("./mistral_ai-QDKM4N3R.js"),
35240
+ mother_duck: () => import("./mother_duck-XSKR4GVL.js"),
35241
+ ngrok: () => import("./ngrok-NQMLM24P.js"),
35242
+ notes: () => import("./notes-ZWMVZQWJ.js"),
35243
+ notion: () => import("./notion-6544KSMM.js"),
35244
+ open_exchange_rates: () => import("./open_exchange_rates-4CLN7O2N.js"),
35245
+ openai: () => import("./openai-HLFGPVI5.js"),
35246
+ opengraph_io: () => import("./opengraph_io-57JDHT3M.js"),
35247
+ openrouter: () => import("./openrouter-WDAVB2OP.js"),
35248
+ outline: () => import("./outline-A6MDLZVH.js"),
35249
+ paddle: () => import("./paddle-WX5ULOPP.js"),
35250
+ perplexity: () => import("./perplexity-LYTWWWCZ.js"),
35251
+ pinecone: () => import("./pinecone-7KAF3S7U.js"),
35252
+ pipedrive: () => import("./pipedrive-YQY243G7.js"),
35253
+ polar: () => import("./polar-A5HKXSQY.js"),
35254
+ posthog: () => import("./posthog-CF2LHLS4.js"),
35255
+ postmark: () => import("./postmark-W756TMJM.js"),
35256
+ prerender: () => import("./prerender-ZYM4UQ5R.js"),
35257
+ pubmed: () => import("./pubmed-QXTUQCTQ.js"),
35258
+ railway: () => import("./railway-F4MOZ3LQ.js"),
35259
+ readwise: () => import("./readwise-S7MF5SR5.js"),
35260
+ render: () => import("./render-D7EIVDUA.js"),
35261
+ replicate: () => import("./replicate-ABNKPZR7.js"),
35262
+ resend: () => import("./resend-7VJEY4KC.js"),
35263
+ rootly: () => import("./rootly-UMFJOKXC.js"),
35264
+ scrapfly: () => import("./scrapfly-UDT4KNFL.js"),
35265
+ scrapingbee: () => import("./scrapingbee-XTFD54NB.js"),
35266
+ screenshot_fyi: () => import("./screenshot_fyi-5GTW3SFY.js"),
35267
+ semantic_scholar: () => import("./semantic_scholar-Y6WK2MST.js"),
35268
+ sentry: () => import("./sentry-ZFPGDA6C.js"),
35269
+ shodan: () => import("./shodan-3SCDBOQ3.js"),
35270
+ shopify: () => import("./shopify-LMTBS2I2.js"),
35271
+ stripe: () => import("./stripe-4JQJ2CUG.js"),
35272
+ supabase: () => import("./supabase-7HA3BEFK.js"),
35273
+ tavily: () => import("./tavily-H34ZBPGC.js"),
35274
+ telegram: () => import("./telegram-CRX4YWQ3.js"),
35275
+ telnyx: () => import("./telnyx-TIKGEU34.js"),
35276
+ todoist: () => import("./todoist-LU563DGZ.js"),
35277
+ trello: () => import("./trello-NTRGEROX.js"),
35278
+ turso: () => import("./turso-EY3CNVPZ.js"),
35279
+ twilio: () => import("./twilio-ICX3WRQH.js"),
35280
+ umami: () => import("./umami-NPMRVI3M.js"),
35281
+ unsplash: () => import("./unsplash-TIHBZFIM.js"),
35282
+ upstash_redis: () => import("./upstash_redis-2DO6EHCN.js"),
35283
+ uptimerobot: () => import("./uptimerobot-BGYOCKGI.js"),
35284
+ v2ex: () => import("./v2ex-GOWDPGGA.js"),
35285
+ vercel: () => import("./vercel-G33RXVBI.js"),
35286
+ wolfram_alpha_api: () => import("./wolfram_alpha_api-IRZSMD3P.js"),
35287
+ wordpress: () => import("./wordpress-ATWGGUC3.js"),
35288
+ workos: () => import("./workos-LHJDETBX.js"),
35289
+ zhihu: () => import("./zhihu-IAH53YPP.js")
35472
35290
  };
35473
35291
 
35474
35292
  // ../plugins/src/catalog.generated.ts