@pipeshub-ai/mcp 2.1.0 → 2.3.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 (146) hide show
  1. package/README.md +92 -2
  2. package/bin/mcp-server.js +976 -169
  3. package/bin/mcp-server.js.map +28 -15
  4. package/bin/pipeshub.js +946 -0
  5. package/bin/pipeshub.js.map +14 -0
  6. package/esm/cli/client.d.ts +54 -0
  7. package/esm/cli/client.d.ts.map +1 -0
  8. package/esm/cli/client.js +230 -0
  9. package/esm/cli/client.js.map +1 -0
  10. package/esm/cli/commands.d.ts +30 -0
  11. package/esm/cli/commands.d.ts.map +1 -0
  12. package/esm/cli/commands.js +321 -0
  13. package/esm/cli/commands.js.map +1 -0
  14. package/esm/cli/config.d.ts +73 -0
  15. package/esm/cli/config.d.ts.map +1 -0
  16. package/esm/cli/config.js +218 -0
  17. package/esm/cli/config.js.map +1 -0
  18. package/esm/cli/init-qm.d.ts +11 -0
  19. package/esm/cli/init-qm.d.ts.map +1 -0
  20. package/esm/cli/init-qm.js +170 -0
  21. package/esm/cli/init-qm.js.map +1 -0
  22. package/esm/cli/pipeshub.d.ts +2 -0
  23. package/esm/cli/pipeshub.d.ts.map +1 -0
  24. package/esm/cli/pipeshub.js +296 -0
  25. package/esm/cli/pipeshub.js.map +1 -0
  26. package/esm/funcs/connectorGetRecordContent.d.ts +43 -0
  27. package/esm/funcs/connectorGetRecordContent.d.ts.map +1 -0
  28. package/esm/funcs/connectorGetRecordContent.js +114 -0
  29. package/esm/funcs/connectorGetRecordContent.js.map +1 -0
  30. package/esm/funcs/connectorLookupRecordByIdentifier.d.ts +68 -0
  31. package/esm/funcs/connectorLookupRecordByIdentifier.d.ts.map +1 -0
  32. package/esm/funcs/connectorLookupRecordByIdentifier.js +138 -0
  33. package/esm/funcs/connectorLookupRecordByIdentifier.js.map +1 -0
  34. package/esm/funcs/connectorNavigateKnowledgeGraph.d.ts +75 -0
  35. package/esm/funcs/connectorNavigateKnowledgeGraph.d.ts.map +1 -0
  36. package/esm/funcs/connectorNavigateKnowledgeGraph.js +152 -0
  37. package/esm/funcs/connectorNavigateKnowledgeGraph.js.map +1 -0
  38. package/esm/funcs/conversationsStreamConversation.js +1 -1
  39. package/esm/funcs/conversationsStreamConversation.js.map +1 -1
  40. package/esm/funcs/userGroupsGetAllUserGroups.js +1 -1
  41. package/esm/funcs/userGroupsGetAllUserGroups.js.map +1 -1
  42. package/esm/hooks/registration.d.ts.map +1 -1
  43. package/esm/hooks/registration.js +2 -1
  44. package/esm/hooks/registration.js.map +1 -1
  45. package/esm/hooks/request-context.d.ts +10 -0
  46. package/esm/hooks/request-context.d.ts.map +1 -0
  47. package/esm/hooks/request-context.js +38 -0
  48. package/esm/hooks/request-context.js.map +1 -0
  49. package/esm/hooks/requestid.d.ts +5 -0
  50. package/esm/hooks/requestid.d.ts.map +1 -0
  51. package/esm/hooks/requestid.js +58 -0
  52. package/esm/hooks/requestid.js.map +1 -0
  53. package/esm/lib/base64.d.ts +1 -1
  54. package/esm/lib/base64.d.ts.map +1 -1
  55. package/esm/lib/base64.js +6 -3
  56. package/esm/lib/base64.js.map +1 -1
  57. package/esm/lib/bytes-to-base64.d.ts +16 -0
  58. package/esm/lib/bytes-to-base64.d.ts.map +1 -0
  59. package/esm/lib/bytes-to-base64.js +23 -0
  60. package/esm/lib/bytes-to-base64.js.map +1 -0
  61. package/esm/mcp-server/instructions.d.ts +1 -1
  62. package/esm/mcp-server/instructions.d.ts.map +1 -1
  63. package/esm/mcp-server/instructions.js +62 -9
  64. package/esm/mcp-server/instructions.js.map +1 -1
  65. package/esm/mcp-server/server.d.ts.map +1 -1
  66. package/esm/mcp-server/server.js +10 -3
  67. package/esm/mcp-server/server.js.map +1 -1
  68. package/esm/mcp-server/shared.d.ts +2 -2
  69. package/esm/mcp-server/shared.d.ts.map +1 -1
  70. package/esm/mcp-server/shared.js +7 -3
  71. package/esm/mcp-server/shared.js.map +1 -1
  72. package/esm/mcp-server/tools/_agui.d.ts +34 -0
  73. package/esm/mcp-server/tools/_agui.d.ts.map +1 -0
  74. package/esm/mcp-server/tools/_agui.js +91 -0
  75. package/esm/mcp-server/tools/_agui.js.map +1 -0
  76. package/esm/mcp-server/tools/_helpers.d.ts.map +1 -1
  77. package/esm/mcp-server/tools/_helpers.js +13 -6
  78. package/esm/mcp-server/tools/_helpers.js.map +1 -1
  79. package/esm/mcp-server/tools/pipeshubChat.d.ts +0 -3
  80. package/esm/mcp-server/tools/pipeshubChat.d.ts.map +1 -1
  81. package/esm/mcp-server/tools/pipeshubChat.js +75 -92
  82. package/esm/mcp-server/tools/pipeshubChat.js.map +1 -1
  83. package/esm/mcp-server/tools/pipeshubGetRecordContent.d.ts +125 -0
  84. package/esm/mcp-server/tools/pipeshubGetRecordContent.d.ts.map +1 -0
  85. package/esm/mcp-server/tools/pipeshubGetRecordContent.js +214 -0
  86. package/esm/mcp-server/tools/pipeshubGetRecordContent.js.map +1 -0
  87. package/esm/mcp-server/tools/pipeshubSearch.d.ts.map +1 -1
  88. package/esm/mcp-server/tools/pipeshubSearch.js +22 -5
  89. package/esm/mcp-server/tools/pipeshubSearch.js.map +1 -1
  90. package/esm/mcp-server/tools.d.ts.map +1 -1
  91. package/esm/mcp-server/tools.js +13 -1
  92. package/esm/mcp-server/tools.js.map +1 -1
  93. package/esm/models/availablemodelsresponse.d.ts +1 -1
  94. package/esm/models/conversation.d.ts +1 -1
  95. package/esm/models/getrecordcontentop.d.ts +6 -0
  96. package/esm/models/getrecordcontentop.d.ts.map +1 -0
  97. package/esm/models/getrecordcontentop.js +5 -0
  98. package/esm/models/getrecordcontentop.js.map +1 -0
  99. package/esm/models/lookuprecordbyidentifierop.d.ts +7 -0
  100. package/esm/models/lookuprecordbyidentifierop.d.ts.map +1 -0
  101. package/esm/models/lookuprecordbyidentifierop.js +14 -0
  102. package/esm/models/lookuprecordbyidentifierop.js.map +1 -0
  103. package/esm/models/navigateknowledgegraphop.d.ts +14 -0
  104. package/esm/models/navigateknowledgegraphop.d.ts.map +1 -0
  105. package/esm/models/navigateknowledgegraphop.js +25 -0
  106. package/esm/models/navigateknowledgegraphop.js.map +1 -0
  107. package/esm/models/userteamsresponse.d.ts +1 -1
  108. package/esm/tool-names.d.ts.map +1 -1
  109. package/esm/tool-names.js +6 -2
  110. package/esm/tool-names.js.map +1 -1
  111. package/package.json +4 -2
  112. package/qm/README.md +247 -0
  113. package/qm/SECURITY.md +134 -0
  114. package/qm/TROUBLESHOOTING.md +218 -0
  115. package/qm/qm.config.fragment.jsonc +42 -0
  116. package/qm/sandbox/Dockerfile +22 -0
  117. package/qm/sandbox/skills/pipeshub/SKILL.md +69 -0
  118. package/qm/sandbox/tools/pipeshub/tool.json +36 -0
  119. package/src/cli/client.ts +272 -0
  120. package/src/cli/commands.ts +403 -0
  121. package/src/cli/config.ts +229 -0
  122. package/src/cli/init-qm.ts +215 -0
  123. package/src/cli/pipeshub.ts +333 -0
  124. package/src/funcs/connectorGetRecordContent.ts +179 -0
  125. package/src/funcs/connectorLookupRecordByIdentifier.ts +200 -0
  126. package/src/funcs/connectorNavigateKnowledgeGraph.ts +215 -0
  127. package/src/funcs/conversationsStreamConversation.ts +1 -1
  128. package/src/funcs/userGroupsGetAllUserGroups.ts +1 -1
  129. package/src/hooks/registration.ts +2 -1
  130. package/src/hooks/request-context.ts +47 -0
  131. package/src/hooks/requestid.ts +62 -0
  132. package/src/lib/base64.ts +6 -3
  133. package/src/lib/bytes-to-base64.ts +24 -0
  134. package/src/mcp-server/instructions.ts +62 -9
  135. package/src/mcp-server/server.ts +11 -3
  136. package/src/mcp-server/shared.ts +7 -3
  137. package/src/mcp-server/tools/_agui.ts +138 -0
  138. package/src/mcp-server/tools/_helpers.ts +13 -6
  139. package/src/mcp-server/tools/pipeshubChat.ts +78 -91
  140. package/src/mcp-server/tools/pipeshubGetRecordContent.ts +251 -0
  141. package/src/mcp-server/tools/pipeshubSearch.ts +22 -5
  142. package/src/mcp-server/tools.ts +14 -1
  143. package/src/models/getrecordcontentop.ts +11 -0
  144. package/src/models/lookuprecordbyidentifierop.ts +26 -0
  145. package/src/models/navigateknowledgegraphop.ts +56 -0
  146. package/src/tool-names.ts +6 -2
package/bin/mcp-server.js CHANGED
@@ -50394,14 +50394,35 @@ PipesHub is the user's workplace AI platform. It indexes their documents,
50394
50394
  knowledge base content, and connector sources (Drive, Box, Confluence,
50395
50395
  Slack, Jira, Gmail, ...). When in doubt, the answer is in PipesHub.
50396
50396
 
