@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.
Files changed (132) hide show
  1. package/.dagger/.gitattributes +1 -0
  2. package/.dagger/package.json +6 -0
  3. package/.dagger/src/index.ts +83 -0
  4. package/.dagger/tsconfig.json +13 -0
  5. package/.dagger/yarn.lock +8 -0
  6. package/.github/workflows/ci.yml +17 -27
  7. package/.github/workflows/release.yml +16 -19
  8. package/CHANGELOG.md +13 -0
  9. package/README.md +11 -9
  10. package/build/code/chunker/tree-sitter-chunker.d.ts.map +1 -1
  11. package/build/code/chunker/tree-sitter-chunker.js +15 -3
  12. package/build/code/chunker/tree-sitter-chunker.js.map +1 -1
  13. package/build/code/indexer.d.ts +1 -0
  14. package/build/code/indexer.d.ts.map +1 -1
  15. package/build/code/indexer.js +24 -4
  16. package/build/code/indexer.js.map +1 -1
  17. package/build/embeddings/cohere.d.ts +1 -0
  18. package/build/embeddings/cohere.d.ts.map +1 -1
  19. package/build/embeddings/cohere.js +8 -1
  20. package/build/embeddings/cohere.js.map +1 -1
  21. package/build/embeddings/cohere.test.js +11 -0
  22. package/build/embeddings/cohere.test.js.map +1 -1
  23. package/build/embeddings/factory.d.ts.map +1 -1
  24. package/build/embeddings/factory.js +2 -0
  25. package/build/embeddings/factory.js.map +1 -1
  26. package/build/embeddings/factory.test.js +12 -1
  27. package/build/embeddings/factory.test.js.map +1 -1
  28. package/build/embeddings/ollama.d.ts +1 -0
  29. package/build/embeddings/ollama.d.ts.map +1 -1
  30. package/build/embeddings/ollama.js +8 -1
  31. package/build/embeddings/ollama.js.map +1 -1
  32. package/build/embeddings/ollama.test.js +11 -0
  33. package/build/embeddings/ollama.test.js.map +1 -1
  34. package/build/embeddings/openai.d.ts +1 -0
  35. package/build/embeddings/openai.d.ts.map +1 -1
  36. package/build/embeddings/openai.js +8 -1
  37. package/build/embeddings/openai.js.map +1 -1
  38. package/build/embeddings/openai.test.js +11 -0
  39. package/build/embeddings/openai.test.js.map +1 -1
  40. package/build/embeddings/voyage.d.ts +1 -0
  41. package/build/embeddings/voyage.d.ts.map +1 -1
  42. package/build/embeddings/voyage.js +8 -1
  43. package/build/embeddings/voyage.js.map +1 -1
  44. package/build/embeddings/voyage.test.js +11 -0
  45. package/build/embeddings/voyage.test.js.map +1 -1
  46. package/build/git/indexer.d.ts +1 -0
  47. package/build/git/indexer.d.ts.map +1 -1
  48. package/build/git/indexer.js +16 -3
  49. package/build/git/indexer.js.map +1 -1
  50. package/build/git/indexer.test.js +15 -9
  51. package/build/git/indexer.test.js.map +1 -1
  52. package/build/index.js +35 -26
  53. package/build/index.js.map +1 -1
  54. package/build/index.test.js +105 -91
  55. package/build/index.test.js.map +1 -1
  56. package/build/logger.d.ts +4 -0
  57. package/build/logger.d.ts.map +1 -0
  58. package/build/logger.js +24 -0
  59. package/build/logger.js.map +1 -0
  60. package/build/qdrant/client.d.ts +1 -0
  61. package/build/qdrant/client.d.ts.map +1 -1
  62. package/build/qdrant/client.js +10 -0
  63. package/build/qdrant/client.js.map +1 -1
  64. package/build/qdrant/client.test.js +11 -0
  65. package/build/qdrant/client.test.js.map +1 -1
  66. package/build/tools/code.d.ts.map +1 -1
  67. package/build/tools/code.js +44 -13
  68. package/build/tools/code.js.map +1 -1
  69. package/build/tools/collection.d.ts.map +1 -1
  70. package/build/tools/collection.js +15 -8
  71. package/build/tools/collection.js.map +1 -1
  72. package/build/tools/document.d.ts.map +1 -1
  73. package/build/tools/document.js +9 -4
  74. package/build/tools/document.js.map +1 -1
  75. package/build/tools/federated.d.ts.map +1 -1
  76. package/build/tools/federated.js +9 -4
  77. package/build/tools/federated.js.map +1 -1
  78. package/build/tools/federated.test.js +11 -0
  79. package/build/tools/federated.test.js.map +1 -1
  80. package/build/tools/git-history.d.ts.map +1 -1
  81. package/build/tools/git-history.js +44 -12
  82. package/build/tools/git-history.js.map +1 -1
  83. package/build/tools/logging.d.ts +16 -0
  84. package/build/tools/logging.d.ts.map +1 -0
  85. package/build/tools/logging.js +68 -0
  86. package/build/tools/logging.js.map +1 -0
  87. package/build/tools/logging.test.d.ts +2 -0
  88. package/build/tools/logging.test.d.ts.map +1 -0
  89. package/build/tools/logging.test.js +139 -0
  90. package/build/tools/logging.test.js.map +1 -0
  91. package/build/tools/schemas.d.ts +32 -19
  92. package/build/tools/schemas.d.ts.map +1 -1
  93. package/build/tools/schemas.js +9 -3
  94. package/build/tools/schemas.js.map +1 -1
  95. package/build/tools/search.d.ts.map +1 -1
  96. package/build/tools/search.js +13 -4
  97. package/build/tools/search.js.map +1 -1
  98. package/dagger.json +8 -0
  99. package/mise.toml +2 -0
  100. package/package.json +14 -13
  101. package/src/code/chunker/tree-sitter-chunker.ts +41 -9
  102. package/src/code/indexer.ts +41 -6
  103. package/src/embeddings/cohere.test.ts +12 -0
  104. package/src/embeddings/cohere.ts +10 -2
  105. package/src/embeddings/factory.test.ts +13 -1
  106. package/src/embeddings/factory.ts +3 -0
  107. package/src/embeddings/ollama.test.ts +12 -0
  108. package/src/embeddings/ollama.ts +10 -2
  109. package/src/embeddings/openai.test.ts +12 -0
  110. package/src/embeddings/openai.ts +10 -2
  111. package/src/embeddings/voyage.test.ts +12 -0
  112. package/src/embeddings/voyage.ts +10 -2
  113. package/src/git/indexer.test.ts +22 -16
  114. package/src/git/indexer.ts +30 -4
  115. package/src/index.test.ts +128 -106
  116. package/src/index.ts +59 -38
  117. package/src/logger.ts +33 -0
  118. package/src/qdrant/client.test.ts +12 -0
  119. package/src/qdrant/client.ts +22 -0
  120. package/src/tools/code.ts +107 -62
  121. package/src/tools/collection.ts +39 -22
  122. package/src/tools/document.ts +52 -22
  123. package/src/tools/federated.test.ts +12 -0
  124. package/src/tools/federated.ts +143 -125
  125. package/src/tools/git-history.ts +117 -60
  126. package/src/tools/logging.test.ts +206 -0
  127. package/src/tools/logging.ts +85 -0
  128. package/src/tools/schemas.ts +9 -3
  129. package/src/tools/search.ts +93 -71
  130. package/tests/code/chunker/tree-sitter-chunker.test.ts +13 -1
  131. package/tests/code/indexer.test.ts +12 -0
  132. package/tests/code/integration.test.ts +14 -1
