@attrove/mcp 0.1.3 → 0.1.4

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 (53) hide show
  1. package/README.md +52 -1
  2. package/cjs/README.md +247 -0
  3. package/cjs/bin/attrove-mcp.js +69 -0
  4. package/cjs/package.json +69 -0
  5. package/cjs/src/__mocks__/version.js +17 -0
  6. package/cjs/src/__mocks__/version.js.map +1 -0
  7. package/cjs/src/constants.js +17 -0
  8. package/cjs/src/constants.js.map +1 -0
  9. package/cjs/src/index.js +43 -0
  10. package/cjs/src/index.js.map +1 -0
  11. package/cjs/src/server.js +247 -0
  12. package/cjs/src/server.js.map +1 -0
  13. package/cjs/src/tools/index.js +26 -0
  14. package/cjs/src/tools/index.js.map +1 -0
  15. package/cjs/src/tools/integrations.js +50 -0
  16. package/cjs/src/tools/integrations.js.map +1 -0
  17. package/cjs/src/tools/query.js +70 -0
  18. package/cjs/src/tools/query.js.map +1 -0
  19. package/cjs/src/tools/search.js +147 -0
  20. package/cjs/src/tools/search.js.map +1 -0
  21. package/cjs/src/version.js +142 -0
  22. package/cjs/src/version.js.map +1 -0
  23. package/esm/README.md +247 -0
  24. package/esm/bin/attrove-mcp.js +69 -0
  25. package/esm/package.json +69 -0
  26. package/esm/src/__mocks__/version.js +12 -0
  27. package/esm/src/__mocks__/version.js.map +1 -0
  28. package/esm/src/constants.js +14 -0
  29. package/esm/src/constants.js.map +1 -0
  30. package/esm/src/index.js +32 -0
  31. package/esm/src/index.js.map +1 -0
  32. package/esm/src/server.js +241 -0
  33. package/esm/src/server.js.map +1 -0
  34. package/esm/src/tools/index.js +19 -0
  35. package/esm/src/tools/index.js.map +1 -0
  36. package/esm/src/tools/integrations.js +46 -0
  37. package/esm/src/tools/integrations.js.map +1 -0
  38. package/esm/src/tools/query.js +66 -0
  39. package/esm/src/tools/query.js.map +1 -0
  40. package/esm/src/tools/search.js +143 -0
  41. package/esm/src/tools/search.js.map +1 -0
  42. package/esm/src/version.js +137 -0
  43. package/esm/src/version.js.map +1 -0
  44. package/package.json +13 -11
  45. package/types/src/__mocks__/version.d.ts +7 -0
  46. package/types/src/constants.d.ts +13 -0
  47. package/types/src/index.d.ts +32 -0
  48. package/types/src/server.d.ts +38 -0
  49. package/types/src/tools/index.d.ts +80 -0
  50. package/types/src/tools/integrations.d.ts +22 -0
  51. package/types/src/tools/query.d.ts +47 -0
  52. package/types/src/tools/search.d.ts +57 -0
  53. package/types/src/version.d.ts +23 -0