50397
+ ## Full-document tasks: \`pipeshub_search\` → \`pipeshub_get_record_content\`
50398
+
50399
+ \`pipeshub_chat\` answers from a handful of retrieved passages — it never
50400
+ reads a whole document. Whenever the task depends on a document's
50401
+ COMPLETE content, fetch the document itself:
50402
+
50403
+ 1. \`pipeshub_search\` with the document's name / topic.
50404
+ 2. Take the top hit's \`recordId\`.
50405
+ 3. \`pipeshub_get_record_content\`, and answer from the returned content.
50406
+
50407
+ Tasks that need this path — anything where missing part of the document
50408
+ could make the answer wrong:
50409
+
50410
+ - Summarize / TL;DR / key points / takeaways / action items of a doc.
50411
+ - Extract or list ALL of something (dates, owners, requirements, ...).
50412
+ - Check whether / where a doc mentions something.
50413
+ - Translate, rewrite, outline, review, or reformat a doc.
50414
+ - Compare named docs (fetch each \`recordId\`).
50415
+ - Any question explicitly scoped to ONE named document — chat retrieval
50416
+ cannot be restricted to a single record.
50417
+
50397
50418
  ## Default tool: \`pipeshub_chat\`
50398
50419
 
50399
50420
  **Use \`pipeshub_chat\` for any question that could plausibly be answered
50400
- by the user's PipesHub-indexed data.** That includes:
50421
+ by the user's PipesHub-indexed data** and is not a full-document task:
50401
50422
 
50402
- - Anything about a specific document, file, report, ticket, message, or
50403
- page (e.g. "what's in the Q4 sales report?", "summarize the langchain
50404
- doc", "what did Aashil say about onboarding?").
50423
+ - A question that may span several documents, or where you don't yet
50424
+ know which record holds the answer (e.g. "what did Aashil say about
50425
+ onboarding?").
50405
50426
  - Anything about company / org policies, processes, decisions, or
50406
50427
  history (e.g. "what's our vacation policy?", "who owns the auth
50407
50428
  service?").
@@ -50417,15 +50438,17 @@ the user can verify.
50417
50438
 
50418
50439
  ## When to use the other tools
50419
50440
 
50420
- - \`pipeshub_search\` — only when the user asks specifically to **find /
50421
- locate** a document by name or topic (so you can hand them a list, or
50422
- resolve a filename to a \`recordId\` for download). For "what does
50423
- the doc say?" use \`pipeshub_chat\` instead — it does the retrieval
50424
- internally.
50441
+ - \`pipeshub_search\` — locate a document by name or topic and resolve it
50442
+ to a \`recordId\`. To read or summarize one specific document, search,
50443
+ then pass the top hit's \`recordId\` to \`pipeshub_get_record_content\`.
50425
50444
  - \`pipeshub_download_record\` — when the user wants the actual file
50426
50445
  bytes (download, attach, open). Get the \`recordId\` either from
50427
50446
  citations on a prior \`pipeshub_chat\` response or from
50428
50447
  \`pipeshub_search\`.
50448
+ - \`pipeshub_get_record_content\` — when you need a record's full parsed
50449
+ content (returned as a single \`content\` string: metadata header plus
50450
+ the document's text) without downloading the original file. Prefer this
50451
+ over download when the question is about what the record says.
50429
50452
  - \`pipeshub_directory\` — people, groups, teams, and \`whoami\` lookups.
50430
50453
  Not for documents.
50431
50454
  - \`pipeshub_sources\` — call once at the start of a session to discover
@@ -50433,6 +50456,36 @@ the user can verify.
50433
50456
  - \`pipeshub_agents\` — list the org's configured **agents** (specialized
50434
50457
  assistants with their own prompt, tools, and knowledge scope).
50435
50458
 
50459
+ ## Knowledge Sources
50460
+
50461
+ A source (an app connector or a KB) holds record groups (a project, space,
50462
+ drive, folder), which hold records (one ticket, page, file). Records nest —
50463
+ an epic over its stories, a page over its child pages.
50464
+
50465
+ **Every tool returns metadata or content.**
50466
+
50467
+ - \`pipeshub_search\` / \`pipeshub_chat\` — content, but only a ranked sample of
50468
+ blocks: never all blocks of a record, never every record that matches, never
50469
+ a complete list of what exists.
50470
+ - \`mode:"lookup"\` and \`mode:"navigate"\` — metadata: recordIds, fields, and
50471
+ structure. No document text. \`mode:"content"\` — one whole record.
50472
+
50473
+ **Combining them.** Search finds a starting point by wording; navigate on a
50474
+ \`recordId\` reveals what search structurally cannot — siblings, children,
50475
+ linked records, and the group's total count. For a question that must be
50476
+ exhaustive ("all", "how many", "every"), do NOT count search hits or trust a
50477
+ chat answer: navigate the record group, which reports the real total. For a
50478
+ record's siblings, navigate its parent — take the id from the \`Path\` line.
50479
+
50480
+ **A named record** — an issue key, a Confluence / Drive / Slack link, an
50481
+ external ID → \`mode:"lookup"\` FIRST. It returns that record's metadata (for a
50482
+ ticket: status, assignee, priority, dates) plus its \`recordId\`, which often
50483
+ answers the question outright. Never guess a \`recordId\`.
50484
+
50485
+ Pass a source's id from \`pipeshub_sources\` as \`apps: ["<id>"]\` to search or
50486
+ chat, and as \`nodeId\` to navigate. Navigate and lookup end in a \`Next:\` line
50487
+ naming the exact follow-up call — follow it.
50488
+
50436
50489
  ## Agents
50437
50490
 
50438
50491
  Some orgs configure **agents** for specific jobs (e.g. a Slack messenger, a
@@ -50467,13 +50520,122 @@ replay prior messages. Only start a fresh conversation when the user
50467
50520
  explicitly asks to clear context.
50468
50521
  `;
50469
50522
 
50523
+ // node_modules/nanoid/url-alphabet/index.js
50524
+ var urlAlphabet = "useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";
50525
+
50526
+ // node_modules/nanoid/index.js
50527
+ import { webcrypto as crypto3 } from "node:crypto";
50528
+ function fillPool(bytes) {
50529
+ if (bytes < 0)
50530
+ throw new RangeError("Wrong ID size");
50531
+ try {
50532
+ if (!pool || pool.length < bytes) {
50533
+ pool = Buffer.allocUnsafe(bytes * POOL_SIZE_MULTIPLIER);
50534
+ crypto3.getRandomValues(pool);
50535
+ poolOffset = 0;
50536
+ } else if (poolOffset + bytes > pool.length) {
50537
+ crypto3.getRandomValues(pool);
50538
+ poolOffset = 0;
50539
+ }
50540
+ } catch (e) {
50541
+ pool = undefined;
50542
+ throw e;
50543
+ }
50544
+ poolOffset += bytes;
50545
+ }
50546
+ function nanoid2(size = 21) {
50547
+ fillPool(size |= 0);
50548
+ let id = "";
50549
+ for (let i = poolOffset - size;i < poolOffset; i++) {
50550
+ id += urlAlphabet[pool[i] & 63];
50551
+ }
50552
+ return id;
50553
+ }
50554
+ var POOL_SIZE_MULTIPLIER = 128, pool, poolOffset;
50555
+ var init_nanoid = () => {};
50556
+
50557
+ // src/hooks/request-context.ts
50558
+ import { AsyncLocalStorage } from "node:async_hooks";
50559
+ function bindNewRequestId() {
50560
+ storage.enterWith({ random: nanoid2() });
50561
+ }
50562
+ function getRequestContextStore() {
50563
+ return storage.getStore();
50564
+ }
50565
+ function newRequestId() {
50566
+ return `mcp-${nanoid2()}`;
50567
+ }
50568
+ var storage;
50569
+ var init_request_context = __esm(() => {
50570
+ init_nanoid();
50571
+ storage = new AsyncLocalStorage;
50572
+ });
50573
+
50574
+ // src/hooks/requestid.ts
50575
+ function decodeJwtPayload(token) {
50576
+ try {
50577
+ const base64Url = token.split(".")[1];
50578
+ if (!base64Url)
50579
+ return null;
50580
+ const base642 = base64Url.replace(/-/g, "+").replace(/_/g, "/");
50581
+ const padded = base642 + "=".repeat((4 - base642.length % 4) % 4);
50582
+ const claims = JSON.parse(Buffer.from(padded, "base64").toString("utf8"));
50583
+ return typeof claims === "object" && claims !== null ? claims : null;
50584
+ } catch {
50585
+ return null;
50586
+ }
50587
+ }
50588
+ function userIdFromRequest(request) {
50589
+ const auth = request.headers.get("authorization") ?? "";
50590
+ if (!auth.toLowerCase().startsWith("bearer "))
50591
+ return null;
50592
+ const token = auth.slice(7).trim();
50593
+ const claims = decodeJwtPayload(token);
50594
+ return claims?.["userId"] || null;
50595
+ }
50596
+
50597
+ class RequestIDHook {
50598
+ beforeRequest(_hookCtx, request) {
50599
+ if (request.headers.get(REQUEST_ID_HEADER)) {
50600
+ return request;
50601
+ }
50602
+ const store = getRequestContextStore();
50603
+ if (!store) {
50604
+ request.headers.set(REQUEST_ID_HEADER, newRequestId());
50605
+ return request;
50606
+ }
50607
+ if (!store.finalId) {
50608
+ const userId = userIdFromRequest(request);
50609
+ store.finalId = userId ? `mcp-${userId}-${store.random}` : `mcp-${store.random}`;
50610
+ }
50611
+ request.headers.set(REQUEST_ID_HEADER, store.finalId);
50612
+ return request;
50613
+ }
50614
+ }
50615
+ var REQUEST_ID_HEADER = "x-request-id";
50616
+ var init_requestid = __esm(() => {
50617
+ init_request_context();
50618
+ });
50619
+
50470
50620
  // src/hooks/registration.ts
50471
- function initHooks(hooks) {}
50621
+ function initHooks(hooks) {
50622
+ hooks.registerBeforeRequestHook(new RequestIDHook);
50623
+ }
50624
+ var init_registration = __esm(() => {
50625
+ init_requestid();
50626
+ });
50472
50627
 
50473
- // src/lib/base64.ts
50628
+ // src/lib/bytes-to-base64.ts
50474
50629
  function bytesToBase64(u8arr) {
50475
- return btoa(String.fromCodePoint(...u8arr));
50630
+ let binary = "";
50631
+ for (let i = 0;i < u8arr.length; i += BASE64_CHUNK) {
50632
+ binary += String.fromCharCode(...u8arr.subarray(i, i + BASE64_CHUNK));
50633
+ }
50634
+ return btoa(binary);
50476
50635
  }
50636
+ var BASE64_CHUNK = 32768;
50637
+
50638
+ // src/lib/base64.ts
50477
50639
  function bytesFromBase64(encoded) {
50478
50640
  return Uint8Array.from(atob(encoded), (c) => c.charCodeAt(0));
50479
50641
  }
@@ -51058,6 +51220,7 @@ class SDKHooks {
51058
51220
  }
51059
51221
  }
51060
51222
  var init_hooks = __esm(() => {
51223
+ init_registration();
51061
51224
  init_clientcredentials();
51062
51225
  });
51063
51226
 
@@ -51793,9 +51956,6 @@ function createRegisterPrompt(logger, server, getSDK, allowedScopes) {
51793
51956
  }
51794
51957
 
51795
51958
  // src/mcp-server/shared.ts
