@hasna/connectors 1.3.44 → 1.3.46

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 (114) hide show
  1. package/README.md +25 -0
  2. package/bin/index.js +792 -130
  3. package/bin/mcp.js +438 -52
  4. package/bin/serve.js +438 -52
  5. package/connectors/cloudflare-workers/.env.example +5 -0
  6. package/connectors/cloudflare-workers/AGENTS.md +11 -0
  7. package/connectors/cloudflare-workers/CLAUDE.md +11 -0
  8. package/connectors/cloudflare-workers/README.md +45 -0
  9. package/connectors/cloudflare-workers/package.json +47 -0
  10. package/connectors/cloudflare-workers/src/api/client.test.ts +144 -0
  11. package/connectors/cloudflare-workers/src/api/client.ts +386 -0
  12. package/connectors/cloudflare-workers/src/api/index.ts +1 -0
  13. package/connectors/cloudflare-workers/src/cli/index.ts +206 -0
  14. package/connectors/cloudflare-workers/src/index.ts +16 -0
  15. package/connectors/cloudflare-workers/src/types/index.ts +53 -0
  16. package/connectors/cloudflare-workers/src/utils/config.ts +61 -0
  17. package/connectors/cloudflare-workers/src/utils/output.ts +26 -0
  18. package/connectors/cloudflare-workers/tsconfig.build.json +4 -0
  19. package/connectors/cloudflare-workers/tsconfig.json +14 -0
  20. package/connectors/tidio/.env.example +3 -2
  21. package/connectors/tidio/CLAUDE.md +21 -96
  22. package/connectors/tidio/README.md +22 -18
  23. package/connectors/tidio/package.json +4 -2
  24. package/connectors/tidio/src/api/client.ts +26 -15
  25. package/connectors/tidio/src/api/index.ts +185 -128
  26. package/connectors/tidio/src/api/tidio.test.ts +175 -44
  27. package/connectors/tidio/src/cli/index.ts +154 -388
  28. package/connectors/tidio/src/index.ts +5 -3
  29. package/connectors/tidio/src/types/index.ts +135 -82
  30. package/connectors/tidio/src/utils/config.ts +90 -44
  31. package/connectors/wandb/.env.example +7 -0
  32. package/connectors/wandb/AGENTS.md +43 -0
  33. package/connectors/wandb/CLAUDE.md +67 -0
  34. package/connectors/wandb/README.md +65 -0
  35. package/connectors/wandb/package.json +52 -0
  36. package/connectors/wandb/src/api/client.test.ts +116 -0
  37. package/connectors/wandb/src/api/client.ts +83 -0
  38. package/connectors/wandb/src/api/graphql.ts +9 -0
  39. package/connectors/wandb/src/api/index.ts +36 -0
  40. package/connectors/wandb/src/api/projects.ts +36 -0
  41. package/connectors/wandb/src/api/viewer.ts +20 -0
  42. package/connectors/wandb/src/cli/index.ts +265 -0
  43. package/connectors/wandb/src/index.ts +22 -0
  44. package/connectors/wandb/src/types/index.ts +75 -0
  45. package/connectors/wandb/src/utils/config.ts +164 -0
  46. package/connectors/wandb/src/utils/output.ts +119 -0
  47. package/connectors/wandb/tsconfig.json +16 -0
  48. package/connectors/weights-biases/.env.example +7 -0
  49. package/connectors/weights-biases/CLAUDE.md +65 -0
  50. package/connectors/weights-biases/README.md +62 -0
  51. package/connectors/weights-biases/package.json +53 -0
  52. package/connectors/weights-biases/src/api/client.test.ts +46 -0
  53. package/connectors/weights-biases/src/api/client.ts +119 -0
  54. package/connectors/weights-biases/src/api/events.ts +18 -0
  55. package/connectors/weights-biases/src/api/index.ts +56 -0
  56. package/connectors/weights-biases/src/api/runs.ts +28 -0
  57. package/connectors/weights-biases/src/api/search.ts +10 -0
  58. package/connectors/weights-biases/src/cli/index.ts +289 -0
  59. package/connectors/weights-biases/src/index.ts +19 -0
  60. package/connectors/weights-biases/src/types/index.ts +92 -0
  61. package/connectors/weights-biases/src/utils/config.ts +168 -0
  62. package/connectors/weights-biases/src/utils/output.ts +116 -0
  63. package/connectors/weights-biases/tsconfig.json +16 -0
  64. package/connectors/zoominfo/.env.example +4 -0
  65. package/connectors/zoominfo/AGENTS.md +26 -0
  66. package/connectors/zoominfo/CLAUDE.md +20 -0
  67. package/connectors/zoominfo/README.md +69 -0
  68. package/connectors/zoominfo/package.json +52 -0
  69. package/connectors/zoominfo/src/api/client.test.ts +140 -0
  70. package/connectors/zoominfo/src/api/client.ts +228 -0
  71. package/connectors/zoominfo/src/api/index.ts +1 -0
  72. package/connectors/zoominfo/src/cli/index.ts +179 -0
  73. package/connectors/zoominfo/src/index.ts +3 -0
  74. package/connectors/zoominfo/src/types/index.ts +39 -0
  75. package/connectors/zoominfo/src/utils/config.ts +61 -0
  76. package/connectors/zoominfo/src/utils/output.ts +27 -0
  77. package/connectors/zoominfo/tsconfig.json +20 -0
  78. package/connectors/zotero/.env.example +7 -0
  79. package/connectors/zotero/.npmrc.example +2 -0
  80. package/connectors/zotero/AGENTS.md +40 -0
  81. package/connectors/zotero/CLAUDE.md +69 -0
  82. package/connectors/zotero/README.md +91 -0
  83. package/connectors/zotero/package.json +43 -0
  84. package/connectors/zotero/src/api/attachments.ts +130 -0
  85. package/connectors/zotero/src/api/client.test.ts +166 -0
  86. package/connectors/zotero/src/api/client.ts +169 -0
  87. package/connectors/zotero/src/api/collections.ts +26 -0
  88. package/connectors/zotero/src/api/index.ts +45 -0
  89. package/connectors/zotero/src/api/items.ts +64 -0
  90. package/connectors/zotero/src/cli/index.ts +386 -0
  91. package/connectors/zotero/src/index.ts +28 -0
  92. package/connectors/zotero/src/types/index.ts +129 -0
  93. package/connectors/zotero/src/utils/config.ts +245 -0
  94. package/connectors/zotero/src/utils/output.ts +119 -0
  95. package/connectors/zotero/tsconfig.json +16 -0
  96. package/connectors/zymbly/.env.example +2 -0
  97. package/connectors/zymbly/AGENTS.md +11 -0
  98. package/connectors/zymbly/CLAUDE.md +5 -0
  99. package/connectors/zymbly/README.md +35 -0
  100. package/connectors/zymbly/package.json +52 -0
  101. package/connectors/zymbly/src/api/client.test.ts +110 -0
  102. package/connectors/zymbly/src/api/client.ts +166 -0
  103. package/connectors/zymbly/src/api/index.ts +1 -0
  104. package/connectors/zymbly/src/cli/index.ts +156 -0
  105. package/connectors/zymbly/src/index.ts +12 -0
  106. package/connectors/zymbly/src/types/index.ts +34 -0
  107. package/connectors/zymbly/src/utils/config.ts +52 -0
  108. package/connectors/zymbly/src/utils/output.ts +17 -0
  109. package/connectors/zymbly/tsconfig.json +13 -0
  110. package/dist/index.js +45 -2
  111. package/dist/lib/compact-output.d.ts +40 -0
  112. package/dist/mcp/tools/jobs.d.ts +32 -0
  113. package/dist/mcp/tools/jobs.test.d.ts +1 -0
  114. package/package.json +3 -2
