@pipeshub-ai/mcp 2.1.0 → 2.2.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 (64) hide show
  1. package/README.md +90 -2
  2. package/bin/mcp-server.js +408 -74
  3. package/bin/mcp-server.js.map +19 -12
  4. package/esm/funcs/connectorGetRecordContent.d.ts +43 -0
  5. package/esm/funcs/connectorGetRecordContent.d.ts.map +1 -0
  6. package/esm/funcs/connectorGetRecordContent.js +114 -0
  7. package/esm/funcs/connectorGetRecordContent.js.map +1 -0
  8. package/esm/funcs/conversationsStreamConversation.js +1 -1
  9. package/esm/funcs/conversationsStreamConversation.js.map +1 -1
  10. package/esm/funcs/userGroupsGetAllUserGroups.js +1 -1
  11. package/esm/funcs/userGroupsGetAllUserGroups.js.map +1 -1
  12. package/esm/hooks/registration.d.ts.map +1 -1
  13. package/esm/hooks/registration.js +2 -1
  14. package/esm/hooks/registration.js.map +1 -1
  15. package/esm/hooks/request-context.d.ts +10 -0
  16. package/esm/hooks/request-context.d.ts.map +1 -0
  17. package/esm/hooks/request-context.js +38 -0
  18. package/esm/hooks/request-context.js.map +1 -0
  19. package/esm/hooks/requestid.d.ts +5 -0
  20. package/esm/hooks/requestid.d.ts.map +1 -0
  21. package/esm/hooks/requestid.js +58 -0
  22. package/esm/hooks/requestid.js.map +1 -0
  23. package/esm/mcp-server/instructions.d.ts +1 -1
  24. package/esm/mcp-server/instructions.d.ts.map +1 -1
  25. package/esm/mcp-server/instructions.js +32 -9
  26. package/esm/mcp-server/instructions.js.map +1 -1
  27. package/esm/mcp-server/server.d.ts.map +1 -1
  28. package/esm/mcp-server/server.js +10 -3
  29. package/esm/mcp-server/server.js.map +1 -1
  30. package/esm/mcp-server/tools/pipeshubChat.d.ts.map +1 -1
  31. package/esm/mcp-server/tools/pipeshubChat.js +8 -2
  32. package/esm/mcp-server/tools/pipeshubChat.js.map +1 -1
  33. package/esm/mcp-server/tools/pipeshubGetRecordContent.d.ts +8 -0
  34. package/esm/mcp-server/tools/pipeshubGetRecordContent.d.ts.map +1 -0
  35. package/esm/mcp-server/tools/pipeshubGetRecordContent.js +63 -0
  36. package/esm/mcp-server/tools/pipeshubGetRecordContent.js.map +1 -0
  37. package/esm/mcp-server/tools/pipeshubSearch.d.ts.map +1 -1
  38. package/esm/mcp-server/tools/pipeshubSearch.js +8 -4
  39. package/esm/mcp-server/tools/pipeshubSearch.js.map +1 -1
  40. package/esm/mcp-server/tools.d.ts.map +1 -1
  41. package/esm/mcp-server/tools.js +13 -1
  42. package/esm/mcp-server/tools.js.map +1 -1
  43. package/esm/models/getrecordcontentop.d.ts +6 -0
  44. package/esm/models/getrecordcontentop.d.ts.map +1 -0
  45. package/esm/models/getrecordcontentop.js +5 -0
  46. package/esm/models/getrecordcontentop.js.map +1 -0
  47. package/esm/tool-names.d.ts.map +1 -1
  48. package/esm/tool-names.js +6 -2
  49. package/esm/tool-names.js.map +1 -1
  50. package/package.json +2 -1
  51. package/src/funcs/connectorGetRecordContent.ts +179 -0
  52. package/src/funcs/conversationsStreamConversation.ts +1 -1
  53. package/src/funcs/userGroupsGetAllUserGroups.ts +1 -1
  54. package/src/hooks/registration.ts +2 -1
  55. package/src/hooks/request-context.ts +47 -0
  56. package/src/hooks/requestid.ts +62 -0
  57. package/src/mcp-server/instructions.ts +32 -9
  58. package/src/mcp-server/server.ts +11 -3
  59. package/src/mcp-server/tools/pipeshubChat.ts +8 -2
  60. package/src/mcp-server/tools/pipeshubGetRecordContent.ts +67 -0
  61. package/src/mcp-server/tools/pipeshubSearch.ts +8 -4
  62. package/src/mcp-server/tools.ts +14 -1
  63. package/src/models/getrecordcontentop.ts +11 -0
  64. 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
@@ -50467,8 +50490,110 @@ replay prior messages. Only start a fresh conversation when the user
50467
50490
  explicitly asks to clear context.