51796
- function bytesToBase642(u8arr) {
51797
- return btoa(String.fromCodePoint(...u8arr));
51798
- }
51799
51959
  async function consumeStream(stream) {
51800
51960
  const reader = stream.getReader();
51801
51961
  const chunks = [];
@@ -51816,13 +51976,13 @@ async function valueToBase64(value) {
51816
51976
  if (value == null) {
51817
51977
  return null;
51818
51978
  } else if (value instanceof Uint8Array) {
51819
- return bytesToBase642(value);
51979
+ return bytesToBase64(value);
51820
51980
  } else if (value instanceof ArrayBuffer) {
51821
- return bytesToBase642(new Uint8Array(value));
51981
+ return bytesToBase64(new Uint8Array(value));
51822
51982
  } else if (value instanceof Response || value instanceof Blob) {
51823
- return bytesToBase642(new Uint8Array(await value.arrayBuffer()));
51983
+ return bytesToBase64(new Uint8Array(await value.arrayBuffer()));
51824
51984
  } else if (value instanceof ReadableStream) {
51825
- return bytesToBase642(await consumeStream(value));
51985
+ return bytesToBase64(await consumeStream(value));
51826
51986
  } else if (typeof value === "string") {
51827
51987
  return base64Schema.parse(value);
51828
51988
  } else {
@@ -51882,9 +52042,15 @@ async function formatResult(response) {
51882
52042
  } else if (contentType.startsWith("audio/")) {
51883
52043
  const data = await valueToBase64(await response.arrayBuffer());
51884
52044
  content = data == null ? [] : [{ type: "audio", data, mimeType: contentType }];
51885
- } else {
52045
+ } else if (contentType.startsWith("text/") || contentType.includes("json") || contentType.includes("xml") || contentType.includes("yaml")) {
51886
52046
  const text = await response.text();
51887
52047
  content = [{ type: "text", text }];
52048
+ } else {
52049
+ const blob = await valueToBase64(await response.arrayBuffer());
52050
+ content = blob == null ? [] : [{
52051
+ type: "resource",
52052
+ resource: { uri: response.url, mimeType: contentType, blob }
52053
+ }];
51888
52054
  }
51889
52055
  return response.ok ? { content } : { content, isError: true };
51890
52056
  }
@@ -52382,7 +52548,7 @@ async function $do(client$, request, options) {
52382
52548
  options: client$._options,
52383
52549
  baseURL: options?.serverURL ?? client$._baseURL ?? "",
52384
52550
  operationID: "streamConversation",
52385
- oAuth2Scopes: ["conversation:write"],
52551
+ oAuth2Scopes: ["conversation:chat"],
52386
52552
  resolvedSecurity: requestSecurity,
52387
52553
  securitySource: client$._options.security,
52388
52554
  retryConfig: options?.retries || client$._options.retryConfig || { strategy: "none" },
@@ -52780,6 +52946,77 @@ var init_agentsStreamMessage = __esm(() => {
52780
52946
  init_async();
52781
52947
  });
52782
52948
 
52949
+ // src/mcp-server/tools/_agui.ts
52950
+ function newChatStreamState() {
52951
+ return {
52952
+ conversation: null,
52953
+ recordsUsed: undefined,
52954
+ error: null,
52955
+ conversationId: null,
52956
+ title: null,
52957
+ text: new Map,
52958
+ rootMessageIds: new Set
52959
+ };
52960
+ }
52961
+ function applyAGUIFrame(state, frame) {
52962
+ const data = frame.data;
52963
+ const d = data && typeof data === "object" ? data : {};
52964
+ switch (frame.event) {
52965
+ case AGUIEvent.RUN_FINISHED: {
52966
+ const result = d.result;
52967
+ if (!result || typeof result !== "object")
52968
+ return false;
52969
+ state.conversation = result.conversation ?? null;
52970
+ state.recordsUsed = result.recordsUsed ?? result.meta?.recordsUsed;
52971
+ return true;
52972
+ }
52973
+ case AGUIEvent.RUN_ERROR: {
52974
+ state.error = (typeof data === "string" ? data : null) ?? d.message ?? d.error ?? frame.raw ?? "Stream error";
52975
+ return true;
52976
+ }
52977
+ case AGUIEvent.CUSTOM: {
52978
+ if (d.name === "conversation_created") {
52979
+ const value = d.value ?? {};
52980
+ state.conversationId = value.conversationId ?? state.conversationId;
52981
+ state.title = value.title ?? state.title;
52982
+ }
52983
+ return false;
52984
+ }
52985
+ case AGUIEvent.TEXT_MESSAGE_CONTENT: {
52986
+ if (typeof d.delta !== "string" || d.delta.length === 0)
52987
+ return false;
52988
+ const id = typeof d.messageId === "string" ? d.messageId : "";
52989
+ state.text.set(id, (state.text.get(id) ?? "") + d.delta);
52990
+ if (d.parentRunId == null)
52991
+ state.rootMessageIds.add(id);
52992
+ return false;
52993
+ }
52994
+ default:
52995
+ return false;
52996
+ }
52997
+ }
52998
+ function salvagedText(state) {
52999
+ const pick2 = (ids) => {
53000
+ let best = null;
53001
+ for (const id of ids) {
53002
+ const text = state.text.get(id);
53003
+ if (text && (best === null || text.length > best.length))
53004
+ best = text;
53005
+ }
53006
+ return best;
53007
+ };
53008
+ return pick2(state.rootMessageIds) ?? pick2(state.text.keys());
53009
+ }
53010
+ var AGUIEvent;
53011
+ var init__agui = __esm(() => {
53012
+ AGUIEvent = {
53013
+ RUN_FINISHED: "RUN_FINISHED",
53014
+ RUN_ERROR: "RUN_ERROR",
53015
+ CUSTOM: "CUSTOM",
53016
+ TEXT_MESSAGE_CONTENT: "TEXT_MESSAGE_CONTENT"
53017
+ };
53018
+ });
53019
+
52783
53020
  // src/funcs/agentsListAgents.ts
52784
53021
  function agentsListAgents(client$, request, options) {
52785
53022
  return new APIPromise($do5(client$, request, options));
@@ -52989,15 +53226,17 @@ function trimCitations(citations) {
52989
53226
  if (!Array.isArray(citations))
52990
53227
  return [];
52991
53228
  return citations.map((c) => {
52992
- const md = c?.metadata ?? {};
53229
+ const cd = c?.citationData ?? c;
53230
+ const md = cd?.metadata ?? c?.metadata ?? {};
53231
+ const content = typeof cd?.content === "string" ? cd.content : c?.content;
52993
53232
  return {
52994
- recordId: md.recordId ?? c?.recordId,
52995
- recordName: md.recordName ?? c?.recordName,
52996
- snippet: typeof c?.content === "string" ? c.content.slice(0, 280) : md.blockText ?? null,
53233
+ recordId: md.recordId ?? cd?.recordId ?? c?.recordId,
53234
+ recordName: md.recordName ?? cd?.recordName ?? c?.recordName,
53235
+ snippet: typeof content === "string" ? content.slice(0, 280) : md.blockText ?? null,
52997
53236
  mimeType: md.mimeType,
52998
53237
  webUrl: md.webUrl,
52999
53238
  pageNum: md.pageNum,
53000
- chunkIndex: c?.chunkIndex ?? md.chunkIndex
53239
+ chunkIndex: cd?.chunkIndex ?? c?.chunkIndex ?? md.chunkIndex
53001
53240
  };
53002
53241
  });
53003
53242
  }
@@ -53170,9 +53409,10 @@ var init_pipeshubChat = __esm(() => {
53170
53409
  init_conversationsStreamMessage();
53171
53410
  init_agentsStreamConversation();
53172
53411
  init_agentsStreamMessage();
53412
+ init__agui();
53173
53413
  init__helpers();
53174
53414
  FiltersShape = object({
53175
- apps: array(string2()).optional().describe("Source-scoping ids. Mix connector instance UUIDs with the synthetic " + "`knowledgeBase_<orgId>` id (use pipeshub_sources to discover them). " + "Empty / omitted means no app-side restriction."),
53415
+ apps: array(string2()).optional().describe("Source-scoping ids from `pipeshub_sources` — connector instance and / " + "or knowledge base ids, mixed freely. The legacy org-wide " + "`knowledgeBase_<orgId>` id is still accepted on deployments that " + "predate per-KB sources. Empty / omitted means no app-side " + "restriction."),
53176
53416
  kb: array(string2()).optional().describe("Legacy / unused. Leave empty.")
53177
53417
  }).optional();
53178
53418
  args = {
@@ -53186,34 +53426,45 @@ var init_pipeshubChat = __esm(() => {
53186
53426
  chatMode: _enum([
53187
53427
  "internal_search",
53188
53428
  "web_search",
53189
- "auto",
53190
- "quick",
53191
- "verification",
53192
- "deep"
53429
+ "quick"
53193
53430
  ]).optional().describe("Response strategy. The valid values depend on whether `agentId` is set:\n" + "- WITHOUT `agentId` (plain chat): `internal_search` — answer from the " + "org's indexed knowledge (default) — or `web_search` — answer from the " + `live web.
53194
- ` + "- WITH `agentId` (agent chat): `auto` (let the agent decide; default), " + "`quick`, `verification`, or `deep`.")
53431
+ ` + "- WITH `agentId` (agent chat): `quick` is the only supported mode and " + "is sent automatically, so this argument can be omitted.")
53195
53432
  };
53196
53433
  tool$pipeshubChat = {
53197
53434
  name: "pipeshub_chat",
53198
- description: `**Primary chat tool handles both internal knowledge queries and web search.**
53199
-
53200
- **Internal search** (default, \`chatMode: "internal_search"\`): Use whenever
53201
- the user asks about their documents, files, knowledge base, company policies,
53202
- or anything that could plausibly be answered by content in their PipesHub-indexed
53203
- sources (Drive, Box, Confluence, Slack, Gmail, Jira, the org's KB, ...).
53204
- Grounds the answer in the user's actual data and returns citations.
53205
-
53206
- **Web search** (\`chatMode: "web_search"\`): Use when the user asks about
53207
- current events, public information, or anything unlikely to be in the org's
53208
- internal knowledge base. Pass \`chatMode: "web_search"\` and this tool will
53209
- search the public web instead.
53210
-
53211
- **When to pick this over other tools:**
53212
- - "What does <document> say about X?" → \`pipeshub_chat\` (internal_search)
53213
- - "Summarize <topic / doc>." \`pipeshub_chat\` (internal_search)
53435
+ description: `Ask a question, get an answer grounded in the org's indexed data with
53436
+ citations. It reads a few retrieved passages — never a whole document,
53437
+ never a complete list.
53438
+
53439
+ **Three questions this tool gets WRONG. Check them first:**
53440
+ - **Structure** "what's under this epic?", "which pages are in this
53441
+ space?", "what links to this ticket?", "what's in this folder?"
53442
+ \`pipeshub_get_record_content\` \`mode:"navigate"\`. Ranking cannot see how
53443
+ records relate.
53444
+ - **Exhaustive** "how many X?", "list ALL the Y", "every Z"
53445
+ \`mode:"navigate"\`, which reports the group's real total. This tool
53446
+ undercounts and will not say so.
53447
+ - **One named document** — summarize it, extract from it, what does it say
53448
+ about X \`pipeshub_search\` for the \`recordId\`, then \`mode:"content"\`.
53449
+
53450
+ Everything else about the org's knowledge belongs here: policies,
53451
+ processes, decisions, history, "what do we know about X", and any question
53452
+ spanning several documents.
53453
+
53454
+ **Internal search** (default, \`chatMode: "internal_search"\`): the user's
53455
+ documents, files, knowledge base, company policies — anything in their
53456
+ PipesHub-indexed sources (Drive, Box, Confluence, Slack, Gmail, Jira, the
53457
+ org's KB, ...).
53458
+
53459
+ **Web search** (\`chatMode: "web_search"\`): current events or public
53460
+ information unlikely to be in the org's knowledge base.
53461
+
53462
+ Both are plain-chat modes. **Agent chat** — pass an \`agentId\` from
53463
+ \`pipeshub_agents\` — runs against that agent's own prompt, tools and knowledge;
53464
+ \`quick\` is its only mode, requires the \`agentId\`, and is sent automatically.
53465
+
53214
53466
  - "What's our policy on Y?" → \`pipeshub_chat\` (internal_search)
53215
53467
  - "What's in the news about Z?" → \`pipeshub_chat\` (web_search)
53216
- - "What is the latest version of <library>?" → \`pipeshub_chat\` (web_search)
53217
53468
  - "Find / locate the file named X" → \`pipeshub_search\` (then
53218
53469
  \`pipeshub_download_record\` if the user wants the bytes).
53219
53470
 
@@ -53243,9 +53494,10 @@ cited document, take \`citations[*].recordId\` and call
53243
53494
  args,
53244
53495
  tool: async (client, args2, ctx) => {
53245
53496
  const fetchOptions = { signal: ctx.signal };
53497
+ const plainChatMode = args2.chatMode === "web_search" ? "web_search" : "internal_search";
53246
53498
  let response;
53247
53499
  if (args2.agentId) {
53248
- const agentChatMode = args2.chatMode ?? "auto";
53500
+ const agentChatMode = "quick";
53249
53501
  if (args2.conversationId) {
53250
53502
  const [result] = await agentsStreamMessage(client, {
53251
53503
  agentKey: args2.agentId,
@@ -53285,7 +53537,7 @@ cited document, take \`citations[*].recordId\` and call
53285
53537
  modelKey: args2.modelKey,
53286
53538
  modelName: args2.modelName,
53287
53539
  modelFriendlyName: args2.modelFriendlyName,
53288
- chatMode: args2.chatMode ?? "internal_search"
53540
+ chatMode: plainChatMode
53289
53541
  }
53290
53542
  }, { fetchOptions }).$inspect();
53291
53543
  if (!result.ok)
@@ -53298,7 +53550,7 @@ cited document, take \`citations[*].recordId\` and call
53298
53550
  modelKey: args2.modelKey,
53299
53551
  modelName: args2.modelName,
53300
53552
  modelFriendlyName: args2.modelFriendlyName,
53301
- chatMode: args2.chatMode ?? "internal_search"
53553
+ chatMode: plainChatMode
53302
53554
  }, { fetchOptions }).$inspect();
53303
53555
  if (!result.ok)
53304
53556
  return errorResult(result.error.message);
@@ -53307,62 +53559,36 @@ cited document, take \`citations[*].recordId\` and call
53307
53559
  const httpErr = await httpErrorResult(response, "PipesHub chat request");
53308
53560
  if (httpErr)
53309
53561
  return httpErr;
53310
- let finalConversation = null;
53311
- let recordsUsed;
53312
- let lastAccumulated = null;
53313
- let errorMessage = null;
53562
+ const state = newChatStreamState();
53314
53563
  try {
53315
53564
  for await (const frame of iterateSSE(response)) {
53316
- switch (frame.event) {
53317
- case "complete": {
53318
- const d = frame.data ?? {};
53319
- finalConversation = d.conversation ?? null;
53320
- recordsUsed = d.recordsUsed ?? d.meta?.recordsUsed;
53321
- break;
53322
- }
53323
- case "error": {
53324
- const d = frame.data ?? {};
53325
- errorMessage = typeof d === "string" ? d : d.error ?? d.message ?? frame.raw ?? "Stream error";
53326
- break;
53327
- }
53328
- case "answer_chunk": {
53329
- const d = frame.data ?? {};
53330
- if (typeof d.accumulated === "string") {
53331
- lastAccumulated = d.accumulated;
53332
- } else if (typeof d.content === "string") {
53333
- lastAccumulated = (lastAccumulated ?? "") + d.content;
53334
- }
53335
- break;
53336
- }
53337
- default:
53338
- break;
53339
- }
53340
- if (finalConversation || errorMessage)
53565
+ if (applyAGUIFrame(state, frame))
53341
53566
  break;
53342
53567
  }
53343
53568
  } catch (e) {
53344
53569
  return errorResult(`SSE stream failed: ${e.message}`);
53345
53570
  }
53346
- if (errorMessage)
53347
- return errorResult(errorMessage);
53348
- if (finalConversation) {
53571
+ if (state.error)
53572
+ return errorResult(state.error);
53573
+ if (state.conversation) {
53349
53574
  return jsonResult({
53350
- ...trimConversation(finalConversation),
53351
- recordsUsed
53575
+ ...trimConversation(state.conversation),
53576
+ recordsUsed: state.recordsUsed
53352
53577
  });
53353
53578
  }
53354
- if (lastAccumulated) {
53579
+ const salvaged = salvagedText(state);
53580
+ if (salvaged) {
53355
53581
  return jsonResult({
53356
- conversationId: null,
53357
- title: null,
53582
+ conversationId: state.conversationId,
53583
+ title: state.title,
53358
53584
  status: "Inprogress",
53359
- answer: lastAccumulated,
53585
+ answer: salvaged,
53360
53586
  confidence: null,
53361
53587
  citations: [],
53362
53588
  followUpQuestions: [],
53363
53589
  messageCount: 0,
53364
- recordsUsed,
53365
- warning: "Stream ended without a `complete` frame; answer is " + "the last accumulated chunk and citations are unavailable."
53590
+ recordsUsed: state.recordsUsed,
53591
+ warning: "Stream ended without a terminal RUN_FINISHED; answer is the " + "accumulated TEXT_MESSAGE_CONTENT and citations are unavailable."
53366
53592
  });
53367
53593
  }
53368
53594
  return errorResult("Stream ended without any usable frames.");
@@ -53516,21 +53742,38 @@ var init_pipeshubSearch = __esm(() => {
53516
53742
  name: "pipeshub_search",
53517
53743
  description: `Vector / semantic search across the org's indexed documents.
53518
53744
 
53519
- **Use this only when the user wants to LOCATE a document** — by name,
53520
- topic, or a phrase to grep for. For "what does the document say about
53521
- X?" or any open-ended question, use \`pipeshub_chat\` instead, which
53522
- does the retrieval internally and grounds the answer in citations.
53745
+ **Use this when the user wants to LOCATE a document** — by name, topic,
53746
+ or a phrase to grep for and to resolve it to a \`recordId\`. For
53747
+ open-ended questions across many documents, use \`pipeshub_chat\`
53748
+ instead, which does the retrieval internally and grounds the answer in
53749
+ citations.
53523
53750
 
53524
53751
  Typical uses:
53752
+ - Resolve a doc name / topic into a \`recordId\` for
53753
+ \`pipeshub_get_record_content\` — step 1 of any full-document task
53754
+ (summarize, extract, review, "what does the doc say?").
53525
53755
  - Resolve a filename / phrase into a \`recordId\` for
53526
53756
  \`pipeshub_download_record\`.
53527
53757
  - Show the user a ranked list of matching files when they ask "find /
53528
53758
  search for X".
53529
53759
 
53760
+ Not for structural questions — what is under this epic, which pages are
53761
+ in this space, what links to this ticket. Ranking by content cannot show
53762
+ how records relate; use \`pipeshub_get_record_content\` \`mode:"navigate"\`.
53763
+
53764
+ **A ranked sample, never a complete list.** Hits are the top-scoring
53765
+ blocks from the best-matching records — not all blocks of any record, and
53766
+ not every record that matches. Never count them to answer "how many" /
53767
+ "all" / "every"; navigate the record group instead, which reports its
53768
+ real total.
53769
+
53530
53770
  The response is trimmed to one row per hit:
53531
53771
  \`{ recordId, recordName, score, snippet, mimeType, webUrl, ... }\`.
53532
53772
  Highest \`score\` first; multiple hits may share the same \`recordId\`
53533
- (different chunks of the same record).`,
53773
+ (different blocks of the same record).
53774
+
53775
+ When presenting results to the user, link each record using its
53776
+ \`webUrl\` (when present).`,
53534
53777
  scopes: ["read"],
53535
53778
  annotations: {
53536
53779
  title: "Semantic search",
@@ -53737,6 +53980,455 @@ returned base64-encoded; text content is returned inline.`,
53737
53980
  };
53738
53981
  });
53739
53982
 
53983
+ // src/models/getrecordcontentop.ts
53984
+ var GetRecordContentRequest$zodSchema;
53985
+ var init_getrecordcontentop = __esm(() => {
53986
+ init_zod();
53987
+ GetRecordContentRequest$zodSchema = object({
53988
+ recordId: string2().describe("Record ID to fetch. Obtain it from a `pipeshub_search` result (`hits[*].recordId`) or a chat citation (`citations[*].recordId`).")
53989
+ });
53990
+ });
53991
+
53992
+ // src/funcs/connectorGetRecordContent.ts
53993
+ function connectorGetRecordContent(client$, request, options) {
53994
+ return new APIPromise($do8(client$, request, options));
53995
+ }
53996
+ async function $do8(client$, request, options) {
53997
+ const parsed$ = safeParse4(request, (value$) => GetRecordContentRequest$zodSchema.parse(value$), "Input validation failed");
53998
+ if (!parsed$.ok) {
53999
+ return [parsed$, { status: "invalid" }];
54000
+ }
54001
+ const payload$ = parsed$.value;
54002
+ const body$ = null;
54003
+ const pathParams$ = {
54004
+ recordId: encodeSimple("recordId", payload$.recordId, {
54005
+ explode: false,
54006
+ charEncoding: "percent"
54007
+ })
54008
+ };
54009
+ const path$ = pathToFunc("/connectors/record/{recordId}/content")(pathParams$);
54010
+ const headers$ = new Headers(compactMap({
54011
+ Accept: "application/json"
54012
+ }));
54013
+ const securityInput = await extractSecurity(client$._options.security);
54014
+ const requestSecurity = resolveGlobalSecurity(securityInput);
54015
+ const context = {
54016
+ options: client$._options,
54017
+ baseURL: options?.serverURL ?? client$._baseURL ?? "",
54018
+ operationID: "getRecordContent",
54019
+ oAuth2Scopes: ["connector:read"],
54020
+ resolvedSecurity: requestSecurity,
54021
+ securitySource: client$._options.security,
54022
+ retryConfig: options?.retries || client$._options.retryConfig || { strategy: "none" },
54023
+ retryCodes: options?.retryCodes || [
54024
+ "429",
54025
+ "500",
54026
+ "502",
54027
+ "503",
54028
+ "504"
54029
+ ]
54030
+ };
54031
+ const requestRes = client$._createRequest(context, {
54032
+ security: requestSecurity,
54033
+ method: "GET",
54034
+ baseURL: options?.serverURL,
54035
+ path: path$,
54036
+ headers: headers$,
54037
+ body: body$,
54038
+ userAgent: client$._options.userAgent,
54039
+ timeoutMs: options?.timeoutMs || client$._options.timeoutMs || -1
54040
+ }, options);
54041
+ if (!requestRes.ok) {
54042
+ return [requestRes, { status: "invalid" }];
54043
+ }
54044
+ const req$ = requestRes.value;
54045
+ const doResult = await client$._do(req$, {
54046
+ context,
54047
+ errorCodes: [],
54048
+ retryConfig: context.retryConfig,
54049
+ retryCodes: context.retryCodes
54050
+ });
54051
+ if (!doResult.ok) {
54052
+ return [doResult, { status: "request-error", request: req$ }];
54053
+ }
54054
+ return [doResult, {
54055
+ status: "complete",
54056
+ request: req$,
54057
+ response: doResult.value
54058
+ }];
54059
+ }
54060
+ var init_connectorGetRecordContent = __esm(() => {
54061
+ init_encodings();
54062
+ init_primitives();
54063
+ init_schemas4();
54064
+ init_security2();
54065
+ init_url();
54066
+ init_getrecordcontentop();
54067
+ init_async();
54068
+ });
54069
+
54070
+ // src/models/lookuprecordbyidentifierop.ts
54071
+ var LookupRecordByIdentifierRequest$zodSchema;
54072
+ var init_lookuprecordbyidentifierop = __esm(() => {
54073
+ init_zod();
54074
+ LookupRecordByIdentifierRequest$zodSchema = object({
54075
+ connectorName: string2().describe("Connector hint to prioritise resolution order, e.g. `JIRA`, `CONFLUENCE`, `GOOGLE_DRIVE`, `SLACK`. Cannot widen beyond the connectors the caller can access.").optional(),
54076
+ identifiers: array(string2().min(1).max(2048)).min(1).max(10).describe("The references to resolve: URLs, issue keys such as `PA-1787`, or bare external system IDs. Paste each exactly as you found it — tracking parameters and fragments are handled. Up to 10 per call.")
54077
+ });
54078
+ });
54079
+
54080
+ // src/funcs/connectorLookupRecordByIdentifier.ts
54081
+ function connectorLookupRecordByIdentifier(client$, request, options) {
54082
+ return new APIPromise($do9(client$, request, options));
54083
+ }
54084
+ async function $do9(client$, request, options) {
54085
+ const parsed$ = safeParse4(request, (value$) => LookupRecordByIdentifierRequest$zodSchema.parse(value$), "Input validation failed");
54086
+ if (!parsed$.ok) {
54087
+ return [parsed$, { status: "invalid" }];
54088
+ }
54089
+ const payload$ = parsed$.value;
54090
+ const body$ = null;
54091
+ const path$ = pathToFunc("/connectors/record/lookup")();
54092
+ const query$ = encodeFormQuery({
54093
+ connectorName: payload$.connectorName,
54094
+ identifiers: payload$.identifiers
54095
+ });
54096
+ const headers$ = new Headers(compactMap({
54097
+ Accept: "application/json"
54098
+ }));
54099
+ const securityInput = await extractSecurity(client$._options.security);
54100
+ const requestSecurity = resolveGlobalSecurity(securityInput);
54101
+ const context = {
54102
+ options: client$._options,
54103
+ baseURL: options?.serverURL ?? client$._baseURL ?? "",
54104
+ operationID: "lookupRecordByIdentifier",
54105
+ oAuth2Scopes: ["kb:read", "connector:read"],
54106
+ resolvedSecurity: requestSecurity,
54107
+ securitySource: client$._options.security,
54108
+ retryConfig: options?.retries || client$._options.retryConfig || { strategy: "none" },
54109
+ retryCodes: options?.retryCodes || [
54110
+ "429",
54111
+ "500",
54112
+ "502",
54113
+ "503",
54114
+ "504"
54115
+ ]
54116
+ };
54117
+ const requestRes = client$._createRequest(context, {
54118
+ security: requestSecurity,
54119
+ method: "GET",
54120
+ baseURL: options?.serverURL,
54121
+ path: path$,
54122
+ headers: headers$,
54123
+ query: query$,
54124
+ body: body$,
54125
+ userAgent: client$._options.userAgent,
54126
+ timeoutMs: options?.timeoutMs || client$._options.timeoutMs || -1
54127
+ }, options);
54128
+ if (!requestRes.ok) {
54129
+ return [requestRes, { status: "invalid" }];
54130
+ }
54131
+ const req$ = requestRes.value;
54132
+ const doResult = await client$._do(req$, {
54133
+ context,
54134
+ errorCodes: [],
54135
+ retryConfig: context.retryConfig,
54136
+ retryCodes: context.retryCodes
54137
+ });
54138
+ if (!doResult.ok) {
54139
+ return [doResult, { status: "request-error", request: req$ }];
54140
+ }
54141
+ return [doResult, {
54142
+ status: "complete",
54143
+ request: req$,
54144
+ response: doResult.value
54145
+ }];
54146
+ }
54147
+ var init_connectorLookupRecordByIdentifier = __esm(() => {
54148
+ init_encodings();
54149
+ init_primitives();
54150
+ init_schemas4();
54151
+ init_security2();
54152
+ init_url();
54153
+ init_lookuprecordbyidentifierop();
54154
+ init_async();
54155
+ });
54156
+
54157
+ // src/models/navigateknowledgegraphop.ts
54158
+ var NavigateKnowledgeGraphRequest$zodSchema;
54159
+ var init_navigateknowledgegraphop = __esm(() => {
54160
+ init_zod();
54161
+ NavigateKnowledgeGraphRequest$zodSchema = object({
54162
+ createdAfter: string2().describe("Filter children by source creation time. ISO 8601 `YYYY-MM-DD`, or a full datetime that MUST carry a timezone offset — a naive datetime is rejected rather than assumed to be UTC.").optional(),
54163
+ createdBefore: string2().describe("Filter children by source creation time. `YYYY-MM-DD` is inclusive of the whole day.").optional(),
54164
+ depth: int().min(1).max(3).describe("Levels of descendants to return in one call. Above 1, `rows` is a flat list of all descendants down to that level rather than only direct children, and each row carries its own `level`.").optional(),
54165
+ limit: int().min(50).max(200).describe("Children per page. The minimum is 50 — smaller values are rejected rather than silently raised.").optional(),
54166
+ modifiedAfter: string2().describe("Filter children by source modification time.").optional(),
54167
+ modifiedBefore: string2().describe("Filter children by source modification time.").optional(),
54168
+ nodeId: string2().min(1).max(2048).describe("The node to open. Take it from an `id` in a previous navigate or lookup response. Omit it entirely for the flat listing of everything reachable — the usual starting point. A URL or an issue key such as `PA-1787` also works: it is resolved to its record automatically.").optional(),
54169
+ nodeTypes: array(string2()).describe("Restrict children to these node types. Repeat the parameter for multiple types: `?nodeTypes=record&nodeTypes=folder`.").optional(),
54170
+ page: int().min(1).describe("Page number, 1-indexed.").optional()
54171
+ });
54172
+ });
54173
+
54174
+ // src/funcs/connectorNavigateKnowledgeGraph.ts
54175
+ function connectorNavigateKnowledgeGraph(client$, request, options) {
54176
+ return new APIPromise($do10(client$, request, options));
54177
+ }
54178
+ async function $do10(client$, request, options) {
54179
+ const parsed$ = safeParse4(request, (value$) => NavigateKnowledgeGraphRequest$zodSchema.optional().parse(value$), "Input validation failed");
54180
+ if (!parsed$.ok) {
54181
+ return [parsed$, { status: "invalid" }];
54182
+ }
54183
+ const payload$ = parsed$.value;
54184
+ const body$ = null;
54185
+ const path$ = pathToFunc("/connectors/navigate")();
54186
+ const query$ = encodeFormQuery({
54187
+ createdAfter: payload$?.createdAfter,
54188
+ createdBefore: payload$?.createdBefore,
54189
+ depth: payload$?.depth,
54190
+ limit: payload$?.limit,
54191
+ modifiedAfter: payload$?.modifiedAfter,
54192
+ modifiedBefore: payload$?.modifiedBefore,
54193
+ nodeId: payload$?.nodeId,
54194
+ nodeTypes: payload$?.nodeTypes,
54195
+ page: payload$?.page
54196
+ });
54197
+ const headers$ = new Headers(compactMap({
54198
+ Accept: "application/json"
54199
+ }));
54200
+ const securityInput = await extractSecurity(client$._options.security);
54201
+ const requestSecurity = resolveGlobalSecurity(securityInput);
54202
+ const context = {
54203
+ options: client$._options,
54204
+ baseURL: options?.serverURL ?? client$._baseURL ?? "",
54205
+ operationID: "navigateKnowledgeGraph",
54206
+ oAuth2Scopes: ["kb:read", "connector:read"],
54207
+ resolvedSecurity: requestSecurity,
54208
+ securitySource: client$._options.security,
54209
+ retryConfig: options?.retries || client$._options.retryConfig || { strategy: "none" },
54210
+ retryCodes: options?.retryCodes || [
54211
+ "429",
54212
+ "500",
54213
+ "502",
54214
+ "503",
54215
+ "504"
54216
+ ]
54217
+ };
54218
+ const requestRes = client$._createRequest(context, {
54219
+ security: requestSecurity,
54220
+ method: "GET",
54221
+ baseURL: options?.serverURL,
54222
+ path: path$,
54223
+ headers: headers$,
54224
+ query: query$,
54225
+ body: body$,
54226
+ userAgent: client$._options.userAgent,
54227
+ timeoutMs: options?.timeoutMs || client$._options.timeoutMs || -1
54228
+ }, options);
54229
+ if (!requestRes.ok) {
54230
+ return [requestRes, { status: "invalid" }];
54231
+ }
54232
+ const req$ = requestRes.value;
54233
+ const doResult = await client$._do(req$, {
54234
+ context,
54235
+ errorCodes: [],
54236
+ retryConfig: context.retryConfig,
54237
+ retryCodes: context.retryCodes
54238
+ });
54239
+ if (!doResult.ok) {
54240
+ return [doResult, { status: "request-error", request: req$ }];
54241
+ }
54242
+ return [doResult, {
54243
+ status: "complete",
54244
+ request: req$,
54245
+ response: doResult.value
54246
+ }];
54247
+ }
54248
+ var init_connectorNavigateKnowledgeGraph = __esm(() => {
54249
+ init_encodings();
54250
+ init_primitives();
54251
+ init_schemas4();
54252
+ init_security2();
54253
+ init_url();
54254
+ init_navigateknowledgegraphop();
54255
+ init_async();
54256
+ });
54257
+
54258
+ // src/mcp-server/tools/pipeshubGetRecordContent.ts
54259
+ async function renderedResult(response) {
54260
+ const parsed = await readJson(response);
54261
+ if (!parsed.ok)
54262
+ return parsed.result;
54263
+ const text = parsed.value?.text;
54264
+ return typeof text === "string" && text.trim().length > 0 ? { content: [{ type: "text", text }] } : jsonResult(parsed.value);
54265
+ }
54266
+ var args4, tool$pipeshubGetRecordContent;
54267
+ var init_pipeshubGetRecordContent = __esm(() => {
54268
+ init_zod();
54269
+ init_connectorGetRecordContent();
54270
+ init_connectorLookupRecordByIdentifier();
54271
+ init_connectorNavigateKnowledgeGraph();
54272
+ init__helpers();
54273
+ args4 = {
54274
+ mode: _enum(["content", "navigate", "lookup"]).default("content").describe("`content` (default) reads a record's full text by `recordId`. " + "`lookup` resolves a URL / issue key / external ID to a recordId. " + "`navigate` browses the knowledge graph tree."),
54275
+ recordId: string2().min(1).optional().describe("Record identifier — usually a UUID for connector-sourced records or " + "a 24-character ObjectId for uploaded records. Get it from a chat " + "citation (`citations[*].recordId`) or from a `pipeshub_search` hit. " + "Required when `mode` is `content`."),
54276
+ nodeId: string2().min(1).max(2048).optional().describe("The node to open. Take it from a `record_id=` or `node_id=` shown in a " + "previous navigate or lookup response, from a search hit's `recordId`, " + "or from a `pipeshub_sources` id — a KB or connector id opens that " + "source directly. Omit it entirely for the flat listing of everything " + "reachable, newest first — the usual starting point. A URL or an issue " + "key such as `PA-1787` also works: it is resolved to its record " + "automatically, so no separate lookup is needed."),
54277
+ page: int().min(1).default(1).describe("Page number, 1-indexed."),
54278
+ limit: int().min(50).max(200).default(50).describe("Children per page. The minimum is 50 — smaller values are rejected " + "rather than silently raised."),
54279
+ depth: int().min(1).max(3).default(1).describe("Levels of descendants to return in one call. Above 1, the listing is a " + "flat list of all descendants down to that level rather than only " + "direct children, and each row carries its own `level`."),
54280
+ nodeTypes: array(string2()).optional().describe('Restrict children to these node types, e.g. `["record", "folder"]`.'),
54281
+ createdAfter: string2().optional().describe("Filter children by source creation time. ISO 8601 `YYYY-MM-DD`, or a " + "full datetime that MUST carry a timezone offset — a naive datetime is " + "rejected rather than assumed to be UTC."),
54282
+ createdBefore: string2().optional().describe("Filter children by source creation time. `YYYY-MM-DD` is inclusive of " + "the whole day."),
54283
+ modifiedAfter: string2().optional().describe("Filter children by source modification time. Same formats as " + "`createdAfter`."),
54284
+ modifiedBefore: string2().optional().describe("Filter children by source modification time. Same formats as " + "`createdBefore`."),
54285
+ identifiers: union([
54286
+ string2().min(1).max(2048),
54287
+ array(string2().min(1).max(2048)).min(1).max(10)
54288
+ ]).optional().describe("The reference(s) to resolve: a URL, an issue key such as `PA-1787`, or " + "a bare external system ID. Paste each exactly as you found it — " + "tracking parameters and fragments are handled. Pass a single string, " + "or an array of up to 10 to resolve them in one call. Required when " + "`mode` is `lookup`."),
54289
+ connectorName: string2().optional().describe("Optional hint that prioritises resolution order, e.g. `JIRA`, " + "`CONFLUENCE`, `GOOGLE_DRIVE`, `SLACK`. It cannot widen the search beyond the " + "connectors you can already access. Useful on a retry when a lookup " + "came back empty.")
54290
+ };
54291
+ tool$pipeshubGetRecordContent = {
54292
+ name: "pipeshub_get_record_content",
54293
+ description: `Three operations on the org's records. Pick by what you hold:
54294
+
54295
+ \`mode:"lookup"\` — a URL, issue key (PA-1787), or external ID
54296
+ → its recordId plus the record's metadata
54297
+ \`mode:"navigate"\` — a question about structure: what is under X,
54298
+ what links to Y → browses the hierarchy
54299
+ \`mode:"content"\` — a recordId, and you need the document's COMPLETE text
54300
+
54301
+ **\`mode:"content"\` (default)** — the only way to see a document's complete
54302
+ text. Use it whenever missing part of the document could make the answer
54303
+ wrong: summarize, extract or list ALL of something, check whether or where
54304
+ a doc mentions X, review, or compare named docs. \`pipeshub_chat\` cannot do
54305
+ these — it never sees a whole document.
54306
+
54307
+ Judge by the user's INTENT, not their keywords: "what's this doc about?",
54308
+ "walk me through the report", "anything in here about Y?" are all
54309
+ full-content tasks. Get the \`recordId\` from a \`pipeshub_search\` top hit, a
54310
+ chat citation, or \`mode:"lookup"\`.
54311
+
54312
+ Returns one \`content\` string: a metadata header (title, source, key fields,
54313
+ pre-generated summary) then the full parsed text. A record with no
54314
+ extractable content returns the literal \`No record found\`. Use
54315
+ \`pipeshub_download_record\` only for the original file bytes.
54316
+
54317
+ **\`mode:"navigate"\`** — browse the hierarchy: RecordGroup (project /
54318
+ space / drive / folder) → Record (epic / story / page / file) → children,
54319
+ with breadcrumbs, related links and record IDs.
54320
+
54321
+ Use it when the question depends on structure rather than wording: what is
54322
+ under this epic, which pages sit in this space, what is linked to this
54323
+ ticket, what is in this folder — and every "how many" / "all of" / "every"
54324
+ question. Search ranks by content; only this shows how records relate, and
54325
+ only this gives a count you can trust.
54326
+
54327
+ Omit \`nodeId\` for a flat listing of everything reachable, most recently
54328
+ updated first — the usual starting point. A URL, an issue key, or a
54329
+ \`pipeshub_sources\` id also works and resolves automatically.
54330
+
54331
+ Pass \`depth:2\` or \`depth:3\` to see several levels in ONE call — an epic's
54332
+ stories AND their subtasks, a space's pages AND their children — instead of
54333
+ one call per level. Use it whenever the question needs an overview of a
54334
+ hierarchy rather than a single node.
54335
+
54336
+ Opening a record also prints that record's own metadata — for a ticket,
54337
+ status, assignee, priority and dates — so a question about one record is
54338
+ often answered by this call alone. It returns no document text; for that,
54339
+ re-call with \`mode:"content"\`.
54340
+
54341
+ Returns \`Path\` breadcrumbs, the current node's metadata, a children listing
54342
+ carrying \`record_id=\` or \`node_id=\` per row plus the group's total
54343
+ (\`Children 1-50 of 61\`), \`Related\` cross-references, and a \`Next:\` line.
54344
+ One page is usually every child, so only pass \`page:2\` when that \`Next:\`
54345
+ line says more exist.
54346
+
54347
+ **\`mode:"lookup"\`** — turn an external reference into a recordId, the first
54348
+ step whenever the question names one. Returns that record's metadata (for a
54349
+ ticket: status, assignee, priority, dates) plus its recordId, which
54350
+ \`mode:"navigate"\` takes to list what is under it and \`mode:"content"\` takes
54351
+ to read it.
54352
+
54353
+ Handles Jira keys and URLs, Confluence, Drive, Slack permalinks, Linear,
54354
+ Notion, ServiceNow sys_id, SharePoint, Gmail/Outlook, and any connector
54355
+ whose records index a web URL. Resolution searches ALL connectors you can
54356
+ access, regardless of any source filter you used elsewhere.
54357
+
54358
+ A miss is a 200 with empty \`matches\` and the input echoed in
54359
+ \`not_found_identifiers\` — that may mean no-access, not non-existence. Use
54360
+ \`mode:"navigate"\` to confirm the record exists before telling the user it
54361
+ does not. If \`ambiguous\` is true, pick from \`matches\` rather than taking
54362
+ the first.
54363
+
54364
+ Navigate and lookup return a rendered text view whose closing \`Next:\` line
54365
+ names the exact follow-up call — follow it. When presenting a record, link
54366
+ it using the \`Web URL\` from its metadata header (when present).`,
54367
+ scopes: ["read"],
54368
+ annotations: {
54369
+ title: "Read, browse, or resolve records",
54370
+ destructiveHint: false,
54371
+ idempotentHint: true,
54372
+ openWorldHint: false,
54373
+ readOnlyHint: true
54374
+ },
54375
+ args: args4,
54376
+ tool: async (client, args5, ctx) => {
54377
+ const fetchOptions = { fetchOptions: { signal: ctx.signal } };
54378
+ if (args5.mode === "navigate") {
54379
+ const [r] = await connectorNavigateKnowledgeGraph(client, {
54380
+ nodeId: args5.nodeId,
54381
+ page: args5.page,
54382
+ limit: args5.limit,
54383
+ depth: args5.depth,
54384
+ nodeTypes: args5.nodeTypes,
54385
+ createdAfter: args5.createdAfter,
54386
+ createdBefore: args5.createdBefore,
54387
+ modifiedAfter: args5.modifiedAfter,
54388
+ modifiedBefore: args5.modifiedBefore
54389
+ }, fetchOptions).$inspect();
54390
+ if (!r.ok)
54391
+ return errorResult(r.error.message);
54392
+ const httpErr2 = await httpErrorResult(r.value, "Navigate knowledge graph");
54393
+ if (httpErr2)
54394
+ return httpErr2;
54395
+ return renderedResult(r.value);
54396
+ }
54397
+ if (args5.mode === "lookup") {
54398
+ const identifiers = typeof args5.identifiers === "string" ? [args5.identifiers] : args5.identifiers ?? [];
54399
+ if (identifiers.length === 0) {
54400
+ return errorResult('`identifiers` is required when mode is "lookup".');
54401
+ }
54402
+ const [r] = await connectorLookupRecordByIdentifier(client, {
54403
+ identifiers,
54404
+ connectorName: args5.connectorName
54405
+ }, fetchOptions).$inspect();
54406
+ if (!r.ok)
54407
+ return errorResult(r.error.message);
54408
+ const httpErr2 = await httpErrorResult(r.value, "Record lookup");
54409
+ if (httpErr2)
54410
+ return httpErr2;
54411
+ return renderedResult(r.value);
54412
+ }
54413
+ if (!args5.recordId) {
54414
+ return errorResult('`recordId` is required when mode is "content".');
54415
+ }
54416
+ const [result] = await connectorGetRecordContent(client, {
54417
+ recordId: args5.recordId
54418
+ }, fetchOptions).$inspect();
54419
+ if (!result.ok)
54420
+ return errorResult(result.error.message);
54421
+ const httpErr = await httpErrorResult(result.value, "Get record content");
54422
+ if (httpErr)
54423
+ return httpErr;
54424
+ const parsed = await readJson(result.value);
54425
+ if (!parsed.ok)
54426
+ return parsed.result;
54427
+ return { content: [{ type: "text", text: parsed.value.content ?? "" }] };
54428
+ }
54429
+ };
54430
+ });
54431
+
53740
54432
  // src/models/getallusersop.ts
53741
54433
  var GetAllUsersRequest$zodSchema;
53742
54434
  var init_getallusersop = __esm(() => {
@@ -53750,9 +54442,9 @@ var init_getallusersop = __esm(() => {
53750
54442
 
53751
54443
  // src/funcs/usersGetAllUsers.ts
53752
54444
  function usersGetAllUsers(client$, request, options) {
53753
- return new APIPromise($do8(client$, request, options));
54445
+ return new APIPromise($do11(client$, request, options));
53754
54446
  }
53755
- async function $do8(client$, request, options) {
54447
+ async function $do11(client$, request, options) {
53756
54448
  const parsed$ = safeParse4(request, (value$) => GetAllUsersRequest$zodSchema.optional().parse(value$), "Input validation failed");
53757
54449
  if (!parsed$.ok) {
53758
54450
  return [parsed$, { status: "invalid" }];
@@ -53837,9 +54529,9 @@ var init_getuserbyidop = __esm(() => {
53837
54529
 
53838
54530
  // src/funcs/usersGetUserById.ts
53839
54531
  function usersGetUserById(client$, request, options) {
53840
- return new APIPromise($do9(client$, request, options));
54532
+ return new APIPromise($do12(client$, request, options));
53841
54533
  }
53842
- async function $do9(client$, request, options) {
54534
+ async function $do12(client$, request, options) {
53843
54535
  const parsed$ = safeParse4(request, (value$) => GetUserByIdRequest$zodSchema.parse(value$), "Input validation failed");
53844
54536
  if (!parsed$.ok) {
53845
54537
  return [parsed$, { status: "invalid" }];
@@ -53926,9 +54618,9 @@ var init_getallusergroupsop = __esm(() => {
53926
54618
 
53927
54619
  // src/funcs/userGroupsGetAllUserGroups.ts
53928
54620
  function userGroupsGetAllUserGroups(client$, request, options) {
53929
- return new APIPromise($do10(client$, request, options));
54621
+ return new APIPromise($do13(client$, request, options));
53930
54622
  }
53931
- async function $do10(client$, request, options) {
54623
+ async function $do13(client$, request, options) {
53932
54624
  const parsed$ = safeParse4(request, (value$) => GetAllUserGroupsRequest$zodSchema.optional().parse(value$), "Input validation failed");
53933
54625
  if (!parsed$.ok) {
53934
54626
  return [parsed$, { status: "invalid" }];
@@ -53950,7 +54642,7 @@ async function $do10(client$, request, options) {
53950
54642
  options: client$._options,
53951
54643
  baseURL: options?.serverURL ?? client$._baseURL ?? "",
53952
54644
  operationID: "getAllUserGroups",
53953
- oAuth2Scopes: [],
54645
+ oAuth2Scopes: ["usergroup:read"],
53954
54646
  resolvedSecurity: requestSecurity,
53955
54647
  securitySource: client$._options.security,
53956
54648
  retryConfig: options?.retries || client$._options.retryConfig || { strategy: "none" },
@@ -54018,9 +54710,9 @@ var init_getuserteamsop = __esm(() => {
54018
54710
 
54019
54711
  // src/funcs/teamsGetUserTeams.ts
54020
54712
  function teamsGetUserTeams(client$, request, options) {
54021
- return new APIPromise($do11(client$, request, options));
54713
+ return new APIPromise($do14(client$, request, options));
54022
54714
  }
54023
- async function $do11(client$, request, options) {
54715
+ async function $do14(client$, request, options) {
54024
54716
  const parsed$ = safeParse4(request, (value$) => GetUserTeamsRequest$zodSchema.optional().parse(value$), "Input validation failed");
54025
54717
  if (!parsed$.ok) {
54026
54718
  return [parsed$, { status: "invalid" }];
@@ -54098,7 +54790,7 @@ var init_teamsGetUserTeams = __esm(() => {
54098
54790
  });
54099
54791
 
54100
54792
  // src/mcp-server/tools/pipeshubDirectory.ts
54101
- var args4, tool$pipeshubDirectory;
54793
+ var args5, tool$pipeshubDirectory;
54102
54794
  var init_pipeshubDirectory = __esm(() => {
54103
54795
  init_zod();
54104
54796
  init_usersGetAllUsers();
@@ -54106,7 +54798,7 @@ var init_pipeshubDirectory = __esm(() => {
54106
54798
  init_userGroupsGetAllUserGroups();
54107
54799
  init_teamsGetUserTeams();
54108
54800
  init__helpers();
54109
- args4 = {
54801
+ args5 = {
54110
54802
  action: _enum([
54111
54803
  "whoami",
54112
54804
  "list_users",
@@ -54144,10 +54836,10 @@ Output shape varies by action; see each action's docs above.`,
54144
54836
  openWorldHint: false,
54145
54837
  readOnlyHint: true
54146
54838
  },
54147
- args: args4,
54148
- tool: async (client, args5, ctx) => {
54839
+ args: args5,
54840
+ tool: async (client, args6, ctx) => {
54149
54841
  const fetchOptions = { signal: ctx.signal };
54150
- switch (args5.action) {
54842
+ switch (args6.action) {
54151
54843
  case "whoami": {
54152
54844
  const claims = await decodeBearer(client);
54153
54845
  if (!claims) {
@@ -54164,9 +54856,9 @@ Output shape varies by action; see each action's docs above.`,
54164
54856
  }
54165
54857
  case "list_users": {
54166
54858
  const [result] = await usersGetAllUsers(client, {
54167
- page: args5.page,
54168
- limit: args5.limit,
54169
- search: args5.search
54859
+ page: args6.page,
54860
+ limit: args6.limit,
54861
+ search: args6.search
54170
54862
  }, { fetchOptions }).$inspect();
54171
54863
  if (!result.ok)
54172
54864
  return errorResult(result.error.message);
@@ -54176,11 +54868,11 @@ Output shape varies by action; see each action's docs above.`,
54176
54868
  return jsonResult(parsed.value);
54177
54869
  }
54178
54870
  case "get_user": {
54179
- if (!args5.userId) {
54871
+ if (!args6.userId) {
54180
54872
  return errorResult("`userId` is required when `action` is `get_user`. " + "Use `whoami` to find your own id, or `list_users` " + "to look up by name / email.");
54181
54873
  }
54182
54874
  const [result] = await usersGetUserById(client, {
54183
- id: args5.userId
54875
+ id: args6.userId
54184
54876
  }, { fetchOptions }).$inspect();
54185
54877
  if (!result.ok)
54186
54878
  return errorResult(result.error.message);
@@ -54191,9 +54883,9 @@ Output shape varies by action; see each action's docs above.`,
54191
54883
  }
54192
54884
  case "list_groups": {
54193
54885
  const [result] = await userGroupsGetAllUserGroups(client, {
54194
- page: args5.page,
54195
- limit: args5.limit,
54196
- search: args5.search
54886
+ page: args6.page,
54887
+ limit: args6.limit,
54888
+ search: args6.search
54197
54889
  }, { fetchOptions }).$inspect();
54198
54890
  if (!result.ok)
54199
54891
  return errorResult(result.error.message);
@@ -54204,9 +54896,9 @@ Output shape varies by action; see each action's docs above.`,
54204
54896
  }
54205
54897
  case "list_my_teams": {
54206
54898
  const [result] = await teamsGetUserTeams(client, {
54207
- page: args5.page,
54208
- limit: args5.limit,
54209
- search: args5.search
54899
+ page: args6.page,
54900
+ limit: args6.limit,
54901
+ search: args6.search
54210
54902
  }, { fetchOptions }).$inspect();
54211
54903
  if (!result.ok)
54212
54904
  return errorResult(result.error.message);
@@ -54250,9 +54942,9 @@ var init_getknowledgehubrootnodesop = __esm(() => {
54250
54942
 
54251
54943
  // src/funcs/knowledgeHubGetKnowledgeHubRootNodes.ts
54252
54944
  function knowledgeHubGetKnowledgeHubRootNodes(client$, request, options) {
54253
- return new APIPromise($do12(client$, request, options));
54945
+ return new APIPromise($do15(client$, request, options));
54254
54946
  }
54255
- async function $do12(client$, request, options) {
54947
+ async function $do15(client$, request, options) {
54256
54948
  const parsed$ = safeParse4(request, (value$) => GetKnowledgeHubRootNodesRequest$zodSchema.optional().parse(value$), "Input validation failed");
54257
54949
  if (!parsed$.ok) {
54258
54950
  return [parsed$, { status: "invalid" }];
@@ -54368,9 +55060,9 @@ var init_getavailablemodelsbytypeop = __esm(() => {
54368
55060
 
54369
55061
  // src/funcs/aiModelsProvidersGetAvailableModelsByType.ts
54370
55062
  function aiModelsProvidersGetAvailableModelsByType(client$, request, options) {
54371
- return new APIPromise($do13(client$, request, options));
55063
+ return new APIPromise($do16(client$, request, options));
54372
55064
  }
54373
- async function $do13(client$, request, options) {
55065
+ async function $do16(client$, request, options) {
54374
55066
  const parsed$ = safeParse4(request, (value$) => GetAvailableModelsByTypeRequest$zodSchema.parse(value$), "Input validation failed");
54375
55067
  if (!parsed$.ok) {
54376
55068
  return [parsed$, { status: "invalid" }];
@@ -54445,13 +55137,13 @@ var init_aiModelsProvidersGetAvailableModelsByType = __esm(() => {
54445
55137
  });
54446
55138
 
54447
55139
  // src/mcp-server/tools/pipeshubSources.ts
54448
- var args5, tool$pipeshubSources;
55140
+ var args6, tool$pipeshubSources;
54449
55141
  var init_pipeshubSources = __esm(() => {
54450
55142
  init_zod();
54451
55143
  init_knowledgeHubGetKnowledgeHubRootNodes();
54452
55144
  init_aiModelsProvidersGetAvailableModelsByType();
54453
55145
  init__helpers();
54454
- args5 = {
55146
+ args6 = {
54455
55147
  include: array(_enum(["sources", "llmModels", "embeddingModels"])).optional().describe('Which sections to fetch. Default: `["sources", "llmModels"]`. ' + "Add `embeddingModels` if the user is configuring re-embedding.")
54456
55148
  };
54457
55149
  tool$pipeshubSources = {
@@ -54482,10 +55174,10 @@ are returned by default; pass \`include\` to override.`,
54482
55174
  openWorldHint: false,
54483
55175
  readOnlyHint: true
54484
55176
  },
54485
- args: args5,
54486
- tool: async (client, args6, ctx) => {
55177
+ args: args6,
55178
+ tool: async (client, args7, ctx) => {
54487
55179
  const fetchOptions = { signal: ctx.signal };
54488
- const include = args6.include ?? ["sources", "llmModels"];
55180
+ const include = args7.include ?? ["sources", "llmModels"];
54489
55181
  const want = (s) => include.includes(s);
54490
55182
  const result = {};
54491
55183
  if (want("sources")) {
@@ -54535,11 +55227,11 @@ are returned by default; pass \`include\` to override.`,
54535
55227
  });
54536
55228
 
54537
55229
  // src/mcp-server/tools/pipeshubAgents.ts
54538
- var args6, tool$pipeshubAgents;
55230
+ var args7, tool$pipeshubAgents;
54539
55231
  var init_pipeshubAgents = __esm(() => {
54540
55232
  init_zod();
54541
55233
  init__helpers();
54542
- args6 = {
55234
+ args7 = {
54543
55235
  search: string2().optional().describe("Optional case-insensitive substring match across agent name, " + "description, and tags. Omit to return every agent.")
54544
55236
  };
54545
55237
  tool$pipeshubAgents = {
@@ -54578,10 +55270,10 @@ specific agent is needed, use \`pipeshub_chat\` WITHOUT \`agentId\` and pick a
54578
55270
  openWorldHint: false,
54579
55271
  readOnlyHint: true
54580
55272
  },
54581
- args: args6,
54582
- tool: async (client, args7, ctx) => {
55273
+ args: args7,
55274
+ tool: async (client, args8, ctx) => {
54583
55275
  const all = await listAllAgents(client, {
54584
- search: args7.search,
55276
+ search: args8.search,
54585
55277
  signal: ctx.signal
54586
55278
  });
54587
55279
  if (!all.ok)
@@ -54596,25 +55288,25 @@ specific agent is needed, use \`pipeshub_chat\` WITHOUT \`agentId\` and pick a
54596
55288
  });
54597
55289
 
54598
55290
  // src/mcp-server/prompts/pipeshubAssistant.ts
54599
- var args7, prompt$pipeshubAssistant;
55291
+ var args8, prompt$pipeshubAssistant;
54600
55292
  var init_pipeshubAssistant = __esm(() => {
54601
55293
  init_zod();
54602
- args7 = {
55294
+ args8 = {
54603
55295
  query: string2().optional().describe("Optional. The user's request to route. Provide it to have the guidance " + "applied to a concrete request; omit it to just load the routing " + "guidance as a seed system prompt at the start of a session.")
54604
55296
  };
54605
55297
  prompt$pipeshubAssistant = {
54606
55298
  name: "pipeshub-assistant",
54607
55299
  description: "Load PipesHub tool-routing guidance so the assistant picks the correct " + "tool (pipeshub_chat / search / agents / directory) and lists agents " + "with pipeshub_agents when unsure which route fits the query.",
54608
55300
  scopes: ["read"],
54609
- args: args7,
54610
- prompt: (_client, args8, _extra) => {
54611
- const text = args8.query ? `${PIPESHUB_INSTRUCTIONS}
55301
+ args: args8,
55302
+ prompt: (_client, args9, _extra) => {
55303
+ const text = args9.query ? `${PIPESHUB_INSTRUCTIONS}
54612
55304
 
54613
55305
  ---
54614
55306
 
54615
55307
  Follow the routing rules above to ` + `handle this request, picking the right tool (and listing agents via ` + `\`pipeshub_agents\` if unsure which route fits):
54616
55308
 
54617
- ${args8.query}` : PIPESHUB_INSTRUCTIONS;
55309
+ ${args9.query}` : PIPESHUB_INSTRUCTIONS;
54618
55310
  return {
54619
55311
  messages: [
54620
55312
  {
@@ -54635,17 +55327,21 @@ function createMCPServer(deps) {
54635
55327
  }, {
54636
55328
  instructions: PIPESHUB_INSTRUCTIONS
54637
55329
  });
54638
- const getClient = deps.getSDK || (() => new PipeshubCore({
55330
+ const resolveClient = deps.getSDK || (() => new PipeshubCore({
54639
55331
  security: deps.security,
54640
55332
  serverURL: deps.serverURL,
54641
55333
  serverIdx: deps.serverIdx,
54642
55334
  instance_url: deps.instance_url,
54643
55335
  debugLogger: deps.logger.level === "debug" ? {
54644
- log: (...args8) => console.log(...args8),
54645
- group: (...args8) => console.group(...args8),
54646
- groupEnd: (...args8) => console.groupEnd(...args8)
55336
+ log: (...args9) => console.log(...args9),
55337
+ group: (...args9) => console.group(...args9),
55338
+ groupEnd: (...args9) => console.groupEnd(...args9)
54647
55339
  } : undefined
54648
55340
  }));
55341
+ const getClient = () => {
55342
+ bindNewRequestId();
55343
+ return resolveClient();
55344
+ };
54649
55345
  const scopes = new Set(deps.scopes);
54650
55346
  const allowedTools = deps.allowedTools && new Set(deps.allowedTools);
54651
55347
  const [tool, tools, toolMap] = createRegisterTool(deps.logger, server, getClient, scopes, allowedTools, deps.dynamic);
@@ -54657,6 +55353,7 @@ function createMCPServer(deps) {
54657
55353
  tool(tool$pipeshubChat);
54658
55354
  tool(tool$pipeshubSearch);
54659
55355
  tool(tool$pipeshubDownloadRecord);
55356
+ tool(tool$pipeshubGetRecordContent);
54660
55357
  tool(tool$pipeshubDirectory);
54661
55358
  tool(tool$pipeshubAgents);
54662
55359
  prompt(prompt$pipeshubAssistant);
@@ -54668,11 +55365,13 @@ function createMCPServer(deps) {
54668
55365
  var init_server2 = __esm(() => {
54669
55366
  init_mcp();
54670
55367
  init_core3();
55368
+ init_request_context();
54671
55369
  init_resources();
54672
55370
  init_tools();
54673
55371
  init_pipeshubChat();
54674
55372
  init_pipeshubSearch();
54675
55373
  init_pipeshubDownloadRecord();
55374
+ init_pipeshubGetRecordContent();
54676
55375
  init_pipeshubDirectory();
54677
55376
  init_pipeshubSources();
54678
55377
  init_pipeshubAgents();
@@ -54689,25 +55388,39 @@ var init_tool_names = __esm(() => {
54689
55388
  },
54690
55389
  {
54691
55390
  name: "pipeshub_chat",
54692
- description: `**Primary chat tool handles both internal knowledge queries and web search.**
54693
-
54694
- **Internal search** (default, \`chatMode: "internal_search"\`): Use whenever
54695
- the user asks about their documents, files, knowledge base, company policies,
54696
- or anything that could plausibly be answered by content in their PipesHub-indexed
54697
- sources (Drive, Box, Confluence, Slack, Gmail, Jira, the org's KB, ...).
54698
- Grounds the answer in the user's actual data and returns citations.
54699
-
54700
- **Web search** (\`chatMode: "web_search"\`): Use when the user asks about
54701
- current events, public information, or anything unlikely to be in the org's
54702
- internal knowledge base. Pass \`chatMode: "web_search"\` and this tool will
54703
- search the public web instead.
54704
-
54705
- **When to pick this over other tools:**
54706
- - "What does <document> say about X?" → \`pipeshub_chat\` (internal_search)
54707
- - "Summarize <topic / doc>." \`pipeshub_chat\` (internal_search)
55391
+ description: `Ask a question, get an answer grounded in the org's indexed data with
55392
+ citations. It reads a few retrieved passages — never a whole document,
55393
+ never a complete list.
55394
+
55395
+ **Three questions this tool gets WRONG. Check them first:**
55396
+ - **Structure** "what's under this epic?", "which pages are in this
55397
+ space?", "what links to this ticket?", "what's in this folder?"
55398
+ \`pipeshub_get_record_content\` \`mode:"navigate"\`. Ranking cannot see how
55399
+ records relate.
55400
+ - **Exhaustive** "how many X?", "list ALL the Y", "every Z"
55401
+ \`mode:"navigate"\`, which reports the group's real total. This tool
55402
+ undercounts and will not say so.
55403
+ - **One named document** — summarize it, extract from it, what does it say
55404
+ about X \`pipeshub_search\` for the \`recordId\`, then \`mode:"content"\`.
55405
+
55406
+ Everything else about the org's knowledge belongs here: policies,
55407
+ processes, decisions, history, "what do we know about X", and any question
55408
+ spanning several documents.
55409
+
55410
+ **Internal search** (default, \`chatMode: "internal_search"\`): the user's
55411
+ documents, files, knowledge base, company policies — anything in their
55412
+ PipesHub-indexed sources (Drive, Box, Confluence, Slack, Gmail, Jira, the
55413
+ org's KB, ...).
55414
+
55415
+ **Web search** (\`chatMode: "web_search"\`): current events or public
55416
+ information unlikely to be in the org's knowledge base.
55417
+
55418
+ Both are plain-chat modes. **Agent chat** — pass an \`agentId\` from
55419
+ \`pipeshub_agents\` — runs against that agent's own prompt, tools and knowledge;
55420
+ \`quick\` is its only mode, requires the \`agentId\`, and is sent automatically.
55421
+
54708
55422
  - "What's our policy on Y?" → \`pipeshub_chat\` (internal_search)
54709
55423
  - "What's in the news about Z?" → \`pipeshub_chat\` (web_search)
54710
- - "What is the latest version of <library>?" → \`pipeshub_chat\` (web_search)
54711
55424
  - "Find / locate the file named X" → \`pipeshub_search\` (then
54712
55425
  \`pipeshub_download_record\` if the user wants the bytes).
54713
55426
 
@@ -54731,26 +55444,120 @@ cited document, take \`citations[*].recordId\` and call
54731
55444
  name: "pipeshub_search",
54732
55445
  description: `Vector / semantic search across the org's indexed documents.
54733
55446
 
54734
- **Use this only when the user wants to LOCATE a document** — by name,
54735
- topic, or a phrase to grep for. For "what does the document say about
54736
- X?" or any open-ended question, use \`pipeshub_chat\` instead, which
54737
- does the retrieval internally and grounds the answer in citations.
55447
+ **Use this when the user wants to LOCATE a document** — by name, topic,
55448
+ or a phrase to grep for and to resolve it to a \`recordId\`. For
55449
+ open-ended questions across many documents, use \`pipeshub_chat\`
55450
+ instead, which does the retrieval internally and grounds the answer in
55451
+ citations.
54738
55452
 
54739
55453
  Typical uses:
55454
+ - Resolve a doc name / topic into a \`recordId\` for
55455
+ \`pipeshub_get_record_content\` — step 1 of any full-document task
55456
+ (summarize, extract, review, "what does the doc say?").
54740
55457
  - Resolve a filename / phrase into a \`recordId\` for
54741
55458
  \`pipeshub_download_record\`.
54742
55459
  - Show the user a ranked list of matching files when they ask "find /
54743
55460
  search for X".
54744
55461
 
55462
+ Not for structural questions — what is under this epic, which pages are
55463
+ in this space, what links to this ticket. Ranking by content cannot show
55464
+ how records relate; use \`pipeshub_get_record_content\` \`mode:"navigate"\`.
55465
+
55466
+ **A ranked sample, never a complete list.** Hits are the top-scoring
55467
+ blocks from the best-matching records — not all blocks of any record, and
55468
+ not every record that matches. Never count them to answer "how many" /
55469
+ "all" / "every"; navigate the record group instead, which reports its
55470
+ real total.
55471
+
54745
55472
  The response is trimmed to one row per hit:
54746
55473
  \`{ recordId, recordName, score, snippet, mimeType, webUrl, ... }\`.
54747
55474
  Highest \`score\` first; multiple hits may share the same \`recordId\`
54748
- (different chunks of the same record).`
55475
+ (different blocks of the same record).
55476
+
55477
+ When presenting results to the user, link each record using its
55478
+ \`webUrl\` (when present).`
54749
55479
  },
54750
55480
  {
54751
55481
  name: "pipeshub_download_record",
54752
55482
  description: "Stream the binary content of a single record from PipesHub.\n\nTypical sources for the `recordId`:\n- A chat citation:\n `pipeshub_chat` response → `citations[*].recordId`.\n- A search result:\n `pipeshub_search` response → `hits[*].recordId` /\n `uniqueRecords[*].recordId`.\n\nResponse `Content-Type` is forwarded from the upstream service —\n`application/pdf`, `application/octet-stream`, etc. Binary content is\nreturned base64-encoded; text content is returned inline."
54753
55483
  },
55484
+ {
55485
+ name: "pipeshub_get_record_content",
55486
+ description: `Three operations on the org's records. Pick by what you hold:
55487
+
55488
+ \`mode:"lookup"\` — a URL, issue key (PA-1787), or external ID
55489
+ → its recordId plus the record's metadata
55490
+ \`mode:"navigate"\` — a question about structure: what is under X,
55491
+ what links to Y → browses the hierarchy
55492
+ \`mode:"content"\` — a recordId, and you need the document's COMPLETE text
55493
+
55494
+ **\`mode:"content"\` (default)** — the only way to see a document's complete
55495
+ text. Use it whenever missing part of the document could make the answer
55496
+ wrong: summarize, extract or list ALL of something, check whether or where
55497
+ a doc mentions X, review, or compare named docs. \`pipeshub_chat\` cannot do
55498
+ these — it never sees a whole document.
55499
+
55500
+ Judge by the user's INTENT, not their keywords: "what's this doc about?",
55501
+ "walk me through the report", "anything in here about Y?" are all
55502
+ full-content tasks. Get the \`recordId\` from a \`pipeshub_search\` top hit, a
55503
+ chat citation, or \`mode:"lookup"\`.
55504
+
55505
+ Returns one \`content\` string: a metadata header (title, source, key fields,
55506
+ pre-generated summary) then the full parsed text. A record with no
55507
+ extractable content returns the literal \`No record found\`. Use
55508
+ \`pipeshub_download_record\` only for the original file bytes.
55509
+
55510
+ **\`mode:"navigate"\`** — browse the hierarchy: RecordGroup (project /
55511
+ space / drive / folder) → Record (epic / story / page / file) → children,
55512
+ with breadcrumbs, related links and record IDs.
55513
+
55514
+ Use it when the question depends on structure rather than wording: what is
55515
+ under this epic, which pages sit in this space, what is linked to this
55516
+ ticket, what is in this folder — and every "how many" / "all of" / "every"
55517
+ question. Search ranks by content; only this shows how records relate, and
55518
+ only this gives a count you can trust.
55519
+
55520
+ Omit \`nodeId\` for a flat listing of everything reachable, most recently
55521
+ updated first — the usual starting point. A URL, an issue key, or a
55522
+ \`pipeshub_sources\` id also works and resolves automatically.
55523
+
55524
+ Pass \`depth:2\` or \`depth:3\` to see several levels in ONE call — an epic's
55525
+ stories AND their subtasks, a space's pages AND their children — instead of
55526
+ one call per level. Use it whenever the question needs an overview of a
55527
+ hierarchy rather than a single node.
55528
+
55529
+ Opening a record also prints that record's own metadata — for a ticket,
55530
+ status, assignee, priority and dates — so a question about one record is
55531
+ often answered by this call alone. It returns no document text; for that,
55532
+ re-call with \`mode:"content"\`.
55533
+
55534
+ Returns \`Path\` breadcrumbs, the current node's metadata, a children listing
55535
+ carrying \`record_id=\` or \`node_id=\` per row plus the group's total
55536
+ (\`Children 1-50 of 61\`), \`Related\` cross-references, and a \`Next:\` line.
55537
+ One page is usually every child, so only pass \`page:2\` when that \`Next:\`
55538
+ line says more exist.
55539
+
55540
+ **\`mode:"lookup"\`** — turn an external reference into a recordId, the first
55541
+ step whenever the question names one. Returns that record's metadata (for a
55542
+ ticket: status, assignee, priority, dates) plus its recordId, which
55543
+ \`mode:"navigate"\` takes to list what is under it and \`mode:"content"\` takes
55544
+ to read it.
55545
+
55546
+ Handles Jira keys and URLs, Confluence, Drive, Slack permalinks, Linear,
55547
+ Notion, ServiceNow sys_id, SharePoint, Gmail/Outlook, and any connector
55548
+ whose records index a web URL. Resolution searches ALL connectors you can
55549
+ access, regardless of any source filter you used elsewhere.
55550
+
55551
+ A miss is a 200 with empty \`matches\` and the input echoed in
55552
+ \`not_found_identifiers\` — that may mean no-access, not non-existence. Use
55553
+ \`mode:"navigate"\` to confirm the record exists before telling the user it
55554
+ does not. If \`ambiguous\` is true, pick from \`matches\` rather than taking
55555
+ the first.
55556
+
55557
+ Navigate and lookup return a rendered text view whose closing \`Next:\` line
55558
+ names the exact follow-up call — follow it. When presenting a record, link
55559
+ it using the \`Web URL\` from its metadata header (when present).`
55560
+ },
54754
55561
  {
54755
55562
  name: "pipeshub_directory",
54756
55563
  description: "Look up people, groups, and teams in PipesHub. One tool with five\nactions — pick the right `action`:\n\n- `whoami` — who is the caller? Use this whenever you need the\n authenticated user's own id, email, or full name (e.g. before\n `get_user` on themselves).\n- `list_users` — search / page through org users.\n- `get_user` — full `User` document for one user (requires `userId`).\n- `list_groups` — list user groups with `userCount`.\n- `list_my_teams` — teams the caller belongs to, with capability flags\n (`canEdit` / `canDelete` / `canManageMembers`).\n\nOutput shape varies by action; see each action's docs above."
@@ -58386,5 +59193,5 @@ export {
58386
59193
  app
58387
59194
  };
58388
59195
 
58389
- //# debugId=E589470B4E3C258364756E2164756E21
59196
+ //# debugId=90FD24D95D2C4D3664756E2164756E21
58390
59197
  //# sourceMappingURL=mcp-server.js.map