airweave-mcp-search 0.5.7

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 ADDED
@@ -0,0 +1,360 @@
1
+ # Airweave MCP Search Server
2
+
3
+ An MCP (Model Context Protocol) server that provides comprehensive search capabilities for Airweave collections. This server allows AI assistants to search through your Airweave data using natural language queries with full parameter control.
4
+
5
+ ## Features
6
+
7
+ - ๐Ÿ” **Enhanced Search Tool**: Query Airweave collections with natural language and full parameter control
8
+ - ๐Ÿค– **AI Completion**: Get AI-processed responses from search results
9
+ - ๐Ÿ“Š **Pagination Control**: Limit results and control pagination with offset
10
+ - โฐ **Recency Bias**: Prioritize recent results with configurable recency weighting
11
+ - โš™๏ธ **Configuration Tool**: View current server configuration
12
+ - ๐Ÿ” **Secure**: Uses API key authentication
13
+ - ๐ŸŒ **Flexible**: Configurable base URL for different environments
14
+ - ๐Ÿงช **Comprehensive Testing**: Full test suite with LLM testing strategy
15
+ - ๐Ÿ—๏ธ **Simple Architecture**: Clean, maintainable code structure without over-engineering
16
+
17
+ ## Version History
18
+
19
+ ### v2.1.0 - Advanced Search Features
20
+
21
+ ๐Ÿš€ **New advanced search capabilities:**
22
+
23
+ - **Advanced Parameters**: Added `score_threshold`, `search_method`, `expansion_strategy`, `enable_reranking`, `enable_query_interpretation`
24
+ - **Smart Endpoint Selection**: Automatically uses POST endpoint for advanced features, GET for basic search
25
+ - **Enhanced AI Integration**: Better parameter extraction from natural language queries
26
+ - **Comprehensive Testing**: Full test suite including LLM simulation tests
27
+
28
+ ### v2.0.0 - Enhanced Search Parameters
29
+
30
+ โš ๏ธ **Major version update with breaking changes:**
31
+
32
+ - **Parameter Structure**: The search tool now uses an object-based parameter structure instead of positional arguments
33
+ - **New Parameters**: Added `limit`, `offset`, and `recency_bias` parameters
34
+ - **Enhanced Validation**: Improved parameter validation with detailed error messages
35
+ - **Version Bump**: Updated from v1.0.7 to v2.0.0
36
+
37
+ **Migration Guide:**
38
+ ```typescript
39
+ // Old format (v1.0.7)
40
+ search("customer feedback", "raw")
41
+
42
+ // New format (v2.0.0+)
43
+ search({ query: "customer feedback", response_type: "raw" })
44
+ ```
45
+
46
+ ## Quick Start
47
+
48
+ ### Installation from npm
49
+
50
+ The easiest way to use this server is via npx:
51
+
52
+ ```bash
53
+ npx airweave-mcp-search
54
+ ```
55
+
56
+ ### Installation from GitHub
57
+ THIS IS NOT CORRECT, THE MCP IS NOT A SEPARATE REPO YET
58
+
59
+ You can also install directly from the GitHub repository:
60
+
61
+ ```bash
62
+ npm install -g https://github.com/your-org/airweave-mcp-search.git
63
+ ```
64
+
65
+ ## Configuration
66
+
67
+ The server requires environment variables to connect to your Airweave instance:
68
+
69
+ ### Required Environment Variables
70
+
71
+ - `AIRWEAVE_API_KEY`: Your Airweave API key (get this from your Airweave dashboard)
72
+ - `AIRWEAVE_COLLECTION`: The readable ID of the collection to search
73
+
74
+ ### Optional Environment Variables
75
+
76
+ - `AIRWEAVE_BASE_URL`: Base URL for the Airweave API (default: `https://api.airweave.ai`)
77
+
78
+ ## Usage with Cursor/Claude Desktop
79
+
80
+ ### 1. Configure in Claude Desktop
81
+
82
+ Add the following to your Claude Desktop configuration file (`~/.cursor/mcp.json` or similar):
83
+
84
+ ```json
85
+ {
86
+ "mcpServers": {
87
+ "airweave-search": {
88
+ "command": "npx",
89
+ "args": ["airweave-mcp-search"],
90
+ "env": {
91
+ "AIRWEAVE_API_KEY": "your-api-key-here",
92
+ "AIRWEAVE_COLLECTION": "your-collection-id",
93
+ "AIRWEAVE_BASE_URL": "https://api.airweave.ai"
94
+ }
95
+ }
96
+ }
97
+ }
98
+ ```
99
+
100
+ ### 2. Local Development Configuration
101
+
102
+ For local development with a self-hosted Airweave instance:
103
+
104
+ ```json
105
+ {
106
+ "mcpServers": {
107
+ "airweave-search": {
108
+ "command": "node",
109
+ "args": ["/absolute/path/to/airweave/mcp/build/index.js"],
110
+ "env": {
111
+ "AIRWEAVE_API_KEY": "your-api-key-here",
112
+ "AIRWEAVE_COLLECTION": "your-collection-id",
113
+ "AIRWEAVE_BASE_URL": "http://localhost:8001"
114
+ }
115
+ }
116
+ }
117
+ }
118
+ ```
119
+
120
+ ### 3. Using the Tools
121
+
122
+ Once configured, you can use natural language to search:
123
+
124
+ - "Search for customer feedback about pricing"
125
+ - "Find documents related to API documentation"
126
+ - "Look up information about data privacy policies"
127
+
128
+ ## Available Tools
129
+
130
+ ### `search-{collection}`
131
+
132
+ Searches within the configured Airweave collection with full parameter control.
133
+
134
+ **Parameters:**
135
+
136
+ **Core Parameters:**
137
+ - `query` (required): The search query text to find relevant documents and data
138
+ - `response_type` (optional, default: "raw"): Format of the response: 'raw' returns search results, 'completion' returns AI-generated answers
139
+ - `limit` (optional, default: 100): Maximum number of results to return (1-1000)
140
+ - `offset` (optional, default: 0): Number of results to skip for pagination (โ‰ฅ0)
141
+ - `recency_bias` (optional): How much to weigh recency vs similarity (0..1). 0 = no recency effect; 1 = rank by recency only
142
+
143
+ **Advanced Parameters:**
144
+ - `score_threshold` (optional): Minimum similarity score threshold (0..1). Only return results above this score
145
+ - `search_method` (optional): Search method: 'hybrid' (default, combines neural + keyword), 'neural' (semantic only), 'keyword' (text matching only)
146
+ - `expansion_strategy` (optional): Query expansion strategy: 'auto' (default, generates query variations), 'llm' (AI-powered expansion), 'no_expansion' (use exact query)
147
+ - `enable_reranking` (optional): Enable LLM-based reranking to improve result relevance (default: true)
148
+ - `enable_query_interpretation` (optional): Enable automatic filter extraction from natural language query (default: true)
149
+
150
+ **Examples:**
151
+ ```typescript
152
+ // Basic search
153
+ search({ query: "customer feedback about pricing" })
154
+
155
+ // Search with AI completion
156
+ search({
157
+ query: "billing issues",
158
+ response_type: "completion"
159
+ })
160
+
161
+ // Paginated search
162
+ search({
163
+ query: "API documentation",
164
+ limit: 10,
165
+ offset: 20
166
+ })
167
+
168
+ // Recent results with recency bias
169
+ search({
170
+ query: "customer complaints",
171
+ recency_bias: 0.8
172
+ })
173
+
174
+ // Advanced search with high-quality results
175
+ search({
176
+ query: "customer complaints",
177
+ score_threshold: 0.8,
178
+ search_method: "neural",
179
+ enable_reranking: true
180
+ })
181
+
182
+ // Fast keyword search without expansion
183
+ search({
184
+ query: "API documentation",
185
+ search_method: "keyword",
186
+ expansion_strategy: "no_expansion",
187
+ enable_reranking: false
188
+ })
189
+
190
+ // Full parameter search
191
+ search({
192
+ query: "support tickets",
193
+ response_type: "completion",
194
+ limit: 5,
195
+ offset: 0,
196
+ recency_bias: 0.7,
197
+ score_threshold: 0.6,
198
+ search_method: "hybrid",
199
+ expansion_strategy: "llm",
200
+ enable_reranking: true,
201
+ enable_query_interpretation: true
202
+ })
203
+ ```
204
+
205
+ ### `get-config`
206
+
207
+ Shows the current server configuration and status.
208
+
209
+ **Parameters:** None
210
+
211
+ **Example:**
212
+ ```
213
+ get-config()
214
+ ```
215
+
216
+ ## API Integration
217
+
218
+ This server interfaces with the Airweave Collections API:
219
+
220
+ - **Endpoint**: `GET /collections/{collection_id}/search`
221
+ - **Authentication**: `x-api-key` header
222
+ - **Query Parameters**:
223
+ - `query`: Search query string
224
+ - `response_type`: `RAW` or `COMPLETION`
225
+
226
+ ## Testing
227
+
228
+ This MCP server includes comprehensive testing to ensure reliability and proper LLM interaction.
229
+
230
+ ### Running Tests
231
+
232
+ ```bash
233
+ # Run all tests
234
+ npm test
235
+
236
+ # Run tests in watch mode
237
+ npm run test:watch
238
+
239
+ # Run tests with coverage
240
+ npm run test:coverage
241
+
242
+ # Run LLM-specific tests
243
+ npm run test:llm
244
+ ```
245
+
246
+ ### Test Categories
247
+
248
+ 1. **Unit Tests**: Parameter validation and schema testing
249
+ 2. **Integration Tests**: API calls and error handling
250
+ 3. **LLM Tests**: How AI assistants interact with the enhanced parameters
251
+
252
+ ### LLM Testing Strategy
253
+
254
+ The server includes a comprehensive LLM testing framework to evaluate how different AI assistants use the enhanced parameters:
255
+
256
+ - **Basic Tests**: Simple parameter usage
257
+ - **Advanced Tests**: Complex parameter combinations
258
+ - **Error Tests**: Invalid parameter handling
259
+ - **Edge Tests**: Boundary conditions and special cases
260
+
261
+ See `tests/llm-testing-strategy.md` for detailed testing methodology.
262
+
263
+ ## Development
264
+
265
+ ### Building from Source
266
+
267
+ 1. Clone the repository:
268
+ ```bash
269
+ git clone <repository-url>
270
+ cd airweave/mcp
271
+ ```
272
+
273
+ 2. Install dependencies:
274
+ ```bash
275
+ npm install
276
+ ```
277
+
278
+ 3. Build the project:
279
+ ```bash
280
+ npm run build
281
+ ```
282
+
283
+ 4. Run locally:
284
+ ```bash
285
+ AIRWEAVE_API_KEY=your-key AIRWEAVE_COLLECTION=your-collection npm run start
286
+ ```
287
+
288
+ ### Development Workflow
289
+
290
+ ```bash
291
+ # Build and run
292
+ npm run dev
293
+
294
+ # Build only
295
+ npm run build
296
+
297
+ # Run built version
298
+ npm run start
299
+
300
+ # Run tests
301
+ npm test
302
+ ```
303
+
304
+ ## Error Handling
305
+
306
+ The server provides detailed error messages for common issues:
307
+
308
+ - **Missing API Key**: Clear message when `AIRWEAVE_API_KEY` is not set
309
+ - **Missing Collection**: Clear message when `AIRWEAVE_COLLECTION` is not set
310
+ - **API Errors**: Detailed error messages from the Airweave API
311
+ - **Network Issues**: Connection and timeout error handling
312
+
313
+ ## Security
314
+
315
+ - API keys are never logged or exposed in responses
316
+ - All requests use HTTPS (when using the default base URL)
317
+ - Environment variables are validated at startup
318
+
319
+ ## Troubleshooting
320
+
321
+ ### Common Issues
322
+
323
+ 1. **"Error: AIRWEAVE_API_KEY environment variable is required"**
324
+ - Make sure you've set the `AIRWEAVE_API_KEY` environment variable
325
+ - Check that your API key is valid and has access to the collection
326
+
327
+ 2. **"Error: AIRWEAVE_COLLECTION environment variable is required"**
328
+ - Set the `AIRWEAVE_COLLECTION` environment variable to your collection's readable ID
329
+ - Verify the collection ID exists in your Airweave instance
330
+
331
+ 3. **"Airweave API error (404)"**
332
+ - Check that the collection ID is correct
333
+ - Verify the collection exists and you have access to it
334
+
335
+ 4. **"Airweave API error (401)"**
336
+ - Check that your API key is valid
337
+ - Ensure the API key has the necessary permissions
338
+
339
+ ### Debug Mode
340
+
341
+ For debugging, you can check the stderr output where the server logs its startup information:
342
+
343
+ ```bash
344
+ # The server logs to stderr (won't interfere with MCP protocol)
345
+ # Look for messages like:
346
+ # "Airweave MCP Search Server started"
347
+ # "Collection: your-collection-id"
348
+ # "Base URL: https://api.airweave.ai"
349
+ ```
350
+
351
+ ## License
352
+
353
+ MIT License - see LICENSE file for details.
354
+
355
+ ## Support
356
+
357
+ For issues and questions:
358
+ - Check the [Airweave documentation](https://docs.airweave.ai)
359
+ - Open an issue on GitHub
360
+ - Contact your Airweave administrator for API key and access issues
@@ -0,0 +1,10 @@
1
+ import { AirweaveConfig, SearchResponse } from './types.js';
2
+ export declare class AirweaveClient {
3
+ private config;
4
+ private client;
5
+ constructor(config: AirweaveConfig);
6
+ search(searchRequest: any): Promise<SearchResponse>;
7
+ private hasAdvancedParameters;
8
+ private getMockResponse;
9
+ }
10
+ //# sourceMappingURL=airweave-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"airweave-client.d.ts","sourceRoot":"","sources":["../../src/api/airweave-client.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE5D,qBAAa,cAAc;IAGX,OAAO,CAAC,MAAM;IAF1B,OAAO,CAAC,MAAM,CAAoB;gBAEd,MAAM,EAAE,cAAc;IAOpC,MAAM,CAAC,aAAa,EAAE,GAAG,GAAG,OAAO,CAAC,cAAc,CAAC;IAoCzD,OAAO,CAAC,qBAAqB;IAU7B,OAAO,CAAC,eAAe;CAkD1B"}
@@ -0,0 +1,102 @@
1
+ // Airweave API client using the official SDK
2
+ import { AirweaveSDKClient } from '@airweave/sdk';
3
+ export class AirweaveClient {
4
+ config;
5
+ client;
6
+ constructor(config) {
7
+ this.config = config;
8
+ this.client = new AirweaveSDKClient({
9
+ apiKey: config.apiKey,
10
+ baseUrl: config.baseUrl
11
+ });
12
+ }
13
+ async search(searchRequest) {
14
+ // Mock mode for testing
15
+ if (this.config.apiKey === 'test-key' && this.config.baseUrl.includes('localhost')) {
16
+ return this.getMockResponse(searchRequest);
17
+ }
18
+ try {
19
+ // Check if this should use advanced search (POST endpoint)
20
+ const hasAdvancedParams = this.hasAdvancedParameters(searchRequest);
21
+ if (hasAdvancedParams) {
22
+ // Use the official SDK for advanced search
23
+ const response = await this.client.collections.searchAdvanced(this.config.collection, searchRequest);
24
+ return response;
25
+ }
26
+ else {
27
+ // Use the official SDK for basic search
28
+ const { query, response_type, limit, offset, recency_bias } = searchRequest;
29
+ const response = await this.client.collections.search(this.config.collection, {
30
+ query,
31
+ response_type,
32
+ limit,
33
+ offset,
34
+ recency_bias
35
+ });
36
+ return response;
37
+ }
38
+ }
39
+ catch (error) {
40
+ // Handle SDK errors and convert to our error format
41
+ if (error.statusCode) {
42
+ throw new Error(`Airweave API error (${error.statusCode}): ${error.message}`);
43
+ }
44
+ else {
45
+ throw new Error(`Airweave API error: ${error.message}`);
46
+ }
47
+ }
48
+ }
49
+ hasAdvancedParameters(params) {
50
+ return !!(params.score_threshold !== undefined ||
51
+ params.search_method !== undefined ||
52
+ params.expansion_strategy !== undefined ||
53
+ params.enable_reranking !== undefined ||
54
+ params.enable_query_interpretation !== undefined);
55
+ }
56
+ getMockResponse(request) {
57
+ const { query, response_type, limit, offset, recency_bias, score_threshold, search_method, expansion_strategy, enable_reranking, enable_query_interpretation } = request;
58
+ // Generate mock results based on the query
59
+ const mockResults = [];
60
+ const resultCount = Math.min(limit || 100, 5); // Limit to 5 for testing
61
+ const hasAdvancedParams = this.hasAdvancedParameters(request);
62
+ for (let i = 0; i < resultCount; i++) {
63
+ const score = 0.95 - (i * 0.1);
64
+ // Apply score threshold if specified
65
+ if (score_threshold !== undefined && score < score_threshold) {
66
+ continue;
67
+ }
68
+ mockResults.push({
69
+ score: score,
70
+ payload: {
71
+ source_name: `Mock Source ${i + 1}`,
72
+ entity_id: `mock_${i + 1}`,
73
+ title: `Mock Document ${i + 1} about "${query}"`,
74
+ md_content: `This is a mock response for the query "${query}". This document contains relevant information about ${query} and demonstrates how the MCP server would return search results.`,
75
+ created_at: new Date(Date.now() - (i * 24 * 60 * 60 * 1000)).toISOString(), // Different dates
76
+ metadata: {
77
+ test: true,
78
+ query: query,
79
+ limit: limit,
80
+ offset: offset,
81
+ recency_bias: recency_bias,
82
+ score_threshold: score_threshold,
83
+ search_method: search_method,
84
+ expansion_strategy: expansion_strategy,
85
+ enable_reranking: enable_reranking,
86
+ enable_query_interpretation: enable_query_interpretation,
87
+ used_advanced_search: hasAdvancedParams
88
+ }
89
+ }
90
+ });
91
+ }
92
+ return {
93
+ results: mockResults,
94
+ response_type: response_type || "raw",
95
+ status: "success",
96
+ completion: response_type === "completion"
97
+ ? `Based on the search results for "${query}", here's a comprehensive summary of the findings...`
98
+ : undefined
99
+ };
100
+ }
101
+ }
102
+ //# sourceMappingURL=airweave-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"airweave-client.js","sourceRoot":"","sources":["../../src/api/airweave-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import { AirweaveSDK } from '@airweave/sdk';
2
+ export type SearchResponse = AirweaveSDK.SearchResponse;
3
+ export type SearchRequest = AirweaveSDK.SearchRequest;
4
+ export interface AirweaveConfig {
5
+ apiKey: string;
6
+ collection: string;
7
+ baseUrl: string;
8
+ }
9
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/api/types.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAG5C,MAAM,MAAM,cAAc,GAAG,WAAW,CAAC,cAAc,CAAC;AACxD,MAAM,MAAM,aAAa,GAAG,WAAW,CAAC,aAAa,CAAC;AAGtD,MAAM,WAAW,cAAc;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CACnB"}
@@ -0,0 +1,3 @@
1
+ // Type definitions for Airweave API responses
2
+ export {};
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/api/types.ts"],"names":[],"mappings":"AAAA,8CAA8C"}
@@ -0,0 +1,21 @@
1
+ export declare const DEFAULT_BASE_URL = "https://api.airweave.ai";
2
+ export declare const DEFAULT_LIMIT = 100;
3
+ export declare const DEFAULT_OFFSET = 0;
4
+ export declare const DEFAULT_RESPONSE_TYPE = "raw";
5
+ export declare const PARAMETER_LIMITS: {
6
+ readonly QUERY_MIN_LENGTH: 1;
7
+ readonly QUERY_MAX_LENGTH: 1000;
8
+ readonly LIMIT_MIN: 1;
9
+ readonly LIMIT_MAX: 1000;
10
+ readonly OFFSET_MIN: 0;
11
+ readonly RECENCY_BIAS_MIN: 0;
12
+ readonly RECENCY_BIAS_MAX: 1;
13
+ };
14
+ export declare const ERROR_MESSAGES: {
15
+ readonly MISSING_API_KEY: "Error: AIRWEAVE_API_KEY environment variable is required";
16
+ readonly MISSING_COLLECTION: "Error: AIRWEAVE_COLLECTION environment variable is required";
17
+ readonly INVALID_JSON_RESPONSE: "Invalid JSON response";
18
+ readonly API_ERROR: "Airweave API error";
19
+ readonly PARAMETER_VALIDATION_ERROR: "Parameter Validation Errors";
20
+ };
21
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/config/constants.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,gBAAgB,4BAA4B,CAAC;AAC1D,eAAO,MAAM,aAAa,MAAM,CAAC;AACjC,eAAO,MAAM,cAAc,IAAI,CAAC;AAChC,eAAO,MAAM,qBAAqB,QAAQ,CAAC;AAE3C,eAAO,MAAM,gBAAgB;;;;;;;;CAQnB,CAAC;AAEX,eAAO,MAAM,cAAc;;;;;;CAMjB,CAAC"}
@@ -0,0 +1,22 @@
1
+ // Configuration constants for the MCP server
2
+ export const DEFAULT_BASE_URL = "https://api.airweave.ai";
3
+ export const DEFAULT_LIMIT = 100;
4
+ export const DEFAULT_OFFSET = 0;
5
+ export const DEFAULT_RESPONSE_TYPE = "raw";
6
+ export const PARAMETER_LIMITS = {
7
+ QUERY_MIN_LENGTH: 1,
8
+ QUERY_MAX_LENGTH: 1000,
9
+ LIMIT_MIN: 1,
10
+ LIMIT_MAX: 1000,
11
+ OFFSET_MIN: 0,
12
+ RECENCY_BIAS_MIN: 0.0,
13
+ RECENCY_BIAS_MAX: 1.0
14
+ };
15
+ export const ERROR_MESSAGES = {
16
+ MISSING_API_KEY: "Error: AIRWEAVE_API_KEY environment variable is required",
17
+ MISSING_COLLECTION: "Error: AIRWEAVE_COLLECTION environment variable is required",
18
+ INVALID_JSON_RESPONSE: "Invalid JSON response",
19
+ API_ERROR: "Airweave API error",
20
+ PARAMETER_VALIDATION_ERROR: "Parameter Validation Errors"
21
+ };
22
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/config/constants.ts"],"names":[],"mappings":"AAAA,6CAA6C;AAE7C,MAAM,CAAC,MAAM,gBAAgB,GAAG,yBAAyB,CAAC;AAC1D,MAAM,CAAC,MAAM,aAAa,GAAG,GAAG,CAAC;AACjC,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC;AAChC,MAAM,CAAC,MAAM,qBAAqB,GAAG,KAAK,CAAC;AAE3C,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC5B,gBAAgB,EAAE,CAAC;IACnB,gBAAgB,EAAE,IAAI;IACtB,SAAS,EAAE,CAAC;IACZ,SAAS,EAAE,IAAI;IACf,UAAU,EAAE,CAAC;IACb,gBAAgB,EAAE,GAAG;IACrB,gBAAgB,EAAE,GAAG;CACf,CAAC;AAEX,MAAM,CAAC,MAAM,cAAc,GAAG;IAC1B,eAAe,EAAE,0DAA0D;IAC3E,kBAAkB,EAAE,6DAA6D;IACjF,qBAAqB,EAAE,uBAAuB;IAC9C,SAAS,EAAE,oBAAoB;IAC/B,0BAA0B,EAAE,6BAA6B;CACnD,CAAC"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/build/index.js ADDED
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env node
2
+ // Main entry point for the Airweave MCP Search Server
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import { createMcpServer, validateEnvironment } from "./server.js";
5
+ // Validate environment variables and get configuration
6
+ const config = validateEnvironment();
7
+ // Create MCP server
8
+ const server = createMcpServer(config);
9
+ // Main function to start the server
10
+ async function main() {
11
+ const transport = new StdioServerTransport();
12
+ await server.connect(transport);
13
+ // Log to stderr so it doesn't interfere with MCP protocol
14
+ console.error("Airweave MCP Search Server started");
15
+ console.error(`Collection: ${config.collection}`);
16
+ console.error(`Base URL: ${config.baseUrl}`);
17
+ }
18
+ // Handle graceful shutdown
19
+ process.on("SIGINT", () => {
20
+ console.error("Shutting down Airweave MCP server...");
21
+ process.exit(0);
22
+ });
23
+ process.on("SIGTERM", () => {
24
+ console.error("Shutting down Airweave MCP server...");
25
+ process.exit(0);
26
+ });
27
+ // Start the server
28
+ main().catch((error) => {
29
+ console.error("Fatal error in Airweave MCP server:", error);
30
+ process.exit(1);
31
+ });
32
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,sDAAsD;AAEtD,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAEnE,uDAAuD;AACvD,MAAM,MAAM,GAAG,mBAAmB,EAAE,CAAC;AAErC,oBAAoB;AACpB,MAAM,MAAM,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;AAEvC,oCAAoC;AACpC,KAAK,UAAU,IAAI;IACjB,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAEhC,0DAA0D;IAC1D,OAAO,CAAC,KAAK,CAAC,oCAAoC,CAAC,CAAC;IACpD,OAAO,CAAC,KAAK,CAAC,eAAe,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;IAClD,OAAO,CAAC,KAAK,CAAC,aAAa,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;AAC/C,CAAC;AAED,2BAA2B;AAC3B,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;IACxB,OAAO,CAAC,KAAK,CAAC,sCAAsC,CAAC,CAAC;IACtD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC;AAEH,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE;IACzB,OAAO,CAAC,KAAK,CAAC,sCAAsC,CAAC,CAAC;IACtD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC;AAEH,mBAAmB;AACnB,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,OAAO,CAAC,KAAK,CAAC,qCAAqC,EAAE,KAAK,CAAC,CAAC;IAC5D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,5 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { AirweaveConfig } from "./api/types.js";
3
+ export declare function createMcpServer(config: AirweaveConfig): McpServer;
4
+ export declare function validateEnvironment(): AirweaveConfig;
5
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAKhD,wBAAgB,eAAe,CAAC,MAAM,EAAE,cAAc,aAoCrD;AAED,wBAAgB,mBAAmB,IAAI,cAAc,CAgBpD"}
@@ -0,0 +1,42 @@
1
+ // MCP server setup and tool registration
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { AirweaveClient } from "./api/airweave-client.js";
4
+ import { createSearchTool } from "./tools/search-tool.js";
5
+ import { createConfigTool } from "./tools/config-tool.js";
6
+ import { DEFAULT_BASE_URL, ERROR_MESSAGES } from "./config/constants.js";
7
+ export function createMcpServer(config) {
8
+ // Create MCP server instance
9
+ const server = new McpServer({
10
+ name: "airweave-search",
11
+ version: "2.1.0", // Minor version bump for advanced search features
12
+ capabilities: {
13
+ tools: {},
14
+ },
15
+ });
16
+ // Create dynamic tool name based on collection
17
+ const toolName = `search-${config.collection}`;
18
+ // Initialize Airweave client
19
+ const airweaveClient = new AirweaveClient(config);
20
+ // Create tools
21
+ const searchTool = createSearchTool(toolName, config.collection, airweaveClient);
22
+ const configTool = createConfigTool(toolName, config.collection, config.baseUrl, config.apiKey);
23
+ // Register tools
24
+ server.tool(searchTool.name, searchTool.description, searchTool.schema, searchTool.handler);
25
+ server.tool(configTool.name, configTool.description, configTool.schema, configTool.handler);
26
+ return server;
27
+ }
28
+ export function validateEnvironment() {
29
+ const apiKey = process.env.AIRWEAVE_API_KEY;
30
+ const collection = process.env.AIRWEAVE_COLLECTION;
31
+ const baseUrl = process.env.AIRWEAVE_BASE_URL || DEFAULT_BASE_URL;
32
+ if (!apiKey) {
33
+ console.error(ERROR_MESSAGES.MISSING_API_KEY);
34
+ process.exit(1);
35
+ }
36
+ if (!collection) {
37
+ console.error(ERROR_MESSAGES.MISSING_COLLECTION);
38
+ process.exit(1);
39
+ }
40
+ return { apiKey, collection, baseUrl };
41
+ }
42
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,yCAAyC;AAEzC,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAE1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEzE,MAAM,UAAU,eAAe,CAAC,MAAsB;IAClD,6BAA6B;IAC7B,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QACzB,IAAI,EAAE,iBAAiB;QACvB,OAAO,EAAE,OAAO,EAAE,kDAAkD;QACpE,YAAY,EAAE;YACV,KAAK,EAAE,EAAE;SACZ;KACJ,CAAC,CAAC;IAEH,+CAA+C;IAC/C,MAAM,QAAQ,GAAG,UAAU,MAAM,CAAC,UAAU,EAAE,CAAC;IAE/C,6BAA6B;IAC7B,MAAM,cAAc,GAAG,IAAI,cAAc,CAAC,MAAM,CAAC,CAAC;IAElD,eAAe;IACf,MAAM,UAAU,GAAG,gBAAgB,CAAC,QAAQ,EAAE,MAAM,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC;IACjF,MAAM,UAAU,GAAG,gBAAgB,CAAC,QAAQ,EAAE,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IAEhG,iBAAiB;IACjB,MAAM,CAAC,IAAI,CACP,UAAU,CAAC,IAAI,EACf,UAAU,CAAC,WAAW,EACtB,UAAU,CAAC,MAAM,EACjB,UAAU,CAAC,OAAO,CACrB,CAAC;IAEF,MAAM,CAAC,IAAI,CACP,UAAU,CAAC,IAAI,EACf,UAAU,CAAC,WAAW,EACtB,UAAU,CAAC,MAAM,EACjB,UAAU,CAAC,OAAO,CACrB,CAAC;IAEF,OAAO,MAAM,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,mBAAmB;IAC/B,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;IAC5C,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC;IACnD,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,gBAAgB,CAAC;IAElE,IAAI,CAAC,MAAM,EAAE,CAAC;QACV,OAAO,CAAC,KAAK,CAAC,cAAc,CAAC,eAAe,CAAC,CAAC;QAC9C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;IAED,IAAI,CAAC,UAAU,EAAE,CAAC;QACd,OAAO,CAAC,KAAK,CAAC,cAAc,CAAC,kBAAkB,CAAC,CAAC;QACjD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC;AAC3C,CAAC"}
@@ -0,0 +1,12 @@
1
+ export declare function createConfigTool(toolName: string, collection: string, baseUrl: string, apiKey: string): {
2
+ name: string;
3
+ description: string;
4
+ schema: {};
5
+ handler: () => Promise<{
6
+ content: {
7
+ type: "text";
8
+ text: string;
9
+ }[];
10
+ }>;
11
+ };
12
+ //# sourceMappingURL=config-tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-tool.d.ts","sourceRoot":"","sources":["../../src/tools/config-tool.ts"],"names":[],"mappings":"AAEA,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;;;;;;;;;;EA0BrG"}
@@ -0,0 +1,29 @@
1
+ // Configuration tool implementation
2
+ export function createConfigTool(toolName, collection, baseUrl, apiKey) {
3
+ return {
4
+ name: "get-config",
5
+ description: "Get the current Airweave MCP server configuration",
6
+ schema: {}, // Empty schema for no parameters
7
+ handler: async () => {
8
+ return {
9
+ content: [
10
+ {
11
+ type: "text",
12
+ text: [
13
+ "**Airweave MCP Server Configuration:**",
14
+ "",
15
+ `- **Collection ID:** ${collection}`,
16
+ `- **Base URL:** ${baseUrl}`,
17
+ `- **API Key:** ${apiKey ? "โœ“ Configured" : "โœ— Missing"}`,
18
+ "",
19
+ "**Available Commands:**",
20
+ `- \`${toolName}\`: Search within the configured Airweave collection`,
21
+ "- `get-config`: Show this configuration information",
22
+ ].join("\n"),
23
+ },
24
+ ],
25
+ };
26
+ }
27
+ };
28
+ }
29
+ //# sourceMappingURL=config-tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-tool.js","sourceRoot":"","sources":["../../src/tools/config-tool.ts"],"names":[],"mappings":"AAAA,oCAAoC;AAEpC,MAAM,UAAU,gBAAgB,CAAC,QAAgB,EAAE,UAAkB,EAAE,OAAe,EAAE,MAAc;IAClG,OAAO;QACH,IAAI,EAAE,YAAY;QAClB,WAAW,EAAE,mDAAmD;QAChE,MAAM,EAAE,EAAE,EAAE,iCAAiC;QAC7C,OAAO,EAAE,KAAK,IAAI,EAAE;YAChB,OAAO;gBACH,OAAO,EAAE;oBACL;wBACI,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE;4BACF,wCAAwC;4BACxC,EAAE;4BACF,wBAAwB,UAAU,EAAE;4BACpC,mBAAmB,OAAO,EAAE;4BAC5B,kBAAkB,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,WAAW,EAAE;4BACzD,EAAE;4BACF,yBAAyB;4BACzB,OAAO,QAAQ,sDAAsD;4BACrE,qDAAqD;yBACxD,CAAC,IAAI,CAAC,IAAI,CAAC;qBACf;iBACJ;aACJ,CAAC;QACN,CAAC;KACJ,CAAC;AACN,CAAC"}
@@ -0,0 +1,25 @@
1
+ import { z } from "zod";
2
+ import { AirweaveClient } from "../api/airweave-client.js";
3
+ export declare function createSearchTool(toolName: string, collection: string, airweaveClient: AirweaveClient): {
4
+ name: string;
5
+ description: string;
6
+ schema: {
7
+ query: z.ZodString;
8
+ response_type: z.ZodDefault<z.ZodOptional<z.ZodEnum<["raw", "completion"]>>>;
9
+ limit: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
10
+ offset: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
11
+ recency_bias: z.ZodOptional<z.ZodNumber>;
12
+ score_threshold: z.ZodOptional<z.ZodNumber>;
13
+ search_method: z.ZodOptional<z.ZodEnum<["hybrid", "neural", "keyword"]>>;
14
+ expansion_strategy: z.ZodOptional<z.ZodEnum<["auto", "llm", "no_expansion"]>>;
15
+ enable_reranking: z.ZodOptional<z.ZodBoolean>;
16
+ enable_query_interpretation: z.ZodOptional<z.ZodBoolean>;
17
+ };
18
+ handler: (params: any) => Promise<{
19
+ content: {
20
+ type: "text";
21
+ text: string;
22
+ }[];
23
+ }>;
24
+ };
25
+ //# sourceMappingURL=search-tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search-tool.d.ts","sourceRoot":"","sources":["../../src/tools/search-tool.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAG3D,wBAAgB,gBAAgB,CAC5B,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,cAAc,EAAE,cAAc;;;;;;;;;;;;;;;sBA2DF,GAAG;;;;;;EA4BlC"}
@@ -0,0 +1,84 @@
1
+ // Search tool implementation
2
+ import { z } from "zod";
3
+ import { formatSearchResponse, formatErrorResponse } from "../utils/error-handling.js";
4
+ export function createSearchTool(toolName, collection, airweaveClient) {
5
+ // Define the enhanced schema shape for MCP SDK (ZodRawShape format)
6
+ const searchSchema = {
7
+ // Core parameters (existing)
8
+ query: z.string().min(1).max(1000).describe("The search query text to find relevant documents and data"),
9
+ response_type: z.enum(["raw", "completion"]).optional().default("raw").describe("Format of the response: 'raw' returns search results, 'completion' returns AI-generated answers"),
10
+ limit: z.number().min(1).max(1000).optional().default(100).describe("Maximum number of results to return"),
11
+ offset: z.number().min(0).optional().default(0).describe("Number of results to skip for pagination"),
12
+ recency_bias: z.number().min(0).max(1).optional().describe("How much to weigh recency vs similarity (0..1). 0 = no recency effect; 1 = rank by recency only"),
13
+ // Advanced parameters (Phase 1 - safe parameters)
14
+ score_threshold: z.number().min(0).max(1).optional().describe("Minimum similarity score threshold (0..1). Only return results above this score"),
15
+ search_method: z.enum(["hybrid", "neural", "keyword"]).optional().describe("Search method: 'hybrid' (combines neural + keyword), 'neural' (semantic only), 'keyword' (text matching only)"),
16
+ expansion_strategy: z.enum(["auto", "llm", "no_expansion"]).optional().describe("Query expansion strategy: 'auto' (generates query variations), 'llm' (AI-powered expansion), 'no_expansion' (use exact query)"),
17
+ enable_reranking: z.boolean().optional().describe("Enable LLM-based reranking to improve result relevance"),
18
+ enable_query_interpretation: z.boolean().optional().describe("Enable automatic filter extraction from natural language query")
19
+ };
20
+ // Create the full schema for validation
21
+ const fullSchema = z.object(searchSchema);
22
+ const parameterDescriptions = [
23
+ "**Core Parameters:**",
24
+ "- `query`: The search query text to find relevant documents and data (required)",
25
+ "- `response_type`: Format of the response: 'raw' returns search results, 'completion' returns AI-generated answers (optional, default: raw)",
26
+ "- `limit`: Maximum number of results to return (optional, default: 100)",
27
+ "- `offset`: Number of results to skip for pagination (optional, default: 0)",
28
+ "- `recency_bias`: How much to weigh recency vs similarity (0..1). 0 = no recency effect; 1 = rank by recency only (optional)",
29
+ "",
30
+ "**Advanced Parameters:**",
31
+ "- `score_threshold`: Minimum similarity score threshold (0..1). Only return results above this score (optional)",
32
+ "- `search_method`: Search method: 'hybrid' (default, combines neural + keyword), 'neural' (semantic only), 'keyword' (text matching only) (optional)",
33
+ "- `expansion_strategy`: Query expansion strategy: 'auto' (default, generates query variations), 'llm' (AI-powered expansion), 'no_expansion' (use exact query) (optional)",
34
+ "- `enable_reranking`: Enable LLM-based reranking to improve result relevance (default: true) (optional)",
35
+ "- `enable_query_interpretation`: Enable automatic filter extraction from natural language query (default: true) (optional)"
36
+ ].join("\n");
37
+ const naturalLanguageExamples = [
38
+ "**Natural Language Examples:**",
39
+ "",
40
+ "**Basic Search:**",
41
+ "- 'Find the first 5 results' โ†’ limit: 5",
42
+ "- 'Show me results 11-20' โ†’ limit: 10, offset: 10",
43
+ "- 'Give me a summary' โ†’ response_type: 'completion'",
44
+ "- 'Find the most recent documents' โ†’ recency_bias: 0.8",
45
+ "",
46
+ "**Advanced Search:**",
47
+ "- 'Find high-quality results only' โ†’ score_threshold: 0.8",
48
+ "- 'Use keyword search instead of semantic' โ†’ search_method: 'keyword'",
49
+ "- 'Don't expand my query' โ†’ expansion_strategy: 'no_expansion'",
50
+ "- 'Disable reranking' โ†’ enable_reranking: false",
51
+ "- 'Find recent high-quality results' โ†’ recency_bias: 0.7, score_threshold: 0.8"
52
+ ].join("\n");
53
+ return {
54
+ name: toolName,
55
+ description: `Enhanced search within the Airweave collection '${collection}' with advanced filtering and ranking options.\n\n**Parameters:**\n${parameterDescriptions}\n\n${naturalLanguageExamples}`,
56
+ schema: searchSchema, // Use the shape, not the full ZodObject
57
+ handler: async (params) => {
58
+ try {
59
+ // Zod will automatically validate and apply defaults
60
+ const validatedParams = fullSchema.parse(params);
61
+ const { response_type } = validatedParams;
62
+ const searchResponse = await airweaveClient.search(validatedParams);
63
+ return formatSearchResponse(searchResponse, response_type);
64
+ }
65
+ catch (error) {
66
+ console.error("Error in search tool:", error);
67
+ if (error instanceof z.ZodError) {
68
+ // Handle validation errors
69
+ const errorMessages = error.errors.map(e => `${e.path.join('.')}: ${e.message}`);
70
+ return {
71
+ content: [
72
+ {
73
+ type: "text",
74
+ text: `**Parameter Validation Errors:**\n${errorMessages.join("\n")}`,
75
+ },
76
+ ],
77
+ };
78
+ }
79
+ return formatErrorResponse(error, params);
80
+ }
81
+ }
82
+ };
83
+ }
84
+ //# sourceMappingURL=search-tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search-tool.js","sourceRoot":"","sources":["../../src/tools/search-tool.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import { SearchResponse } from "../api/types.js";
2
+ export declare function formatSearchResponse(searchResponse: SearchResponse, responseType: string): {
3
+ content: {
4
+ type: "text";
5
+ text: string;
6
+ }[];
7
+ };
8
+ export declare function formatErrorResponse(error: Error, searchRequest: any): {
9
+ content: {
10
+ type: "text";
11
+ text: string;
12
+ }[];
13
+ };
14
+ //# sourceMappingURL=error-handling.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-handling.d.ts","sourceRoot":"","sources":["../../src/utils/error-handling.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAGjD,wBAAgB,oBAAoB,CAAC,cAAc,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM;;;;;EA2CxF;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,KAAK,EAAE,aAAa,EAAE,GAAG;;;;;EAWnE"}
@@ -0,0 +1,55 @@
1
+ // Error handling utilities
2
+ export function formatSearchResponse(searchResponse, responseType) {
3
+ if (responseType === "completion") {
4
+ // For AI completion, return the completion text
5
+ return {
6
+ content: [
7
+ {
8
+ type: "text",
9
+ text: searchResponse.completion || "No response generated",
10
+ },
11
+ ],
12
+ };
13
+ }
14
+ else {
15
+ // For raw results, format the search results simply
16
+ const formattedResults = searchResponse.results
17
+ .map((result, index) => {
18
+ const parts = [
19
+ `**Result ${index + 1}${result.score ? ` (Score: ${result.score.toFixed(3)})` : ""}:**`
20
+ ];
21
+ // Extract content from various possible fields
22
+ const content = result.content || result.text || result.payload?.content || result.payload?.text || JSON.stringify(result, null, 2);
23
+ parts.push(content);
24
+ return parts.join("\n");
25
+ })
26
+ .join("\n\n---\n\n");
27
+ const summaryText = [
28
+ `**Collection:** ${process.env.AIRWEAVE_COLLECTION}`,
29
+ `**Results:** ${searchResponse.results.length}`,
30
+ "",
31
+ formattedResults || "No results found.",
32
+ ].join("\n");
33
+ return {
34
+ content: [
35
+ {
36
+ type: "text",
37
+ text: summaryText,
38
+ },
39
+ ],
40
+ };
41
+ }
42
+ }
43
+ export function formatErrorResponse(error, searchRequest) {
44
+ const errorMessage = error.message;
45
+ return {
46
+ content: [
47
+ {
48
+ type: "text",
49
+ text: `**Error:** Failed to search collection.\n\n**Details:** ${errorMessage}\n\n**Debugging Info:**\n- Collection: ${process.env.AIRWEAVE_COLLECTION}\n- Base URL: ${process.env.AIRWEAVE_BASE_URL || "https://api.airweave.ai"}\n- Endpoint: /collections/${process.env.AIRWEAVE_COLLECTION}/search\n- Parameters: ${JSON.stringify(searchRequest, null, 2)}`,
50
+ },
51
+ ],
52
+ };
53
+ }
54
+ // Validation errors are now handled directly in the search tool
55
+ //# sourceMappingURL=error-handling.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-handling.js","sourceRoot":"","sources":["../../src/utils/error-handling.ts"],"names":[],"mappings":"AAAA,2BAA2B;AAK3B,MAAM,UAAU,oBAAoB,CAAC,cAA8B,EAAE,YAAoB;IACrF,IAAI,YAAY,KAAK,YAAY,EAAE,CAAC;QAChC,gDAAgD;QAChD,OAAO;YACH,OAAO,EAAE;gBACL;oBACI,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,cAAc,CAAC,UAAU,IAAI,uBAAuB;iBAC7D;aACJ;SACJ,CAAC;IACN,CAAC;SAAM,CAAC;QACJ,oDAAoD;QACpD,MAAM,gBAAgB,GAAG,cAAc,CAAC,OAAO;aAC1C,GAAG,CAAC,CAAC,MAAW,EAAE,KAAK,EAAE,EAAE;YACxB,MAAM,KAAK,GAAG;gBACV,YAAY,KAAK,GAAG,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,YAAY,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK;aAC1F,CAAC;YAEF,+CAA+C;YAC/C,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,OAAO,EAAE,OAAO,IAAI,MAAM,CAAC,OAAO,EAAE,IAAI,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;YACpI,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAEpB,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC5B,CAAC,CAAC;aACD,IAAI,CAAC,aAAa,CAAC,CAAC;QAEzB,MAAM,WAAW,GAAG;YAChB,mBAAmB,OAAO,CAAC,GAAG,CAAC,mBAAmB,EAAE;YACpD,gBAAgB,cAAc,CAAC,OAAO,CAAC,MAAM,EAAE;YAC/C,EAAE;YACF,gBAAgB,IAAI,mBAAmB;SAC1C,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAEb,OAAO;YACH,OAAO,EAAE;gBACL;oBACI,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,WAAW;iBACpB;aACJ;SACJ,CAAC;IACN,CAAC;AACL,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,KAAY,EAAE,aAAkB;IAChE,MAAM,YAAY,GAAG,KAAK,CAAC,OAAO,CAAC;IAEnC,OAAO;QACH,OAAO,EAAE;YACL;gBACI,IAAI,EAAE,MAAe;gBACrB,IAAI,EAAE,2DAA2D,YAAY,0CAA0C,OAAO,CAAC,GAAG,CAAC,mBAAmB,iBAAiB,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,yBAAyB,8BAA8B,OAAO,CAAC,GAAG,CAAC,mBAAmB,0BAA0B,IAAI,CAAC,SAAS,CAAC,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE;aACnW;SACJ;KACJ,CAAC;AACN,CAAC;AAED,gEAAgE"}
package/package.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "airweave-mcp-search",
3
+ "version": "0.5.7",
4
+ "description": "MCP server for searching Airweave collections",
5
+ "type": "module",
6
+ "main": "build/index.js",
7
+ "bin": {
8
+ "airweave-mcp-search": "./build/index.js"
9
+ },
10
+ "scripts": {
11
+ "build": "tsc && chmod 755 build/index.js",
12
+ "start": "node build/index.js",
13
+ "dev": "npm run build && npm run start",
14
+ "test": "vitest run",
15
+ "test:watch": "vitest",
16
+ "test:coverage": "vitest run --coverage",
17
+ "test:integration": "vitest run tests/integration-live.test.ts --reporter=verbose",
18
+ "test:llm": "node tests/run-llm-tests.js",
19
+ "test:ci": "npm run test && npm run test:integration && npm run test:llm",
20
+ "prepublishOnly": "npm run build"
21
+ },
22
+ "keywords": [
23
+ "mcp",
24
+ "airweave",
25
+ "search",
26
+ "model-context-protocol",
27
+ "ai",
28
+ "vector-search",
29
+ "claude",
30
+ "cursor"
31
+ ],
32
+ "author": "Airweave",
33
+ "license": "MIT",
34
+ "repository": {
35
+ "type": "git",
36
+ "url": "https://github.com/airweave-ai/airweave.git",
37
+ "directory": "mcp"
38
+ },
39
+ "homepage": "https://airweave.ai",
40
+ "bugs": {
41
+ "url": "https://github.com/airweave-ai/airweave/issues"
42
+ },
43
+ "engines": {
44
+ "node": ">=18.0.0"
45
+ },
46
+ "dependencies": {
47
+ "@airweave/sdk": "^0.5.4",
48
+ "@modelcontextprotocol/sdk": "^1.12.0",
49
+ "zod": "^3.23.8"
50
+ },
51
+ "devDependencies": {
52
+ "@types/node": "^22.10.7",
53
+ "@vitest/coverage-v8": "^2.0.0",
54
+ "typescript": "^5.7.3",
55
+ "vitest": "^2.0.0"
56
+ },
57
+ "files": [
58
+ "build",
59
+ "README.md"
60
+ ]
61
+ }