@pipeshub-ai/mcp 2.0.0 → 2.1.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 (80) hide show
  1. package/bin/mcp-server.js +719 -100
  2. package/bin/mcp-server.js.map +20 -13
  3. package/esm/funcs/agentsListAgents.d.ts +10 -0
  4. package/esm/funcs/agentsListAgents.d.ts.map +1 -0
  5. package/esm/funcs/agentsListAgents.js +83 -0
  6. package/esm/funcs/agentsListAgents.js.map +1 -0
  7. package/esm/funcs/agentsStreamConversation.d.ts +10 -0
  8. package/esm/funcs/agentsStreamConversation.d.ts.map +1 -0
  9. package/esm/funcs/agentsStreamConversation.js +83 -0
  10. package/esm/funcs/agentsStreamConversation.js.map +1 -0
  11. package/esm/funcs/agentsStreamMessage.d.ts +10 -0
  12. package/esm/funcs/agentsStreamMessage.d.ts.map +1 -0
  13. package/esm/funcs/agentsStreamMessage.js +86 -0
  14. package/esm/funcs/agentsStreamMessage.js.map +1 -0
  15. package/esm/funcs/conversationsStreamConversation.d.ts.map +1 -1
  16. package/esm/funcs/conversationsStreamConversation.js +1 -3
  17. package/esm/funcs/conversationsStreamConversation.js.map +1 -1
  18. package/esm/funcs/conversationsStreamMessage.d.ts.map +1 -1
  19. package/esm/funcs/conversationsStreamMessage.js +0 -7
  20. package/esm/funcs/conversationsStreamMessage.js.map +1 -1
  21. package/esm/mcp-server/instructions.d.ts +2 -0
  22. package/esm/mcp-server/instructions.d.ts.map +1 -0
  23. package/esm/mcp-server/instructions.js +83 -0
  24. package/esm/mcp-server/instructions.js.map +1 -0
  25. package/esm/mcp-server/prompts/pipeshubAssistant.d.ts +8 -0
  26. package/esm/mcp-server/prompts/pipeshubAssistant.d.ts.map +1 -0
  27. package/esm/mcp-server/prompts/pipeshubAssistant.js +31 -0
  28. package/esm/mcp-server/prompts/pipeshubAssistant.js.map +1 -0
  29. package/esm/mcp-server/server.d.ts.map +1 -1
  30. package/esm/mcp-server/server.js +7 -60
  31. package/esm/mcp-server/server.js.map +1 -1
  32. package/esm/mcp-server/tools/_helpers.d.ts +78 -0
  33. package/esm/mcp-server/tools/_helpers.d.ts.map +1 -1
  34. package/esm/mcp-server/tools/_helpers.js +155 -1
  35. package/esm/mcp-server/tools/_helpers.js.map +1 -1
  36. package/esm/mcp-server/tools/pipeshubAgents.d.ts +8 -0
  37. package/esm/mcp-server/tools/pipeshubAgents.d.ts.map +1 -0
  38. package/esm/mcp-server/tools/pipeshubAgents.js +62 -0
  39. package/esm/mcp-server/tools/pipeshubAgents.js.map +1 -0
  40. package/esm/mcp-server/tools/pipeshubChat.d.ts +6 -1
  41. package/esm/mcp-server/tools/pipeshubChat.d.ts.map +1 -1
  42. package/esm/mcp-server/tools/pipeshubChat.js +88 -26
  43. package/esm/mcp-server/tools/pipeshubChat.js.map +1 -1
  44. package/esm/mcp-server/tools/pipeshubDirectory.d.ts.map +1 -1
  45. package/esm/mcp-server/tools/pipeshubDirectory.js +0 -1
  46. package/esm/mcp-server/tools/pipeshubDirectory.js.map +1 -1
  47. package/esm/mcp-server/tools/pipeshubDownloadRecord.d.ts.map +1 -1
  48. package/esm/mcp-server/tools/pipeshubDownloadRecord.js +0 -3
  49. package/esm/mcp-server/tools/pipeshubDownloadRecord.js.map +1 -1
  50. package/esm/mcp-server/tools/pipeshubSearch.d.ts.map +1 -1
  51. package/esm/mcp-server/tools/pipeshubSearch.js +0 -3
  52. package/esm/mcp-server/tools/pipeshubSearch.js.map +1 -1
  53. package/esm/mcp-server/tools/pipeshubSources.d.ts.map +1 -1
  54. package/esm/mcp-server/tools/pipeshubSources.js +0 -4
  55. package/esm/mcp-server/tools/pipeshubSources.js.map +1 -1
  56. package/esm/models/agentops.d.ts +119 -0
  57. package/esm/models/agentops.d.ts.map +1 -0
  58. package/esm/models/agentops.js +97 -0
  59. package/esm/models/agentops.js.map +1 -0
  60. package/esm/tool-names.d.ts.map +1 -1
  61. package/esm/tool-names.js +5 -1
  62. package/esm/tool-names.js.map +1 -1
  63. package/package.json +2 -2
  64. package/src/funcs/agentsListAgents.ts +141 -0
  65. package/src/funcs/agentsStreamConversation.ts +144 -0
  66. package/src/funcs/agentsStreamMessage.ts +147 -0
  67. package/src/funcs/conversationsStreamConversation.ts +1 -3
  68. package/src/funcs/conversationsStreamMessage.ts +0 -8
  69. package/src/mcp-server/instructions.ts +83 -0
  70. package/src/mcp-server/prompts/pipeshubAssistant.ts +37 -0
  71. package/src/mcp-server/server.ts +8 -62
  72. package/src/mcp-server/tools/_helpers.ts +216 -1
  73. package/src/mcp-server/tools/pipeshubAgents.ts +68 -0
  74. package/src/mcp-server/tools/pipeshubChat.ts +87 -26
  75. package/src/mcp-server/tools/pipeshubDirectory.ts +0 -1
  76. package/src/mcp-server/tools/pipeshubDownloadRecord.ts +0 -4
  77. package/src/mcp-server/tools/pipeshubSearch.ts +0 -3
  78. package/src/mcp-server/tools/pipeshubSources.ts +0 -5
  79. package/src/models/agentops.ts +160 -0
  80. package/src/tool-names.ts +5 -1
