@mhalder/qdrant-mcp-server 3.2.0 → 3.3.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/.dagger/.gitattributes +1 -0
- package/.dagger/package.json +6 -0
- package/.dagger/src/index.ts +83 -0
- package/.dagger/tsconfig.json +13 -0
- package/.dagger/yarn.lock +8 -0
- package/.github/workflows/ci.yml +17 -27
- package/.github/workflows/release.yml +16 -19
- package/CHANGELOG.md +13 -0
- package/README.md +11 -9
- package/build/code/chunker/tree-sitter-chunker.d.ts.map +1 -1
- package/build/code/chunker/tree-sitter-chunker.js +15 -3
- package/build/code/chunker/tree-sitter-chunker.js.map +1 -1
- package/build/code/indexer.d.ts +1 -0
- package/build/code/indexer.d.ts.map +1 -1
- package/build/code/indexer.js +24 -4
- package/build/code/indexer.js.map +1 -1
- package/build/embeddings/cohere.d.ts +1 -0
- package/build/embeddings/cohere.d.ts.map +1 -1
- package/build/embeddings/cohere.js +8 -1
- package/build/embeddings/cohere.js.map +1 -1
- package/build/embeddings/cohere.test.js +11 -0
- package/build/embeddings/cohere.test.js.map +1 -1
- package/build/embeddings/factory.d.ts.map +1 -1
- package/build/embeddings/factory.js +2 -0
- package/build/embeddings/factory.js.map +1 -1
- package/build/embeddings/factory.test.js +12 -1
- package/build/embeddings/factory.test.js.map +1 -1
- package/build/embeddings/ollama.d.ts +1 -0
- package/build/embeddings/ollama.d.ts.map +1 -1
- package/build/embeddings/ollama.js +8 -1
- package/build/embeddings/ollama.js.map +1 -1
- package/build/embeddings/ollama.test.js +11 -0
- package/build/embeddings/ollama.test.js.map +1 -1
- package/build/embeddings/openai.d.ts +1 -0
- package/build/embeddings/openai.d.ts.map +1 -1
- package/build/embeddings/openai.js +8 -1
- package/build/embeddings/openai.js.map +1 -1
- package/build/embeddings/openai.test.js +11 -0
- package/build/embeddings/openai.test.js.map +1 -1
- package/build/embeddings/voyage.d.ts +1 -0
- package/build/embeddings/voyage.d.ts.map +1 -1
- package/build/embeddings/voyage.js +8 -1
- package/build/embeddings/voyage.js.map +1 -1
- package/build/embeddings/voyage.test.js +11 -0
- package/build/embeddings/voyage.test.js.map +1 -1
- package/build/git/indexer.d.ts +1 -0
- package/build/git/indexer.d.ts.map +1 -1
- package/build/git/indexer.js +16 -3
- package/build/git/indexer.js.map +1 -1
- package/build/git/indexer.test.js +15 -9
- package/build/git/indexer.test.js.map +1 -1
- package/build/index.js +35 -26
- package/build/index.js.map +1 -1
- package/build/index.test.js +105 -91
- package/build/index.test.js.map +1 -1
- package/build/logger.d.ts +4 -0
- package/build/logger.d.ts.map +1 -0
- package/build/logger.js +24 -0
- package/build/logger.js.map +1 -0
- package/build/qdrant/client.d.ts +1 -0
- package/build/qdrant/client.d.ts.map +1 -1
- package/build/qdrant/client.js +10 -0
- package/build/qdrant/client.js.map +1 -1
- package/build/qdrant/client.test.js +11 -0
- package/build/qdrant/client.test.js.map +1 -1
- package/build/tools/code.d.ts.map +1 -1
- package/build/tools/code.js +44 -13
- package/build/tools/code.js.map +1 -1
- package/build/tools/collection.d.ts.map +1 -1
- package/build/tools/collection.js +15 -8
- package/build/tools/collection.js.map +1 -1
- package/build/tools/document.d.ts.map +1 -1
- package/build/tools/document.js +9 -4
- package/build/tools/document.js.map +1 -1
- package/build/tools/federated.d.ts.map +1 -1
- package/build/tools/federated.js +9 -4
- package/build/tools/federated.js.map +1 -1
- package/build/tools/federated.test.js +11 -0
- package/build/tools/federated.test.js.map +1 -1
- package/build/tools/git-history.d.ts.map +1 -1
- package/build/tools/git-history.js +44 -12
- package/build/tools/git-history.js.map +1 -1
- package/build/tools/logging.d.ts +16 -0
- package/build/tools/logging.d.ts.map +1 -0
- package/build/tools/logging.js +68 -0
- package/build/tools/logging.js.map +1 -0
- package/build/tools/logging.test.d.ts +2 -0
- package/build/tools/logging.test.d.ts.map +1 -0
- package/build/tools/logging.test.js +139 -0
- package/build/tools/logging.test.js.map +1 -0
- package/build/tools/schemas.d.ts +32 -19
- package/build/tools/schemas.d.ts.map +1 -1
- package/build/tools/schemas.js +9 -3
- package/build/tools/schemas.js.map +1 -1
- package/build/tools/search.d.ts.map +1 -1
- package/build/tools/search.js +13 -4
- package/build/tools/search.js.map +1 -1
- package/dagger.json +8 -0
- package/mise.toml +2 -0
- package/package.json +14 -13
- package/src/code/chunker/tree-sitter-chunker.ts +41 -9
- package/src/code/indexer.ts +41 -6
- package/src/embeddings/cohere.test.ts +12 -0
- package/src/embeddings/cohere.ts +10 -2
- package/src/embeddings/factory.test.ts +13 -1
- package/src/embeddings/factory.ts +3 -0
- package/src/embeddings/ollama.test.ts +12 -0
- package/src/embeddings/ollama.ts +10 -2
- package/src/embeddings/openai.test.ts +12 -0
- package/src/embeddings/openai.ts +10 -2
- package/src/embeddings/voyage.test.ts +12 -0
- package/src/embeddings/voyage.ts +10 -2
- package/src/git/indexer.test.ts +22 -16
- package/src/git/indexer.ts +30 -4
- package/src/index.test.ts +128 -106
- package/src/index.ts +59 -38
- package/src/logger.ts +33 -0
- package/src/qdrant/client.test.ts +12 -0
- package/src/qdrant/client.ts +22 -0
- package/src/tools/code.ts +107 -62
- package/src/tools/collection.ts +39 -22
- package/src/tools/document.ts +52 -22
- package/src/tools/federated.test.ts +12 -0
- package/src/tools/federated.ts +143 -125
- package/src/tools/git-history.ts +117 -60
- package/src/tools/logging.test.ts +206 -0
- package/src/tools/logging.ts +85 -0
- package/src/tools/schemas.ts +9 -3
- package/src/tools/search.ts +93 -71
- package/tests/code/chunker/tree-sitter-chunker.test.ts +13 -1
- package/tests/code/indexer.test.ts +12 -0
- package/tests/code/integration.test.ts +14 -1
package/src/tools/search.ts
CHANGED
|
@@ -3,11 +3,15 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
6
|
+
import logger from "../logger.js";
|
|
6
7
|
import type { EmbeddingProvider } from "../embeddings/base.js";
|
|
7
8
|
import { BM25SparseVectorGenerator } from "../embeddings/sparse.js";
|
|
8
9
|
import type { QdrantManager } from "../qdrant/client.js";
|
|
10
|
+
import { withToolLogging } from "./logging.js";
|
|
9
11
|
import * as schemas from "./schemas.js";
|
|
10
12
|
|
|
13
|
+
const log = logger.child({ component: "tools" });
|
|
14
|
+
|
|
11
15
|
export interface SearchToolDependencies {
|
|
12
16
|
qdrant: QdrantManager;
|
|
13
17
|
embeddings: EmbeddingProvider;
|
|
@@ -28,36 +32,47 @@ export function registerSearchTools(
|
|
|
28
32
|
"Search for documents using natural language queries. Returns the most semantically similar documents.",
|
|
29
33
|
inputSchema: schemas.SemanticSearchSchema,
|
|
30
34
|
},
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
35
|
+
withToolLogging(
|
|
36
|
+
"semantic_search",
|
|
37
|
+
async ({ collection, query, limit, filter }) => {
|
|
38
|
+
log.info(
|
|
39
|
+
{
|
|
40
|
+
tool: "semantic_search",
|
|
41
|
+
collection,
|
|
42
|
+
query: query.substring(0, 80),
|
|
43
|
+
},
|
|
44
|
+
"Tool called",
|
|
45
|
+
);
|
|
46
|
+
// Check if collection exists
|
|
47
|
+
const exists = await qdrant.collectionExists(collection);
|
|
48
|
+
if (!exists) {
|
|
49
|
+
return {
|
|
50
|
+
content: [
|
|
51
|
+
{
|
|
52
|
+
type: "text",
|
|
53
|
+
text: `Error: Collection "${collection}" does not exist.`,
|
|
54
|
+
},
|
|
55
|
+
],
|
|
56
|
+
isError: true,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
45
59
|
|
|
46
|
-
|
|
47
|
-
|
|
60
|
+
// Generate embedding for query
|
|
61
|
+
const { embedding } = await embeddings.embed(query);
|
|
48
62
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
63
|
+
// Search
|
|
64
|
+
const results = await qdrant.search(
|
|
65
|
+
collection,
|
|
66
|
+
embedding,
|
|
67
|
+
limit || 5,
|
|
68
|
+
filter,
|
|
69
|
+
);
|
|
56
70
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
71
|
+
return {
|
|
72
|
+
content: [{ type: "text", text: JSON.stringify(results, null, 2) }],
|
|
73
|
+
};
|
|
74
|
+
},
|
|
75
|
+
),
|
|
61
76
|
);
|
|
62
77
|
|
|
63
78
|
// hybrid_search
|
|
@@ -69,54 +84,61 @@ export function registerSearchTools(
|
|
|
69
84
|
"Perform hybrid search combining semantic vector search with keyword search using BM25. This provides better results by combining the strengths of both approaches. The collection must be created with enableHybrid set to true.",
|
|
70
85
|
inputSchema: schemas.HybridSearchSchema,
|
|
71
86
|
},
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
87
|
+
withToolLogging(
|
|
88
|
+
"hybrid_search",
|
|
89
|
+
async ({ collection, query, limit, filter }) => {
|
|
90
|
+
log.info(
|
|
91
|
+
{ tool: "hybrid_search", collection, query: query.substring(0, 80) },
|
|
92
|
+
"Tool called",
|
|
93
|
+
);
|
|
94
|
+
// Check if collection exists
|
|
95
|
+
const exists = await qdrant.collectionExists(collection);
|
|
96
|
+
if (!exists) {
|
|
97
|
+
return {
|
|
98
|
+
content: [
|
|
99
|
+
{
|
|
100
|
+
type: "text",
|
|
101
|
+
text: `Error: Collection "${collection}" does not exist.`,
|
|
102
|
+
},
|
|
103
|
+
],
|
|
104
|
+
isError: true,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
86
107
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
108
|
+
// Check if collection has hybrid search enabled
|
|
109
|
+
const collectionInfo = await qdrant.getCollectionInfo(collection);
|
|
110
|
+
if (!collectionInfo.hybridEnabled) {
|
|
111
|
+
return {
|
|
112
|
+
content: [
|
|
113
|
+
{
|
|
114
|
+
type: "text",
|
|
115
|
+
text: `Error: Collection "${collection}" does not have hybrid search enabled. Create a new collection with enableHybrid set to true.`,
|
|
116
|
+
},
|
|
117
|
+
],
|
|
118
|
+
isError: true,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
100
121
|
|
|
101
|
-
|
|
102
|
-
|
|
122
|
+
// Generate dense embedding for query
|
|
123
|
+
const { embedding } = await embeddings.embed(query);
|
|
103
124
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
125
|
+
// Generate sparse vector for query
|
|
126
|
+
const sparseGenerator = new BM25SparseVectorGenerator();
|
|
127
|
+
const sparseVector = sparseGenerator.generate(query);
|
|
107
128
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
129
|
+
// Perform hybrid search
|
|
130
|
+
const results = await qdrant.hybridSearch(
|
|
131
|
+
collection,
|
|
132
|
+
embedding,
|
|
133
|
+
sparseVector,
|
|
134
|
+
limit || 5,
|
|
135
|
+
filter,
|
|
136
|
+
);
|
|
116
137
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
138
|
+
return {
|
|
139
|
+
content: [{ type: "text", text: JSON.stringify(results, null, 2) }],
|
|
140
|
+
};
|
|
141
|
+
},
|
|
142
|
+
),
|
|
121
143
|
);
|
|
122
144
|
}
|
|
@@ -1,7 +1,19 @@
|
|
|
1
|
-
import { beforeEach, describe, expect, it } from "vitest";
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
2
|
import { TreeSitterChunker } from "../../../src/code/chunker/tree-sitter-chunker.js";
|
|
3
3
|
import type { ChunkerConfig } from "../../../src/code/types.js";
|
|
4
4
|
|
|
5
|
+
vi.mock("../../logger.js", () => ({
|
|
6
|
+
default: {
|
|
7
|
+
info: vi.fn(),
|
|
8
|
+
warn: vi.fn(),
|
|
9
|
+
error: vi.fn(),
|
|
10
|
+
debug: vi.fn(),
|
|
11
|
+
fatal: vi.fn(),
|
|
12
|
+
trace: vi.fn(),
|
|
13
|
+
child: vi.fn().mockReturnThis(),
|
|
14
|
+
},
|
|
15
|
+
}));
|
|
16
|
+
|
|
5
17
|
describe("TreeSitterChunker", () => {
|
|
6
18
|
let chunker: TreeSitterChunker;
|
|
7
19
|
let config: ChunkerConfig;
|
|
@@ -7,6 +7,18 @@ import type { CodeConfig } from "../../src/code/types.js";
|
|
|
7
7
|
import type { EmbeddingProvider } from "../../src/embeddings/base.js";
|
|
8
8
|
import type { QdrantManager } from "../../src/qdrant/client.js";
|
|
9
9
|
|
|
10
|
+
vi.mock("../logger.js", () => ({
|
|
11
|
+
default: {
|
|
12
|
+
info: vi.fn(),
|
|
13
|
+
warn: vi.fn(),
|
|
14
|
+
error: vi.fn(),
|
|
15
|
+
debug: vi.fn(),
|
|
16
|
+
fatal: vi.fn(),
|
|
17
|
+
trace: vi.fn(),
|
|
18
|
+
child: vi.fn().mockReturnThis(),
|
|
19
|
+
},
|
|
20
|
+
}));
|
|
21
|
+
|
|
10
22
|
// Mock implementations
|
|
11
23
|
class MockQdrantManager implements Partial<QdrantManager> {
|
|
12
24
|
private collections = new Map<string, any>();
|
|
@@ -1,7 +1,20 @@
|
|
|
1
1
|
import { promises as fs } from "node:fs";
|
|
2
2
|
import { tmpdir } from "node:os";
|
|
3
3
|
import { join } from "node:path";
|
|
4
|
-
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
4
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
5
|
+
|
|
6
|
+
vi.mock("../../src/logger.js", () => ({
|
|
7
|
+
default: {
|
|
8
|
+
info: vi.fn(),
|
|
9
|
+
warn: vi.fn(),
|
|
10
|
+
error: vi.fn(),
|
|
11
|
+
debug: vi.fn(),
|
|
12
|
+
fatal: vi.fn(),
|
|
13
|
+
trace: vi.fn(),
|
|
14
|
+
child: vi.fn().mockReturnThis(),
|
|
15
|
+
},
|
|
16
|
+
}));
|
|
17
|
+
|
|
5
18
|
import { CodeIndexer } from "../../src/code/indexer.js";
|
|
6
19
|
import type { CodeConfig } from "../../src/code/types.js";
|
|
7
20
|
import type { EmbeddingProvider } from "../../src/embeddings/base.js";
|