semantic-code-mcp 2.1.1 → 2.2.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.
@@ -9,7 +9,7 @@ export class HybridSearch {
9
9
  this.indexer = indexer; // Reference to indexer for status checking
10
10
  }
11
11
 
12
- async search(query, maxResults) {
12
+ async search(query, maxResults, scopePath = "") {
13
13
  const hasAnnSearch = typeof this.cache?.searchByVector === "function";
14
14
 
15
15
  // Show warning if indexing is still in progress but we have some results
@@ -22,9 +22,12 @@ export class HybridSearch {
22
22
  const queryEmbed = await this.embedder(query, { pooling: "mean", normalize: true });
23
23
  const queryVector = Array.from(queryEmbed.data);
24
24
 
25
+ // Build Milvus filter for scoped search
26
+ const filter = scopePath ? `file like '${scopePath.replace(/'/g, "\\'")}%'` : null;
27
+
25
28
  if (hasAnnSearch) {
26
29
  const annTopK = Math.max(maxResults * 5, 20);
27
- const candidates = await this.cache.searchByVector(queryVector, annTopK);
30
+ const candidates = await this.cache.searchByVector(queryVector, annTopK, filter);
28
31
 
29
32
  const scoredChunks = candidates.map((chunk) => {
30
33
  // Base semantic score from provider (Milvus or fallback cache) plus lexical boost.
@@ -124,11 +127,11 @@ export class HybridSearch {
124
127
  return results.map((r, idx) => {
125
128
  const relPath = path.relative(this.config.searchDirectory, r.file);
126
129
  return `## Result ${idx + 1} (Relevance: ${(r.score * 100).toFixed(1)}%)\n` +
127
- `**File:** \`${relPath}\`\n` +
128
- `**Lines:** ${r.startLine}-${r.endLine}\n\n` +
129
- "```" + path.extname(r.file).slice(1) + "\n" +
130
- r.content + "\n" +
131
- "```\n";
130
+ `**File:** \`${relPath}\`\n` +
131
+ `**Lines:** ${r.startLine}-${r.endLine}\n\n` +
132
+ "```" + path.extname(r.file).slice(1) + "\n" +
133
+ r.content + "\n" +
134
+ "```\n";
132
135
  }).join("\n");
133
136
  }
134
137
  }
@@ -141,14 +144,19 @@ export function getToolDefinition(config) {
141
144
  inputSchema: {
142
145
  type: "object",
143
146
  properties: {
144
- query: {
145
- type: "string",
146
- description: "Search query - can be natural language (e.g., 'where do we handle user login') or specific terms"
147
+ query: {
148
+ type: "string",
149
+ description: "Search query - can be natural language (e.g., 'where do we handle user login') or specific terms"
147
150
  },
148
151
  maxResults: {
149
152
  type: "number",
150
153
  description: "Maximum number of results to return (default: from config)",
151
154
  default: config.maxResults
155
+ },
156
+ scopePath: {
157
+ type: "string",
158
+ description: "Limit search to files under this absolute path prefix (e.g., '/path/to/subfolder'). Empty string searches all.",
159
+ default: ""
152
160
  }
153
161
  },
154
162
  required: ["query"]
@@ -167,9 +175,10 @@ export function getToolDefinition(config) {
167
175
  export async function handleToolCall(request, hybridSearch) {
168
176
  const query = request.params.arguments.query;
169
177
  const maxResults = request.params.arguments.maxResults || hybridSearch.config.maxResults;
170
-
171
- const { results, message, indexingWarning } = await hybridSearch.search(query, maxResults);
172
-
178
+ const scopePath = request.params.arguments.scopePath || "";
179
+
180
+ const { results, message, indexingWarning } = await hybridSearch.search(query, maxResults, scopePath);
181
+
173
182
  if (message) {
174
183
  return {
175
184
  content: [{ type: "text", text: message }]
@@ -177,12 +186,12 @@ export async function handleToolCall(request, hybridSearch) {
177
186
  }
178
187
 
179
188
  let formattedText = hybridSearch.formatResults(results);
180
-
189
+
181
190
  // Prepend indexing warning if present
182
191
  if (indexingWarning) {
183
192
  formattedText = indexingWarning + formattedText;
184
193
  }
185
-
194
+
186
195
  return {
187
196
  content: [{ type: "text", text: formattedText }]
188
197
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "semantic-code-mcp",
3
- "version": "2.1.1",
3
+ "version": "2.2.0",
4
4
  "description": "AI-powered semantic code search for coding agents. MCP server with multi-provider embeddings and hybrid search.",
5
5
  "type": "module",
6
6
  "main": "index.js",