@@ -0,0 +1,141 @@
1
+ // Mirrors `usersGetAllUsers.ts`
2
+ // but hits `GET /agents` (operationId `listAgents`). Returns the raw JSON
3
+ // `Response`; the caller parses the `{ success, agents, pagination }` envelope.
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 {
13
+ ListAgentsRequest,
14
+ ListAgentsRequest$zodSchema,
15
+ } from "../models/agentops.js";
16
+ import { APIError } from "../models/errors/apierror.js";
17
+ import {
18
+ ConnectionError,
19
+ InvalidRequestError,
20
+ RequestAbortedError,
21
+ RequestTimeoutError,
22
+ UnexpectedClientError,
23
+ } from "../models/errors/httpclienterrors.js";
24
+ import { SDKValidationError } from "../models/errors/sdkvalidationerror.js";
25
+ import { APICall, APIPromise } from "../types/async.js";
26
+ import { Result } from "../types/fp.js";
27
+
28
+ export function agentsListAgents(
29
+ client$: PipeshubCore,
30
+ request?: ListAgentsRequest | undefined,
31
+ options?: RequestOptions,
32
+ ): APIPromise<
33
+ Result<
34
+ Response,
35
+ | APIError
36
+ | SDKValidationError
37
+ | UnexpectedClientError
38
+ | InvalidRequestError
39
+ | RequestAbortedError
40
+ | RequestTimeoutError
41
+ | ConnectionError
42
+ >
43
+ > {
44
+ return new APIPromise($do(client$, request, options));
45
+ }
46
+
47
+ async function $do(
48
+ client$: PipeshubCore,
49
+ request?: ListAgentsRequest | undefined,
50
+ options?: RequestOptions,
51
+ ): Promise<
52
+ [
53
+ Result<
54
+ Response,
55
+ | APIError
56
+ | SDKValidationError
57
+ | UnexpectedClientError
58
+ | InvalidRequestError
59
+ | RequestAbortedError
60
+ | RequestTimeoutError
61
+ | ConnectionError
62
+ >,
63
+ APICall,
64
+ ]
65
+ > {
66
+ const parsed$ = safeParse(
67
+ request,
68
+ (value$) => ListAgentsRequest$zodSchema.optional().parse(value$),
69
+ "Input validation failed",
70
+ );
71
+ if (!parsed$.ok) {
72
+ return [parsed$, { status: "invalid" }];
73
+ }
74
+ const payload$ = parsed$.value;
75
+ const body$ = null;
76
+ const path$ = pathToFunc("/agents")();
77
+ const query$ = encodeFormQuery({
78
+ "page": payload$?.page,
79
+ "limit": payload$?.limit,
80
+ "search": payload$?.search,
81
+ "sort_by": payload$?.sortBy,
82
+ "sort_order": payload$?.sortOrder,
83
+ });
84
+
85
+ const headers$ = new Headers(compactMap({
86
+ Accept: "application/json",
87
+ }));
88
+ const securityInput = await extractSecurity(client$._options.security);
89
+ const requestSecurity = resolveGlobalSecurity(securityInput);
90
+
91
+ const context = {
92
+ options: client$._options,
93
+ baseURL: options?.serverURL ?? client$._baseURL ?? "",
94
+ operationID: "listAgents",
95
+ oAuth2Scopes: ["agent:read"],
96
+ resolvedSecurity: requestSecurity,
97
+ securitySource: client$._options.security,
98
+ retryConfig: options?.retries
99
+ || client$._options.retryConfig
100
+ || { strategy: "none" },
101
+ retryCodes: options?.retryCodes || [
102
+ "429",
103
+ "500",
104
+ "502",
105
+ "503",
106
+ "504",
107
+ ],
108
+ };
109
+
110
+ const requestRes = client$._createRequest(context, {
111
+ security: requestSecurity,
112
+ method: "GET",
113
+ baseURL: options?.serverURL,
114
+ path: path$,
115
+ headers: headers$,
116
+ query: query$,
117
+ body: body$,
118
+ userAgent: client$._options.userAgent,
119
+ timeoutMs: options?.timeoutMs || client$._options.timeoutMs
120
+ || -1,
121
+ }, options);
122
+ if (!requestRes.ok) {
123
+ return [requestRes, { status: "invalid" }];
124
+ }
125
+ const req$ = requestRes.value;
126
+
127
+ const doResult = await client$._do(req$, {
128
+ context,
129
+ errorCodes: [],
130
+ retryConfig: context.retryConfig,
131
+ retryCodes: context.retryCodes,
132
+ });
133
+ if (!doResult.ok) {
134
+ return [doResult, { status: "request-error", request: req$ }];
135
+ }
136
+ return [doResult, {
137
+ status: "complete",
138
+ "request": req$,
139
+ response: doResult.value,
140
+ }];
141
+ }
@@ -0,0 +1,144 @@
1
+ // POST `/agents/{agentKey}/conversations/stream` (operationId
2
+ // `streamAgentConversation`) to start a conversation with a specific agent.
3
+ // Returns the raw streaming `Response`; the caller parses `text/event-stream`
4
+ // line-by-line.
5
+
6
+ import { PipeshubCore } from "../core.js";
7
+ import { encodeJSON, encodeSimple } from "../lib/encodings.js";
8
+ import { compactMap } from "../lib/primitives.js";
9
+ import { safeParse } from "../lib/schemas.js";
10
+ import { RequestOptions } from "../lib/sdks.js";
11
+ import { extractSecurity, resolveGlobalSecurity } from "../lib/security.js";
12
+ import { pathToFunc } from "../lib/url.js";
13
+ import {
14
+ AgentStreamCreateConversationRequest,
15
+ AgentStreamCreateConversationRequest$zodSchema,
16
+ } from "../models/agentops.js";
17
+ import { APIError } from "../models/errors/apierror.js";
18
+ import {
19
+ ConnectionError,
20
+ InvalidRequestError,
21
+ RequestAbortedError,
22
+ RequestTimeoutError,
23
+ UnexpectedClientError,
24
+ } from "../models/errors/httpclienterrors.js";
25
+ import { SDKValidationError } from "../models/errors/sdkvalidationerror.js";
26
+ import { APICall, APIPromise } from "../types/async.js";
27
+ import { Result } from "../types/fp.js";
28
+
29
+ export function agentsStreamConversation(
30
+ client$: PipeshubCore,
31
+ request: AgentStreamCreateConversationRequest,
32
+ options?: RequestOptions,
33
+ ): APIPromise<
34
+ Result<
35
+ Response,
36
+ | APIError
37
+ | SDKValidationError
38
+ | UnexpectedClientError
39
+ | InvalidRequestError
40
+ | RequestAbortedError
41
+ | RequestTimeoutError
42
+ | ConnectionError
43
+ >
44
+ > {
45
+ return new APIPromise($do(client$, request, options));
46
+ }
47
+
48
+ async function $do(
49
+ client$: PipeshubCore,
50
+ request: AgentStreamCreateConversationRequest,
51
+ options?: RequestOptions,
52
+ ): Promise<
53
+ [
54
+ Result<
55
+ Response,
56
+ | APIError
57
+ | SDKValidationError
58
+ | UnexpectedClientError
59
+ | InvalidRequestError
60
+ | RequestAbortedError
61
+ | RequestTimeoutError
62
+ | ConnectionError
63
+ >,
64
+ APICall,
65
+ ]
66
+ > {
67
+ const parsed$ = safeParse(
68
+ request,
69
+ (value$) => AgentStreamCreateConversationRequest$zodSchema.parse(value$),
70
+ "Input validation failed",
71
+ );
72
+ if (!parsed$.ok) {
73
+ return [parsed$, { status: "invalid" }];
74
+ }
75
+ const payload$ = parsed$.value;
76
+ const body$ = encodeJSON("body", payload$.body, { explode: true });
77
+
78
+ const pathParams$ = {
79
+ agentKey: encodeSimple("agentKey", payload$.agentKey, {
80
+ explode: false,
81
+ charEncoding: "percent",
82
+ }),
83
+ };
84
+ const path$ = pathToFunc(
85
+ "/agents/{agentKey}/conversations/stream",
86
+ )(pathParams$);
87
+
88
+ const headers$ = new Headers(compactMap({
89
+ "Content-Type": "application/json",
90
+ Accept: "text/event-stream",
91
+ }));
92
+ const securityInput = await extractSecurity(client$._options.security);
93
+ const requestSecurity = resolveGlobalSecurity(securityInput);
94
+
95
+ const context = {
96
+ options: client$._options,
97
+ baseURL: options?.serverURL ?? client$._baseURL ?? "",
98
+ operationID: "streamAgentConversation",
99
+ oAuth2Scopes: ["agent:execute"],
100
+ resolvedSecurity: requestSecurity,
101
+ securitySource: client$._options.security,
102
+ retryConfig: options?.retries
103
+ || client$._options.retryConfig
104
+ || { strategy: "none" },
105
+ retryCodes: options?.retryCodes || [
106
+ "429",
107
+ "500",
108
+ "502",
109
+ "503",
110
+ "504",
111
+ ],
112
+ };
113
+
114
+ const requestRes = client$._createRequest(context, {
115
+ security: requestSecurity,
116
+ method: "POST",
117
+ baseURL: options?.serverURL,
118
+ path: path$,
119
+ headers: headers$,
120
+ body: body$,
121
+ userAgent: client$._options.userAgent,
122
+ // SSE streams are long-lived; let the caller's AbortSignal cap it.
123
+ timeoutMs: options?.timeoutMs || -1,
124
+ }, options);
125
+ if (!requestRes.ok) {
126
+ return [requestRes, { status: "invalid" }];
127
+ }
128
+ const req$ = requestRes.value;
129
+
130
+ const doResult = await client$._do(req$, {
131
+ context,
132
+ errorCodes: [],
133
+ retryConfig: context.retryConfig,
134
+ retryCodes: context.retryCodes,
135
+ });
136
+ if (!doResult.ok) {
137
+ return [doResult, { status: "request-error", request: req$ }];
138
+ }
139
+ return [doResult, {
140
+ status: "complete",
141
+ "request": req$,
142
+ response: doResult.value,
143
+ }];
144
+ }
@@ -0,0 +1,147 @@
1
+ // POSTs to `/agents/{agentKey}/conversations/{conversationId}/messages/stream`
2
+ // (operationId `streamAgentConversationMessage`) to append a follow-up turn
3
+ // to an existing agent conversation. Returns the raw streaming `Response`.
4
+
5
+ import { PipeshubCore } from "../core.js";
6
+ import { encodeJSON, 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 {
13
+ AgentAddMessageStreamRequest,
14
+ AgentAddMessageStreamRequest$zodSchema,
15
+ } from "../models/agentops.js";
16
+ import { APIError } from "../models/errors/apierror.js";
17
+ import {
18
+ ConnectionError,
19
+ InvalidRequestError,
20
+ RequestAbortedError,
21
+ RequestTimeoutError,
22
+ UnexpectedClientError,
23
+ } from "../models/errors/httpclienterrors.js";
24
+ import { SDKValidationError } from "../models/errors/sdkvalidationerror.js";
25
+ import { APICall, APIPromise } from "../types/async.js";
26
+ import { Result } from "../types/fp.js";
27
+
28
+ export function agentsStreamMessage(
29
+ client$: PipeshubCore,
30
+ request: AgentAddMessageStreamRequest,
31
+ options?: RequestOptions,
32
+ ): APIPromise<
33
+ Result<
34
+ Response,
35
+ | APIError
36
+ | SDKValidationError
37
+ | UnexpectedClientError
38
+ | InvalidRequestError
39
+ | RequestAbortedError
40
+ | RequestTimeoutError
41
+ | ConnectionError
42
+ >
43
+ > {
44
+ return new APIPromise($do(client$, request, options));
45
+ }
46
+
47
+ async function $do(
48
+ client$: PipeshubCore,
49
+ request: AgentAddMessageStreamRequest,
50
+ options?: RequestOptions,
51
+ ): Promise<
52
+ [
53
+ Result<
54
+ Response,
55
+ | APIError
56
+ | SDKValidationError
57
+ | UnexpectedClientError
58
+ | InvalidRequestError
59
+ | RequestAbortedError
60
+ | RequestTimeoutError
61
+ | ConnectionError
62
+ >,
63
+ APICall,
64
+ ]
65
+ > {
66
+ const parsed$ = safeParse(
67
+ request,
68
+ (value$) => AgentAddMessageStreamRequest$zodSchema.parse(value$),
69
+ "Input validation failed",
70
+ );
71
+ if (!parsed$.ok) {
72
+ return [parsed$, { status: "invalid" }];
73
+ }
74
+ const payload$ = parsed$.value;
75
+ const body$ = encodeJSON("body", payload$.body, { explode: true });
76
+
77
+ const pathParams$ = {
78
+ agentKey: encodeSimple("agentKey", payload$.agentKey, {
79
+ explode: false,
80
+ charEncoding: "percent",
81
+ }),
82
+ conversationId: encodeSimple("conversationId", payload$.conversationId, {
83
+ explode: false,
84
+ charEncoding: "percent",
85
+ }),
86
+ };
87
+ const path$ = pathToFunc(
88
+ "/agents/{agentKey}/conversations/{conversationId}/messages/stream",
89
+ )(pathParams$);
90
+
91
+ const headers$ = new Headers(compactMap({
92
+ "Content-Type": "application/json",
93
+ Accept: "text/event-stream",
94
+ }));
95
+ const securityInput = await extractSecurity(client$._options.security);
96
+ const requestSecurity = resolveGlobalSecurity(securityInput);
97
+
98
+ const context = {
99
+ options: client$._options,
100
+ baseURL: options?.serverURL ?? client$._baseURL ?? "",
101
+ operationID: "streamAgentConversationMessage",
102
+ oAuth2Scopes: ["agent:execute"],
103
+ resolvedSecurity: requestSecurity,
104
+ securitySource: client$._options.security,
105
+ retryConfig: options?.retries
106
+ || client$._options.retryConfig
107
+ || { strategy: "none" },
108
+ retryCodes: options?.retryCodes || [
109
+ "429",
110
+ "500",
111
+ "502",
112
+ "503",
113
+ "504",
114
+ ],
115
+ };
116
+
117
+ const requestRes = client$._createRequest(context, {
118
+ security: requestSecurity,
119
+ method: "POST",
120
+ baseURL: options?.serverURL,
121
+ path: path$,
122
+ headers: headers$,
123
+ body: body$,
124
+ userAgent: client$._options.userAgent,
125
+ // SSE streams are long-lived; let the caller's AbortSignal cap it.
126
+ timeoutMs: options?.timeoutMs || -1,
127
+ }, options);
128
+ if (!requestRes.ok) {
129
+ return [requestRes, { status: "invalid" }];
130
+ }
131
+ const req$ = requestRes.value;
132
+
133
+ const doResult = await client$._do(req$, {
134
+ context,
135
+ errorCodes: [],
136
+ retryConfig: context.retryConfig,
137
+ retryCodes: context.retryCodes,
138
+ });
139
+ if (!doResult.ok) {
140
+ return [doResult, { status: "request-error", request: req$ }];
141
+ }
142
+ return [doResult, {
143
+ status: "complete",
144
+ "request": req$,
145
+ response: doResult.value,
146
+ }];
147
+ }
@@ -1,6 +1,4 @@
1
- // Hand-written supplement (NOT generated). Mirrors
2
- // `conversationsCreateConversation.ts` but POSTs to `/conversations/stream`
3
- // and asks for an SSE response. The body shape is identical to the
1
+ // POSTs to `/conversations/stream` and asks for an SSE response. The body shape is identical to the
4
2
  // non-streaming sibling, so we reuse `CreateConversationRequest`'s zod
5
3
  // schema. Returns the raw streaming `Response`; the caller is expected to
6
4
  // parse `text/event-stream` line-by-line.
@@ -1,11 +1,3 @@
1
- // Hand-written supplement (NOT generated). Mirrors
2
- // `conversationsAddMessage.ts` but POSTs to
3
- // `/conversations/{conversationId}/messages/stream` and asks for an SSE
4
- // response. The body shape is identical to the non-streaming sibling, so
5
- // we reuse `AddMessageRequestRequest`'s zod schema. Returns the raw
6
- // streaming `Response`; the caller is expected to parse `text/event-stream`
7
- // line-by-line.
8
-
9
1
  import { PipeshubCore } from "../core.js";
10
2
  import { encodeJSON, encodeSimple } from "../lib/encodings.js";
11
3
  import { compactMap } from "../lib/primitives.js";
@@ -0,0 +1,83 @@
1
+ // Shared routing guidance for the host LLM. Surfaced two ways:
2
+ // 1. As the server `instructions` (always present at `initialize`).
3
+ // 2. As the body of the user-invokable `pipeshub-assistant` prompt.
4
+ // Keeping it in one place avoids the two copies drifting apart.
5
+
6
+ export const PIPESHUB_INSTRUCTIONS = `# PipesHub MCP — instructions for the LLM
7
+
8
+ PipesHub is the user's workplace AI platform. It indexes their documents,
9
+ knowledge base content, and connector sources (Drive, Box, Confluence,
10
+ Slack, Jira, Gmail, ...). When in doubt, the answer is in PipesHub.
11
+
12
+ ## Default tool: \`pipeshub_chat\`
13
+
14
+ **Use \`pipeshub_chat\` for any question that could plausibly be answered
15
+ by the user's PipesHub-indexed data.** That includes:
16
+
17
+ - Anything about a specific document, file, report, ticket, message, or
18
+ page (e.g. "what's in the Q4 sales report?", "summarize the langchain
19
+ doc", "what did Aashil say about onboarding?").
20
+ - Anything about company / org policies, processes, decisions, or
21
+ history (e.g. "what's our vacation policy?", "who owns the auth
22
+ service?").
23
+ - Anything explicitly mentioning PipesHub itself, or its sources
24
+ (Drive / Box / Confluence / Slack / Gmail / Jira / etc.) when the
25
+ user has those connected.
26
+ - Open-ended "what do we know about X" questions where the answer
27
+ likely lives in the org's documents.
28
+
29
+ Do NOT answer those from your own knowledge — \`pipeshub_chat\` grounds
30
+ the answer in the user's actual indexed content and returns citations
31
+ the user can verify.
32
+
33
+ ## When to use the other tools
34
+
35
+ - \`pipeshub_search\` — only when the user asks specifically to **find /
36
+ locate** a document by name or topic (so you can hand them a list, or
37
+ resolve a filename to a \`recordId\` for download). For "what does
38
+ the doc say?" use \`pipeshub_chat\` instead — it does the retrieval
39
+ internally.
40
+ - \`pipeshub_download_record\` — when the user wants the actual file
41
+ bytes (download, attach, open). Get the \`recordId\` either from
42
+ citations on a prior \`pipeshub_chat\` response or from
43
+ \`pipeshub_search\`.
44
+ - \`pipeshub_directory\` — people, groups, teams, and \`whoami\` lookups.
45
+ Not for documents.
46
+ - \`pipeshub_sources\` — call once at the start of a session to discover
47
+ which connectors / KB / models are available, then cache the result.
48
+ - \`pipeshub_agents\` — list the org's configured **agents** (specialized
49
+ assistants with their own prompt, tools, and knowledge scope).
50
+
51
+ ## Agents
52
+
53
+ Some orgs configure **agents** for specific jobs (e.g. a Slack messenger, a
54
+ Jira ticket creator, a Salesforce CRM updater). To run a turn against an
55
+ agent, call \`pipeshub_chat\` with its \`agentId\` (from \`pipeshub_agents\`)
56
+ — optionally with an agent \`chatMode\` (\`auto\` by default, or \`quick\` /
57
+ \`verification\` / \`deep\`). Keep passing the same \`agentId\` plus the
58
+ returned \`conversationId\` on follow-up turns.
59
+
60
+ **When to route to an agent vs plain chat:**
61
+ - The user names a system/action that maps to an agent (e.g. "post to
62
+ Slack", "create a Jira ticket", "update the Salesforce deal") → call
63
+ \`pipeshub_agents\`, pick the matching agent, and use it.
64
+ - Plain question about the org's knowledge or the public web → just use
65
+ \`pipeshub_chat\` (no \`agentId\`) with \`internal_search\` or \`web_search\`.
66
+
67
+ **If you are unsure which agent or route fits the request**, call
68
+ \`pipeshub_agents\` FIRST and read the returned names/descriptions, then
69
+ either pick the best match or present the list to the user and let them
70
+ choose. Do NOT guess an agent blindly, and do NOT refuse — list the agents
71
+ and decide from real data. The list may be empty (no agents configured),
72
+ in which case fall back to plain \`pipeshub_chat\`.
73
+
74
+ ## Conversation lifecycle
75
+
76
+ \`pipeshub_chat\` is a single tool that handles both starting and
77
+ continuing conversations (plain or with an \`agentId\`). On the first turn
78
+ omit \`conversationId\`; on every subsequent turn pass back the
79
+ \`conversationId\` returned by the previous call (along with the same
80
+ \`agentId\` if you used one). Server-side context is preserved — do NOT
81
+ replay prior messages. Only start a fresh conversation when the user
82
+ explicitly asks to clear context.
83
+ `;
@@ -0,0 +1,37 @@
1
+ import * as z from "zod";
2
+ import { PromptDefinition } from "../prompts.js";
3
+ import { PIPESHUB_INSTRUCTIONS } from "../instructions.js";
4
+
5
+ const args = {
6
+ query: z.string().optional().describe(
7
+ "Optional. The user's request to route. Provide it to have the guidance "
8
+ + "applied to a concrete request; omit it to just load the routing "
9
+ + "guidance as a seed system prompt at the start of a session.",
10
+ ),
11
+ };
12
+
13
+ export const prompt$pipeshubAssistant: PromptDefinition<typeof args> = {
14
+ name: "pipeshub-assistant",
15
+ description:
16
+ "Load PipesHub tool-routing guidance so the assistant picks the correct "
17
+ + "tool (pipeshub_chat / search / agents / directory) and lists agents "
18
+ + "with pipeshub_agents when unsure which route fits the query.",
19
+ scopes: ["read"],
20
+ args,
21
+ prompt: (_client, args, _extra) => {
22
+ const text = args.query
23
+ ? `${PIPESHUB_INSTRUCTIONS}\n\n---\n\nFollow the routing rules above to `
24
+ + `handle this request, picking the right tool (and listing agents via `
25
+ + `\`pipeshub_agents\` if unsure which route fits):\n\n${args.query}`
26
+ : PIPESHUB_INSTRUCTIONS;
27
+
28
+ return {
29
+ messages: [
30
+ {
31
+ role: "user",
32
+ content: { type: "text", text },
33
+ },
34
+ ],
35
+ };
36
+ },
37
+ };
@@ -1,65 +1,6 @@
1
- // Hand-written; replaces the Speakeasy-generated server.ts. Registers the
2
- // five curated PipesHub tools instead of one tool per OpenAPI operation.
3
-
4
1
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
5
2
 
6
- // Top-level instructions surfaced to the host LLM at server initialize.
7
- // These set defaults so the model picks `pipeshub_chat` as the natural
8
- // entry point for anything that touches the user's PipesHub data —
9
- // documents, files, knowledge base content, citations, etc.
10
- const PIPESHUB_INSTRUCTIONS = `# PipesHub MCP — instructions for the LLM
11
-
12
- PipesHub is the user's workplace AI platform. It indexes their documents,
13
- knowledge base content, and connector sources (Drive, Box, Confluence,
14
- Slack, Jira, Gmail, ...). When in doubt, the answer is in PipesHub.
15
-
16
- ## Default tool: \`pipeshub_chat\`
17
-
18
- **Use \`pipeshub_chat\` for any question that could plausibly be answered
19
- by the user's PipesHub-indexed data.** That includes:
20
-
21
- - Anything about a specific document, file, report, ticket, message, or
22
- page (e.g. "what's in the Q4 sales report?", "summarize the langchain
23
- doc", "what did Aashil say about onboarding?").
24
- - Anything about company / org policies, processes, decisions, or
25
- history (e.g. "what's our vacation policy?", "who owns the auth
26
- service?").
27
- - Anything explicitly mentioning PipesHub itself, or its sources
28
- (Drive / Box / Confluence / Slack / Gmail / Jira / etc.) when the
29
- user has those connected.
30
- - Open-ended "what do we know about X" questions where the answer
31
- likely lives in the org's documents.
32
-
33
- Do NOT answer those from your own knowledge — \`pipeshub_chat\` grounds
34
- the answer in the user's actual indexed content and returns citations
35
- the user can verify.
36
-
37
- ## When to use the other tools
38
-
39
- - \`pipeshub_search\` — only when the user asks specifically to **find /
40
- locate** a document by name or topic (so you can hand them a list, or
41
- resolve a filename to a \`recordId\` for download). For "what does
42
- the doc say?" use \`pipeshub_chat\` instead — it does the retrieval
43
- internally.
44
- - \`pipeshub_download_record\` — when the user wants the actual file
45
- bytes (download, attach, open). Get the \`recordId\` either from
46
- citations on a prior \`pipeshub_chat\` response or from
47
- \`pipeshub_search\`.
48
- - \`pipeshub_directory\` — people, groups, teams, and \`whoami\` lookups.
49
- Not for documents.
50
- - \`pipeshub_sources\` — call once at the start of a session to discover
51
- which connectors / KB / models are available, then cache the result.
52
-
53
- ## Conversation lifecycle
54
-
55
- \`pipeshub_chat\` is a single tool that handles both starting and
56
- continuing conversations. On the first turn omit \`conversationId\`; on
57
- every subsequent turn pass back the \`conversationId\` returned by the
58
- previous call. Server-side context is preserved — do NOT replay prior
59
- messages. Only start a fresh conversation when the user explicitly
60
- asks to clear context.
61
- `;
62
-
3
+ import { PIPESHUB_INSTRUCTIONS } from "./instructions.js";
63
4
  import { PipeshubCore } from "../core.js";
64
5
  import { SDKOptions } from "../lib/config.js";
65
6
  import type { ConsoleLogger } from "./console-logger.js";
@@ -75,6 +16,8 @@ import { tool$pipeshubSearch } from "./tools/pipeshubSearch.js";
75
16
  import { tool$pipeshubDownloadRecord } from "./tools/pipeshubDownloadRecord.js";
76
17
  import { tool$pipeshubDirectory } from "./tools/pipeshubDirectory.js";
77
18
  import { tool$pipeshubSources } from "./tools/pipeshubSources.js";
19
+ import { tool$pipeshubAgents } from "./tools/pipeshubAgents.js";
20
+ import { prompt$pipeshubAssistant } from "./prompts/pipeshubAssistant.js";
78
21
 
79
22
  export function createMCPServer(deps: {
80
23
  logger: ConsoleLogger;
@@ -139,13 +82,16 @@ export function createMCPServer(deps: {
139
82
  const register = { tool, resource, resourceTemplate, prompt };
140
83
  void register; // suppress unused warnings
141
84
 
142
- // Curated tool set. Five tools instead of ten one-per-op generated tools.
143
- // Order = preferred discovery order shown to the LLM.
85
+ // Curated tool set. Order = preferred discovery order shown to the LLM.
144
86
  tool(tool$pipeshubSources); // 1. discover sources + models
145
87
  tool(tool$pipeshubChat); // 2. ask questions (start + continue)
146
88
  tool(tool$pipeshubSearch); // 3. resolve filename → recordId
147
89
  tool(tool$pipeshubDownloadRecord); // 4. fetch a document by id
148
90
  tool(tool$pipeshubDirectory); // 5. people / groups / teams / whoami
91
+ tool(tool$pipeshubAgents); // 6. discover org agents
92
+
93
+ // Curated prompt: user-invokable tool-routing guidance.
94
+ prompt(prompt$pipeshubAssistant);
149
95
 
150
96
  if (deps.dynamic) {
151
97
  registerDynamicTools(deps.logger, server, getClient, toolMap, scopes);