50468
50491
  `;
50469
50492
 
50493
+ // node_modules/nanoid/url-alphabet/index.js
50494
+ var urlAlphabet = "useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";
50495
+
50496
+ // node_modules/nanoid/index.js
50497
+ import { webcrypto as crypto3 } from "node:crypto";
50498
+ function fillPool(bytes) {
50499
+ if (bytes < 0)
50500
+ throw new RangeError("Wrong ID size");
50501
+ try {
50502
+ if (!pool || pool.length < bytes) {
50503
+ pool = Buffer.allocUnsafe(bytes * POOL_SIZE_MULTIPLIER);
50504
+ crypto3.getRandomValues(pool);
50505
+ poolOffset = 0;
50506
+ } else if (poolOffset + bytes > pool.length) {
50507
+ crypto3.getRandomValues(pool);
50508
+ poolOffset = 0;
50509
+ }
50510
+ } catch (e) {
50511
+ pool = undefined;
50512
+ throw e;
50513
+ }
50514
+ poolOffset += bytes;
50515
+ }
50516
+ function nanoid2(size = 21) {
50517
+ fillPool(size |= 0);
50518
+ let id = "";
50519
+ for (let i = poolOffset - size;i < poolOffset; i++) {
50520
+ id += urlAlphabet[pool[i] & 63];
50521
+ }
50522
+ return id;
50523
+ }
50524
+ var POOL_SIZE_MULTIPLIER = 128, pool, poolOffset;
50525
+ var init_nanoid = () => {};
50526
+
50527
+ // src/hooks/request-context.ts
50528
+ import { AsyncLocalStorage } from "node:async_hooks";
50529
+ function bindNewRequestId() {
50530
+ storage.enterWith({ random: nanoid2() });
50531
+ }
50532
+ function getRequestContextStore() {
50533
+ return storage.getStore();
50534
+ }
50535
+ function newRequestId() {
50536
+ return `mcp-${nanoid2()}`;
50537
+ }
50538
+ var storage;
50539
+ var init_request_context = __esm(() => {
50540
+ init_nanoid();
50541
+ storage = new AsyncLocalStorage;
50542
+ });
50543
+
50544
+ // src/hooks/requestid.ts
50545
+ function decodeJwtPayload(token) {
50546
+ try {
50547
+ const base64Url = token.split(".")[1];
50548
+ if (!base64Url)
50549
+ return null;
50550
+ const base642 = base64Url.replace(/-/g, "+").replace(/_/g, "/");
50551
+ const padded = base642 + "=".repeat((4 - base642.length % 4) % 4);
50552
+ const claims = JSON.parse(Buffer.from(padded, "base64").toString("utf8"));
50553
+ return typeof claims === "object" && claims !== null ? claims : null;
50554
+ } catch {
50555
+ return null;
50556
+ }
50557
+ }
50558
+ function userIdFromRequest(request) {
50559
+ const auth = request.headers.get("authorization") ?? "";
50560
+ if (!auth.toLowerCase().startsWith("bearer "))
50561
+ return null;
50562
+ const token = auth.slice(7).trim();
50563
+ const claims = decodeJwtPayload(token);
50564
+ return claims?.["userId"] || null;
50565
+ }
50566
+
50567
+ class RequestIDHook {
50568
+ beforeRequest(_hookCtx, request) {
50569
+ if (request.headers.get(REQUEST_ID_HEADER)) {
50570
+ return request;
50571
+ }
50572
+ const store = getRequestContextStore();
50573
+ if (!store) {
50574
+ request.headers.set(REQUEST_ID_HEADER, newRequestId());
50575
+ return request;
50576
+ }
50577
+ if (!store.finalId) {
50578
+ const userId = userIdFromRequest(request);
50579
+ store.finalId = userId ? `mcp-${userId}-${store.random}` : `mcp-${store.random}`;
50580
+ }
50581
+ request.headers.set(REQUEST_ID_HEADER, store.finalId);
50582
+ return request;
50583
+ }
50584
+ }
50585
+ var REQUEST_ID_HEADER = "x-request-id";
50586
+ var init_requestid = __esm(() => {
50587
+ init_request_context();
50588
+ });
50589
+
50470
50590
  // src/hooks/registration.ts
50471
- function initHooks(hooks) {}
50591
+ function initHooks(hooks) {
50592
+ hooks.registerBeforeRequestHook(new RequestIDHook);
50593
+ }
50594
+ var init_registration = __esm(() => {
50595
+ init_requestid();
50596
+ });
50472
50597
 
50473
50598
  // src/lib/base64.ts
50474
50599
  function bytesToBase64(u8arr) {
@@ -51058,6 +51183,7 @@ class SDKHooks {
51058
51183
  }
51059
51184
  }
51060
51185
  var init_hooks = __esm(() => {
51186
+ init_registration();
51061
51187
  init_clientcredentials();
51062
51188
  });
51063
51189
 
@@ -51882,9 +52008,15 @@ async function formatResult(response) {
51882
52008
  } else if (contentType.startsWith("audio/")) {
51883
52009
  const data = await valueToBase64(await response.arrayBuffer());
51884
52010
  content = data == null ? [] : [{ type: "audio", data, mimeType: contentType }];
51885
- } else {
52011
+ } else if (contentType.startsWith("text/") || contentType.includes("json") || contentType.includes("xml") || contentType.includes("yaml")) {
51886
52012
  const text = await response.text();
51887
52013
  content = [{ type: "text", text }];
52014
+ } else {
52015
+ const blob = await valueToBase64(await response.arrayBuffer());
52016
+ content = blob == null ? [] : [{
52017
+ type: "resource",
52018
+ resource: { uri: response.url, mimeType: contentType, blob }
52019
+ }];
51888
52020
  }
51889
52021
  return response.ok ? { content } : { content, isError: true };
51890
52022
  }
@@ -52382,7 +52514,7 @@ async function $do(client$, request, options) {
52382
52514
  options: client$._options,
52383
52515
  baseURL: options?.serverURL ?? client$._baseURL ?? "",
52384
52516
  operationID: "streamConversation",
52385
- oAuth2Scopes: ["conversation:write"],
52517
+ oAuth2Scopes: ["conversation:chat"],
52386
52518
  resolvedSecurity: requestSecurity,
52387
52519
  securitySource: client$._options.security,
52388
52520
  retryConfig: options?.retries || client$._options.retryConfig || { strategy: "none" },
@@ -53202,6 +53334,9 @@ the user asks about their documents, files, knowledge base, company policies,
53202
53334
  or anything that could plausibly be answered by content in their PipesHub-indexed
53203
53335
  sources (Drive, Box, Confluence, Slack, Gmail, Jira, the org's KB, ...).
53204
53336
  Grounds the answer in the user's actual data and returns citations.
53337
+ Answers come from a few retrieved passages, not whole documents — for
53338
+ any task needing a document's full content, use
53339
+ \`pipeshub_get_record_content\` instead.
53205
53340
 
53206
53341
  **Web search** (\`chatMode: "web_search"\`): Use when the user asks about
53207
53342
  current events, public information, or anything unlikely to be in the org's
@@ -53209,8 +53344,11 @@ internal knowledge base. Pass \`chatMode: "web_search"\` and this tool will
53209
53344
  search the public web instead.
53210
53345
 
53211
53346
  **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)
53347
+ - "Summarize <doc>" / "key points of <doc>" / "what does <document> say
53348
+ about X?" NOT this tool. Use \`pipeshub_search\`
53349
+ \`pipeshub_get_record_content\`: answering for a specific document
53350
+ requires its full content, and chat only sees a few retrieved
53351
+ passages, never the whole document.
53214
53352
  - "What's our policy on Y?" → \`pipeshub_chat\` (internal_search)
53215
53353
  - "What's in the news about Z?" → \`pipeshub_chat\` (web_search)
53216
53354
  - "What is the latest version of <library>?" → \`pipeshub_chat\` (web_search)
@@ -53516,12 +53654,16 @@ var init_pipeshubSearch = __esm(() => {
53516
53654
  name: "pipeshub_search",
53517
53655
  description: `Vector / semantic search across the org's indexed documents.