@@ -0,0 +1,241 @@
1
+ /**
2
+ * Attrove MCP Server
3
+ *
4
+ * Model Context Protocol server that enables AI assistants like Claude
5
+ * to access user context through the Attrove API.
6
+ */
7
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
8
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
9
+ import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
10
+ import { Attrove, isAttroveError, ValidationError, ErrorCodes } from '@attrove/sdk';
11
+ import { allToolDefinitions, executeQueryTool, executeSearchTool, executeIntegrationsTool, } from './tools';
12
+ import { getVersion } from './version';
13
+ /**
14
+ * Validate that a value is an array of strings.
15
+ * Returns undefined if value is null/undefined.
16
+ * Throws ValidationError if value is present but invalid.
17
+ */
18
+ function validateStringArray(value, fieldName) {
19
+ if (value === undefined || value === null) {
20
+ return undefined;
21
+ }
22
+ if (!Array.isArray(value)) {
23
+ throw new ValidationError(`${fieldName} must be an array of strings, received ${typeof value}`, ErrorCodes.VALIDATION_INVALID_FORMAT, { field: fieldName, received: typeof value });
24
+ }
25
+ if (!value.every((item) => typeof item === 'string')) {
26
+ const types = value.map(item => typeof item).join(', ');
27
+ throw new ValidationError(`${fieldName} must contain only strings, received types: [${types}]`, ErrorCodes.VALIDATION_INVALID_FORMAT, { field: fieldName, receivedTypes: types });
28
+ }
29
+ return value;
30
+ }
31
+ /**
32
+ * Validate input for the query tool.
33
+ *
34
+ * @throws {ValidationError} If arguments are missing or invalid
35
+ */
36
+ function validateQueryInput(args) {
37
+ if (!args || typeof args !== 'object') {
38
+ throw new ValidationError('Missing or invalid arguments. Expected an object with a "query" field.', ErrorCodes.VALIDATION_REQUIRED_FIELD, { expected: 'object with query field', received: typeof args });
39
+ }
40
+ const input = args;
41
+ if (typeof input.query !== 'string' || input.query.trim() === '') {
42
+ throw new ValidationError('Missing required parameter "query". Please provide a question to ask.', ErrorCodes.VALIDATION_REQUIRED_FIELD, { field: 'query' });
43
+ }
44
+ return {
45
+ query: input.query,
46
+ integration_ids: validateStringArray(input.integration_ids, 'integration_ids'),
47
+ include_sources: typeof input.include_sources === 'boolean' ? input.include_sources : undefined,
48
+ };
49
+ }
50
+ /**
51
+ * Validate input for the search tool.
52
+ *
53
+ * @throws {ValidationError} If arguments are missing or invalid
54
+ */
55
+ function validateSearchInput(args) {
56
+ if (!args || typeof args !== 'object') {
57
+ throw new ValidationError('Missing or invalid arguments. Expected an object with a "query" field.', ErrorCodes.VALIDATION_REQUIRED_FIELD, { expected: 'object with query field', received: typeof args });
58
+ }
59
+ const input = args;
60
+ if (typeof input.query !== 'string' || input.query.trim() === '') {
61
+ throw new ValidationError('Missing required parameter "query". Please provide a search query.', ErrorCodes.VALIDATION_REQUIRED_FIELD, { field: 'query' });
62
+ }
63
+ return {
64
+ query: input.query,
65
+ after_date: typeof input.after_date === 'string' ? input.after_date : undefined,
66
+ before_date: typeof input.before_date === 'string' ? input.before_date : undefined,
67
+ sender_domains: validateStringArray(input.sender_domains, 'sender_domains'),
68
+ include_body_text: typeof input.include_body_text === 'boolean' ? input.include_body_text : undefined,
69
+ };
70
+ }
71
+ /**
72
+ * Format an error for MCP response.
73
+ * Preserves error type information, code, and details for debugging.
74
+ */
75
+ function formatErrorResponse(error) {
76
+ let errorMessage;
77
+ let errorDetails;
78
+ if (isAttroveError(error)) {
79
+ errorMessage = `${error.name}: ${error.message}`;
80
+ const detailParts = [];
81
+ if (error.code) {
82
+ detailParts.push(`Code: ${error.code}`);
83
+ }
84
+ if (error.status) {
85
+ detailParts.push(`Status: ${error.status}`);
86
+ }
87
+ if (error.details) {
88
+ try {
89
+ detailParts.push(`Details: ${JSON.stringify(error.details)}`);
90
+ }
91
+ catch (serializeError) {
92
+ const reason = serializeError instanceof Error ? serializeError.message : 'Unknown reason';
93
+ detailParts.push(`Details: [Not serializable: ${reason}]`);
94
+ }
95
+ }
96
+ if (detailParts.length > 0) {
97
+ errorDetails = detailParts.join('\n');
98
+ }
99
+ }
100
+ else if (error instanceof Error) {
101
+ errorMessage = error.message;
102
+ }
103
+ else {
104
+ errorMessage = String(error);
105
+ }
106
+ const text = errorDetails
107
+ ? `Error: ${errorMessage}\n\n${errorDetails}`
108
+ : `Error: ${errorMessage}`;
109
+ return {
110
+ content: [{ type: 'text', text }],
111
+ isError: true,
112
+ };
113
+ }
114
+ /**
115
+ * Create and configure the Attrove MCP server.
116
+ */
117
+ export function createServer(config) {
118
+ const server = new Server({
119
+ name: 'attrove',
120
+ version: getVersion(),
121
+ }, {
122
+ capabilities: {
123
+ tools: {},
124
+ },
125
+ });
126
+ // Create Attrove client
127
+ // Type assertion is safe because startServer validates the apiKey prefix
128
+ const client = new Attrove({
129
+ apiKey: config.apiKey,
130
+ userId: config.userId,
131
+ baseUrl: config.baseUrl,
132
+ });
133
+ // Register tool list handler
134
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
135
+ return {
136
+ tools: allToolDefinitions.map((tool) => ({
137
+ name: tool.name,
138
+ description: tool.description,
139
+ inputSchema: tool.inputSchema,
140
+ })),
141
+ };
142
+ });
143
+ // Register tool call handler
144
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
145
+ const { name, arguments: args } = request.params;
146
+ // Validate input outside try-catch so validation errors propagate clearly
147
+ // and programming bugs in validation don't get caught as API errors
148
+ let validatedInput;
149
+ switch (name) {
150
+ case 'attrove_query':
151
+ validatedInput = validateQueryInput(args);
152
+ break;
153
+ case 'attrove_search':
154
+ validatedInput = validateSearchInput(args);
155
+ break;
156
+ case 'attrove_integrations':
157
+ // No input validation needed
158
+ break;
159
+ default:
160
+ return {
161
+ content: [
162
+ {
163
+ type: 'text',
164
+ text: `Unknown tool: ${name}. Available tools: attrove_query, attrove_search, attrove_integrations`,
165
+ },
166
+ ],
167
+ isError: true,
168
+ };
169
+ }
170
+ // Execute tool with narrowed try-catch for API/network errors only
171
+ try {
172
+ let result;
173
+ switch (name) {
174
+ case 'attrove_query':
175
+ result = await executeQueryTool(client, validatedInput);
176
+ break;
177
+ case 'attrove_search':
178
+ result = await executeSearchTool(client, validatedInput);
179
+ break;
180
+ case 'attrove_integrations':
181
+ result = await executeIntegrationsTool(client);
182
+ break;
183
+ default:
184
+ // Already handled above, but TypeScript needs this
185
+ throw new Error(`Unexpected tool: ${name}`);
186
+ }
187
+ return {
188
+ content: [
189
+ {
190
+ type: 'text',
191
+ text: result,
192
+ },
193
+ ],
194
+ };
195
+ }
196
+ catch (error) {
197
+ // Expected API/network errors - format directly for user
198
+ if (isAttroveError(error) || error instanceof ValidationError) {
199
+ return formatErrorResponse(error);
200
+ }
201
+ // Unexpected errors (programming bugs, system errors) - always log, then format for user.
202
+ // We catch all errors to keep the MCP server running, but logging ensures visibility.
203
+ // prettier-ignore
204
+ console.error('[AttroveMCP] Unexpected error in tool handler:', error);
205
+ return formatErrorResponse(error);
206
+ }
207
+ });
208
+ return server;
209
+ }
210
+ /**
211
+ * Start the MCP server with stdio transport.
212
+ */
213
+ export async function startServer(config) {
214
+ const server = createServer(config);
215
+ const transport = new StdioServerTransport();
216
+ await server.connect(transport);
217
+ }
218
+ /**
219
+ * Get configuration from environment variables.
220
+ *
221
+ * @throws {Error} If required environment variables are missing
222
+ */
223
+ export function getConfigFromEnv() {
224
+ const apiKey = process.env.ATTROVE_API_KEY;
225
+ const userId = process.env.ATTROVE_USER_ID;
226
+ const baseUrl = process.env.ATTROVE_BASE_URL;
227
+ if (!apiKey) {
228
+ throw new Error('ATTROVE_API_KEY environment variable is required. ' +
229
+ 'Set it to your Attrove API key (sk_...).');
230
+ }
231
+ if (!userId) {
232
+ throw new Error('ATTROVE_USER_ID environment variable is required. ' +
233
+ 'Set it to the user ID (UUID) for the user whose context you want to access.');
234
+ }
235
+ return {
236
+ apiKey,
237
+ userId,
238
+ baseUrl,
239
+ };
240
+ }
241
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../../../../packages/mcp/src/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * MCP Tools
3
+ *
4
+ * Tool definitions and executors for the Attrove MCP server.
5
+ */
6
+ import { queryToolDefinition, executeQueryTool } from './query';
7
+ import { searchToolDefinition, executeSearchTool } from './search';
8
+ import { integrationsToolDefinition, executeIntegrationsTool } from './integrations';
9
+ // Re-export tool definitions
10
+ export { queryToolDefinition, executeQueryTool, searchToolDefinition, executeSearchTool, integrationsToolDefinition, executeIntegrationsTool, };
11
+ /**
12
+ * All tool definitions for registration with MCP.
13
+ */
14
+ export const allToolDefinitions = [
15
+ queryToolDefinition,
16
+ searchToolDefinition,
17
+ integrationsToolDefinition,
18
+ ];
19
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../packages/mcp/src/tools/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAkB,MAAM,SAAS,CAAC;AAChF,OAAO,EAAE,oBAAoB,EAAE,iBAAiB,EAAmB,MAAM,UAAU,CAAC;AACpF,OAAO,EAAE,0BAA0B,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;AAErF,6BAA6B;AAC7B,OAAO,EACL,mBAAmB,EACnB,gBAAgB,EAChB,oBAAoB,EACpB,iBAAiB,EACjB,0BAA0B,EAC1B,uBAAuB,GACxB,CAAC;AAKF;;GAEG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG;IAChC,mBAAmB;IACnB,oBAAoB;IACpB,0BAA0B;CAClB,CAAC"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Integrations Tool
3
+ *
4
+ * MCP tool for listing and managing connected integrations.
5
+ */
6
+ /**
7
+ * Tool definition for attrove_integrations.
8
+ */
9
+ export const integrationsToolDefinition = {
10
+ name: 'attrove_integrations',
11
+ description: `List the user's connected integrations (Gmail, Slack, etc.).
12
+
13
+ This tool shows which services the user has connected and their current status. Use this to:
14
+ - Check what data sources are available for queries
15
+ - Verify integration status before searching
16
+ - Help users understand their connected services
17
+
18
+ The response includes:
19
+ - Integration ID (for filtering queries)
20
+ - Provider name (gmail, slack, google_calendar, etc.)
21
+ - Connection status (connected, disconnected, expired, error, pending)`,
22
+ inputSchema: {
23
+ type: 'object',
24
+ properties: {},
25
+ required: [],
26
+ },
27
+ };
28
+ /**
29
+ * Execute the integrations tool.
30
+ */
31
+ export async function executeIntegrationsTool(client) {
32
+ const integrations = await client.integrations.list();
33
+ if (integrations.length === 0) {
34
+ return 'No integrations connected. The user needs to connect their Gmail, Slack, or other services first.';
35
+ }
36
+ let result = `Connected integrations (${integrations.length}):\n`;
37
+ for (const integration of integrations) {
38
+ const status = integration.is_active ? '[Active]' : '[Inactive]';
39
+ const authStatus = integration.auth_status === 'connected' ? '' : ` (${integration.auth_status})`;
40
+ result += `\n- **${integration.name}** (${integration.provider})\n`;
41
+ result += ` - ID: ${integration.id}\n`;
42
+ result += ` - Status: ${status}${authStatus}\n`;
43
+ }
44
+ return result;
45
+ }
46
+ //# sourceMappingURL=integrations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"integrations.js","sourceRoot":"","sources":["../../../../../../packages/mcp/src/tools/integrations.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH;;GAEG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG;IACxC,IAAI,EAAE,sBAAsB;IAC5B,WAAW,EAAE;;;;;;;;;;uEAUwD;IACrE,WAAW,EAAE;QACX,IAAI,EAAE,QAAiB;QACvB,UAAU,EAAE,EAAE;QACd,QAAQ,EAAE,EAAE;KACb;CACF,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,MAAe;IAEf,MAAM,YAAY,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;IAEtD,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC9B,OAAO,mGAAmG,CAAC;IAC7G,CAAC;IAED,IAAI,MAAM,GAAG,2BAA2B,YAAY,CAAC,MAAM,MAAM,CAAC;IAElE,KAAK,MAAM,WAAW,IAAI,YAAY,EAAE,CAAC;QACvC,MAAM,MAAM,GAAG,WAAW,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,YAAY,CAAC;QACjE,MAAM,UAAU,GAAG,WAAW,CAAC,WAAW,KAAK,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,WAAW,CAAC,WAAW,GAAG,CAAC;QAElG,MAAM,IAAI,SAAS,WAAW,CAAC,IAAI,OAAO,WAAW,CAAC,QAAQ,KAAK,CAAC;QACpE,MAAM,IAAI,WAAW,WAAW,CAAC,EAAE,IAAI,CAAC;QACxC,MAAM,IAAI,eAAe,MAAM,GAAG,UAAU,IAAI,CAAC;IACnD,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Query Tool
3
+ *
4
+ * MCP tool for RAG queries against user context.
5
+ */
6
+ /**
7
+ * Tool definition for attrove_query.
8
+ */
9
+ export const queryToolDefinition = {
10
+ name: 'attrove_query',
11
+ description: `Ask a question about the user's communications and get an AI-generated answer.
12
+
13
+ This tool searches across all connected integrations (Gmail, Slack, Google Meet, etc.) and returns a comprehensive answer based on the relevant context.
14
+
15
+ Use this tool when the user asks questions like:
16
+ - "What did Sarah say about the Q4 budget?"
17
+ - "Summarize my meeting with the engineering team"
18
+ - "What are the action items from yesterday's standup?"
19
+ - "When is my next meeting with John?"`,
20
+ inputSchema: {
21
+ type: 'object',
22
+ properties: {
23
+ query: {
24
+ type: 'string',
25
+ description: 'The question to ask about the user\'s context',
26
+ },
27
+ integration_ids: {
28
+ type: 'array',
29
+ items: { type: 'string' },
30
+ description: 'Optional: Filter to specific integration IDs (UUIDs)',
31
+ },
32
+ include_sources: {
33
+ type: 'boolean',
34
+ description: 'Optional: Include source snippets in the response',
35
+ default: false,
36
+ },
37
+ },
38
+ required: ['query'],
39
+ },
40
+ };
41
+ /**
42
+ * Execute the query tool.
43
+ */
44
+ export async function executeQueryTool(client, input) {
45
+ const options = {};
46
+ if (input.integration_ids?.length) {
47
+ options.integrationIds = input.integration_ids;
48
+ }
49
+ if (input.include_sources) {
50
+ options.includeSources = true;
51
+ }
52
+ const response = await client.query(input.query, options);
53
+ // Format the response for MCP
54
+ let result = response.answer;
55
+ if (response.sources?.length) {
56
+ result += '\n\n**Sources:**';
57
+ for (const source of response.sources) {
58
+ result += `\n- ${source.title}: "${source.snippet}"`;
59
+ }
60
+ }
61
+ if (response.used_message_ids.length > 0) {
62
+ result += `\n\n_Based on ${response.used_message_ids.length} messages._`;
63
+ }
64
+ return result;
65
+ }
66
+ //# sourceMappingURL=query.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query.js","sourceRoot":"","sources":["../../../../../../packages/mcp/src/tools/query.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH;;GAEG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,IAAI,EAAE,eAAe;IACrB,WAAW,EAAE;;;;;;;;uCAQwB;IACrC,WAAW,EAAE;QACX,IAAI,EAAE,QAAiB;QACvB,UAAU,EAAE;YACV,KAAK,EAAE;gBACL,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,+CAA+C;aAC7D;YACD,eAAe,EAAE;gBACf,IAAI,EAAE,OAAO;gBACb,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;gBACzB,WAAW,EAAE,sDAAsD;aACpE;YACD,eAAe,EAAE;gBACf,IAAI,EAAE,SAAS;gBACf,WAAW,EAAE,mDAAmD;gBAChE,OAAO,EAAE,KAAK;aACf;SACF;QACD,QAAQ,EAAE,CAAC,OAAO,CAAC;KACpB;CACF,CAAC;AAWF;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,MAAe,EACf,KAAqB;IAErB,MAAM,OAAO,GAAiB,EAAE,CAAC;IAEjC,IAAI,KAAK,CAAC,eAAe,EAAE,MAAM,EAAE,CAAC;QAClC,OAAO,CAAC,cAAc,GAAG,KAAK,CAAC,eAAe,CAAC;IACjD,CAAC;IACD,IAAI,KAAK,CAAC,eAAe,EAAE,CAAC;QAC1B,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAChC,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IAE1D,8BAA8B;IAC9B,IAAI,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC;IAE7B,IAAI,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC;QAC7B,MAAM,IAAI,kBAAkB,CAAC;QAC7B,KAAK,MAAM,MAAM,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC;YACtC,MAAM,IAAI,OAAO,MAAM,CAAC,KAAK,MAAM,MAAM,CAAC,OAAO,GAAG,CAAC;QACvD,CAAC;IACH,CAAC;IAED,IAAI,QAAQ,CAAC,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzC,MAAM,IAAI,iBAAiB,QAAQ,CAAC,gBAAgB,CAAC,MAAM,aAAa,CAAC;IAC3E,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,143 @@
1
+ /**
2
+ * Search Tool
3
+ *
4
+ * MCP tool for semantic search across user context.
5
+ */
6
+ import { MAX_BODY_PREVIEW_LENGTH } from '../constants';
7
+ /**
8
+ * Tool definition for attrove_search.
9
+ */
10
+ export const searchToolDefinition = {
11
+ name: 'attrove_search',
12
+ description: `Search for specific messages or conversations in the user's communications.
13
+
14
+ This tool performs semantic search across connected integrations and returns matching messages grouped by conversation. Use this when you need:
15
+ - Raw message data without AI summarization
16
+ - To find specific conversations or threads
17
+ - To explore what information is available about a topic
18
+
19
+ Use this tool when the user asks things like:
20
+ - "Find all emails about the product launch"
21
+ - "Show me conversations with the marketing team"
22
+ - "Search for messages mentioning the deadline"`,
23
+ inputSchema: {
24
+ type: 'object',
25
+ properties: {
26
+ query: {
27
+ type: 'string',
28
+ description: 'The search query (semantic, not keyword-based)',
29
+ },
30
+ after_date: {
31
+ type: 'string',
32
+ description: 'Optional: Only include messages after this date (ISO 8601)',
33
+ },
34
+ before_date: {
35
+ type: 'string',
36
+ description: 'Optional: Only include messages before this date (ISO 8601)',
37
+ },
38
+ sender_domains: {
39
+ type: 'array',
40
+ items: { type: 'string' },
41
+ description: 'Optional: Filter by sender email domains (e.g., ["acme.com"])',
42
+ },
43
+ include_body_text: {
44
+ type: 'boolean',
45
+ description: 'Optional: Include full message body text',
46
+ default: true,
47
+ },
48
+ },
49
+ required: ['query'],
50
+ },
51
+ };
52
+ /**
53
+ * Execute the search tool.
54
+ */
55
+ export async function executeSearchTool(client, input) {
56
+ const options = {
57
+ includeBodyText: input.include_body_text !== false,
58
+ };
59
+ if (input.after_date) {
60
+ options.afterDate = input.after_date;
61
+ }
62
+ if (input.before_date) {
63
+ options.beforeDate = input.before_date;
64
+ }
65
+ if (input.sender_domains?.length) {
66
+ options.senderDomains = input.sender_domains;
67
+ }
68
+ const response = await client.search(input.query, options);
69
+ // Format the response for MCP
70
+ const messageCount = response.key_messages?.length ?? 0;
71
+ if (messageCount === 0) {
72
+ return `No messages found matching "${input.query}".`;
73
+ }
74
+ // Defensive check for conversations structure
75
+ if (!response.conversations || typeof response.conversations !== 'object') {
76
+ return `Found ${messageCount} messages, but conversation data is unavailable.`;
77
+ }
78
+ const conversationCount = Object.keys(response.conversations).length;
79
+ let result = `Found ${messageCount} relevant messages across ${conversationCount} conversations:\n`;
80
+ // Track skipped data for warnings
81
+ let skippedConversations = 0;
82
+ let skippedThreads = 0;
83
+ let skippedMessages = 0;
84
+ for (const [convId, conv] of Object.entries(response.conversations)) {
85
+ // Skip malformed conversation entries
86
+ if (!conv || !conv.threads) {
87
+ skippedConversations++;
88
+ continue;
89
+ }
90
+ const convName = conv.conversation_name || `Conversation ${convId}`;
91
+ result += `\n## ${convName}\n`;
92
+ for (const [threadId, messages] of Object.entries(conv.threads)) {
93
+ // Skip malformed thread entries
94
+ if (!Array.isArray(messages)) {
95
+ skippedThreads++;
96
+ continue;
97
+ }
98
+ if (messages.length > 1) {
99
+ result += `\n**Thread (${messages.length} messages):**\n`;
100
+ }
101
+ for (const msg of messages) {
102
+ if (!msg) {
103
+ skippedMessages++;
104
+ continue;
105
+ }
106
+ // Defensive date formatting to handle invalid dates gracefully
107
+ let dateStr = 'Unknown date';
108
+ if (msg.received_at) {
109
+ const parsedDate = new Date(msg.received_at);
110
+ dateStr = Number.isNaN(parsedDate.getTime()) ? 'Invalid date' : parsedDate.toLocaleDateString();
111
+ }
112
+ result += `- **${msg.sender_name || 'Unknown'}** (${dateStr}): `;
113
+ if (msg.body_text) {
114
+ const preview = msg.body_text.length > MAX_BODY_PREVIEW_LENGTH
115
+ ? msg.body_text.substring(0, MAX_BODY_PREVIEW_LENGTH) + '...'
116
+ : msg.body_text;
117
+ result += preview.replace(/\n/g, ' ');
118
+ }
119
+ else {
120
+ result += '[Message content not included]';
121
+ }
122
+ result += '\n';
123
+ }
124
+ }
125
+ }
126
+ // Add warning if data was skipped due to malformed entries
127
+ const totalSkipped = skippedConversations + skippedThreads + skippedMessages;
128
+ if (totalSkipped > 0) {
129
+ const warnings = [];
130
+ if (skippedConversations > 0) {
131
+ warnings.push(`${skippedConversations} conversation(s)`);
132
+ }
133
+ if (skippedThreads > 0) {
134
+ warnings.push(`${skippedThreads} thread(s)`);
135
+ }
136
+ if (skippedMessages > 0) {
137
+ warnings.push(`${skippedMessages} message(s)`);
138
+ }
139
+ result += `\n---\n_Note: ${warnings.join(', ')} skipped due to incomplete data._\n`;
140
+ }
141
+ return result;
142
+ }
143
+ //# sourceMappingURL=search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.js","sourceRoot":"","sources":["../../../../../../packages/mcp/src/tools/search.ts"],"names":[],"mappings":"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"}