@@ -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
- async ({ collection, query, limit, filter }) => {
32
- // Check if collection exists
33
- const exists = await qdrant.collectionExists(collection);
34
- if (!exists) {
35
- return {
36
- content: [
37
- {
38
- type: "text",
39
- text: `Error: Collection "${collection}" does not exist.`,
40
- },
41
- ],
42
- isError: true,
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
- // Generate embedding for query
47
- const { embedding } = await embeddings.embed(query);
60
+ // Generate embedding for query
61
+ const { embedding } = await embeddings.embed(query);
48
62
 
49
- // Search
50
- const results = await qdrant.search(
51
- collection,
52
- embedding,
53
- limit || 5,
54
- filter,
55
- );
63
+ // Search
64
+ const results = await qdrant.search(
65
+ collection,
66
+ embedding,
67
+ limit || 5,
68
+ filter,
69
+ );
56
70
 
57
- return {
58
- content: [{ type: "text", text: JSON.stringify(results, null, 2) }],
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
- async ({ collection, query, limit, filter }) => {
73
- // Check if collection exists
74
- const exists = await qdrant.collectionExists(collection);
75
- if (!exists) {
76
- return {
77
- content: [
78
- {
79
- type: "text",
80
- text: `Error: Collection "${collection}" does not exist.`,
81
- },
82
- ],
83
- isError: true,
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
- // Check if collection has hybrid search enabled
88
- const collectionInfo = await qdrant.getCollectionInfo(collection);
89
- if (!collectionInfo.hybridEnabled) {
90
- return {
91
- content: [
92
- {
93
- type: "text",
94
- text: `Error: Collection "${collection}" does not have hybrid search enabled. Create a new collection with enableHybrid set to true.`,
95
- },
96
- ],
97
- isError: true,
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
- // Generate dense embedding for query
102
- const { embedding } = await embeddings.embed(query);
122
+ // Generate dense embedding for query
123
+ const { embedding } = await embeddings.embed(query);
103
124
 
104
- // Generate sparse vector for query
105
- const sparseGenerator = new BM25SparseVectorGenerator();
106
- const sparseVector = sparseGenerator.generate(query);
125
+ // Generate sparse vector for query
126
+ const sparseGenerator = new BM25SparseVectorGenerator();
127
+ const sparseVector = sparseGenerator.generate(query);
107
128
 
108
- // Perform hybrid search
109
- const results = await qdrant.hybridSearch(
110
- collection,
111
- embedding,
112
- sparseVector,
113
- limit || 5,
114
- filter,
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
- return {
118
- content: [{ type: "text", text: JSON.stringify(results, null, 2) }],
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";