53518
53656
 
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.
53657
+ **Use this when the user wants to LOCATE a document** — by name, topic,
53658
+ or a phrase to grep for and to resolve it to a \`recordId\`. For
53659
+ open-ended questions across many documents, use \`pipeshub_chat\`
53660
+ instead, which does the retrieval internally and grounds the answer in
53661
+ citations.
53523
53662
 
53524
53663
  Typical uses:
53664
+ - Resolve a doc name / topic into a \`recordId\` for
53665
+ \`pipeshub_get_record_content\` — step 1 of any full-document task
53666
+ (summarize, extract, review, "what does the doc say?").
53525
53667
  - Resolve a filename / phrase into a \`recordId\` for
53526
53668
  \`pipeshub_download_record\`.
53527
53669
  - Show the user a ranked list of matching files when they ask "find /
@@ -53737,6 +53879,154 @@ returned base64-encoded; text content is returned inline.`,
53737
53879
  };
53738
53880
  });
53739
53881
 
53882
+ // src/models/getrecordcontentop.ts
53883
+ var GetRecordContentRequest$zodSchema;
53884
+ var init_getrecordcontentop = __esm(() => {
53885
+ init_zod();
53886
+ GetRecordContentRequest$zodSchema = object({
53887
+ recordId: string2().describe("Record ID to fetch. Obtain it from a `pipeshub_search` result (`hits[*].recordId`) or a chat citation (`citations[*].recordId`).")
53888
+ });
53889
+ });
53890
+
53891
+ // src/funcs/connectorGetRecordContent.ts
53892
+ function connectorGetRecordContent(client$, request, options) {
53893
+ return new APIPromise($do8(client$, request, options));
53894
+ }
53895
+ async function $do8(client$, request, options) {
53896
+ const parsed$ = safeParse4(request, (value$) => GetRecordContentRequest$zodSchema.parse(value$), "Input validation failed");
53897
+ if (!parsed$.ok) {
53898
+ return [parsed$, { status: "invalid" }];
53899
+ }
53900
+ const payload$ = parsed$.value;
53901
+ const body$ = null;
53902
+ const pathParams$ = {
53903
+ recordId: encodeSimple("recordId", payload$.recordId, {
53904
+ explode: false,
53905
+ charEncoding: "percent"
53906
+ })
53907
+ };
53908
+ const path$ = pathToFunc("/connectors/record/{recordId}/content")(pathParams$);
53909
+ const headers$ = new Headers(compactMap({
53910
+ Accept: "application/json"
53911
+ }));
53912
+ const securityInput = await extractSecurity(client$._options.security);
53913
+ const requestSecurity = resolveGlobalSecurity(securityInput);
53914
+ const context = {
53915
+ options: client$._options,
53916
+ baseURL: options?.serverURL ?? client$._baseURL ?? "",
53917
+ operationID: "getRecordContent",
53918
+ oAuth2Scopes: ["connector:read"],
53919
+ resolvedSecurity: requestSecurity,
53920
+ securitySource: client$._options.security,
53921
+ retryConfig: options?.retries || client$._options.retryConfig || { strategy: "none" },
53922
+ retryCodes: options?.retryCodes || [
53923
+ "429",
53924
+ "500",
53925
+ "502",
53926
+ "503",
53927
+ "504"
53928
+ ]
53929
+ };
53930
+ const requestRes = client$._createRequest(context, {
53931
+ security: requestSecurity,
53932
+ method: "GET",
53933
+ baseURL: options?.serverURL,
53934
+ path: path$,
53935
+ headers: headers$,
53936
+ body: body$,
53937
+ userAgent: client$._options.userAgent,
53938
+ timeoutMs: options?.timeoutMs || client$._options.timeoutMs || -1
53939
+ }, options);
53940
+ if (!requestRes.ok) {
53941
+ return [requestRes, { status: "invalid" }];
53942
+ }
53943
+ const req$ = requestRes.value;
53944
+ const doResult = await client$._do(req$, {
53945
+ context,
53946
+ errorCodes: [],
53947
+ retryConfig: context.retryConfig,
53948
+ retryCodes: context.retryCodes
53949
+ });
53950
+ if (!doResult.ok) {
53951
+ return [doResult, { status: "request-error", request: req$ }];
53952
+ }
53953
+ return [doResult, {
53954
+ status: "complete",
53955
+ request: req$,
53956
+ response: doResult.value
53957
+ }];
53958
+ }
53959
+ var init_connectorGetRecordContent = __esm(() => {
53960
+ init_encodings();
53961
+ init_primitives();
53962
+ init_schemas4();
53963
+ init_security2();
53964
+ init_url();
53965
+ init_getrecordcontentop();
53966
+ init_async();
53967
+ });
53968
+
53969
+ // src/mcp-server/tools/pipeshubGetRecordContent.ts
53970
+ var args4, tool$pipeshubGetRecordContent;
53971
+ var init_pipeshubGetRecordContent = __esm(() => {
53972
+ init_zod();
53973
+ init_connectorGetRecordContent();
53974
+ init__helpers();
53975
+ args4 = {
53976
+ recordId: string2().min(1).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.")
53977
+ };
53978
+ tool$pipeshubGetRecordContent = {
53979
+ name: "pipeshub_get_record_content",
53980
+ description: `Read a record's full parsed content by \`recordId\` — the only way to
53981
+ see a document's COMPLETE text.
53982
+
53983
+ Use it whenever the answer depends on a document's full content — any
53984
+ task where missing a part could make the answer wrong: summarize / key
53985
+ points / action items; extract or list ALL of something; check whether
53986
+ or where the doc mentions X; translate, rewrite, outline, or review the
53987
+ doc; compare named docs (fetch each); any question scoped to one named
53988
+ document. \`pipeshub_chat\` cannot do these — it only sees a few
53989
+ retrieved passages, never the whole document. Get the \`recordId\` from
53990
+ a \`pipeshub_search\` top hit or a chat citation.
53991
+
53992
+ Judge by the user's INTENT, not their keywords: they need not say
53993
+ "summarize", "key points", or "extract". Reason about what a good
53994
+ answer requires — if it would need the whole document (e.g. "what's
53995
+ this doc about?", "walk me through the report", "anything in here
53996
+ about Y?"), that is a full-content task, so call this tool.
53997
+
53998
+ Returns a single \`content\` string: a short metadata header (title,
53999
+ source, key fields, and a pre-generated summary) followed by the
54000
+ record's full parsed text — paragraphs, tables, and lists in reading
54001
+ order. For a record with no extractable content, \`content\` is the
54002
+ literal \`No record found\`. Use \`pipeshub_download_record\` only when
54003
+ you need the original file bytes.`,
54004
+ scopes: ["read"],
54005
+ annotations: {
54006
+ title: "Get a record's full parsed content",
54007
+ destructiveHint: false,
54008
+ idempotentHint: true,
54009
+ openWorldHint: false,
54010
+ readOnlyHint: true
54011
+ },
54012
+ args: args4,
54013
+ tool: async (client, args5, ctx) => {
54014
+ const [result] = await connectorGetRecordContent(client, {
54015
+ recordId: args5.recordId
54016
+ }, { fetchOptions: { signal: ctx.signal } }).$inspect();
54017
+ if (!result.ok)
54018
+ return errorResult(result.error.message);
54019
+ const httpErr = await httpErrorResult(result.value, "Get record content");
54020
+ if (httpErr)
54021
+ return httpErr;
54022
+ const parsed = await readJson(result.value);
54023
+ if (!parsed.ok)
54024
+ return parsed.result;
54025
+ return { content: [{ type: "text", text: parsed.value.content ?? "" }] };
54026
+ }
54027
+ };
54028
+ });
54029
+
53740
54030
  // src/models/getallusersop.ts
