@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.
- package/README.md +52 -1
- package/cjs/README.md +247 -0
- package/cjs/bin/attrove-mcp.js +69 -0
- package/cjs/package.json +69 -0
- package/cjs/src/__mocks__/version.js +17 -0
- package/cjs/src/__mocks__/version.js.map +1 -0
- package/cjs/src/constants.js +17 -0
- package/cjs/src/constants.js.map +1 -0
- package/cjs/src/index.js +43 -0
- package/cjs/src/index.js.map +1 -0
- package/cjs/src/server.js +247 -0
- package/cjs/src/server.js.map +1 -0
- package/cjs/src/tools/index.js +26 -0
- package/cjs/src/tools/index.js.map +1 -0
- package/cjs/src/tools/integrations.js +50 -0
- package/cjs/src/tools/integrations.js.map +1 -0
- package/cjs/src/tools/query.js +70 -0
- package/cjs/src/tools/query.js.map +1 -0
- package/cjs/src/tools/search.js +147 -0
- package/cjs/src/tools/search.js.map +1 -0
- package/cjs/src/version.js +142 -0
- package/cjs/src/version.js.map +1 -0
- package/esm/README.md +247 -0
- package/esm/bin/attrove-mcp.js +69 -0
- package/esm/package.json +69 -0
- package/esm/src/__mocks__/version.js +12 -0
- package/esm/src/__mocks__/version.js.map +1 -0
- package/esm/src/constants.js +14 -0
- package/esm/src/constants.js.map +1 -0
- package/esm/src/index.js +32 -0
- package/esm/src/index.js.map +1 -0
- package/esm/src/server.js +241 -0
- package/esm/src/server.js.map +1 -0
- package/esm/src/tools/index.js +19 -0
- package/esm/src/tools/index.js.map +1 -0
- package/esm/src/tools/integrations.js +46 -0
- package/esm/src/tools/integrations.js.map +1 -0
- package/esm/src/tools/query.js +66 -0
- package/esm/src/tools/query.js.map +1 -0
- package/esm/src/tools/search.js +143 -0
- package/esm/src/tools/search.js.map +1 -0
- package/esm/src/version.js +137 -0
- package/esm/src/version.js.map +1 -0
- package/package.json +13 -11
- package/types/src/__mocks__/version.d.ts +7 -0
- package/types/src/constants.d.ts +13 -0
- package/types/src/index.d.ts +32 -0
- package/types/src/server.d.ts +38 -0
- package/types/src/tools/index.d.ts +80 -0
- package/types/src/tools/integrations.d.ts +22 -0
- package/types/src/tools/query.d.ts +47 -0
- package/types/src/tools/search.d.ts +57 -0
- 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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"}
|