better-qdrant-mcp-server 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +124 -0
- package/build/index.d.ts +2 -0
- package/build/index.js +347 -0
- package/build/index.js.map +1 -0
- package/build/services/embeddings/base.d.ts +11 -0
- package/build/services/embeddings/base.js +16 -0
- package/build/services/embeddings/base.js.map +1 -0
- package/build/services/embeddings/fastembed.d.ts +11 -0
- package/build/services/embeddings/fastembed.js +34 -0
- package/build/services/embeddings/fastembed.js.map +1 -0
- package/build/services/embeddings/index.d.ts +6 -0
- package/build/services/embeddings/index.js +29 -0
- package/build/services/embeddings/index.js.map +1 -0
- package/build/services/embeddings/ollama.d.ts +10 -0
- package/build/services/embeddings/ollama.js +41 -0
- package/build/services/embeddings/ollama.js.map +1 -0
- package/build/services/embeddings/openai.d.ts +10 -0
- package/build/services/embeddings/openai.js +44 -0
- package/build/services/embeddings/openai.js.map +1 -0
- package/build/services/embeddings/openrouter.d.ts +9 -0
- package/build/services/embeddings/openrouter.js +38 -0
- package/build/services/embeddings/openrouter.js.map +1 -0
- package/build/services/qdrant.d.ts +18 -0
- package/build/services/qdrant.js +215 -0
- package/build/services/qdrant.js.map +1 -0
- package/build/services/text-processing.d.ts +19 -0
- package/build/services/text-processing.js +41 -0
- package/build/services/text-processing.js.map +1 -0
- package/build/types.d.ts +43 -0
- package/build/types.js +2 -0
- package/build/types.js.map +1 -0
- package/package.json +64 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Will Reeves
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# Better Qdrant MCP Server
|
|
2
|
+
|
|
3
|
+
A Model Context Protocol (MCP) server for enhanced Qdrant vector database functionality. This server provides tools for managing Qdrant collections, adding documents, and performing semantic searches.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **List Collections**: View all available Qdrant collections
|
|
8
|
+
- **Add Documents**: Process and add documents to a Qdrant collection with various embedding services
|
|
9
|
+
- **Search**: Perform semantic searches across your vector database
|
|
10
|
+
- **Delete Collection**: Remove collections from your Qdrant database
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install -g better-qdrant-mcp-server
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Or use it directly with npx:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npx better-qdrant-mcp-server
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Configuration
|
|
25
|
+
|
|
26
|
+
The server uses environment variables for configuration. You can set these in a `.env` file in your project root:
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
# Qdrant Configuration
|
|
30
|
+
QDRANT_URL=http://localhost:6333
|
|
31
|
+
QDRANT_API_KEY=your_api_key_if_needed
|
|
32
|
+
|
|
33
|
+
# Embedding Service API Keys
|
|
34
|
+
OPENAI_API_KEY=your_openai_api_key
|
|
35
|
+
OPENROUTER_API_KEY=your_openrouter_api_key
|
|
36
|
+
OLLAMA_ENDPOINT=http://localhost:11434
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Supported Embedding Services
|
|
40
|
+
|
|
41
|
+
- **OpenAI**: Requires an API key
|
|
42
|
+
- **OpenRouter**: Requires an API key
|
|
43
|
+
- **Ollama**: Local embedding models (default endpoint: http://localhost:11434)
|
|
44
|
+
- **FastEmbed**: Local embedding models
|
|
45
|
+
|
|
46
|
+
## Usage with Claude
|
|
47
|
+
|
|
48
|
+
To use this MCP server with Claude, add it to your MCP settings configuration file:
|
|
49
|
+
|
|
50
|
+
```json
|
|
51
|
+
{
|
|
52
|
+
"mcpServers": {
|
|
53
|
+
"better-qdrant": {
|
|
54
|
+
"command": "npx",
|
|
55
|
+
"args": ["better-qdrant-mcp-server"],
|
|
56
|
+
"env": {
|
|
57
|
+
"QDRANT_URL": "http://localhost:6333",
|
|
58
|
+
"OPENAI_API_KEY": "your_openai_api_key"
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Example Commands
|
|
66
|
+
|
|
67
|
+
#### List Collections
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
use_mcp_tool
|
|
71
|
+
server_name: better-qdrant
|
|
72
|
+
tool_name: list_collections
|
|
73
|
+
arguments: {}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
#### Add Documents
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
use_mcp_tool
|
|
80
|
+
server_name: better-qdrant
|
|
81
|
+
tool_name: add_documents
|
|
82
|
+
arguments: {
|
|
83
|
+
"filePath": "/path/to/your/document.pdf",
|
|
84
|
+
"collection": "my-collection",
|
|
85
|
+
"embeddingService": "openai",
|
|
86
|
+
"chunkSize": 1000,
|
|
87
|
+
"chunkOverlap": 200
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
#### Search
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
use_mcp_tool
|
|
95
|
+
server_name: better-qdrant
|
|
96
|
+
tool_name: search
|
|
97
|
+
arguments: {
|
|
98
|
+
"query": "your search query",
|
|
99
|
+
"collection": "my-collection",
|
|
100
|
+
"embeddingService": "openai",
|
|
101
|
+
"limit": 5
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
#### Delete Collection
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
use_mcp_tool
|
|
109
|
+
server_name: better-qdrant
|
|
110
|
+
tool_name: delete_collection
|
|
111
|
+
arguments: {
|
|
112
|
+
"collection": "my-collection"
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Requirements
|
|
117
|
+
|
|
118
|
+
- Node.js >= 18.0.0
|
|
119
|
+
- A running Qdrant server (local or remote)
|
|
120
|
+
- API keys for the embedding services you want to use
|
|
121
|
+
|
|
122
|
+
## License
|
|
123
|
+
|
|
124
|
+
MIT
|
package/build/index.d.ts
ADDED
package/build/index.js
ADDED
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
3
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
|
+
import { CallToolRequestSchema, ErrorCode, ListToolsRequestSchema, McpError, } from '@modelcontextprotocol/sdk/types.js';
|
|
5
|
+
import { config } from 'dotenv';
|
|
6
|
+
import { createQdrantService } from './services/qdrant.js';
|
|
7
|
+
import { createEmbeddingService } from './services/embeddings/index.js';
|
|
8
|
+
import { TextProcessor } from './services/text-processing.js';
|
|
9
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
10
|
+
import { readFileSync } from 'fs';
|
|
11
|
+
// Load environment variables
|
|
12
|
+
config();
|
|
13
|
+
class BetterQdrantServer {
|
|
14
|
+
constructor() {
|
|
15
|
+
this.server = new Server({
|
|
16
|
+
name: 'better-qdrant',
|
|
17
|
+
version: '0.1.0',
|
|
18
|
+
}, {
|
|
19
|
+
capabilities: {
|
|
20
|
+
tools: {},
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
// Initialize services
|
|
24
|
+
this.qdrantService = createQdrantService(process.env.QDRANT_URL || 'http://localhost:6333', process.env.QDRANT_API_KEY);
|
|
25
|
+
this.textProcessor = new TextProcessor();
|
|
26
|
+
this.setupToolHandlers();
|
|
27
|
+
// Error handling
|
|
28
|
+
this.server.onerror = (error) => console.error('[MCP Error]', error);
|
|
29
|
+
process.on('SIGINT', async () => {
|
|
30
|
+
await this.server.close();
|
|
31
|
+
process.exit(0);
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
isAddDocumentsArgs(args) {
|
|
35
|
+
if (!args || typeof args !== 'object')
|
|
36
|
+
return false;
|
|
37
|
+
const a = args;
|
|
38
|
+
return (typeof a.filePath === 'string' &&
|
|
39
|
+
typeof a.collection === 'string' &&
|
|
40
|
+
typeof a.embeddingService === 'string' &&
|
|
41
|
+
['openai', 'openrouter', 'fastembed', 'ollama'].includes(a.embeddingService) &&
|
|
42
|
+
(a.chunkSize === undefined || typeof a.chunkSize === 'number') &&
|
|
43
|
+
(a.chunkOverlap === undefined || typeof a.chunkOverlap === 'number'));
|
|
44
|
+
}
|
|
45
|
+
isSearchArgs(args) {
|
|
46
|
+
if (!args || typeof args !== 'object')
|
|
47
|
+
return false;
|
|
48
|
+
const a = args;
|
|
49
|
+
return (typeof a.query === 'string' &&
|
|
50
|
+
typeof a.collection === 'string' &&
|
|
51
|
+
typeof a.embeddingService === 'string' &&
|
|
52
|
+
['openai', 'openrouter', 'fastembed', 'ollama'].includes(a.embeddingService) &&
|
|
53
|
+
(a.limit === undefined || typeof a.limit === 'number'));
|
|
54
|
+
}
|
|
55
|
+
isDeleteCollectionArgs(args) {
|
|
56
|
+
if (!args || typeof args !== 'object')
|
|
57
|
+
return false;
|
|
58
|
+
const a = args;
|
|
59
|
+
return typeof a.collection === 'string';
|
|
60
|
+
}
|
|
61
|
+
setupToolHandlers() {
|
|
62
|
+
this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
63
|
+
tools: [
|
|
64
|
+
{
|
|
65
|
+
name: 'list_collections',
|
|
66
|
+
description: 'List all available Qdrant collections',
|
|
67
|
+
inputSchema: {
|
|
68
|
+
type: 'object',
|
|
69
|
+
properties: {},
|
|
70
|
+
required: [],
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
name: 'add_documents',
|
|
75
|
+
description: 'Add documents to a Qdrant collection with specified embedding service',
|
|
76
|
+
inputSchema: {
|
|
77
|
+
type: 'object',
|
|
78
|
+
properties: {
|
|
79
|
+
filePath: {
|
|
80
|
+
type: 'string',
|
|
81
|
+
description: 'Path to the file to process',
|
|
82
|
+
},
|
|
83
|
+
collection: {
|
|
84
|
+
type: 'string',
|
|
85
|
+
description: 'Name of the collection to add documents to',
|
|
86
|
+
},
|
|
87
|
+
embeddingService: {
|
|
88
|
+
type: 'string',
|
|
89
|
+
enum: ['openai', 'openrouter', 'fastembed', 'ollama'],
|
|
90
|
+
description: 'Embedding service to use',
|
|
91
|
+
},
|
|
92
|
+
chunkSize: {
|
|
93
|
+
type: 'number',
|
|
94
|
+
description: 'Size of text chunks (optional)',
|
|
95
|
+
},
|
|
96
|
+
chunkOverlap: {
|
|
97
|
+
type: 'number',
|
|
98
|
+
description: 'Overlap between chunks (optional)',
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
required: ['filePath', 'collection', 'embeddingService'],
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
name: 'search',
|
|
106
|
+
description: 'Search for similar documents in a collection',
|
|
107
|
+
inputSchema: {
|
|
108
|
+
type: 'object',
|
|
109
|
+
properties: {
|
|
110
|
+
query: {
|
|
111
|
+
type: 'string',
|
|
112
|
+
description: 'Search query',
|
|
113
|
+
},
|
|
114
|
+
collection: {
|
|
115
|
+
type: 'string',
|
|
116
|
+
description: 'Name of the collection to search in',
|
|
117
|
+
},
|
|
118
|
+
embeddingService: {
|
|
119
|
+
type: 'string',
|
|
120
|
+
enum: ['openai', 'openrouter', 'fastembed', 'ollama'],
|
|
121
|
+
description: 'Embedding service to use',
|
|
122
|
+
},
|
|
123
|
+
limit: {
|
|
124
|
+
type: 'number',
|
|
125
|
+
description: 'Maximum number of results to return (optional)',
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
required: ['query', 'collection', 'embeddingService'],
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
name: 'delete_collection',
|
|
133
|
+
description: 'Delete a Qdrant collection',
|
|
134
|
+
inputSchema: {
|
|
135
|
+
type: 'object',
|
|
136
|
+
properties: {
|
|
137
|
+
collection: {
|
|
138
|
+
type: 'string',
|
|
139
|
+
description: 'Name of the collection to delete',
|
|
140
|
+
},
|
|
141
|
+
},
|
|
142
|
+
required: ['collection'],
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
],
|
|
146
|
+
}));
|
|
147
|
+
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
148
|
+
switch (request.params.name) {
|
|
149
|
+
case 'list_collections':
|
|
150
|
+
return this.handleListCollections();
|
|
151
|
+
case 'add_documents':
|
|
152
|
+
if (!this.isAddDocumentsArgs(request.params.arguments)) {
|
|
153
|
+
throw new McpError(ErrorCode.InvalidParams, 'Invalid arguments for add_documents');
|
|
154
|
+
}
|
|
155
|
+
return this.handleAddDocuments(request.params.arguments);
|
|
156
|
+
case 'search':
|
|
157
|
+
if (!this.isSearchArgs(request.params.arguments)) {
|
|
158
|
+
throw new McpError(ErrorCode.InvalidParams, 'Invalid arguments for search');
|
|
159
|
+
}
|
|
160
|
+
return this.handleSearch(request.params.arguments);
|
|
161
|
+
case 'delete_collection':
|
|
162
|
+
if (!this.isDeleteCollectionArgs(request.params.arguments)) {
|
|
163
|
+
throw new McpError(ErrorCode.InvalidParams, 'Invalid arguments for delete_collection');
|
|
164
|
+
}
|
|
165
|
+
return this.handleDeleteCollection(request.params.arguments);
|
|
166
|
+
default:
|
|
167
|
+
throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${request.params.name}`);
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
async handleListCollections() {
|
|
172
|
+
try {
|
|
173
|
+
const collections = await this.qdrantService.listCollections();
|
|
174
|
+
return {
|
|
175
|
+
content: [
|
|
176
|
+
{
|
|
177
|
+
type: 'text',
|
|
178
|
+
text: JSON.stringify(collections, null, 2),
|
|
179
|
+
},
|
|
180
|
+
],
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
catch (error) {
|
|
184
|
+
console.error('Error in handleListCollections:', error);
|
|
185
|
+
let errorDetails = '';
|
|
186
|
+
if (error instanceof Error) {
|
|
187
|
+
errorDetails = `${error.name}: ${error.message}\nStack: ${error.stack}`;
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
errorDetails = String(error);
|
|
191
|
+
}
|
|
192
|
+
return {
|
|
193
|
+
content: [
|
|
194
|
+
{
|
|
195
|
+
type: 'text',
|
|
196
|
+
text: `Error listing collections: ${errorDetails}`,
|
|
197
|
+
},
|
|
198
|
+
],
|
|
199
|
+
isError: true,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
async handleAddDocuments(args) {
|
|
204
|
+
try {
|
|
205
|
+
// Configure text processor if custom settings provided
|
|
206
|
+
if (args.chunkSize) {
|
|
207
|
+
this.textProcessor.setChunkSize(args.chunkSize);
|
|
208
|
+
}
|
|
209
|
+
if (args.chunkOverlap) {
|
|
210
|
+
this.textProcessor.setChunkOverlap(args.chunkOverlap);
|
|
211
|
+
}
|
|
212
|
+
// Read and process the file
|
|
213
|
+
const content = readFileSync(args.filePath, 'utf-8');
|
|
214
|
+
const chunks = await this.textProcessor.processFile(content, args.filePath);
|
|
215
|
+
// Create embedding service
|
|
216
|
+
const embeddingService = createEmbeddingService({
|
|
217
|
+
type: args.embeddingService,
|
|
218
|
+
apiKey: process.env[`${args.embeddingService.toUpperCase()}_API_KEY`],
|
|
219
|
+
endpoint: process.env[`${args.embeddingService.toUpperCase()}_ENDPOINT`],
|
|
220
|
+
});
|
|
221
|
+
// Generate embeddings
|
|
222
|
+
const embeddings = await embeddingService.generateEmbeddings(chunks.map(chunk => chunk.text));
|
|
223
|
+
// Create collection if it doesn't exist
|
|
224
|
+
const collections = await this.qdrantService.listCollections();
|
|
225
|
+
if (!collections.includes(args.collection)) {
|
|
226
|
+
await this.qdrantService.createCollection(args.collection, embeddingService.vectorSize);
|
|
227
|
+
}
|
|
228
|
+
// Add documents to collection
|
|
229
|
+
await this.qdrantService.addDocuments(args.collection, chunks.map((chunk, i) => ({
|
|
230
|
+
id: uuidv4(),
|
|
231
|
+
vector: embeddings[i],
|
|
232
|
+
payload: {
|
|
233
|
+
text: chunk.text,
|
|
234
|
+
...chunk.metadata,
|
|
235
|
+
},
|
|
236
|
+
})));
|
|
237
|
+
return {
|
|
238
|
+
content: [
|
|
239
|
+
{
|
|
240
|
+
type: 'text',
|
|
241
|
+
text: `Successfully processed and added ${chunks.length} chunks to collection ${args.collection}`,
|
|
242
|
+
},
|
|
243
|
+
],
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
catch (error) {
|
|
247
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
248
|
+
return {
|
|
249
|
+
content: [
|
|
250
|
+
{
|
|
251
|
+
type: 'text',
|
|
252
|
+
text: `Error adding documents: ${errorMessage}`,
|
|
253
|
+
},
|
|
254
|
+
],
|
|
255
|
+
isError: true,
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
async handleSearch(args) {
|
|
260
|
+
try {
|
|
261
|
+
// Create embedding service
|
|
262
|
+
const embeddingService = createEmbeddingService({
|
|
263
|
+
type: args.embeddingService,
|
|
264
|
+
apiKey: process.env[`${args.embeddingService.toUpperCase()}_API_KEY`],
|
|
265
|
+
endpoint: process.env[`${args.embeddingService.toUpperCase()}_ENDPOINT`],
|
|
266
|
+
});
|
|
267
|
+
// Generate query embedding
|
|
268
|
+
const [queryEmbedding] = await embeddingService.generateEmbeddings([args.query]);
|
|
269
|
+
// Search collection
|
|
270
|
+
const results = await this.qdrantService.search(args.collection, queryEmbedding, args.limit);
|
|
271
|
+
// Format the results to only include the payload text
|
|
272
|
+
let responseText = '';
|
|
273
|
+
results.forEach((result, index) => {
|
|
274
|
+
// For documents collection, the text is in result.payload.text
|
|
275
|
+
// For other collections, it might be in different fields
|
|
276
|
+
const text = result.payload.text || result.payload.content || JSON.stringify(result.payload);
|
|
277
|
+
const source = result.payload.source || result.payload.metadata?.source || '';
|
|
278
|
+
const score = result.score.toFixed(2);
|
|
279
|
+
responseText += `Result ${index + 1} (Score: ${score}):\n${text}\n`;
|
|
280
|
+
if (source) {
|
|
281
|
+
responseText += `Source: ${source}\n`;
|
|
282
|
+
}
|
|
283
|
+
responseText += '\n';
|
|
284
|
+
});
|
|
285
|
+
if (responseText === '') {
|
|
286
|
+
responseText = 'No results found.';
|
|
287
|
+
}
|
|
288
|
+
return {
|
|
289
|
+
content: [
|
|
290
|
+
{
|
|
291
|
+
type: 'text',
|
|
292
|
+
text: responseText,
|
|
293
|
+
},
|
|
294
|
+
],
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
catch (error) {
|
|
298
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
299
|
+
return {
|
|
300
|
+
content: [
|
|
301
|
+
{
|
|
302
|
+
type: 'text',
|
|
303
|
+
text: `Error searching: ${errorMessage}`,
|
|
304
|
+
},
|
|
305
|
+
],
|
|
306
|
+
isError: true,
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
async handleDeleteCollection(args) {
|
|
311
|
+
try {
|
|
312
|
+
// Delete the collection
|
|
313
|
+
await this.qdrantService.deleteCollection(args.collection);
|
|
314
|
+
return {
|
|
315
|
+
content: [
|
|
316
|
+
{
|
|
317
|
+
type: 'text',
|
|
318
|
+
text: `Successfully deleted collection: ${args.collection}`,
|
|
319
|
+
},
|
|
320
|
+
],
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
catch (error) {
|
|
324
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
325
|
+
return {
|
|
326
|
+
content: [
|
|
327
|
+
{
|
|
328
|
+
type: 'text',
|
|
329
|
+
text: `Error deleting collection: ${errorMessage}`,
|
|
330
|
+
},
|
|
331
|
+
],
|
|
332
|
+
isError: true,
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
async run() {
|
|
337
|
+
const transport = new StdioServerTransport();
|
|
338
|
+
await this.server.connect(transport);
|
|
339
|
+
console.error('Better Qdrant MCP server running on stdio');
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
const server = new BetterQdrantServer();
|
|
343
|
+
server.run().catch((error) => {
|
|
344
|
+
console.error('Server error:', error instanceof Error ? error.message : String(error));
|
|
345
|
+
process.exit(1);
|
|
346
|
+
});
|
|
347
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { EmbeddingGenerator } from '../../types.js';
|
|
2
|
+
export declare abstract class BaseEmbeddingService implements EmbeddingGenerator {
|
|
3
|
+
protected apiKey?: string | undefined;
|
|
4
|
+
protected endpoint?: string | undefined;
|
|
5
|
+
protected model?: string | undefined;
|
|
6
|
+
constructor(apiKey?: string | undefined, endpoint?: string | undefined, model?: string | undefined);
|
|
7
|
+
abstract vectorSize: number;
|
|
8
|
+
abstract generateEmbeddings(texts: string[]): Promise<number[][]>;
|
|
9
|
+
protected validateConfig(): void;
|
|
10
|
+
protected requiresApiKey(): boolean;
|
|
11
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export class BaseEmbeddingService {
|
|
2
|
+
constructor(apiKey, endpoint, model) {
|
|
3
|
+
this.apiKey = apiKey;
|
|
4
|
+
this.endpoint = endpoint;
|
|
5
|
+
this.model = model;
|
|
6
|
+
}
|
|
7
|
+
validateConfig() {
|
|
8
|
+
if (this.requiresApiKey() && !this.apiKey) {
|
|
9
|
+
throw new Error(`${this.constructor.name} requires an API key`);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
requiresApiKey() {
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=base.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base.js","sourceRoot":"","sources":["../../../src/services/embeddings/base.ts"],"names":[],"mappings":"AAEA,MAAM,OAAgB,oBAAoB;IACxC,YAAsB,MAAe,EAAY,QAAiB,EAAY,KAAc;QAAtE,WAAM,GAAN,MAAM,CAAS;QAAY,aAAQ,GAAR,QAAQ,CAAS;QAAY,UAAK,GAAL,KAAK,CAAS;IAAG,CAAC;IAKtF,cAAc;QACtB,IAAI,IAAI,CAAC,cAAc,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YAC1C,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,sBAAsB,CAAC,CAAC;QAClE,CAAC;IACH,CAAC;IAES,cAAc;QACtB,OAAO,IAAI,CAAC;IACd,CAAC;CACF"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { BaseEmbeddingService } from './base.js';
|
|
2
|
+
export declare class FastEmbedService extends BaseEmbeddingService {
|
|
3
|
+
readonly vectorSize = 384;
|
|
4
|
+
private readonly defaultModel;
|
|
5
|
+
private embedder;
|
|
6
|
+
constructor(model?: string);
|
|
7
|
+
private initializeEmbedder;
|
|
8
|
+
generateEmbeddings(texts: string[]): Promise<number[][]>;
|
|
9
|
+
protected requiresApiKey(): boolean;
|
|
10
|
+
protected validateConfig(): void;
|
|
11
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { BaseEmbeddingService } from './base.js';
|
|
2
|
+
export class FastEmbedService extends BaseEmbeddingService {
|
|
3
|
+
constructor(model) {
|
|
4
|
+
super(undefined, undefined, model || 'BAAI/bge-small-en');
|
|
5
|
+
// FastEmbed models typically produce 384-dimensional embeddings
|
|
6
|
+
this.vectorSize = 384;
|
|
7
|
+
this.defaultModel = 'BAAI/bge-small-en';
|
|
8
|
+
this.embedder = null;
|
|
9
|
+
}
|
|
10
|
+
async initializeEmbedder() {
|
|
11
|
+
if (!this.embedder) {
|
|
12
|
+
// Dynamic import to handle CommonJS module
|
|
13
|
+
const fastembed = await import('fastembed');
|
|
14
|
+
this.embedder = new fastembed.FastEmbed({
|
|
15
|
+
model: this.model || this.defaultModel
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
async generateEmbeddings(texts) {
|
|
20
|
+
await this.initializeEmbedder();
|
|
21
|
+
if (!this.embedder) {
|
|
22
|
+
throw new Error('FastEmbed embedder not initialized');
|
|
23
|
+
}
|
|
24
|
+
const embeddings = await this.embedder.embed(texts);
|
|
25
|
+
return embeddings.map((embedding) => Array.from(embedding));
|
|
26
|
+
}
|
|
27
|
+
requiresApiKey() {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
validateConfig() {
|
|
31
|
+
// No validation needed as FastEmbed runs locally
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=fastembed.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fastembed.js","sourceRoot":"","sources":["../../../src/services/embeddings/fastembed.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAEjD,MAAM,OAAO,gBAAiB,SAAQ,oBAAoB;IAMxD,YAAY,KAAc;QACxB,KAAK,CAAC,SAAS,EAAE,SAAS,EAAE,KAAK,IAAI,mBAAmB,CAAC,CAAC;QAN5D,gEAAgE;QACvD,eAAU,GAAG,GAAG,CAAC;QACT,iBAAY,GAAG,mBAAmB,CAAC;QAC5C,aAAQ,GAAQ,IAAI,CAAC;IAI7B,CAAC;IAEO,KAAK,CAAC,kBAAkB;QAC9B,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACnB,2CAA2C;YAC3C,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,CAAC;YAC5C,IAAI,CAAC,QAAQ,GAAG,IAAI,SAAS,CAAC,SAAS,CAAC;gBACtC,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,YAAY;aACvC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,KAAK,CAAC,kBAAkB,CAAC,KAAe;QACtC,MAAM,IAAI,CAAC,kBAAkB,EAAE,CAAC;QAChC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACnB,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;QACxD,CAAC;QAED,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACpD,OAAO,UAAU,CAAC,GAAG,CAAC,CAAC,SAAuB,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;IAC5E,CAAC;IAES,cAAc;QACtB,OAAO,KAAK,CAAC;IACf,CAAC;IAES,cAAc;QACtB,iDAAiD;IACnD,CAAC;CACF"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { EmbeddingGenerator, EmbeddingServiceConfig } from '../../types.js';
|
|
2
|
+
export declare function createEmbeddingService(config: EmbeddingServiceConfig): EmbeddingGenerator;
|
|
3
|
+
export { OpenAIEmbeddingService } from './openai.js';
|
|
4
|
+
export { OpenRouterEmbeddingService } from './openrouter.js';
|
|
5
|
+
export { OllamaEmbeddingService } from './ollama.js';
|
|
6
|
+
export { FastEmbedService } from './fastembed.js';
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { OpenAIEmbeddingService } from './openai.js';
|
|
2
|
+
import { OpenRouterEmbeddingService } from './openrouter.js';
|
|
3
|
+
import { OllamaEmbeddingService } from './ollama.js';
|
|
4
|
+
import { FastEmbedService } from './fastembed.js';
|
|
5
|
+
export function createEmbeddingService(config) {
|
|
6
|
+
switch (config.type) {
|
|
7
|
+
case 'openai':
|
|
8
|
+
if (!config.apiKey) {
|
|
9
|
+
throw new Error('OpenAI API key is required');
|
|
10
|
+
}
|
|
11
|
+
return new OpenAIEmbeddingService(config.apiKey, config.endpoint, config.model);
|
|
12
|
+
case 'openrouter':
|
|
13
|
+
if (!config.apiKey) {
|
|
14
|
+
throw new Error('OpenRouter API key is required');
|
|
15
|
+
}
|
|
16
|
+
return new OpenRouterEmbeddingService(config.apiKey, config.endpoint, config.model);
|
|
17
|
+
case 'ollama':
|
|
18
|
+
return new OllamaEmbeddingService(config.endpoint, config.model);
|
|
19
|
+
case 'fastembed':
|
|
20
|
+
return new FastEmbedService(config.model);
|
|
21
|
+
default:
|
|
22
|
+
throw new Error(`Unknown embedding service type: ${config.type}`);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export { OpenAIEmbeddingService } from './openai.js';
|
|
26
|
+
export { OpenRouterEmbeddingService } from './openrouter.js';
|
|
27
|
+
export { OllamaEmbeddingService } from './ollama.js';
|
|
28
|
+
export { FastEmbedService } from './fastembed.js';
|
|
29
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/services/embeddings/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,0BAA0B,EAAE,MAAM,iBAAiB,CAAC;AAC7D,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAElD,MAAM,UAAU,sBAAsB,CAAC,MAA8B;IACnE,QAAQ,MAAM,CAAC,IAAI,EAAE,CAAC;QACpB,KAAK,QAAQ;YACX,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;gBACnB,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;YAChD,CAAC;YACD,OAAO,IAAI,sBAAsB,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;QAElF,KAAK,YAAY;YACf,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;gBACnB,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;YACpD,CAAC;YACD,OAAO,IAAI,0BAA0B,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;QAEtF,KAAK,QAAQ;YACX,OAAO,IAAI,sBAAsB,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;QAEnE,KAAK,WAAW;YACd,OAAO,IAAI,gBAAgB,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAE5C;YACE,MAAM,IAAI,KAAK,CAAC,mCAAmC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;IACtE,CAAC;AACH,CAAC;AAED,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,0BAA0B,EAAE,MAAM,iBAAiB,CAAC;AAC7D,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { BaseEmbeddingService } from './base.js';
|
|
2
|
+
export declare class OllamaEmbeddingService extends BaseEmbeddingService {
|
|
3
|
+
readonly vectorSize = 768;
|
|
4
|
+
private readonly defaultModel;
|
|
5
|
+
private readonly defaultEndpoint;
|
|
6
|
+
constructor(endpoint?: string, model?: string);
|
|
7
|
+
generateEmbeddings(texts: string[]): Promise<number[][]>;
|
|
8
|
+
protected requiresApiKey(): boolean;
|
|
9
|
+
protected validateConfig(): void;
|
|
10
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
import { BaseEmbeddingService } from './base.js';
|
|
3
|
+
export class OllamaEmbeddingService extends BaseEmbeddingService {
|
|
4
|
+
constructor(endpoint, model) {
|
|
5
|
+
super(undefined, endpoint || 'http://localhost:11434', model || 'nomic-embed-text');
|
|
6
|
+
// Vector size depends on the model
|
|
7
|
+
// nomic-embed-text produces 768-dimensional embeddings
|
|
8
|
+
this.vectorSize = 768;
|
|
9
|
+
this.defaultModel = 'nomic-embed-text';
|
|
10
|
+
this.defaultEndpoint = 'http://localhost:11434';
|
|
11
|
+
this.validateConfig();
|
|
12
|
+
}
|
|
13
|
+
async generateEmbeddings(texts) {
|
|
14
|
+
const embeddings = [];
|
|
15
|
+
// Ollama API requires sequential processing of texts
|
|
16
|
+
for (const text of texts) {
|
|
17
|
+
const response = await axios.post(`${this.endpoint}/api/embeddings`, {
|
|
18
|
+
model: this.model || this.defaultModel,
|
|
19
|
+
prompt: text,
|
|
20
|
+
}, {
|
|
21
|
+
headers: {
|
|
22
|
+
'Content-Type': 'application/json',
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
if (!response.data.embedding || !Array.isArray(response.data.embedding)) {
|
|
26
|
+
throw new Error('Invalid response from Ollama API');
|
|
27
|
+
}
|
|
28
|
+
embeddings.push(response.data.embedding);
|
|
29
|
+
}
|
|
30
|
+
return embeddings;
|
|
31
|
+
}
|
|
32
|
+
requiresApiKey() {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
validateConfig() {
|
|
36
|
+
if (!this.endpoint) {
|
|
37
|
+
throw new Error('Ollama endpoint is required');
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=ollama.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ollama.js","sourceRoot":"","sources":["../../../src/services/embeddings/ollama.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAEjD,MAAM,OAAO,sBAAuB,SAAQ,oBAAoB;IAO9D,YAAY,QAAiB,EAAE,KAAc;QAC3C,KAAK,CAAC,SAAS,EAAE,QAAQ,IAAI,wBAAwB,EAAE,KAAK,IAAI,kBAAkB,CAAC,CAAC;QAPtF,mCAAmC;QACnC,uDAAuD;QAC9C,eAAU,GAAG,GAAG,CAAC;QACT,iBAAY,GAAG,kBAAkB,CAAC;QAClC,oBAAe,GAAG,wBAAwB,CAAC;QAI1D,IAAI,CAAC,cAAc,EAAE,CAAC;IACxB,CAAC;IAED,KAAK,CAAC,kBAAkB,CAAC,KAAe;QACtC,MAAM,UAAU,GAAe,EAAE,CAAC;QAElC,qDAAqD;QACrD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,IAAI,CAC/B,GAAG,IAAI,CAAC,QAAQ,iBAAiB,EACjC;gBACE,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,YAAY;gBACtC,MAAM,EAAE,IAAI;aACb,EACD;gBACE,OAAO,EAAE;oBACP,cAAc,EAAE,kBAAkB;iBACnC;aACF,CACF,CAAC;YAEF,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;gBACxE,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;YACtD,CAAC;YAED,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC3C,CAAC;QAED,OAAO,UAAU,CAAC;IACpB,CAAC;IAES,cAAc;QACtB,OAAO,KAAK,CAAC;IACf,CAAC;IAES,cAAc;QACtB,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACnB,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;QACjD,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { BaseEmbeddingService } from './base.js';
|
|
2
|
+
export declare class OpenAIEmbeddingService extends BaseEmbeddingService {
|
|
3
|
+
readonly vectorSize = 1536;
|
|
4
|
+
private readonly defaultModel;
|
|
5
|
+
private readonly defaultEndpoint;
|
|
6
|
+
constructor(apiKey: string, endpoint?: string, model?: string);
|
|
7
|
+
generateEmbeddings(texts: string[]): Promise<number[][]>;
|
|
8
|
+
protected requiresApiKey(): boolean;
|
|
9
|
+
protected validateConfig(): void;
|
|
10
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
import { BaseEmbeddingService } from './base.js';
|
|
3
|
+
export class OpenAIEmbeddingService extends BaseEmbeddingService {
|
|
4
|
+
constructor(apiKey, endpoint, model) {
|
|
5
|
+
super(apiKey, endpoint || 'https://api.openai.com/v1', model || 'text-embedding-ada-002');
|
|
6
|
+
// OpenAI's text-embedding-ada-002 produces 1536-dimensional embeddings
|
|
7
|
+
this.vectorSize = 1536;
|
|
8
|
+
this.defaultModel = 'text-embedding-ada-002';
|
|
9
|
+
this.defaultEndpoint = 'https://api.openai.com/v1';
|
|
10
|
+
this.validateConfig();
|
|
11
|
+
}
|
|
12
|
+
async generateEmbeddings(texts) {
|
|
13
|
+
const response = await axios.post(`${this.endpoint}/embeddings`, {
|
|
14
|
+
input: texts,
|
|
15
|
+
model: this.model || this.defaultModel,
|
|
16
|
+
}, {
|
|
17
|
+
headers: {
|
|
18
|
+
'Authorization': `Bearer ${this.apiKey}`,
|
|
19
|
+
'Content-Type': 'application/json',
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
if (!response.data.data || !Array.isArray(response.data.data)) {
|
|
23
|
+
throw new Error('Invalid response from OpenAI API');
|
|
24
|
+
}
|
|
25
|
+
return response.data.data.map((item) => {
|
|
26
|
+
if (!item.embedding || !Array.isArray(item.embedding)) {
|
|
27
|
+
throw new Error('Invalid embedding format in OpenAI response');
|
|
28
|
+
}
|
|
29
|
+
return item.embedding;
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
requiresApiKey() {
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
validateConfig() {
|
|
36
|
+
if (!this.apiKey) {
|
|
37
|
+
throw new Error('OpenAI API key is required');
|
|
38
|
+
}
|
|
39
|
+
if (!this.endpoint) {
|
|
40
|
+
throw new Error('OpenAI endpoint is required');
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=openai.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai.js","sourceRoot":"","sources":["../../../src/services/embeddings/openai.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAEjD,MAAM,OAAO,sBAAuB,SAAQ,oBAAoB;IAM9D,YAAY,MAAc,EAAE,QAAiB,EAAE,KAAc;QAC3D,KAAK,CACH,MAAM,EACN,QAAQ,IAAI,2BAA2B,EACvC,KAAK,IAAI,wBAAwB,CAClC,CAAC;QAVJ,uEAAuE;QAC9D,eAAU,GAAG,IAAI,CAAC;QACV,iBAAY,GAAG,wBAAwB,CAAC;QACxC,oBAAe,GAAG,2BAA2B,CAAC;QAQ7D,IAAI,CAAC,cAAc,EAAE,CAAC;IACxB,CAAC;IAED,KAAK,CAAC,kBAAkB,CAAC,KAAe;QACtC,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,IAAI,CAC/B,GAAG,IAAI,CAAC,QAAQ,aAAa,EAC7B;YACE,KAAK,EAAE,KAAK;YACZ,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,YAAY;SACvC,EACD;YACE,OAAO,EAAE;gBACP,eAAe,EAAE,UAAU,IAAI,CAAC,MAAM,EAAE;gBACxC,cAAc,EAAE,kBAAkB;aACnC;SACF,CACF,CAAC;QAEF,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAC9D,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;QACtD,CAAC;QAED,OAAO,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAS,EAAE,EAAE;YAC1C,IAAI,CAAC,IAAI,CAAC,SAAS,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;gBACtD,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;YACjE,CAAC;YACD,OAAO,IAAI,CAAC,SAAS,CAAC;QACxB,CAAC,CAAC,CAAC;IACL,CAAC;IAES,cAAc;QACtB,OAAO,IAAI,CAAC;IACd,CAAC;IAES,cAAc;QACtB,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;QAChD,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACnB,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;QACjD,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { BaseEmbeddingService } from './base.js';
|
|
2
|
+
export declare class OpenRouterEmbeddingService extends BaseEmbeddingService {
|
|
3
|
+
readonly vectorSize = 1536;
|
|
4
|
+
private readonly defaultModel;
|
|
5
|
+
private readonly defaultEndpoint;
|
|
6
|
+
constructor(apiKey: string, endpoint?: string, model?: string);
|
|
7
|
+
generateEmbeddings(texts: string[]): Promise<number[][]>;
|
|
8
|
+
protected requiresApiKey(): boolean;
|
|
9
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
import { BaseEmbeddingService } from './base.js';
|
|
3
|
+
export class OpenRouterEmbeddingService extends BaseEmbeddingService {
|
|
4
|
+
constructor(apiKey, endpoint, model) {
|
|
5
|
+
super(apiKey, endpoint || 'https://openrouter.ai/api/v1', model || 'openai/text-embedding-ada-002');
|
|
6
|
+
// Using OpenAI-compatible model by default, which produces 1536-dimensional embeddings
|
|
7
|
+
this.vectorSize = 1536;
|
|
8
|
+
this.defaultModel = 'openai/text-embedding-ada-002';
|
|
9
|
+
this.defaultEndpoint = 'https://openrouter.ai/api/v1';
|
|
10
|
+
this.validateConfig();
|
|
11
|
+
}
|
|
12
|
+
async generateEmbeddings(texts) {
|
|
13
|
+
const response = await axios.post(`${this.endpoint}/embeddings`, {
|
|
14
|
+
input: texts,
|
|
15
|
+
model: this.model || this.defaultModel,
|
|
16
|
+
}, {
|
|
17
|
+
headers: {
|
|
18
|
+
'Authorization': `Bearer ${this.apiKey}`,
|
|
19
|
+
'Content-Type': 'application/json',
|
|
20
|
+
'HTTP-Referer': 'https://github.com/wreeves/better-qdrant',
|
|
21
|
+
'X-Title': 'Better Qdrant',
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
if (!response.data.data || !Array.isArray(response.data.data)) {
|
|
25
|
+
throw new Error('Invalid response from OpenRouter API');
|
|
26
|
+
}
|
|
27
|
+
return response.data.data.map((item) => {
|
|
28
|
+
if (!item.embedding || !Array.isArray(item.embedding)) {
|
|
29
|
+
throw new Error('Invalid embedding format in OpenRouter response');
|
|
30
|
+
}
|
|
31
|
+
return item.embedding;
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
requiresApiKey() {
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=openrouter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openrouter.js","sourceRoot":"","sources":["../../../src/services/embeddings/openrouter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAEjD,MAAM,OAAO,0BAA2B,SAAQ,oBAAoB;IAMlE,YAAY,MAAc,EAAE,QAAiB,EAAE,KAAc;QAC3D,KAAK,CACH,MAAM,EACN,QAAQ,IAAI,8BAA8B,EAC1C,KAAK,IAAI,+BAA+B,CACzC,CAAC;QAVJ,uFAAuF;QAC9E,eAAU,GAAG,IAAI,CAAC;QACV,iBAAY,GAAG,+BAA+B,CAAC;QAC/C,oBAAe,GAAG,8BAA8B,CAAC;QAQhE,IAAI,CAAC,cAAc,EAAE,CAAC;IACxB,CAAC;IAED,KAAK,CAAC,kBAAkB,CAAC,KAAe;QACtC,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,IAAI,CAC/B,GAAG,IAAI,CAAC,QAAQ,aAAa,EAC7B;YACE,KAAK,EAAE,KAAK;YACZ,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,YAAY;SACvC,EACD;YACE,OAAO,EAAE;gBACP,eAAe,EAAE,UAAU,IAAI,CAAC,MAAM,EAAE;gBACxC,cAAc,EAAE,kBAAkB;gBAClC,cAAc,EAAE,0CAA0C;gBAC1D,SAAS,EAAE,eAAe;aAC3B;SACF,CACF,CAAC;QAEF,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAC9D,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;QAC1D,CAAC;QAED,OAAO,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAS,EAAE,EAAE;YAC1C,IAAI,CAAC,IAAI,CAAC,SAAS,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;gBACtD,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;YACrE,CAAC;YACD,OAAO,IAAI,CAAC,SAAS,CAAC;QACxB,CAAC,CAAC,CAAC;IACL,CAAC;IAES,cAAc;QACtB,OAAO,IAAI,CAAC;IACd,CAAC;CACF"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { QdrantClient } from '@qdrant/js-client-rest';
|
|
2
|
+
import { QdrantService, SearchResult } from '../types.js';
|
|
3
|
+
export declare class DefaultQdrantService implements QdrantService {
|
|
4
|
+
client: QdrantClient;
|
|
5
|
+
private url;
|
|
6
|
+
private apiKey?;
|
|
7
|
+
constructor(client: QdrantClient, url: string, apiKey?: string);
|
|
8
|
+
listCollections(): Promise<string[]>;
|
|
9
|
+
createCollection(name: string, vectorSize: number): Promise<void>;
|
|
10
|
+
addDocuments(collection: string, documents: {
|
|
11
|
+
id: string;
|
|
12
|
+
vector: number[];
|
|
13
|
+
payload: Record<string, any>;
|
|
14
|
+
}[]): Promise<void>;
|
|
15
|
+
deleteCollection(name: string): Promise<void>;
|
|
16
|
+
search(collection: string, vector: number[], limit?: number): Promise<SearchResult[]>;
|
|
17
|
+
}
|
|
18
|
+
export declare function createQdrantService(url: string, apiKey?: string): QdrantService;
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import { QdrantClient } from '@qdrant/js-client-rest';
|
|
2
|
+
import fetch from 'node-fetch';
|
|
3
|
+
export class DefaultQdrantService {
|
|
4
|
+
constructor(client, url, apiKey) {
|
|
5
|
+
this.client = client;
|
|
6
|
+
this.url = url;
|
|
7
|
+
this.apiKey = apiKey;
|
|
8
|
+
}
|
|
9
|
+
async listCollections() {
|
|
10
|
+
try {
|
|
11
|
+
console.log('Attempting to connect to Qdrant server using direct fetch...');
|
|
12
|
+
// Use direct fetch instead of the client
|
|
13
|
+
const collectionsUrl = `${this.url}/collections`;
|
|
14
|
+
console.log(`Fetching from: ${collectionsUrl}`);
|
|
15
|
+
const response = await fetch(collectionsUrl, {
|
|
16
|
+
method: 'GET',
|
|
17
|
+
headers: {
|
|
18
|
+
'Content-Type': 'application/json',
|
|
19
|
+
...(this.apiKey ? { 'api-key': this.apiKey } : {})
|
|
20
|
+
},
|
|
21
|
+
// @ts-ignore - node-fetch supports timeout
|
|
22
|
+
timeout: 5000 // 5 second timeout
|
|
23
|
+
});
|
|
24
|
+
if (!response.ok) {
|
|
25
|
+
throw new Error(`HTTP error! Status: ${response.status}`);
|
|
26
|
+
}
|
|
27
|
+
const data = await response.json();
|
|
28
|
+
console.log('Successfully retrieved collections:', data);
|
|
29
|
+
return data.result.collections.map(c => c.name);
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
console.error('Error in listCollections:', error);
|
|
33
|
+
if (error instanceof Error) {
|
|
34
|
+
console.error(`${error.name}: ${error.message}`);
|
|
35
|
+
console.error('Stack:', error.stack);
|
|
36
|
+
}
|
|
37
|
+
throw error;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
async createCollection(name, vectorSize) {
|
|
41
|
+
try {
|
|
42
|
+
console.log('Attempting to create Qdrant collection using direct fetch...');
|
|
43
|
+
// Use direct fetch instead of the client
|
|
44
|
+
const createUrl = `${this.url}/collections/${name}`;
|
|
45
|
+
console.log(`Fetching from: ${createUrl}`);
|
|
46
|
+
const response = await fetch(createUrl, {
|
|
47
|
+
method: 'PUT',
|
|
48
|
+
headers: {
|
|
49
|
+
'Content-Type': 'application/json',
|
|
50
|
+
...(this.apiKey ? { 'api-key': this.apiKey } : {})
|
|
51
|
+
},
|
|
52
|
+
// @ts-ignore - node-fetch supports timeout
|
|
53
|
+
timeout: 5000, // 5 second timeout
|
|
54
|
+
body: JSON.stringify({
|
|
55
|
+
vectors: {
|
|
56
|
+
size: vectorSize,
|
|
57
|
+
distance: 'Cosine',
|
|
58
|
+
}
|
|
59
|
+
})
|
|
60
|
+
});
|
|
61
|
+
if (!response.ok) {
|
|
62
|
+
throw new Error(`HTTP error! Status: ${response.status}`);
|
|
63
|
+
}
|
|
64
|
+
const data = await response.json();
|
|
65
|
+
console.log('Successfully created collection:', data);
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
console.error('Error in createCollection:', error);
|
|
69
|
+
if (error instanceof Error) {
|
|
70
|
+
console.error(`${error.name}: ${error.message}`);
|
|
71
|
+
console.error('Stack:', error.stack);
|
|
72
|
+
}
|
|
73
|
+
throw error;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
async addDocuments(collection, documents) {
|
|
77
|
+
try {
|
|
78
|
+
console.log('Attempting to add documents to Qdrant collection using direct fetch...');
|
|
79
|
+
// Use direct fetch instead of the client
|
|
80
|
+
const upsertUrl = `${this.url}/collections/${collection}/points`;
|
|
81
|
+
console.log(`Fetching from: ${upsertUrl}`);
|
|
82
|
+
const points = documents.map(doc => ({
|
|
83
|
+
id: doc.id,
|
|
84
|
+
vector: doc.vector,
|
|
85
|
+
payload: doc.payload,
|
|
86
|
+
}));
|
|
87
|
+
const response = await fetch(upsertUrl, {
|
|
88
|
+
method: 'PUT',
|
|
89
|
+
headers: {
|
|
90
|
+
'Content-Type': 'application/json',
|
|
91
|
+
...(this.apiKey ? { 'api-key': this.apiKey } : {})
|
|
92
|
+
},
|
|
93
|
+
// @ts-ignore - node-fetch supports timeout
|
|
94
|
+
timeout: 10000, // 10 second timeout for potentially larger uploads
|
|
95
|
+
body: JSON.stringify({
|
|
96
|
+
points
|
|
97
|
+
})
|
|
98
|
+
});
|
|
99
|
+
if (!response.ok) {
|
|
100
|
+
throw new Error(`HTTP error! Status: ${response.status}`);
|
|
101
|
+
}
|
|
102
|
+
const data = await response.json();
|
|
103
|
+
console.log('Successfully added documents:', data);
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
console.error('Error in addDocuments:', error);
|
|
107
|
+
if (error instanceof Error) {
|
|
108
|
+
console.error(`${error.name}: ${error.message}`);
|
|
109
|
+
console.error('Stack:', error.stack);
|
|
110
|
+
}
|
|
111
|
+
throw error;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
async deleteCollection(name) {
|
|
115
|
+
try {
|
|
116
|
+
console.log('Attempting to delete Qdrant collection using direct fetch...');
|
|
117
|
+
// Use direct fetch instead of the client
|
|
118
|
+
const deleteUrl = `${this.url}/collections/${name}`;
|
|
119
|
+
console.log(`Fetching from: ${deleteUrl}`);
|
|
120
|
+
const response = await fetch(deleteUrl, {
|
|
121
|
+
method: 'DELETE',
|
|
122
|
+
headers: {
|
|
123
|
+
'Content-Type': 'application/json',
|
|
124
|
+
...(this.apiKey ? { 'api-key': this.apiKey } : {})
|
|
125
|
+
},
|
|
126
|
+
// @ts-ignore - node-fetch supports timeout
|
|
127
|
+
timeout: 5000 // 5 second timeout
|
|
128
|
+
});
|
|
129
|
+
if (!response.ok) {
|
|
130
|
+
throw new Error(`HTTP error! Status: ${response.status}`);
|
|
131
|
+
}
|
|
132
|
+
const data = await response.json();
|
|
133
|
+
console.log('Successfully deleted collection:', data);
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
console.error('Error in deleteCollection:', error);
|
|
137
|
+
if (error instanceof Error) {
|
|
138
|
+
console.error(`${error.name}: ${error.message}`);
|
|
139
|
+
console.error('Stack:', error.stack);
|
|
140
|
+
}
|
|
141
|
+
throw error;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
async search(collection, vector, limit = 10) {
|
|
145
|
+
try {
|
|
146
|
+
console.log('Attempting to search Qdrant collection using direct fetch...');
|
|
147
|
+
// Use direct fetch instead of the client
|
|
148
|
+
const searchUrl = `${this.url}/collections/${collection}/points/search`;
|
|
149
|
+
console.log(`Fetching from: ${searchUrl}`);
|
|
150
|
+
const response = await fetch(searchUrl, {
|
|
151
|
+
method: 'POST',
|
|
152
|
+
headers: {
|
|
153
|
+
'Content-Type': 'application/json',
|
|
154
|
+
...(this.apiKey ? { 'api-key': this.apiKey } : {})
|
|
155
|
+
},
|
|
156
|
+
// @ts-ignore - node-fetch supports timeout
|
|
157
|
+
timeout: 5000, // 5 second timeout
|
|
158
|
+
body: JSON.stringify({
|
|
159
|
+
vector,
|
|
160
|
+
limit,
|
|
161
|
+
with_payload: true,
|
|
162
|
+
with_vector: true
|
|
163
|
+
})
|
|
164
|
+
});
|
|
165
|
+
if (!response.ok) {
|
|
166
|
+
throw new Error(`HTTP error! Status: ${response.status}`);
|
|
167
|
+
}
|
|
168
|
+
const data = await response.json();
|
|
169
|
+
console.log('Successfully retrieved search results:', data);
|
|
170
|
+
return data.result.map(result => {
|
|
171
|
+
const searchResult = {
|
|
172
|
+
id: result.id,
|
|
173
|
+
score: result.score,
|
|
174
|
+
payload: result.payload,
|
|
175
|
+
};
|
|
176
|
+
// Only include vector if it's a number array
|
|
177
|
+
if (Array.isArray(result.vector) && result.vector.every(v => typeof v === 'number')) {
|
|
178
|
+
searchResult.vector = result.vector;
|
|
179
|
+
}
|
|
180
|
+
return searchResult;
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
catch (error) {
|
|
184
|
+
console.error('Error in search:', error);
|
|
185
|
+
if (error instanceof Error) {
|
|
186
|
+
console.error(`${error.name}: ${error.message}`);
|
|
187
|
+
console.error('Stack:', error.stack);
|
|
188
|
+
}
|
|
189
|
+
throw error;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
export function createQdrantService(url, apiKey) {
|
|
194
|
+
// Parse the URL to handle port correctly
|
|
195
|
+
const urlObj = new URL(url);
|
|
196
|
+
// Create client with explicit host and port if provided
|
|
197
|
+
const clientConfig = {
|
|
198
|
+
host: urlObj.hostname,
|
|
199
|
+
apiKey,
|
|
200
|
+
checkCompatibility: false,
|
|
201
|
+
https: urlObj.protocol === 'https:',
|
|
202
|
+
};
|
|
203
|
+
// Only set port if it's explicitly in the URL
|
|
204
|
+
if (urlObj.port) {
|
|
205
|
+
clientConfig.port = parseInt(urlObj.port, 10);
|
|
206
|
+
}
|
|
207
|
+
// Add path if present
|
|
208
|
+
if (urlObj.pathname !== '/' && urlObj.pathname !== '') {
|
|
209
|
+
clientConfig.prefix = urlObj.pathname;
|
|
210
|
+
}
|
|
211
|
+
console.log('Creating Qdrant client with config:', clientConfig);
|
|
212
|
+
const client = new QdrantClient(clientConfig);
|
|
213
|
+
return new DefaultQdrantService(client, url, apiKey);
|
|
214
|
+
}
|
|
215
|
+
//# sourceMappingURL=qdrant.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"qdrant.js","sourceRoot":"","sources":["../../src/services/qdrant.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface TextChunk {
|
|
2
|
+
text: string;
|
|
3
|
+
metadata: {
|
|
4
|
+
index: number;
|
|
5
|
+
source?: string;
|
|
6
|
+
start?: number;
|
|
7
|
+
end?: number;
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
export declare class TextProcessor {
|
|
11
|
+
private chunkSize;
|
|
12
|
+
private chunkOverlap;
|
|
13
|
+
private splitter;
|
|
14
|
+
constructor(chunkSize?: number, chunkOverlap?: number);
|
|
15
|
+
processText(text: string, source?: string): Promise<TextChunk[]>;
|
|
16
|
+
processFile(content: string, filename: string): Promise<TextChunk[]>;
|
|
17
|
+
setChunkSize(size: number): void;
|
|
18
|
+
setChunkOverlap(overlap: number): void;
|
|
19
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { RecursiveCharacterTextSplitter } from '@langchain/textsplitters';
|
|
2
|
+
export class TextProcessor {
|
|
3
|
+
constructor(chunkSize = 1000, chunkOverlap = 200) {
|
|
4
|
+
this.chunkSize = chunkSize;
|
|
5
|
+
this.chunkOverlap = chunkOverlap;
|
|
6
|
+
this.splitter = new RecursiveCharacterTextSplitter({
|
|
7
|
+
chunkSize: this.chunkSize,
|
|
8
|
+
chunkOverlap: this.chunkOverlap,
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
async processText(text, source) {
|
|
12
|
+
const documents = await this.splitter.createDocuments([text]);
|
|
13
|
+
return documents.map((doc, index) => ({
|
|
14
|
+
text: doc.pageContent,
|
|
15
|
+
metadata: {
|
|
16
|
+
index,
|
|
17
|
+
source,
|
|
18
|
+
start: doc.metadata?.start,
|
|
19
|
+
end: doc.metadata?.end,
|
|
20
|
+
},
|
|
21
|
+
}));
|
|
22
|
+
}
|
|
23
|
+
async processFile(content, filename) {
|
|
24
|
+
return this.processText(content, filename);
|
|
25
|
+
}
|
|
26
|
+
setChunkSize(size) {
|
|
27
|
+
this.chunkSize = size;
|
|
28
|
+
this.splitter = new RecursiveCharacterTextSplitter({
|
|
29
|
+
chunkSize: this.chunkSize,
|
|
30
|
+
chunkOverlap: this.chunkOverlap,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
setChunkOverlap(overlap) {
|
|
34
|
+
this.chunkOverlap = overlap;
|
|
35
|
+
this.splitter = new RecursiveCharacterTextSplitter({
|
|
36
|
+
chunkSize: this.chunkSize,
|
|
37
|
+
chunkOverlap: this.chunkOverlap,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=text-processing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text-processing.js","sourceRoot":"","sources":["../../src/services/text-processing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,8BAA8B,EAAE,MAAM,0BAA0B,CAAC;AAa1E,MAAM,OAAO,aAAa;IAGxB,YACU,YAAoB,IAAI,EACxB,eAAuB,GAAG;QAD1B,cAAS,GAAT,SAAS,CAAe;QACxB,iBAAY,GAAZ,YAAY,CAAc;QAElC,IAAI,CAAC,QAAQ,GAAG,IAAI,8BAA8B,CAAC;YACjD,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,YAAY,EAAE,IAAI,CAAC,YAAY;SAChC,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,IAAY,EAAE,MAAe;QAC7C,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QAE9D,OAAO,SAAS,CAAC,GAAG,CAAC,CAAC,GAAa,EAAE,KAAa,EAAE,EAAE,CAAC,CAAC;YACtD,IAAI,EAAE,GAAG,CAAC,WAAW;YACrB,QAAQ,EAAE;gBACR,KAAK;gBACL,MAAM;gBACN,KAAK,EAAE,GAAG,CAAC,QAAQ,EAAE,KAAK;gBAC1B,GAAG,EAAE,GAAG,CAAC,QAAQ,EAAE,GAAG;aACvB;SACF,CAAC,CAAC,CAAC;IACN,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,OAAe,EAAE,QAAgB;QACjD,OAAO,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAC7C,CAAC;IAED,YAAY,CAAC,IAAY;QACvB,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACtB,IAAI,CAAC,QAAQ,GAAG,IAAI,8BAA8B,CAAC;YACjD,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,YAAY,EAAE,IAAI,CAAC,YAAY;SAChC,CAAC,CAAC;IACL,CAAC;IAED,eAAe,CAAC,OAAe;QAC7B,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC;QAC5B,IAAI,CAAC,QAAQ,GAAG,IAAI,8BAA8B,CAAC;YACjD,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,YAAY,EAAE,IAAI,CAAC,YAAY;SAChC,CAAC,CAAC;IACL,CAAC;CACF"}
|
package/build/types.d.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { QdrantClient } from '@qdrant/js-client-rest';
|
|
2
|
+
export type EmbeddingService = 'openai' | 'openrouter' | 'fastembed' | 'ollama';
|
|
3
|
+
export interface EmbeddingServiceConfig {
|
|
4
|
+
type: EmbeddingService;
|
|
5
|
+
apiKey?: string;
|
|
6
|
+
endpoint?: string;
|
|
7
|
+
model?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface QdrantConfig {
|
|
10
|
+
url: string;
|
|
11
|
+
apiKey?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface ServerConfig {
|
|
14
|
+
qdrant: QdrantConfig;
|
|
15
|
+
embedding: EmbeddingServiceConfig;
|
|
16
|
+
}
|
|
17
|
+
export interface Collection {
|
|
18
|
+
name: string;
|
|
19
|
+
vectorSize: number;
|
|
20
|
+
distance: 'Cosine' | 'Euclid' | 'Dot';
|
|
21
|
+
}
|
|
22
|
+
export interface SearchResult {
|
|
23
|
+
id: string;
|
|
24
|
+
score: number;
|
|
25
|
+
payload: Record<string, any>;
|
|
26
|
+
vector?: number[];
|
|
27
|
+
}
|
|
28
|
+
export interface EmbeddingGenerator {
|
|
29
|
+
generateEmbeddings(texts: string[]): Promise<number[][]>;
|
|
30
|
+
vectorSize: number;
|
|
31
|
+
}
|
|
32
|
+
export interface QdrantService {
|
|
33
|
+
client: QdrantClient;
|
|
34
|
+
listCollections(): Promise<string[]>;
|
|
35
|
+
createCollection(name: string, vectorSize: number): Promise<void>;
|
|
36
|
+
deleteCollection(name: string): Promise<void>;
|
|
37
|
+
addDocuments(collection: string, documents: {
|
|
38
|
+
id: string;
|
|
39
|
+
vector: number[];
|
|
40
|
+
payload: Record<string, any>;
|
|
41
|
+
}[]): Promise<void>;
|
|
42
|
+
search(collection: string, vector: number[], limit?: number): Promise<SearchResult[]>;
|
|
43
|
+
}
|
package/build/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "better-qdrant-mcp-server",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "MCP server for enhanced Qdrant vector database functionality",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "build/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"better-qdrant-mcp-server": "build/index.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc && chmod +x build/index.js",
|
|
12
|
+
"start": "node build/index.js",
|
|
13
|
+
"dev": "tsc -w",
|
|
14
|
+
"clean": "rm -rf build",
|
|
15
|
+
"prepare": "npm run build",
|
|
16
|
+
"test": "echo \"No tests yet\""
|
|
17
|
+
},
|
|
18
|
+
"keywords": [
|
|
19
|
+
"mcp",
|
|
20
|
+
"qdrant",
|
|
21
|
+
"vector-database",
|
|
22
|
+
"embeddings",
|
|
23
|
+
"semantic-search",
|
|
24
|
+
"claude",
|
|
25
|
+
"openai",
|
|
26
|
+
"ollama",
|
|
27
|
+
"fastembed"
|
|
28
|
+
],
|
|
29
|
+
"author": "Will Reeves <will@wredia.com>",
|
|
30
|
+
"license": "MIT",
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"@langchain/community": "^0.3.36",
|
|
33
|
+
"@langchain/textsplitters": "^0.1.0",
|
|
34
|
+
"@modelcontextprotocol/sdk": "^1.7.0",
|
|
35
|
+
"@qdrant/js-client-rest": "^1.7.0",
|
|
36
|
+
"axios": "^1.6.7",
|
|
37
|
+
"dotenv": "^16.4.5",
|
|
38
|
+
"fastembed": "^1.1.0",
|
|
39
|
+
"langchain": "^0.3.19",
|
|
40
|
+
"node-fetch": "^3.3.2",
|
|
41
|
+
"uuid": "^9.0.1"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@types/node": "^20.11.24",
|
|
45
|
+
"@types/uuid": "^9.0.8",
|
|
46
|
+
"typescript": "^5.3.3"
|
|
47
|
+
},
|
|
48
|
+
"engines": {
|
|
49
|
+
"node": ">=18.0.0"
|
|
50
|
+
},
|
|
51
|
+
"files": [
|
|
52
|
+
"build",
|
|
53
|
+
"README.md",
|
|
54
|
+
"LICENSE"
|
|
55
|
+
],
|
|
56
|
+
"repository": {
|
|
57
|
+
"type": "git",
|
|
58
|
+
"url": "git+https://github.com/wrediam/better-qdrant-mcp-server.git"
|
|
59
|
+
},
|
|
60
|
+
"bugs": {
|
|
61
|
+
"url": "https://github.com/wrediam/better-qdrant-mcp-server/issues"
|
|
62
|
+
},
|
|
63
|
+
"homepage": "https://github.com/wrediam/better-qdrant-mcp-server#readme"
|
|
64
|
+
}
|