package/bin/mcp.js CHANGED
@@ -5804,7 +5804,7 @@ var package_default;
5804
5804
  var init_package = __esm(() => {
5805
5805
  package_default = {
5806
5806
  name: "@hasna/connectors",
5807
- version: "1.3.41",
5807
+ version: "1.3.46",
5808
5808
  description: "Open source connector library - Install API connectors with a single command",
5809
5809
  type: "module",
5810
5810
  bin: {
@@ -5836,11 +5836,12 @@ var init_package = __esm(() => {
5836
5836
  "build:dashboard": "cd dashboard && bun run build",
5837
5837
  postinstall: 'mkdir -p $HOME/.hasna/connectors 2>/dev/null || true; [ "$SKIP_DASHBOARD" = "1" ] || [ ! -f dashboard/package.json ] || [ -d dashboard/node_modules ] || (cd dashboard && bun install)',
5838
5838
  dev: "bun run ./src/cli/index.tsx",
5839
+ "check:package-secrets": "bun run scripts/check-package-secrets.ts",
5839
5840
  typecheck: "tsc --noEmit && tsc -p tsconfig.social.json --noEmit",
5840
5841
  test: "bun test",
5841
5842
  "secrets:scan:npmrc": "bun run scripts/scan-npmrc-auth.mjs",
5842
5843
  "sdk:build": "cd sdk && bun run build",
5843
- prepublishOnly: "bun run secrets:scan:npmrc && bun run build && bun test"
5844
+ prepublishOnly: "bun run secrets:scan:npmrc && bun run check:package-secrets && bun run build && bun test"
5844
5845
  },
5845
5846
  keywords: [
5846
5847
  "connectors",
@@ -32573,6 +32574,13 @@ var connectors = [
32573
32574
  category: "AI & ML",
32574
32575
  tags: ["transcription", "meetings", "ai"]
32575
32576
  },
32577
+ {
32578
+ name: "wandb",
32579
+ displayName: "Weights & Biases",
32580
+ description: "ML experiment tracking and run management via GraphQL",
32581
+ category: "AI & ML",
32582
+ tags: ["ml", "experiments", "tracking"]
32583
+ },
32576
32584
  {
32577
32585
  name: "wato",
32578
32586
  displayName: "Wato",
@@ -32580,6 +32588,13 @@ var connectors = [
32580
32588
  category: "AI & ML",
32581
32589
  tags: ["ai", "agents", "memory", "workflows"]
32582
32590
  },
32591
+ {
32592
+ name: "weights-biases",
32593
+ displayName: "Weights & Biases",
32594
+ description: "ML experiment tracking (runs, events, search)",
32595
+ category: "AI & ML",
32596
+ tags: ["ai", "ml", "wandb", "experiment-tracking"]
32597
+ },
32583
32598
  {
32584
32599
  name: "wavelineextract",
32585
32600
  displayName: "Waveline Extract",
@@ -34218,6 +34233,20 @@ var connectors3 = [
34218
34233
  description: "HR platform for employees, leave, attendance, and timesheets",
34219
34234
  category: "Business Tools",
34220
34235
  tags: ["hr", "employees", "zoho"]
34236
+ },
34237
+ {
34238
+ name: "zymbly",
34239
+ displayName: "Zymbly",
34240
+ description: "Aircraft maintenance and CMMS platform for work orders, parts, and maintenance notes",
34241
+ category: "Business Tools",
34242
+ tags: ["maintenance", "aircraft", "work-orders", "cmms"]
34243
+ },
34244
+ {
34245
+ name: "zotero",
34246
+ displayName: "Zotero",
34247
+ description: "Bibliography and reference library API for items, collections, and attachments",
34248
+ category: "Business Tools",
34249
+ tags: ["bibliography", "citations", "research", "library", "references"]
34221
34250
  }
34222
34251
  ];
34223
34252
 
@@ -36728,6 +36757,13 @@ var connectors9 = [
36728
36757
  category: "Developer Tools",
36729
36758
  tags: ["cdn", "dns", "edge"]
36730
36759
  },
36760
+ {
36761
+ name: "cloudflare-workers",
36762
+ displayName: "Cloudflare Workers",
36763
+ description: "Cloudflare Workers REST API connector for scripts, multipart uploads, routes, deployments, versions, secrets, cron schedules, tails, subdomains, beta Workers, and scoped raw account or zone requests",
36764
+ category: "Developer Tools",
36765
+ tags: ["cloudflare", "workers", "serverless", "edge", "deployments", "developer-tools"]
36766
+ },
36731
36767
  {
36732
36768
  name: "googlecloud",
36733
36769
  displayName: "Google Cloud",
@@ -39120,6 +39156,13 @@ var connectors14 = [
39120
39156
  description: "Reviews and user-generated content platform for e-commerce",
39121
39157
  category: "Marketing & Sales",
39122
39158
  tags: ["reviews", "ugc", "ecommerce", "marketing"]
39159
+ },
39160
+ {
39161
+ name: "zoominfo",
39162
+ displayName: "ZoomInfo",
39163
+ description: "ZoomInfo B2B sales intelligence API for contact and company search, enrichment, lookup, and output field discovery",
39164
+ category: "Marketing & Sales",
39165
+ tags: ["sales-intelligence", "enrichment", "contacts", "companies", "b2b"]
39123
39166
  }
39124
39167
  ];
39125
39168
 
@@ -43503,30 +43546,126 @@ init_package();
43503
43546
 
43504
43547
  // src/mcp/tools/discovery.ts
43505
43548
  init_zod();
43549
+
43550
+ // src/lib/compact-output.ts
43551
+ var DEFAULT_MCP_LIMIT = 20;
43552
+ var MAX_COMPACT_LIMIT = 100;
43553
+ var DEFAULT_TEXT_WIDTH = 96;
43554
+ var DEFAULT_OUTPUT_CHARS = 6000;
43555
+ function parseNonNegativeInt(raw, flag) {
43556
+ if (raw === undefined)
43557
+ return { value: undefined };
43558
+ if (!/^\d+$/.test(raw)) {
43559
+ return {
43560
+ value: undefined,
43561
+ error: `Invalid value for ${flag}: '${raw}'. Expected a non-negative integer.`
43562
+ };
43563
+ }
43564
+ return { value: parseInt(raw, 10) };
43565
+ }
43566
+ function normalizeLimit(value, fallback, max = MAX_COMPACT_LIMIT) {
43567
+ if (value === undefined || !Number.isFinite(value))
43568
+ return fallback;
43569
+ return Math.min(Math.max(1, Math.floor(value)), max);
43570
+ }
43571
+ function parseCursor(raw) {
43572
+ if (raw === undefined || raw === "")
43573
+ return { value: 0 };
43574
+ return parseNonNegativeInt(raw, "--cursor");
43575
+ }
43576
+ function pageItems(items, options) {
43577
+ const offset = Math.max(0, options.offset ?? 0);
43578
+ const limit = options.limit === undefined ? undefined : Math.max(1, Math.floor(options.limit));
43579
+ const paged = limit === undefined ? items.slice(offset) : items.slice(offset, offset + limit);
43580
+ const nextOffset = limit === undefined || offset + paged.length >= items.length ? null : offset + paged.length;
43581
+ return {
43582
+ items: paged,
43583
+ total: items.length,
43584
+ offset,
43585
+ limit: limit ?? null,
43586
+ nextOffset
43587
+ };
43588
+ }
43589
+ function truncateText(value, max = DEFAULT_TEXT_WIDTH) {
43590
+ const text = (value ?? "").replace(/\s+/g, " ").trim();
43591
+ if (text.length <= max)
43592
+ return text;
43593
+ if (max <= 3)
43594
+ return text.slice(0, max);
43595
+ return `${text.slice(0, max - 3).trimEnd()}...`;
43596
+ }
43597
+ function firstNonEmptyLines(value, maxLines, maxWidth = DEFAULT_TEXT_WIDTH) {
43598
+ return (value ?? "").split(`
43599
+ `).map((line) => line.trim()).filter(Boolean).slice(0, maxLines).map((line) => truncateText(line, maxWidth));
43600
+ }
43601
+ function compactConnector(connector, descriptionWidth = DEFAULT_TEXT_WIDTH) {
43602
+ return {
43603
+ name: connector.name,
43604
+ displayName: connector.displayName,
43605
+ version: connector.version,
43606
+ category: connector.category,
43607
+ description: truncateText(connector.description, descriptionWidth)
43608
+ };
43609
+ }
43610
+ function maybeTruncateOutput(text, options = {}) {
43611
+ const enabled = options.enabled ?? true;
43612
+ const maxChars = options.maxChars ?? DEFAULT_OUTPUT_CHARS;
43613
+ if (!enabled || text.length <= maxChars) {
43614
+ return { text, truncated: false };
43615
+ }
43616
+ const hint = options.hint ?? "Use --verbose for full output.";
43617
+ const omitted = text.length - maxChars;
43618
+ return {
43619
+ text: `${text.slice(0, maxChars).trimEnd()}
43620
+
43621
+ [truncated ${omitted} chars] ${hint}`,
43622
+ truncated: true
43623
+ };
43624
+ }
43625
+
43626
+ // src/mcp/tools/discovery.ts
43506
43627
  function registerDiscoveryTools(server, stripped) {
43507
43628
  server.registerTool("search_connectors", {
43508
43629
  title: "Search Connectors",
43509
43630
  description: "Search connectors by name or keyword.",
43510
- inputSchema: { query: exports_external.string() }
43511
- }, async ({ query }) => {
43631
+ inputSchema: {
43632
+ query: exports_external.string(),
43633
+ limit: exports_external.number().optional(),
43634
+ verbose: exports_external.boolean().optional()
43635
+ }
43636
+ }, async ({ query, limit, verbose }) => {
43512
43637
  const { getInstalledConnectors: getInstalledConnectors2 } = await Promise.resolve().then(() => (init_installer(), exports_installer));
43513
43638
  const { getPromotedConnectors: getPromotedConnectors2 } = await Promise.resolve().then(() => (init_promotions(), exports_promotions));
43514
43639
  const { getUsageMap: getUsageMap2 } = await Promise.resolve().then(() => (init_usage(), exports_usage));
43640
+ const resultLimit = normalizeLimit(limit, DEFAULT_MCP_LIMIT);
43515
43641
  const results = searchConnectors(query, {
43516
43642
  installed: getInstalledConnectors2(),
43517
43643
  promoted: getPromotedConnectors2(),
43518
- usage: getUsageMap2()
43644
+ usage: getUsageMap2(),
43645
+ limit: resultLimit
43519
43646
  });
43520
- return stripped(JSON.stringify(results.map((c) => ({ name: c.name, displayName: c.displayName, version: c.version, category: c.category, description: c.description, score: c.score, badges: c.badges })), null, 2));
43647
+ return stripped(JSON.stringify(results.map((c) => ({
43648
+ name: c.name,
43649
+ displayName: c.displayName,
43650
+ version: c.version,
43651
+ category: c.category,
43652
+ description: verbose ? c.description : truncateText(c.description, 120),
43653
+ score: c.score,
43654
+ badges: c.badges,
43655
+ ...verbose ? { matchReasons: c.matchReasons } : {}
43656
+ })), null, 2));
43521
43657
  });
43522
43658
  server.registerTool("list_connectors", {
43523
43659
  title: "List Connectors",
43524
- description: "List connectors. category filters; compact=true returns names only.",
43660
+ description: "List connectors with compact, paged defaults. Use verbose=true or compact=false for full metadata.",
43525
43661
  inputSchema: {
43526
43662
  category: exports_external.string().optional(),
43527
- compact: exports_external.boolean().optional()
43663
+ compact: exports_external.boolean().optional(),
43664
+ limit: exports_external.number().optional(),
43665
+ cursor: exports_external.string().optional(),
43666
+ verbose: exports_external.boolean().optional()
43528
43667
  }
43529
- }, async ({ category, compact }) => {
43668
+ }, async ({ category, compact, limit, cursor, verbose }) => {
43530
43669
  let connectors18 = CONNECTORS;
43531
43670
  if (category) {
43532
43671
  const matched = CATEGORIES.find((c) => c.toLowerCase() === category.toLowerCase());
@@ -43543,23 +43682,42 @@ function registerDiscoveryTools(server, stripped) {
43543
43682
  }
43544
43683
  connectors18 = getConnectorsByCategory(matched);
43545
43684
  }
43546
- const data = compact ? connectors18.map((c) => c.name) : connectors18.map((c) => ({
43685
+ const parsedCursor = parseCursor(cursor);
43686
+ if (parsedCursor.error) {
43687
+ return {
43688
+ content: [{ type: "text", text: JSON.stringify({ error: parsedCursor.error }) }],
43689
+ isError: true
43690
+ };
43691
+ }
43692
+ const page = pageItems(connectors18, {
43693
+ offset: parsedCursor.value ?? 0,
43694
+ limit: normalizeLimit(limit, DEFAULT_MCP_LIMIT)
43695
+ });
43696
+ const data = compact === true ? page.items.map((c) => c.name) : verbose || compact === false ? page.items.map((c) => ({
43547
43697
  name: c.name,
43548
43698
  displayName: c.displayName,
43549
43699
  version: c.version,
43550
43700
  category: c.category,
43551
- description: c.description
43552
- }));
43553
- return stripped(JSON.stringify(data, null, 2));
43701
+ description: c.description,
43702
+ tags: c.tags
43703
+ })) : page.items.map((c) => compactConnector(c, 120));
43704
+ return stripped(JSON.stringify({
43705
+ connectors: data,
43706
+ total: connectors18.length,
43707
+ count: data.length,
43708
+ nextCursor: page.nextOffset === null ? null : String(page.nextOffset),
43709
+ hint: page.nextOffset === null ? "Use verbose=true or compact=false for full connector metadata." : `Call again with cursor="${page.nextOffset}", or use verbose=true / compact=false for full connector metadata.`
43710
+ }, null, 2));
43554
43711
  });
43555
43712
  server.registerTool("connector_docs", {
43556
43713
  title: "Connector Documentation",
43557
- description: "Get connector docs. essential=true returns auth+envVars only.",
43714
+ description: "Get compact connector docs by default. Use verbose=true for full parsed docs or essential=true for auth+env only.",
43558
43715
  inputSchema: {
43559
43716
  name: exports_external.string(),
43560
- essential: exports_external.boolean().optional()
43717
+ essential: exports_external.boolean().optional(),
43718
+ verbose: exports_external.boolean().optional()
43561
43719
  }
43562
- }, async ({ name, essential }) => {
43720
+ }, async ({ name, essential, verbose }) => {
43563
43721
  const meta = getConnector(name);
43564
43722
  if (!meta) {
43565
43723
  return {
@@ -43575,7 +43733,7 @@ function registerDiscoveryTools(server, stripped) {
43575
43733
  isError: true
43576
43734
  };
43577
43735
  }
43578
- const data = essential ? { name: meta.name, auth: docs.auth, envVars: docs.envVars } : {
43736
+ const data = essential ? { name: meta.name, auth: docs.auth, envVars: docs.envVars } : verbose ? {
43579
43737
  name: meta.name,
43580
43738
  displayName: meta.displayName,
43581
43739
  version: meta.version,
@@ -43586,6 +43744,19 @@ function registerDiscoveryTools(server, stripped) {
43586
43744
  envVars: docs.envVars,
43587
43745
  cliCommands: docs.cliCommands,
43588
43746
  dataStorage: docs.dataStorage
43747
+ } : {
43748
+ name: meta.name,
43749
+ displayName: meta.displayName,
43750
+ version: meta.version,
43751
+ category: meta.category,
43752
+ description: truncateText(meta.description, 120),
43753
+ overview: firstNonEmptyLines(docs.overview, 1, 140)[0] ?? "",
43754
+ auth: firstNonEmptyLines(docs.auth, 4, 140),
43755
+ envVars: docs.envVars.slice(0, 8),
43756
+ envVarCount: docs.envVars.length,
43757
+ cliCommands: firstNonEmptyLines(docs.cliCommands, 8, 140),
43758
+ dataStorage: firstNonEmptyLines(docs.dataStorage, 2, 140),
43759
+ hint: `Use connector_docs({ name: "${name}", verbose: true }) for full parsed docs, or raw CLI docs with connectors docs ${name} --raw.`
43589
43760
  };
43590
43761
  return {
43591
43762
  content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
@@ -44010,9 +44181,11 @@ function registerOperationsTools(server, stripped) {
44010
44181
  description: "Discover available API operations for a connector. Returns CLI commands the connector supports (e.g. messages, products, customers). Use this before run_connector_operation to know what's available.",
44011
44182
  inputSchema: {
44012
44183
  name: exports_external.string().describe("Connector name (e.g. stripe, gmail, anthropic)"),
44013
- command: exports_external.string().optional().describe("Get detailed help for a specific subcommand (e.g. products, messages)")
44184
+ command: exports_external.string().optional().describe("Get detailed help for a specific subcommand (e.g. products, messages)"),
44185
+ verbose: exports_external.boolean().optional().describe("Include full auth status and raw help text."),
44186
+ limit: exports_external.number().optional().describe("Limit operation rows in compact mode.")
44014
44187
  }
44015
- }, async ({ name, command }) => {
44188
+ }, async ({ name, command, verbose, limit }) => {
44016
44189
  const meta = getConnector(name);
44017
44190
  if (!meta) {
44018
44191
  return {
@@ -44044,6 +44217,32 @@ function registerOperationsTools(server, stripped) {
44044
44217
  }
44045
44218
  const ops = await getConnectorOperations(name);
44046
44219
  const auth = getAuthStatus(name);
44220
+ if (!verbose) {
44221
+ const operationLimit = normalizeLimit(limit, 50);
44222
+ const operations = ops.operations.slice(0, operationLimit).map((operation) => ({
44223
+ name: operation.name,
44224
+ aliases: operation.aliases,
44225
+ usage: operation.usage,
44226
+ summary: truncateText(operation.summary || "", 140),
44227
+ source: operation.source
44228
+ }));
44229
+ return {
44230
+ content: [
44231
+ {
44232
+ type: "text",
44233
+ text: JSON.stringify({
44234
+ connector: name,
44235
+ displayName: meta.displayName,
44236
+ auth: { type: auth.type, configured: auth.configured },
44237
+ commands: ops.commands,
44238
+ operations,
44239
+ totalOperations: ops.operations.length,
44240
+ hint: `Use list_connector_operations({ name: "${name}", verbose: true }) for full help text, or command="<subcommand>" for one command.`
44241
+ }, null, 2)
44242
+ }
44243
+ ]
44244
+ };
44245
+ }
44047
44246
  return {
44048
44247
  content: [
44049
44248
  {
@@ -44067,9 +44266,11 @@ function registerOperationsTools(server, stripped) {
44067
44266
  name: exports_external.string().describe("Connector name (e.g. stripe, gmail, anthropic)"),
44068
44267
  args: exports_external.array(exports_external.string()).describe("CLI arguments for the connector command (e.g. ['products', 'list', '--limit', '5'])"),
44069
44268
  format: exports_external.enum(["json", "pretty"]).optional().describe("Output format (default: json for structured parsing)"),
44070
- timeout: exports_external.number().optional().describe("Timeout in milliseconds (default: 30000)")
44269
+ timeout: exports_external.number().optional().describe("Timeout in milliseconds (default: 30000)"),
44270
+ verbose: exports_external.boolean().optional().describe("Return full stdout/stderr without output truncation."),
44271
+ maxOutputChars: exports_external.number().optional().describe("Maximum output characters when verbose is false (default: 6000).")
44071
44272
  }
44072
- }, async ({ name, args, format, timeout }) => {
44273
+ }, async ({ name, args, format, timeout, verbose, maxOutputChars }) => {
44073
44274
  const meta = getConnector(name);
44074
44275
  if (!meta) {
44075
44276
  return {
@@ -44092,6 +44293,11 @@ function registerOperationsTools(server, stripped) {
44092
44293
  ${result.stderr}`;
44093
44294
  const looksLikeHelp = /Usage:|Commands:|Options:/i.test(combinedOutput);
44094
44295
  if (!result.success && !looksLikeHelp) {
44296
+ const output = maybeTruncateOutput(result.stderr || result.stdout, {
44297
+ enabled: !verbose,
44298
+ maxChars: maxOutputChars ?? DEFAULT_OUTPUT_CHARS,
44299
+ hint: "Set verbose=true or maxOutputChars higher for full error output."
44300
+ });
44095
44301
  return {
44096
44302
  content: [
44097
44303
  {
@@ -44099,7 +44305,9 @@ ${result.stderr}`;
44099
44305
  text: JSON.stringify({
44100
44306
  connector: name,
44101
44307
  success: false,
44102
- error: result.stderr || result.stdout
44308
+ error: output.text,
44309
+ outputTruncated: output.truncated,
44310
+ hint: verbose ? undefined : "MCP error output is compact by default. Set verbose=true or maxOutputChars for more output."
44103
44311
  }, null, 2)
44104
44312
  }
44105
44313
  ],
@@ -44113,7 +44321,11 @@ ${result.stderr}`;
44113
44321
  text: JSON.stringify({
44114
44322
  connector: name,
44115
44323
  success: true,
44116
- output: looksLikeHelp ? (result.stdout || result.stderr).trim() : result.stdout
44324
+ output: maybeTruncateOutput(looksLikeHelp ? (result.stdout || result.stderr).trim() : result.stdout, {
44325
+ enabled: !verbose,
44326
+ maxChars: maxOutputChars ?? DEFAULT_OUTPUT_CHARS,
44327
+ hint: "Set verbose=true or maxOutputChars higher for full output."
44328
+ }).text
44117
44329
  }, null, 2)
44118
44330
  }
44119
44331
  ]
@@ -44130,11 +44342,14 @@ function registerSearchTools(server, stripped) {
44130
44342
  description: "Search for available operations across installed connectors.",
44131
44343
  inputSchema: {
44132
44344
  query: exports_external.string(),
44133
- installedOnly: exports_external.boolean().optional()
44345
+ installedOnly: exports_external.boolean().optional(),
44346
+ limit: exports_external.number().optional(),
44347
+ verbose: exports_external.boolean().optional()
44134
44348
  }
44135
- }, async ({ query, installedOnly }) => {
44349
+ }, async ({ query, installedOnly, limit, verbose }) => {
44136
44350
  const installed = installedOnly ? getInstalledConnectors() : null;
44137
44351
  const results = [];
44352
+ const resultLimit = normalizeLimit(limit, DEFAULT_MCP_LIMIT);
44138
44353
  const connectors18 = installed || getInstalledConnectors();
44139
44354
  for (const name of connectors18) {
44140
44355
  try {
@@ -44153,22 +44368,31 @@ function registerSearchTools(server, stripped) {
44153
44368
  results.push({
44154
44369
  connector: name,
44155
44370
  operation: operation.name,
44156
- description: operation.summary || ops.helpText || ""
44371
+ description: verbose ? operation.summary || ops.helpText || "" : truncateText(operation.summary || ops.helpText || "", 160)
44157
44372
  });
44373
+ if (results.length >= resultLimit)
44374
+ break;
44158
44375
  }
44159
44376
  }
44377
+ if (results.length >= resultLimit)
44378
+ break;
44160
44379
  } catch {}
44161
44380
  }
44162
- return stripped(JSON.stringify(results, null, 2));
44381
+ return stripped(JSON.stringify({
44382
+ results,
44383
+ count: results.length,
44384
+ hint: "Use limit=<n> for more rows and verbose=true for longer descriptions."
44385
+ }, null, 2));
44163
44386
  });
44164
44387
  server.registerTool("describe_tools", {
44165
44388
  title: "Describe Tools",
44166
44389
  description: "Get detailed documentation for a connector's operations.",
44167
44390
  inputSchema: {
44168
44391
  name: exports_external.string(),
44169
- operation: exports_external.string().optional()
44392
+ operation: exports_external.string().optional(),
44393
+ verbose: exports_external.boolean().optional()
44170
44394
  }
44171
- }, async ({ name, operation }) => {
44395
+ }, async ({ name, operation, verbose }) => {
44172
44396
  const meta = getConnector(name);
44173
44397
  if (!meta) {
44174
44398
  return {
@@ -44184,7 +44408,23 @@ function registerSearchTools(server, stripped) {
44184
44408
  };
44185
44409
  }
44186
44410
  const ops = await getConnectorOperations(name);
44187
- return stripped(JSON.stringify({ connector: name, displayName: meta.displayName, ...ops }, null, 2));
44411
+ if (verbose) {
44412
+ return stripped(JSON.stringify({ connector: name, displayName: meta.displayName, ...ops }, null, 2));
44413
+ }
44414
+ return stripped(JSON.stringify({
44415
+ connector: name,
44416
+ displayName: meta.displayName,
44417
+ commands: ops.commands,
44418
+ operations: ops.operations.map((item) => ({
44419
+ name: item.name,
44420
+ aliases: item.aliases,
44421
+ usage: item.usage,
44422
+ summary: truncateText(item.summary || "", 140),
44423
+ source: item.source
44424
+ })),
44425
+ totalOperations: ops.operations.length,
44426
+ hint: `Use describe_tools({ name: "${name}", verbose: true }) for full help text.`
44427
+ }, null, 2));
44188
44428
  });
44189
44429
  }
44190
44430
  // src/mcp/tools/ranking.ts
@@ -44371,60 +44611,179 @@ async function triggerJob(job, db) {
44371
44611
  }
44372
44612
 
44373
44613
  // src/mcp/tools/jobs.ts
44614
+ var DEFAULT_EXECUTION_OUTPUT_CHARS = 2000;
44615
+ var MAX_EXECUTION_OUTPUT_CHARS = 50000;
44616
+ function normalizeOutputChars(value) {
44617
+ return normalizeLimit(value, DEFAULT_EXECUTION_OUTPUT_CHARS, MAX_EXECUTION_OUTPUT_CHARS);
44618
+ }
44619
+ function compactExecutionText(text, options, label) {
44620
+ return maybeTruncateOutput(text, {
44621
+ enabled: !options.verbose,
44622
+ maxChars: normalizeOutputChars(options.maxOutputChars),
44623
+ hint: `Set verbose=true or maxOutputChars higher for full ${label} output.`
44624
+ });
44625
+ }
44626
+ function compactJobExecutionResult(result, options = {}) {
44627
+ const output = compactExecutionText(result.output, options, "job");
44628
+ return {
44629
+ ...result,
44630
+ output: output.text,
44631
+ outputTruncated: output.truncated,
44632
+ hint: options.verbose ? undefined : "MCP job output is compact by default. Set verbose=true or maxOutputChars for more output."
44633
+ };
44634
+ }
44635
+ function compactWorkflowExecutionResult(result, options = {}) {
44636
+ let truncatedOutputs = 0;
44637
+ const steps = result.steps.map((step) => {
44638
+ const output = compactExecutionText(step.output, options, "workflow step");
44639
+ if (output.truncated)
44640
+ truncatedOutputs++;
44641
+ return {
44642
+ ...step,
44643
+ output: output.text,
44644
+ outputTruncated: output.truncated
44645
+ };
44646
+ });
44647
+ const finalOutput = compactExecutionText(result.final_output, options, "workflow final");
44648
+ if (finalOutput.truncated)
44649
+ truncatedOutputs++;
44650
+ return {
44651
+ ...result,
44652
+ steps,
44653
+ final_output: finalOutput.text,
44654
+ finalOutputTruncated: finalOutput.truncated,
44655
+ truncatedOutputs,
44656
+ hint: options.verbose ? undefined : "MCP workflow output is compact by default. Set verbose=true or maxOutputChars for more output."
44657
+ };
44658
+ }
44374
44659
  function registerJobsTools(server, stripped) {
44375
44660
  server.registerTool("list_jobs", {
44376
44661
  title: "List Jobs",
44377
- description: "List scheduled connector jobs.",
44378
- inputSchema: {}
44379
- }, async () => {
44662
+ description: "List scheduled connector jobs with compact, paged defaults.",
44663
+ inputSchema: {
44664
+ limit: exports_external.number().optional(),
44665
+ cursor: exports_external.string().optional(),
44666
+ verbose: exports_external.boolean().optional()
44667
+ }
44668
+ }, async ({ limit, cursor, verbose }) => {
44669
+ const parsedCursor = parseCursor(cursor);
44670
+ if (parsedCursor.error) {
44671
+ return { content: [{ type: "text", text: JSON.stringify({ error: parsedCursor.error }) }], isError: true };
44672
+ }
44380
44673
  const db = getDatabase();
44381
44674
  const jobs = listJobs(db);
44382
- return stripped(JSON.stringify(jobs, null, 2));
44675
+ const page = pageItems(jobs, {
44676
+ offset: parsedCursor.value ?? 0,
44677
+ limit: normalizeLimit(limit, DEFAULT_MCP_LIMIT)
44678
+ });
44679
+ const data = verbose ? page.items : page.items.map((job) => ({
44680
+ name: job.name,
44681
+ connector: job.connector,
44682
+ command: `${job.command}${job.args.length ? ` ${job.args.join(" ")}` : ""}`,
44683
+ cron: job.cron,
44684
+ enabled: job.enabled,
44685
+ strip: job.strip,
44686
+ lastRunAt: job.last_run_at
44687
+ }));
44688
+ return stripped(JSON.stringify({
44689
+ jobs: data,
44690
+ total: jobs.length,
44691
+ count: data.length,
44692
+ nextCursor: page.nextOffset === null ? null : String(page.nextOffset),
44693
+ hint: "Use verbose=true for full job records, get_latest_job_run for run output, or connectors jobs show <name>."
44694
+ }, null, 2));
44383
44695
  });
44384
44696
  server.registerTool("get_latest_job_run", {
44385
44697
  title: "Get Latest Job Run",
44386
- description: "Get the most recent run output for a job.",
44387
- inputSchema: { name: exports_external.string() }
44388
- }, async ({ name }) => {
44698
+ description: "Get the most recent run output for a job. Output is truncated unless verbose=true.",
44699
+ inputSchema: {
44700
+ name: exports_external.string(),
44701
+ verbose: exports_external.boolean().optional(),
44702
+ maxOutputChars: exports_external.number().optional()
44703
+ }
44704
+ }, async ({ name, verbose, maxOutputChars }) => {
44389
44705
  const db = getDatabase();
44390
44706
  const job = getJobByName(name, db);
44391
44707
  if (!job)
44392
44708
  return { content: [{ type: "text", text: JSON.stringify({ error: `Job "${name}" not found` }) }], isError: true };
44393
44709
  const run = getLatestRun(job.id, db);
44394
- return stripped(JSON.stringify(run ?? { message: "No runs yet" }, null, 2));
44710
+ if (!run)
44711
+ return stripped(JSON.stringify({ message: "No runs yet" }, null, 2));
44712
+ const outputLimit = normalizeLimit(maxOutputChars, 2000, 50000);
44713
+ return stripped(JSON.stringify({
44714
+ ...run,
44715
+ raw_output: run.raw_output && !verbose ? truncateText(run.raw_output, outputLimit) : run.raw_output,
44716
+ stripped_output: run.stripped_output && !verbose ? truncateText(run.stripped_output, outputLimit) : run.stripped_output,
44717
+ hint: verbose ? undefined : "Long run output is truncated in MCP. Use verbose=true or maxOutputChars for more output."
44718
+ }, null, 2));
44395
44719
  });
44396
44720
  server.registerTool("run_job", {
44397
44721
  title: "Run Job",
44398
44722
  description: "Manually trigger a scheduled job.",
44399
- inputSchema: { name: exports_external.string() }
44400
- }, async ({ name }) => {
44723
+ inputSchema: {
44724
+ name: exports_external.string(),
44725
+ verbose: exports_external.boolean().optional().describe("Return full job output without truncation."),
44726
+ maxOutputChars: exports_external.number().optional().describe("Maximum output characters when verbose is false (default: 2000).")
44727
+ }
44728
+ }, async ({ name, verbose, maxOutputChars }) => {
44401
44729
  const db = getDatabase();
44402
44730
  const job = getJobByName(name, db);
44403
44731
  if (!job)
44404
44732
  return { content: [{ type: "text", text: JSON.stringify({ error: `Job "${name}" not found` }) }], isError: true };
44405
44733
  const result = await triggerJob(job, db);
44406
- return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
44734
+ return stripped(JSON.stringify(compactJobExecutionResult(result, { verbose, maxOutputChars }), null, 2));
44407
44735
  });
44408
44736
  server.registerTool("list_workflows", {
44409
44737
  title: "List Workflows",
44410
- description: "List connector workflows.",
44411
- inputSchema: {}
44412
- }, async () => {
44738
+ description: "List connector workflows with compact, paged defaults.",
44739
+ inputSchema: {
44740
+ limit: exports_external.number().optional(),
44741
+ cursor: exports_external.string().optional(),
44742
+ verbose: exports_external.boolean().optional()
44743
+ }
44744
+ }, async ({ limit, cursor, verbose }) => {
44745
+ const parsedCursor = parseCursor(cursor);
44746
+ if (parsedCursor.error) {
44747
+ return { content: [{ type: "text", text: JSON.stringify({ error: parsedCursor.error }) }], isError: true };
44748
+ }
44413
44749
  const db = getDatabase();
44414
44750
  const workflows = listWorkflows(db);
44415
- return stripped(JSON.stringify(workflows, null, 2));
44751
+ const page = pageItems(workflows, {
44752
+ offset: parsedCursor.value ?? 0,
44753
+ limit: normalizeLimit(limit, DEFAULT_MCP_LIMIT)
44754
+ });
44755
+ const data = verbose ? page.items : page.items.map((workflow) => ({
44756
+ name: workflow.name,
44757
+ enabled: workflow.enabled,
44758
+ stepCount: workflow.steps.length,
44759
+ steps: workflow.steps.slice(0, 5).map((step) => ({
44760
+ connector: step.connector,
44761
+ command: step.command
44762
+ }))
44763
+ }));
44764
+ return stripped(JSON.stringify({
44765
+ workflows: data,
44766
+ total: workflows.length,
44767
+ count: data.length,
44768
+ nextCursor: page.nextOffset === null ? null : String(page.nextOffset),
44769
+ hint: "Use verbose=true for full workflow records, or connectors workflows show <name>."
44770
+ }, null, 2));
44416
44771
  });
44417
44772
  server.registerTool("run_workflow", {
44418
44773
  title: "Run Workflow",
44419
44774
  description: "Execute a connector workflow pipeline.",
44420
- inputSchema: { name: exports_external.string() }
44421
- }, async ({ name }) => {
44775
+ inputSchema: {
44776
+ name: exports_external.string(),
44777
+ verbose: exports_external.boolean().optional().describe("Return full workflow step output without truncation."),
44778
+ maxOutputChars: exports_external.number().optional().describe("Maximum output characters per output field when verbose is false (default: 2000).")
44779
+ }
44780
+ }, async ({ name, verbose, maxOutputChars }) => {
44422
44781
  const db = getDatabase();
44423
44782
  const wf = getWorkflowByName(name, db);
44424
44783
  if (!wf)
44425
44784
  return { content: [{ type: "text", text: JSON.stringify({ error: `Workflow "${name}" not found` }) }], isError: true };
44426
44785
  const result = await runWorkflow(wf);
44427
- return stripped(JSON.stringify(result, null, 2));
44786
+ return stripped(JSON.stringify(compactWorkflowExecutionResult(result, { verbose, maxOutputChars }), null, 2));
44428
44787
  });
44429
44788
  }
44430
44789
  // src/mcp/tools/llm.ts
@@ -44546,11 +44905,38 @@ function registerAgentTools(server, stripped) {
44546
44905
  });
44547
44906
  server.registerTool("list_agents", {
44548
44907
  title: "List Agents",
44549
- description: "List all registered agents.",
44550
- inputSchema: {}
44551
- }, async () => {
44908
+ description: "List registered agents with compact, paged defaults.",
44909
+ inputSchema: {
44910
+ limit: exports_external.number().optional(),
44911
+ cursor: exports_external.string().optional(),
44912
+ verbose: exports_external.boolean().optional()
44913
+ }
44914
+ }, async ({ limit, cursor, verbose }) => {
44915
+ const parsedCursor = parseCursor(cursor);
44916
+ if (parsedCursor.error) {
44917
+ return { content: [{ type: "text", text: JSON.stringify({ error: parsedCursor.error }) }], isError: true };
44918
+ }
44552
44919
  const agents = listAgents();
44553
- return { content: [{ type: "text", text: JSON.stringify(agents, null, 2) }] };
44920
+ const page = pageItems(agents, {
44921
+ offset: parsedCursor.value ?? 0,
44922
+ limit: normalizeLimit(limit, DEFAULT_MCP_LIMIT)
44923
+ });
44924
+ const data = verbose ? page.items : page.items.map((agent) => ({
44925
+ id: agent.id,
44926
+ name: agent.name,
44927
+ role: agent.role,
44928
+ lastSeenAt: agent.last_seen_at,
44929
+ projectId: agent.project_id
44930
+ }));
44931
+ return {
44932
+ content: [{ type: "text", text: JSON.stringify({
44933
+ agents: data,
44934
+ total: agents.length,
44935
+ count: data.length,
44936
+ nextCursor: page.nextOffset === null ? null : String(page.nextOffset),
44937
+ hint: "Use verbose=true for full agent records."
44938
+ }, null, 2) }]
44939
+ };
44554
44940
  });
44555
44941
  server.registerTool("heartbeat", {
44556
44942
  title: "Heartbeat",