53741
54031
  var GetAllUsersRequest$zodSchema;
53742
54032
  var init_getallusersop = __esm(() => {
@@ -53750,9 +54040,9 @@ var init_getallusersop = __esm(() => {
53750
54040
 
53751
54041
  // src/funcs/usersGetAllUsers.ts
53752
54042
  function usersGetAllUsers(client$, request, options) {
53753
- return new APIPromise($do8(client$, request, options));
54043
+ return new APIPromise($do9(client$, request, options));
53754
54044
  }
53755
- async function $do8(client$, request, options) {
54045
+ async function $do9(client$, request, options) {
53756
54046
  const parsed$ = safeParse4(request, (value$) => GetAllUsersRequest$zodSchema.optional().parse(value$), "Input validation failed");
53757
54047
  if (!parsed$.ok) {
53758
54048
  return [parsed$, { status: "invalid" }];
@@ -53837,9 +54127,9 @@ var init_getuserbyidop = __esm(() => {
53837
54127
 
53838
54128
  // src/funcs/usersGetUserById.ts
53839
54129
  function usersGetUserById(client$, request, options) {
53840
- return new APIPromise($do9(client$, request, options));
54130
+ return new APIPromise($do10(client$, request, options));
53841
54131
  }
53842
- async function $do9(client$, request, options) {
54132
+ async function $do10(client$, request, options) {
53843
54133
  const parsed$ = safeParse4(request, (value$) => GetUserByIdRequest$zodSchema.parse(value$), "Input validation failed");
53844
54134
  if (!parsed$.ok) {
53845
54135
  return [parsed$, { status: "invalid" }];
@@ -53926,9 +54216,9 @@ var init_getallusergroupsop = __esm(() => {
53926
54216
 
53927
54217
  // src/funcs/userGroupsGetAllUserGroups.ts
53928
54218
  function userGroupsGetAllUserGroups(client$, request, options) {
53929
- return new APIPromise($do10(client$, request, options));
54219
+ return new APIPromise($do11(client$, request, options));
53930
54220
  }
53931
- async function $do10(client$, request, options) {
54221
+ async function $do11(client$, request, options) {
53932
54222
  const parsed$ = safeParse4(request, (value$) => GetAllUserGroupsRequest$zodSchema.optional().parse(value$), "Input validation failed");
53933
54223
  if (!parsed$.ok) {
53934
54224
  return [parsed$, { status: "invalid" }];
@@ -53950,7 +54240,7 @@ async function $do10(client$, request, options) {
53950
54240
  options: client$._options,
53951
54241
  baseURL: options?.serverURL ?? client$._baseURL ?? "",
53952
54242
  operationID: "getAllUserGroups",
53953
- oAuth2Scopes: [],
54243
+ oAuth2Scopes: ["usergroup:read"],
53954
54244
  resolvedSecurity: requestSecurity,
53955
54245
  securitySource: client$._options.security,
53956
54246
  retryConfig: options?.retries || client$._options.retryConfig || { strategy: "none" },
@@ -54018,9 +54308,9 @@ var init_getuserteamsop = __esm(() => {
54018
54308
 
54019
54309
  // src/funcs/teamsGetUserTeams.ts
54020
54310
  function teamsGetUserTeams(client$, request, options) {
54021
- return new APIPromise($do11(client$, request, options));
54311
+ return new APIPromise($do12(client$, request, options));
54022
54312
  }
54023
- async function $do11(client$, request, options) {
54313
+ async function $do12(client$, request, options) {
54024
54314
  const parsed$ = safeParse4(request, (value$) => GetUserTeamsRequest$zodSchema.optional().parse(value$), "Input validation failed");
54025
54315
  if (!parsed$.ok) {
54026
54316
  return [parsed$, { status: "invalid" }];
@@ -54098,7 +54388,7 @@ var init_teamsGetUserTeams = __esm(() => {
54098
54388
  });
54099
54389
 
54100
54390
  // src/mcp-server/tools/pipeshubDirectory.ts
54101
- var args4, tool$pipeshubDirectory;
54391
+ var args5, tool$pipeshubDirectory;
54102
54392
  var init_pipeshubDirectory = __esm(() => {
54103
54393
  init_zod();
54104
54394
  init_usersGetAllUsers();
@@ -54106,7 +54396,7 @@ var init_pipeshubDirectory = __esm(() => {
54106
54396
  init_userGroupsGetAllUserGroups();
54107
54397
  init_teamsGetUserTeams();
54108
54398
  init__helpers();
54109
- args4 = {
54399
+ args5 = {
54110
54400
  action: _enum([
54111
54401
  "whoami",
54112
54402
  "list_users",
@@ -54144,10 +54434,10 @@ Output shape varies by action; see each action's docs above.`,
54144
54434
  openWorldHint: false,
54145
54435
  readOnlyHint: true
54146
54436
  },
54147
- args: args4,
54148
- tool: async (client, args5, ctx) => {
54437
+ args: args5,
54438
+ tool: async (client, args6, ctx) => {
54149
54439
  const fetchOptions = { signal: ctx.signal };
54150
- switch (args5.action) {
54440
+ switch (args6.action) {
54151
54441
  case "whoami": {
54152
54442
  const claims = await decodeBearer(client);
54153
54443
  if (!claims) {
@@ -54164,9 +54454,9 @@ Output shape varies by action; see each action's docs above.`,
54164
54454
  }
54165
54455
  case "list_users": {
54166
54456
  const [result] = await usersGetAllUsers(client, {
54167
- page: args5.page,
54168
- limit: args5.limit,
54169
- search: args5.search
54457
+ page: args6.page,
54458
+ limit: args6.limit,
54459
+ search: args6.search
54170
54460
  }, { fetchOptions }).$inspect();
54171
54461
  if (!result.ok)
54172
54462
  return errorResult(result.error.message);
@@ -54176,11 +54466,11 @@ Output shape varies by action; see each action's docs above.`,
54176
54466
  return jsonResult(parsed.value);
54177
54467
  }
54178
54468
  case "get_user": {
54179
- if (!args5.userId) {
54469
+ if (!args6.userId) {
54180
54470
  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
54471
  }
54182
54472
  const [result] = await usersGetUserById(client, {
54183
- id: args5.userId
54473
+ id: args6.userId
54184
54474
  }, { fetchOptions }).$inspect();
54185
54475
  if (!result.ok)
54186
54476
  return errorResult(result.error.message);
@@ -54191,9 +54481,9 @@ Output shape varies by action; see each action's docs above.`,
54191
54481
  }
54192
54482
  case "list_groups": {
54193
54483
  const [result] = await userGroupsGetAllUserGroups(client, {
54194
- page: args5.page,
54195
- limit: args5.limit,
54196
- search: args5.search
54484
+ page: args6.page,
54485
+ limit: args6.limit,
54486
+ search: args6.search
54197
54487
  }, { fetchOptions }).$inspect();
54198
54488
  if (!result.ok)
54199
54489
  return errorResult(result.error.message);
@@ -54204,9 +54494,9 @@ Output shape varies by action; see each action's docs above.`,
54204
54494
  }
54205
54495
  case "list_my_teams": {
54206
54496
  const [result] = await teamsGetUserTeams(client, {
54207
- page: args5.page,
54208
- limit: args5.limit,
54209
- search: args5.search
54497
+ page: args6.page,
54498
+ limit: args6.limit,
54499
+ search: args6.search
54210
54500
  }, { fetchOptions }).$inspect();
54211
54501
  if (!result.ok)
54212
54502
  return errorResult(result.error.message);
@@ -54250,9 +54540,9 @@ var init_getknowledgehubrootnodesop = __esm(() => {
54250
54540
 
54251
54541
  // src/funcs/knowledgeHubGetKnowledgeHubRootNodes.ts
54252
54542
  function knowledgeHubGetKnowledgeHubRootNodes(client$, request, options) {
54253
- return new APIPromise($do12(client$, request, options));
54543
+ return new APIPromise($do13(client$, request, options));
54254
54544
  }
54255
- async function $do12(client$, request, options) {
54545
+ async function $do13(client$, request, options) {
54256
54546
  const parsed$ = safeParse4(request, (value$) => GetKnowledgeHubRootNodesRequest$zodSchema.optional().parse(value$), "Input validation failed");
54257
54547
  if (!parsed$.ok) {
54258
54548
  return [parsed$, { status: "invalid" }];
@@ -54368,9 +54658,9 @@ var init_getavailablemodelsbytypeop = __esm(() => {
54368
54658
 
54369
54659
  // src/funcs/aiModelsProvidersGetAvailableModelsByType.ts
54370
54660
  function aiModelsProvidersGetAvailableModelsByType(client$, request, options) {
54371
- return new APIPromise($do13(client$, request, options));
54661
+ return new APIPromise($do14(client$, request, options));
54372
54662
  }
54373
- async function $do13(client$, request, options) {
54663
+ async function $do14(client$, request, options) {
54374
54664
  const parsed$ = safeParse4(request, (value$) => GetAvailableModelsByTypeRequest$zodSchema.parse(value$), "Input validation failed");
54375
54665
  if (!parsed$.ok) {
54376
54666
  return [parsed$, { status: "invalid" }];
@@ -54445,13 +54735,13 @@ var init_aiModelsProvidersGetAvailableModelsByType = __esm(() => {
54445
54735
  });
54446
54736
 
54447
54737
  // src/mcp-server/tools/pipeshubSources.ts
54448
- var args5, tool$pipeshubSources;
54738
+ var args6, tool$pipeshubSources;
54449
54739
  var init_pipeshubSources = __esm(() => {
54450
54740
  init_zod();
54451
54741
  init_knowledgeHubGetKnowledgeHubRootNodes();
54452
54742
  init_aiModelsProvidersGetAvailableModelsByType();
54453
54743
  init__helpers();
54454
- args5 = {
54744
+ args6 = {
54455
54745
  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
54746
  };
54457
54747
  tool$pipeshubSources = {
@@ -54482,10 +54772,10 @@ are returned by default; pass \`include\` to override.`,
54482
54772
  openWorldHint: false,
54483
54773
  readOnlyHint: true
54484
54774
  },
54485
- args: args5,
54486
- tool: async (client, args6, ctx) => {
54775
+ args: args6,
54776
+ tool: async (client, args7, ctx) => {
54487
54777
  const fetchOptions = { signal: ctx.signal };
54488
- const include = args6.include ?? ["sources", "llmModels"];
54778
+ const include = args7.include ?? ["sources", "llmModels"];
54489
54779
  const want = (s) => include.includes(s);
54490
54780
  const result = {};
54491
54781
  if (want("sources")) {
@@ -54535,11 +54825,11 @@ are returned by default; pass \`include\` to override.`,
54535
54825
  });
54536
54826
 
54537
54827
  // src/mcp-server/tools/pipeshubAgents.ts
54538
- var args6, tool$pipeshubAgents;
54828
+ var args7, tool$pipeshubAgents;
54539
54829
  var init_pipeshubAgents = __esm(() => {
54540
54830
  init_zod();
54541
54831
  init__helpers();
54542
- args6 = {
54832
+ args7 = {
54543
54833
  search: string2().optional().describe("Optional case-insensitive substring match across agent name, " + "description, and tags. Omit to return every agent.")
54544
54834
  };
54545
54835
  tool$pipeshubAgents = {
@@ -54578,10 +54868,10 @@ specific agent is needed, use \`pipeshub_chat\` WITHOUT \`agentId\` and pick a
54578
54868
  openWorldHint: false,
54579
54869
  readOnlyHint: true
54580
54870
  },
54581
- args: args6,
54582
- tool: async (client, args7, ctx) => {
54871
+ args: args7,
54872
+ tool: async (client, args8, ctx) => {
54583
54873
  const all = await listAllAgents(client, {
54584
- search: args7.search,
54874
+ search: args8.search,
54585
54875
  signal: ctx.signal
54586
54876
  });
54587
54877
  if (!all.ok)
@@ -54596,25 +54886,25 @@ specific agent is needed, use \`pipeshub_chat\` WITHOUT \`agentId\` and pick a
54596
54886
  });
54597
54887
 
54598
54888
  // src/mcp-server/prompts/pipeshubAssistant.ts
54599
- var args7, prompt$pipeshubAssistant;
54889
+ var args8, prompt$pipeshubAssistant;
54600
54890
  var init_pipeshubAssistant = __esm(() => {
54601
54891
  init_zod();
54602
- args7 = {
54892
+ args8 = {
54603
54893
  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
54894
  };
54605
54895
  prompt$pipeshubAssistant = {
54606
54896
  name: "pipeshub-assistant",
54607
54897
  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
54898
  scopes: ["read"],
54609
- args: args7,
54610
- prompt: (_client, args8, _extra) => {
54611
- const text = args8.query ? `${PIPESHUB_INSTRUCTIONS}
54899
+ args: args8,
54900
+ prompt: (_client, args9, _extra) => {
54901
+ const text = args9.query ? `${PIPESHUB_INSTRUCTIONS}
54612
54902
 
54613
54903
  ---
54614
54904
 
54615
54905
  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
54906
 
54617
- ${args8.query}` : PIPESHUB_INSTRUCTIONS;
54907
+ ${args9.query}` : PIPESHUB_INSTRUCTIONS;
54618
54908
  return {
54619
54909
  messages: [
54620
54910
  {
@@ -54635,17 +54925,21 @@ function createMCPServer(deps) {
54635
54925
  }, {
54636
54926
  instructions: PIPESHUB_INSTRUCTIONS
54637
54927
  });
54638
- const getClient = deps.getSDK || (() => new PipeshubCore({
54928
+ const resolveClient = deps.getSDK || (() => new PipeshubCore({
54639
54929
  security: deps.security,
54640
54930
  serverURL: deps.serverURL,
54641
54931
  serverIdx: deps.serverIdx,
54642
54932
  instance_url: deps.instance_url,
54643
54933
  debugLogger: deps.logger.level === "debug" ? {
54644
- log: (...args8) => console.log(...args8),
54645
- group: (...args8) => console.group(...args8),
54646
- groupEnd: (...args8) => console.groupEnd(...args8)
54934
+ log: (...args9) => console.log(...args9),
54935
+ group: (...args9) => console.group(...args9),
54936
+ groupEnd: (...args9) => console.groupEnd(...args9)
54647
54937
  } : undefined
54648
54938
  }));
54939
+ const getClient = () => {
54940
+ bindNewRequestId();
54941
+ return resolveClient();
54942
+ };
54649
54943
  const scopes = new Set(deps.scopes);
54650
54944
  const allowedTools = deps.allowedTools && new Set(deps.allowedTools);
54651
54945
  const [tool, tools, toolMap] = createRegisterTool(deps.logger, server, getClient, scopes, allowedTools, deps.dynamic);
@@ -54657,6 +54951,7 @@ function createMCPServer(deps) {
54657
54951
  tool(tool$pipeshubChat);
54658
54952
  tool(tool$pipeshubSearch);
54659
54953
  tool(tool$pipeshubDownloadRecord);
54954
+ tool(tool$pipeshubGetRecordContent);
54660
54955
  tool(tool$pipeshubDirectory);
54661
54956
  tool(tool$pipeshubAgents);
54662
54957
  prompt(prompt$pipeshubAssistant);
@@ -54668,11 +54963,13 @@ function createMCPServer(deps) {
54668
54963
  var init_server2 = __esm(() => {
54669
54964
  init_mcp();
54670
54965
  init_core3();
54966
+ init_request_context();
54671
54967
  init_resources();
54672
54968
  init_tools();
54673
54969
  init_pipeshubChat();
54674
54970
  init_pipeshubSearch();
54675
54971
  init_pipeshubDownloadRecord();
54972
+ init_pipeshubGetRecordContent();
54676
54973
  init_pipeshubDirectory();
54677
54974
  init_pipeshubSources();
54678
54975
  init_pipeshubAgents();
@@ -54696,6 +54993,9 @@ the user asks about their documents, files, knowledge base, company policies,
54696
54993
  or anything that could plausibly be answered by content in their PipesHub-indexed
54697
54994
  sources (Drive, Box, Confluence, Slack, Gmail, Jira, the org's KB, ...).
54698
54995
  Grounds the answer in the user's actual data and returns citations.
54996
+ Answers come from a few retrieved passages, not whole documents — for
54997
+ any task needing a document's full content, use
54998
+ \`pipeshub_get_record_content\` instead.
54699
54999
 
54700
55000
  **Web search** (\`chatMode: "web_search"\`): Use when the user asks about
54701
55001
  current events, public information, or anything unlikely to be in the org's
@@ -54703,8 +55003,11 @@ internal knowledge base. Pass \`chatMode: "web_search"\` and this tool will
54703
55003
  search the public web instead.
54704
55004
 
54705
55005
  **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)
55006
+ - "Summarize <doc>" / "key points of <doc>" / "what does <document> say
55007
+ about X?" NOT this tool. Use \`pipeshub_search\`
55008
+ \`pipeshub_get_record_content\`: answering for a specific document
55009
+ requires its full content, and chat only sees a few retrieved
55010
+ passages, never the whole document.
54708
55011
  - "What's our policy on Y?" → \`pipeshub_chat\` (internal_search)
54709
55012
  - "What's in the news about Z?" → \`pipeshub_chat\` (web_search)
54710
55013
  - "What is the latest version of <library>?" → \`pipeshub_chat\` (web_search)
@@ -54731,12 +55034,16 @@ cited document, take \`citations[*].recordId\` and call
54731
55034
  name: "pipeshub_search",
54732
55035
  description: `Vector / semantic search across the org's indexed documents.
54733
55036
 
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.
55037
+ **Use this when the user wants to LOCATE a document** — by name, topic,
55038
+ or a phrase to grep for and to resolve it to a \`recordId\`. For
55039
+ open-ended questions across many documents, use \`pipeshub_chat\`
55040
+ instead, which does the retrieval internally and grounds the answer in
55041
+ citations.
54738
55042
 
54739
55043
  Typical uses:
55044
+ - Resolve a doc name / topic into a \`recordId\` for
55045
+ \`pipeshub_get_record_content\` — step 1 of any full-document task
55046
+ (summarize, extract, review, "what does the doc say?").
54740
55047
  - Resolve a filename / phrase into a \`recordId\` for
54741
55048
  \`pipeshub_download_record\`.
54742
55049
  - Show the user a ranked list of matching files when they ask "find /
@@ -54751,6 +55058,33 @@ Highest \`score\` first; multiple hits may share the same \`recordId\`
54751
55058
  name: "pipeshub_download_record",
54752
55059
  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
55060
  },
55061
+ {
55062
+ name: "pipeshub_get_record_content",
55063
+ description: `Read a record's full parsed content by \`recordId\` — the only way to
55064
+ see a document's COMPLETE text.
55065
+
55066
+ Use it whenever the answer depends on a document's full content — any
55067
+ task where missing a part could make the answer wrong: summarize / key
55068
+ points / action items; extract or list ALL of something; check whether
55069
+ or where the doc mentions X; translate, rewrite, outline, or review the
55070
+ doc; compare named docs (fetch each); any question scoped to one named
55071
+ document. \`pipeshub_chat\` cannot do these — it only sees a few
55072
+ retrieved passages, never the whole document. Get the \`recordId\` from
55073
+ a \`pipeshub_search\` top hit or a chat citation.
55074
+
55075
+ Judge by the user's INTENT, not their keywords: they need not say
55076
+ "summarize", "key points", or "extract". Reason about what a good
55077
+ answer requires — if it would need the whole document (e.g. "what's
55078
+ this doc about?", "walk me through the report", "anything in here
55079
+ about Y?"), that is a full-content task, so call this tool.
55080
+
55081
+ Returns a single \`content\` string: a short metadata header (title,
55082
+ source, key fields, and a pre-generated summary) followed by the
55083
+ record's full parsed text — paragraphs, tables, and lists in reading
55084
+ order. For a record with no extractable content, \`content\` is the
55085
+ literal \`No record found\`. Use \`pipeshub_download_record\` only when
55086
+ you need the original file bytes.`
55087
+ },
54754
55088
  {
54755
55089
  name: "pipeshub_directory",
54756
55090
  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 +58720,5 @@ export {
58386
58720
  app
58387
58721
  };
58388
58722
 
58389
- //# debugId=E589470B4E3C258364756E2164756E21
58723
+ //# debugId=59975E6F38134B6C64756E2164756E21
58390
58724
  //# sourceMappingURL=mcp-server.js.map