@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
@@ -0,0 +1,179 @@
1
+ /*
2
+ * Adapted from Speakeasy-generated connectorGetRecordContent.
3
+ */
4
+
5
+ import { PipeshubCore } from "../core.js";
6
+ import { encodeSimple } from "../lib/encodings.js";
7
+ import { compactMap } from "../lib/primitives.js";
8
+ import { safeParse } from "../lib/schemas.js";
9
+ import { RequestOptions } from "../lib/sdks.js";
10
+ import { extractSecurity, resolveGlobalSecurity } from "../lib/security.js";
11
+ import { pathToFunc } from "../lib/url.js";
12
+ import { APIError } from "../models/errors/apierror.js";
13
+ import {
14
+ ConnectionError,
15
+ InvalidRequestError,
16
+ RequestAbortedError,
17
+ RequestTimeoutError,
18
+ UnexpectedClientError,
19
+ } from "../models/errors/httpclienterrors.js";
20
+ import { SDKValidationError } from "../models/errors/sdkvalidationerror.js";
21
+ import {
22
+ GetRecordContentRequest,
23
+ GetRecordContentRequest$zodSchema,
24
+ } from "../models/getrecordcontentop.js";
25
+ import { APICall, APIPromise } from "../types/async.js";
26
+ import { Result } from "../types/fp.js";
27
+
28
+ /**
29
+ * Get a record's full parsed content and metadata
30
+ *
31
+ * @remarks
32
+ * Retrieve the full parsed content and metadata of a single record —
33
+ * the same content PipesHub's own RAG/chat pipeline uses to answer
34
+ * questions, returned directly instead of via chat.
35
+ *
36
+ * **When to use this vs. the other record endpoints:**
37
+ * - `GET /knowledgeBase/record/{recordId}` returns metadata only
38
+ * (name, type, indexing status, size) — no content.
39
+ * - `GET /knowledgeBase/stream/record/{recordId}` returns the original,
40
+ * unparsed file bytes — use it to download/open the source file.
41
+ * - **This endpoint** returns the record's full parsed content as a
42
+ * single plain-text `content` string (a metadata header, then the
43
+ * block/table text in reading order) — use it when you need the
44
+ * record's actual textual/tabular content without downloading and
45
+ * re-parsing the original file yourself.
46
+ *
47
+ * **Typical flow:** obtain a `recordId` from a `pipeshub_search` hit or
48
+ * a chat citation's `recordId`, then call this endpoint to read the
49
+ * full content when the search snippet or citation excerpt isn't
50
+ * enough to answer the question.
51
+ *
52
+ * **Permission scoping:**
53
+ *
54
+ * The requesting user/token must have access to the record; access is
55
+ * verified via the knowledge graph before content is returned — a
56
+ * caller with a valid scope but no access to this specific record gets
57
+ * a `403`.
58
+ *
59
+ * If set, this operation will use either {@link Security.bearerAuth} or {@link Security.oauth2} from the global security.
60
+ */
61
+ export function connectorGetRecordContent(
62
+ client$: PipeshubCore,
63
+ request: GetRecordContentRequest,
64
+ options?: RequestOptions,
65
+ ): APIPromise<
66
+ Result<
67
+ Response,
68
+ | APIError
69
+ | SDKValidationError
70
+ | UnexpectedClientError
71
+ | InvalidRequestError
72
+ | RequestAbortedError
73
+ | RequestTimeoutError
74
+ | ConnectionError
75
+ >
76
+ > {
77
+ return new APIPromise($do(
78
+ client$,
79
+ request,
80
+ options,
81
+ ));
82
+ }
83
+
84
+ async function $do(
85
+ client$: PipeshubCore,
86
+ request: GetRecordContentRequest,
87
+ options?: RequestOptions,
88
+ ): Promise<
89
+ [
90
+ Result<
91
+ Response,
92
+ | APIError
93
+ | SDKValidationError
94
+ | UnexpectedClientError
95
+ | InvalidRequestError
96
+ | RequestAbortedError
97
+ | RequestTimeoutError
98
+ | ConnectionError
99
+ >,
100
+ APICall,
101
+ ]
102
+ > {
103
+ const parsed$ = safeParse(
104
+ request,
105
+ (value$) => GetRecordContentRequest$zodSchema.parse(value$),
106
+ "Input validation failed",
107
+ );
108
+ if (!parsed$.ok) {
109
+ return [parsed$, { status: "invalid" }];
110
+ }
111
+ const payload$ = parsed$.value;
112
+ const body$ = null;
113
+
114
+ const pathParams$ = {
115
+ recordId: encodeSimple("recordId", payload$.recordId, {
116
+ explode: false,
117
+ charEncoding: "percent",
118
+ }),
119
+ };
120
+ const path$ = pathToFunc("/connectors/record/{recordId}/content")(
121
+ pathParams$,
122
+ );
123
+
124
+ const headers$ = new Headers(compactMap({
125
+ Accept: "application/json",
126
+ }));
127
+ const securityInput = await extractSecurity(client$._options.security);
128
+ const requestSecurity = resolveGlobalSecurity(securityInput);
129
+
130
+ const context = {
131
+ options: client$._options,
132
+ baseURL: options?.serverURL ?? client$._baseURL ?? "",
133
+ operationID: "getRecordContent",
134
+ oAuth2Scopes: ["connector:read"],
135
+ resolvedSecurity: requestSecurity,
136
+ securitySource: client$._options.security,
137
+ retryConfig: options?.retries
138
+ || client$._options.retryConfig
139
+ || { strategy: "none" },
140
+ retryCodes: options?.retryCodes || [
141
+ "429",
142
+ "500",
143
+ "502",
144
+ "503",
145
+ "504",
146
+ ],
147
+ };
148
+
149
+ const requestRes = client$._createRequest(context, {
150
+ security: requestSecurity,
151
+ method: "GET",
152
+ baseURL: options?.serverURL,
153
+ path: path$,
154
+ headers: headers$,
155
+ body: body$,
156
+ userAgent: client$._options.userAgent,
157
+ timeoutMs: options?.timeoutMs || client$._options.timeoutMs
158
+ || -1,
159
+ }, options);
160
+ if (!requestRes.ok) {
161
+ return [requestRes, { status: "invalid" }];
162
+ }
163
+ const req$ = requestRes.value;
164
+
165
+ const doResult = await client$._do(req$, {
166
+ context,
167
+ errorCodes: [],
168
+ retryConfig: context.retryConfig,
169
+ retryCodes: context.retryCodes,
170
+ });
171
+ if (!doResult.ok) {
172
+ return [doResult, { status: "request-error", request: req$ }];
173
+ }
174
+ return [doResult, {
175
+ status: "complete",
176
+ "request": req$,
177
+ response: doResult.value,
178
+ }];
179
+ }
@@ -0,0 +1,200 @@
1
+ /*
2
+ * Adapted from Speakeasy-generated connectorLookupRecordByIdentifier.
3
+ */
4
+
5
+ import { PipeshubCore } from "../core.js";
6
+ import { encodeFormQuery } from "../lib/encodings.js";
7
+ import { compactMap } from "../lib/primitives.js";
8
+ import { safeParse } from "../lib/schemas.js";
9
+ import { RequestOptions } from "../lib/sdks.js";
10
+ import { extractSecurity, resolveGlobalSecurity } from "../lib/security.js";
11
+ import { pathToFunc } from "../lib/url.js";
12
+ import { APIError } from "../models/errors/apierror.js";
13
+ import {
14
+ ConnectionError,
15
+ InvalidRequestError,
16
+ RequestAbortedError,
17
+ RequestTimeoutError,
18
+ UnexpectedClientError,
19
+ } from "../models/errors/httpclienterrors.js";
20
+ import { SDKValidationError } from "../models/errors/sdkvalidationerror.js";
21
+ import {
22
+ LookupRecordByIdentifierRequest,
23
+ LookupRecordByIdentifierRequest$zodSchema,
24
+ } from "../models/lookuprecordbyidentifierop.js";
25
+ import { APICall, APIPromise } from "../types/async.js";
26
+ import { Result } from "../types/fp.js";
27
+
28
+ /**
29
+ * Resolve a URL, issue key or external ID to a Record ID
30
+ *
31
+ * @remarks
32
+ * Turn an external reference into the matching PipesHub record. Accepts a
33
+ * pasted link, a Jira-style issue key, or a bare external system ID from
34
+ * any connected source. Repeat `identifiers` to batch-resolve up to ten
35
+ * in one call.
36
+ *
37
+ * The response carries a rendered `text` view — each match's metadata
38
+ * block followed by a `Next:` line naming a follow-up call. The structured
39
+ * fields carry the same information for programmatic use.
40
+ *
41
+ * **Accepted identifiers**
42
+ * - Jira issue URL — `https://acme.atlassian.net/browse/PA-1787`
43
+ * - Jira issue key — `PA-1787`
44
+ * - Confluence page URL —
45
+ * `https://acme.atlassian.net/wiki/spaces/SD/pages/450625553/Agent+Loop`
46
+ * - Google Drive / Docs URL — `https://docs.google.com/document/d/1AbC.../edit`
47
+ * - Slack message link — `https://acme.slack.com/archives/C0123/p1720000000000100`
48
+ * - Bare external system ID — `450625553`
49
+ *
50
+ * **When to use this vs. the other record endpoints:**
51
+ * - **This endpoint** converts an *external* reference into an internal
52
+ * Record ID. Reach for it whenever you meet a link or ticket key and
53
+ * need the record behind it.
54
+ * - `GET /connectors/record/{recordId}/content` reads a record you have
55
+ * already identified. It needs an internal Record ID, which is exactly
56
+ * what this endpoint returns.
57
+ * - `GET /connectors/navigate` browses the hierarchy when you have a
58
+ * position in the tree rather than a specific identifier.
59
+ *
60
+ * **Typical flow:** call this with the reference, take a match's `id`
61
+ * from the response, then call
62
+ * `GET /connectors/record/{recordId}/content` to read the record.
63
+ *
64
+ * **Multiple matches:** one identifier can legitimately match more than
65
+ * one record — the same external ID may exist in several connected
66
+ * instances. In that case the response sets `ambiguous: true` and
67
+ * `matches` holds every candidate. Present the choice rather than taking
68
+ * the first; `connectorName` narrows a retry.
69
+ *
70
+ * **Misses are not errors.**
71
+ *
72
+ * Only records the caller can see are returned, and a miss is a `200`
73
+ * with an empty `matches` array and the input echoed in
74
+ * `not_found_identifiers` — not a `404`. The identifier resolved to
75
+ * nothing *or* to something the caller may not access; the two are
76
+ * deliberately indistinguishable, because an identifier is
77
+ * caller-supplied and guessable, and confirming existence would leak
78
+ * records across organizations. `searched_connectors` names what was
79
+ * covered, so a retry with `connectorName` is often the right next move.
80
+ *
81
+ * **Scope:** resolution searches every connector the caller can access,
82
+ * regardless of any source filter used elsewhere.
83
+ *
84
+ * If set, this operation will use either {@link Security.bearerAuth} or {@link Security.oauth2} from the global security.
85
+ */
86
+ export function connectorLookupRecordByIdentifier(
87
+ client$: PipeshubCore,
88
+ request: LookupRecordByIdentifierRequest,
89
+ options?: RequestOptions,
90
+ ): APIPromise<
91
+ Result<
92
+ Response,
93
+ | APIError
94
+ | SDKValidationError
95
+ | UnexpectedClientError
96
+ | InvalidRequestError
97
+ | RequestAbortedError
98
+ | RequestTimeoutError
99
+ | ConnectionError
100
+ >
101
+ > {
102
+ return new APIPromise($do(
103
+ client$,
104
+ request,
105
+ options,
106
+ ));
107
+ }
108
+
109
+ async function $do(
110
+ client$: PipeshubCore,
111
+ request: LookupRecordByIdentifierRequest,
112
+ options?: RequestOptions,
113
+ ): Promise<
114
+ [
115
+ Result<
116
+ Response,
117
+ | APIError
118
+ | SDKValidationError
119
+ | UnexpectedClientError
120
+ | InvalidRequestError
121
+ | RequestAbortedError
122
+ | RequestTimeoutError
123
+ | ConnectionError
124
+ >,
125
+ APICall,
126
+ ]
127
+ > {
128
+ const parsed$ = safeParse(
129
+ request,
130
+ (value$) => LookupRecordByIdentifierRequest$zodSchema.parse(value$),
131
+ "Input validation failed",
132
+ );
133
+ if (!parsed$.ok) {
134
+ return [parsed$, { status: "invalid" }];
135
+ }
136
+ const payload$ = parsed$.value;
137
+ const body$ = null;
138
+ const path$ = pathToFunc("/connectors/record/lookup")();
139
+ const query$ = encodeFormQuery({
140
+ "connectorName": payload$.connectorName,
141
+ "identifiers": payload$.identifiers,
142
+ });
143
+
144
+ const headers$ = new Headers(compactMap({
145
+ Accept: "application/json",
146
+ }));
147
+ const securityInput = await extractSecurity(client$._options.security);
148
+ const requestSecurity = resolveGlobalSecurity(securityInput);
149
+
150
+ const context = {
151
+ options: client$._options,
152
+ baseURL: options?.serverURL ?? client$._baseURL ?? "",
153
+ operationID: "lookupRecordByIdentifier",
154
+ oAuth2Scopes: ["kb:read", "connector:read"],
155
+ resolvedSecurity: requestSecurity,
156
+ securitySource: client$._options.security,
157
+ retryConfig: options?.retries
158
+ || client$._options.retryConfig
159
+ || { strategy: "none" },
160
+ retryCodes: options?.retryCodes || [
161
+ "429",
162
+ "500",
163
+ "502",
164
+ "503",
165
+ "504",
166
+ ],
167
+ };
168
+
169
+ const requestRes = client$._createRequest(context, {
170
+ security: requestSecurity,
171
+ method: "GET",
172
+ baseURL: options?.serverURL,
173
+ path: path$,
174
+ headers: headers$,
175
+ query: query$,
176
+ body: body$,
177
+ userAgent: client$._options.userAgent,
178
+ timeoutMs: options?.timeoutMs || client$._options.timeoutMs
179
+ || -1,
180
+ }, options);
181
+ if (!requestRes.ok) {
182
+ return [requestRes, { status: "invalid" }];
183
+ }
184
+ const req$ = requestRes.value;
185
+
186
+ const doResult = await client$._do(req$, {
187
+ context,
188
+ errorCodes: [],
189
+ retryConfig: context.retryConfig,
190
+ retryCodes: context.retryCodes,
191
+ });
192
+ if (!doResult.ok) {
193
+ return [doResult, { status: "request-error", request: req$ }];
194
+ }
195
+ return [doResult, {
196
+ status: "complete",
197
+ "request": req$,
198
+ response: doResult.value,
199
+ }];
200
+ }
@@ -0,0 +1,215 @@
1
+ /*
2
+ * Adapted from Speakeasy-generated connectorNavigateKnowledgeGraph.
3
+ */
4
+
5
+ import { PipeshubCore } from "../core.js";
6
+ import { encodeFormQuery } from "../lib/encodings.js";
7
+ import { compactMap } from "../lib/primitives.js";
8
+ import { safeParse } from "../lib/schemas.js";
9
+ import { RequestOptions } from "../lib/sdks.js";
10
+ import { extractSecurity, resolveGlobalSecurity } from "../lib/security.js";
11
+ import { pathToFunc } from "../lib/url.js";
12
+ import { APIError } from "../models/errors/apierror.js";
13
+ import {
14
+ ConnectionError,
15
+ InvalidRequestError,
16
+ RequestAbortedError,
17
+ RequestTimeoutError,
18
+ UnexpectedClientError,
19
+ } from "../models/errors/httpclienterrors.js";
20
+ import { SDKValidationError } from "../models/errors/sdkvalidationerror.js";
21
+ import {
22
+ NavigateKnowledgeGraphRequest,
23
+ NavigateKnowledgeGraphRequest$zodSchema,
24
+ } from "../models/navigateknowledgegraphop.js";
25
+ import { APICall, APIPromise } from "../types/async.js";
26
+ import { Result } from "../types/fp.js";
27
+
28
+ /**
29
+ * Browse the knowledge graph from a node
30
+ *
31
+ * @remarks
32
+ * Open a node in the knowledge graph and see what is inside it — a file
33
+ * explorer across every connected source.
34
+ *
35
+ * Call it with no `nodeId` for a flat listing of every record group and
36
+ * record the caller can reach, newest first. This is a starting point to
37
+ * pick a node from, not a roster of connected apps — app nodes are never
38
+ * returned in a listing, though an app's `id` is accepted as a `nodeId`
39
+ * and lists that app's record groups. Pass a node's `id` to descend:
40
+ * record groups contain records and folders, and a record contains its
41
+ * own children — comments, attachments, sub-tasks — plus a `related`
42
+ * section of cross-referenced records, such as the Confluence page linked
43
+ * from a Jira ticket. `nodeId` is tolerant: a URL or an issue key such as
44
+ * `PA-1787` is resolved to its record before navigating, so a link can be
45
+ * pasted straight in without a separate lookup call.
46
+ *
47
+ * The response carries a rendered `text` view — breadcrumbs, the current
48
+ * node, the children listing, `Related:`, and a closing `Next:` line
49
+ * naming a follow-up call. The structured fields carry the same
50
+ * information for programmatic use.
51
+ *
52
+ * **When to use this vs. the other record endpoints:**
53
+ * - **This endpoint** is for structural exploration — "what is in this
54
+ * project", "what is attached to this ticket", "what else links to this
55
+ * page". It returns names, types and IDs; it never returns document
56
+ * text.
57
+ * - `GET /connectors/record/{recordId}/content` returns one record's
58
+ * actual parsed text. Use it once navigation has identified the record
59
+ * you want to read.
60
+ * - `GET /connectors/record/lookup` is the way in when you hold a URL or
61
+ * an issue key rather than a position in the tree.
62
+ *
63
+ * **Typical flow:** call with no `nodeId` to see what is reachable → pass
64
+ * a record group's `id` to list its records → take a row whose
65
+ * `is_record` is true and call
66
+ * `GET /connectors/record/{recordId}/content` to read it.
67
+ *
68
+ * **Paging and depth:** results are paginated; `pagination.has_next`
69
+ * tells you whether to request the next `page`. `depth` above 1 returns
70
+ * all descendants down to that level as one flat list, each row carrying
71
+ * its own `level`, instead of only direct children.
72
+ *
73
+ * **Scope:** everything the caller can read, across both connectors and
74
+ * Knowledge Base collections. No connector-level filter is applied — the
75
+ * listing is bounded by per-node permissions alone.
76
+ *
77
+ * **Permission scoping:**
78
+ *
79
+ * `rows` and `related` carry only nodes the caller can see, and the
80
+ * opened node itself is access-checked before any of its details are
81
+ * returned. A node that does not exist and a node the caller cannot
82
+ * access are deliberately indistinguishable — both return an empty view
83
+ * rather than an error.
84
+ *
85
+ * `breadcrumbs` is the exception: the ancestor trail is resolved by id
86
+ * alone, without a permission check. For a record shared directly with
87
+ * the caller, it can therefore name ancestors the caller cannot open.
88
+ * Treat breadcrumb entries as labels, not as nodes guaranteed to be
89
+ * navigable.
90
+ *
91
+ * If set, this operation will use either {@link Security.bearerAuth} or {@link Security.oauth2} from the global security.
92
+ */
93
+ export function connectorNavigateKnowledgeGraph(
94
+ client$: PipeshubCore,
95
+ request?: NavigateKnowledgeGraphRequest | undefined,
96
+ options?: RequestOptions,
97
+ ): APIPromise<
98
+ Result<
99
+ Response,
100
+ | APIError
101
+ | SDKValidationError
102
+ | UnexpectedClientError
103
+ | InvalidRequestError
104
+ | RequestAbortedError
105
+ | RequestTimeoutError
106
+ | ConnectionError
107
+ >
108
+ > {
109
+ return new APIPromise($do(
110
+ client$,
111
+ request,
112
+ options,
113
+ ));
114
+ }
115
+
116
+ async function $do(
117
+ client$: PipeshubCore,
118
+ request?: NavigateKnowledgeGraphRequest | undefined,
119
+ options?: RequestOptions,
120
+ ): Promise<
121
+ [
122
+ Result<
123
+ Response,
124
+ | APIError
125
+ | SDKValidationError
126
+ | UnexpectedClientError
127
+ | InvalidRequestError
128
+ | RequestAbortedError
129
+ | RequestTimeoutError
130
+ | ConnectionError
131
+ >,
132
+ APICall,
133
+ ]
134
+ > {
135
+ const parsed$ = safeParse(
136
+ request,
137
+ (value$) =>
138
+ NavigateKnowledgeGraphRequest$zodSchema.optional().parse(value$),
139
+ "Input validation failed",
140
+ );
141
+ if (!parsed$.ok) {
142
+ return [parsed$, { status: "invalid" }];
143
+ }
144
+ const payload$ = parsed$.value;
145
+ const body$ = null;
146
+ const path$ = pathToFunc("/connectors/navigate")();
147
+ const query$ = encodeFormQuery({
148
+ "createdAfter": payload$?.createdAfter,
149
+ "createdBefore": payload$?.createdBefore,
150
+ "depth": payload$?.depth,
151
+ "limit": payload$?.limit,
152
+ "modifiedAfter": payload$?.modifiedAfter,
153
+ "modifiedBefore": payload$?.modifiedBefore,
154
+ "nodeId": payload$?.nodeId,
155
+ "nodeTypes": payload$?.nodeTypes,
156
+ "page": payload$?.page,
157
+ });
158
+
159
+ const headers$ = new Headers(compactMap({
160
+ Accept: "application/json",
161
+ }));
162
+ const securityInput = await extractSecurity(client$._options.security);
163
+ const requestSecurity = resolveGlobalSecurity(securityInput);
164
+
165
+ const context = {
166
+ options: client$._options,
167
+ baseURL: options?.serverURL ?? client$._baseURL ?? "",
168
+ operationID: "navigateKnowledgeGraph",
169
+ oAuth2Scopes: ["kb:read", "connector:read"],
170
+ resolvedSecurity: requestSecurity,
171
+ securitySource: client$._options.security,
172
+ retryConfig: options?.retries
173
+ || client$._options.retryConfig
174
+ || { strategy: "none" },
175
+ retryCodes: options?.retryCodes || [
176
+ "429",
177
+ "500",
178
+ "502",
179
+ "503",
180
+ "504",
181
+ ],
182
+ };
183
+
184
+ const requestRes = client$._createRequest(context, {
185
+ security: requestSecurity,
186
+ method: "GET",
187
+ baseURL: options?.serverURL,
188
+ path: path$,
189
+ headers: headers$,
190
+ query: query$,
191
+ body: body$,
192
+ userAgent: client$._options.userAgent,
193
+ timeoutMs: options?.timeoutMs || client$._options.timeoutMs
194
+ || -1,
195
+ }, options);
196
+ if (!requestRes.ok) {
197
+ return [requestRes, { status: "invalid" }];
198
+ }
199
+ const req$ = requestRes.value;
200
+
201
+ const doResult = await client$._do(req$, {
202
+ context,
203
+ errorCodes: [],
204
+ retryConfig: context.retryConfig,
205
+ retryCodes: context.retryCodes,
206
+ });
207
+ if (!doResult.ok) {
208
+ return [doResult, { status: "request-error", request: req$ }];
209
+ }
210
+ return [doResult, {
211
+ status: "complete",
212
+ "request": req$,
213
+ response: doResult.value,
214
+ }];
215
+ }
@@ -87,7 +87,7 @@ async function $do(
87
87
  options: client$._options,
88
88
  baseURL: options?.serverURL ?? client$._baseURL ?? "",
89
89
  operationID: "streamConversation",
90
- oAuth2Scopes: ["conversation:write"],
90
+ oAuth2Scopes: ["conversation:chat"],
91
91
  resolvedSecurity: requestSecurity,
92
92
  securitySource: client$._options.security,
93
93
  retryConfig: options?.retries
@@ -114,7 +114,7 @@ async function $do(
114
114
  options: client$._options,
115
115
  baseURL: options?.serverURL ?? client$._baseURL ?? "",
116
116
  operationID: "getAllUserGroups",
117
- oAuth2Scopes: [],
117
+ oAuth2Scopes: ["usergroup:read"],
118
118
  resolvedSecurity: requestSecurity,
119
119
  securitySource: client$._options.security,
120
120
  retryConfig: options?.retries
@@ -1,3 +1,4 @@
1
+ import { RequestIDHook } from "./requestid.js";
1
2
  import { Hooks } from "./types.js";
2
3
 
3
4
  /*
@@ -6,9 +7,9 @@ import { Hooks } from "./types.js";
6
7
  * in this file or in separate files in the hooks folder.
7
8
  */
8
9
 
9
- // @ts-expect-error remove this line when you add your first hook and hooks is used
10
10
  export function initHooks(hooks: Hooks) {
11
11
  // Add hooks by calling hooks.register{ClientInit/BeforeCreateRequest/BeforeRequest/AfterSuccess/AfterError}Hook
12
12
  // with an instance of a hook that implements that specific Hook interface
13
13
  // Hooks are registered per SDK instance, and are valid for the lifetime of the SDK instance
14
+ hooks.registerBeforeRequestHook(new RequestIDHook());
14
15
  }
@@ -0,0 +1,47 @@
1
+ /*
2
+ * Ambient per-tool-call request-id context (AsyncLocalStorage). Mirrors the
3
+ * pipeshub-ai backend's own request-context pattern (same header name,
4
+ * `x-request-id`) so a single id traces one MCP tool/resource/prompt
5
+ * invocation across every backend HTTP call it makes.
6
+ *
7
+ * `tools.ts` / `resources.ts` / `prompts.ts` are Speakeasy-generated and
8
+ * regenerated on every build, so there is no `next()`-style wrapper point to
9
+ * bind context around a call. Instead `bindNewRequestId` is called from the
10
+ * hand-written `getClient` closure in `server.ts`, which every generated
11
+ * dispatch site calls synchronously as the first thing before invoking a
12
+ * tool/resource/prompt handler — `enterWith` binds the store for the rest of
13
+ * that handler's execution (sync remainder + everything it awaits).
14
+ *
15
+ * The final id (`mcp-<userId>-<random>` or `mcp-<random>`) can't be composed
16
+ * at bind time — `getClient` only has a `PipeshubCore`, not yet a resolved
17
+ * `Authorization` header, and resolving security may be async (OAuth2)
18
+ * while `getClient` must stay sync (generated call sites pass its return
19
+ * value straight into a handler, never await it). So only the random suffix
20
+ * is fixed here; `requestid.ts`'s hook fills in `finalId` off the first
21
+ * outbound request's `Authorization` header and every later call in the
22
+ * same tool invocation reuses that cached value.
23
+ */
24
+
25
+ import { AsyncLocalStorage } from "node:async_hooks";
26
+ import { nanoid } from "nanoid";
27
+
28
+ export interface RequestContextStore {
29
+ random: string;
30
+ finalId?: string;
31
+ }
32
+
33
+ const storage = new AsyncLocalStorage<RequestContextStore>();
34
+
35
+ /** Bind a fresh request-id context for the remainder of the current async chain. */
36
+ export function bindNewRequestId(): void {
37
+ storage.enterWith({ random: nanoid() });
38
+ }
39
+
40
+ export function getRequestContextStore(): RequestContextStore | undefined {
41
+ return storage.getStore();
42
+ }
43
+
44
+ /** One-off id for the rare case a backend call happens with no bound tool-call context. */
45
+ export function newRequestId(): string {
46
+ return `mcp-${nanoid()}`;
47
+ }