smart-coding-mcp 1.4.1 → 2.0.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/README.md +99 -31
- package/config.json +4 -1
- package/features/get-status.js +132 -0
- package/features/index-codebase.js +8 -0
- package/features/set-workspace.js +155 -0
- package/index.js +22 -3
- package/lib/ast-chunker.js +273 -0
- package/lib/config.js +40 -1
- package/lib/embedding-worker.js +29 -2
- package/lib/mrl-embedder.js +133 -0
- package/lib/tokenizer.js +4 -0
- package/package.json +5 -3
- package/test/ast-chunker.test.js +105 -0
- package/test/device-detection.test.js +110 -0
- package/test/embedding-model.test.js +14 -11
- package/test/helpers.js +3 -3
- package/test/mrl-embedder.test.js +108 -0
package/README.md
CHANGED
|
@@ -5,16 +5,18 @@
|
|
|
5
5
|
[](https://opensource.org/licenses/MIT)
|
|
6
6
|
[](https://nodejs.org/)
|
|
7
7
|
|
|
8
|
-
An extensible Model Context Protocol (MCP) server that provides intelligent semantic code search for AI assistants. Built with local AI models (
|
|
8
|
+
An extensible Model Context Protocol (MCP) server that provides intelligent semantic code search for AI assistants. Built with local AI models using Matryoshka Representation Learning (MRL) for flexible embedding dimensions (64-768d), with runtime workspace switching and comprehensive status reporting.
|
|
9
9
|
|
|
10
10
|
### Available Tools
|
|
11
11
|
|
|
12
|
-
| Tool | Description | Example
|
|
13
|
-
| ---------------------- | ------------------------------------------------- |
|
|
14
|
-
| `semantic_search` | Find code by meaning, not just keywords | `"Where do we validate user input?"`
|
|
15
|
-
| `index_codebase` | Manually trigger reindexing | Use after major refactoring or branch switches
|
|
16
|
-
| `clear_cache` | Reset the embeddings cache | Useful when cache becomes corrupted
|
|
17
|
-
| `d_check_last_version` | Get latest version of any package (20 ecosystems) | `"express"`, `"npm:react"`, `"pip:requests"`
|
|
12
|
+
| Tool | Description | Example |
|
|
13
|
+
| ---------------------- | ------------------------------------------------- | ----------------------------------------------- |
|
|
14
|
+
| `semantic_search` | Find code by meaning, not just keywords | `"Where do we validate user input?"` |
|
|
15
|
+
| `index_codebase` | Manually trigger reindexing | Use after major refactoring or branch switches |
|
|
16
|
+
| `clear_cache` | Reset the embeddings cache | Useful when cache becomes corrupted |
|
|
17
|
+
| `d_check_last_version` | Get latest version of any package (20 ecosystems) | `"express"`, `"npm:react"`, `"pip:requests"` |
|
|
18
|
+
| `e_set_workspace` | Change project path at runtime | Switch to different project without restart |
|
|
19
|
+
| `f_get_status` | Get server info: version, index status, config | Check indexing progress, model info, cache size |
|
|
18
20
|
|
|
19
21
|
## What This Does
|
|
20
22
|
|
|
@@ -130,19 +132,22 @@ For clients that support dynamic variables (VS Code, Cursor):
|
|
|
130
132
|
|
|
131
133
|
Override configuration settings via environment variables in your MCP config:
|
|
132
134
|
|
|
133
|
-
| Variable
|
|
134
|
-
|
|
|
135
|
-
| `SMART_CODING_VERBOSE`
|
|
136
|
-
| `SMART_CODING_BATCH_SIZE`
|
|
137
|
-
| `SMART_CODING_MAX_FILE_SIZE`
|
|
138
|
-
| `SMART_CODING_CHUNK_SIZE`
|
|
139
|
-
| `SMART_CODING_MAX_RESULTS`
|
|
140
|
-
| `SMART_CODING_SMART_INDEXING`
|
|
141
|
-
| `SMART_CODING_WATCH_FILES`
|
|
142
|
-
| `SMART_CODING_SEMANTIC_WEIGHT`
|
|
143
|
-
| `SMART_CODING_EXACT_MATCH_BOOST`
|
|
144
|
-
| `SMART_CODING_EMBEDDING_MODEL`
|
|
145
|
-
| `
|
|
135
|
+
| Variable | Type | Default | Description |
|
|
136
|
+
| ---------------------------------- | ------- | -------------------------------- | ------------------------------------------ |
|
|
137
|
+
| `SMART_CODING_VERBOSE` | boolean | `false` | Enable detailed logging |
|
|
138
|
+
| `SMART_CODING_BATCH_SIZE` | number | `100` | Files to process in parallel |
|
|
139
|
+
| `SMART_CODING_MAX_FILE_SIZE` | number | `1048576` | Max file size in bytes (1MB) |
|
|
140
|
+
| `SMART_CODING_CHUNK_SIZE` | number | `25` | Lines of code per chunk |
|
|
141
|
+
| `SMART_CODING_MAX_RESULTS` | number | `5` | Max search results |
|
|
142
|
+
| `SMART_CODING_SMART_INDEXING` | boolean | `true` | Enable smart project detection |
|
|
143
|
+
| `SMART_CODING_WATCH_FILES` | boolean | `false` | Enable file watching for auto-reindex |
|
|
144
|
+
| `SMART_CODING_SEMANTIC_WEIGHT` | number | `0.7` | Weight for semantic similarity (0-1) |
|
|
145
|
+
| `SMART_CODING_EXACT_MATCH_BOOST` | number | `1.5` | Boost for exact text matches |
|
|
146
|
+
| `SMART_CODING_EMBEDDING_MODEL` | string | `nomic-ai/nomic-embed-text-v1.5` | AI embedding model to use |
|
|
147
|
+
| `SMART_CODING_EMBEDDING_DIMENSION` | number | `256` | MRL dimension (64, 128, 256, 512, 768) |
|
|
148
|
+
| `SMART_CODING_DEVICE` | string | `cpu` | Inference device (`cpu`, `webgpu`, `auto`) |
|
|
149
|
+
| `SMART_CODING_CHUNKING_MODE` | string | `smart` | Code chunking (`smart`, `ast`, `line`) |
|
|
150
|
+
| `SMART_CODING_WORKER_THREADS` | string | `auto` | Worker threads (`auto` or 1-32) |
|
|
146
151
|
|
|
147
152
|
**Example with environment variables:**
|
|
148
153
|
|
|
@@ -166,16 +171,72 @@ Override configuration settings via environment variables in your MCP config:
|
|
|
166
171
|
|
|
167
172
|
## How It Works
|
|
168
173
|
|
|
169
|
-
|
|
174
|
+
```mermaid
|
|
175
|
+
flowchart TB
|
|
176
|
+
subgraph IDE["IDE / AI Assistant"]
|
|
177
|
+
Agent["AI Agent<br/>(Claude, GPT, Gemini)"]
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
subgraph MCP["Smart Coding MCP Server"]
|
|
181
|
+
direction TB
|
|
182
|
+
Protocol["Model Context Protocol<br/>JSON-RPC over stdio"]
|
|
183
|
+
Tools["MCP Tools<br/>semantic_search | index_codebase | set_workspace | get_status"]
|
|
184
|
+
|
|
185
|
+
subgraph Indexing["Indexing Pipeline"]
|
|
186
|
+
Discovery["File Discovery<br/>glob patterns + smart ignore"]
|
|
187
|
+
Chunking["Code Chunking<br/>Smart (regex) / AST (Tree-sitter)"]
|
|
188
|
+
Embedding["AI Embedding<br/>transformers.js + ONNX Runtime"]
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
subgraph AI["AI Model"]
|
|
192
|
+
Model["nomic-embed-text-v1.5<br/>Matryoshka Representation Learning"]
|
|
193
|
+
Dimensions["Flexible Dimensions<br/>64 | 128 | 256 | 512 | 768"]
|
|
194
|
+
Normalize["Layer Norm → Slice → L2 Normalize"]
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
subgraph Search["Search"]
|
|
198
|
+
QueryEmbed["Query → Vector"]
|
|
199
|
+
Cosine["Cosine Similarity"]
|
|
200
|
+
Hybrid["Hybrid Search<br/>Semantic + Exact Match Boost"]
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
subgraph Storage["Cache"]
|
|
205
|
+
Vectors["Vector Store<br/>embeddings.json"]
|
|
206
|
+
Hashes["File Hashes<br/>Incremental updates"]
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
Agent <-->|"MCP Protocol"| Protocol
|
|
210
|
+
Protocol --> Tools
|
|
211
|
+
|
|
212
|
+
Tools --> Discovery
|
|
213
|
+
Discovery --> Chunking
|
|
214
|
+
Chunking --> Embedding
|
|
215
|
+
Embedding --> Model
|
|
216
|
+
Model --> Dimensions
|
|
217
|
+
Dimensions --> Normalize
|
|
218
|
+
Normalize --> Vectors
|
|
219
|
+
|
|
220
|
+
Tools --> QueryEmbed
|
|
221
|
+
QueryEmbed --> Model
|
|
222
|
+
Cosine --> Hybrid
|
|
223
|
+
Vectors --> Cosine
|
|
224
|
+
Hybrid --> Agent
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### Tech Stack
|
|
170
228
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
229
|
+
| Component | Technology |
|
|
230
|
+
| ------------- | ------------------------------------- |
|
|
231
|
+
| **Protocol** | Model Context Protocol (JSON-RPC) |
|
|
232
|
+
| **AI Model** | nomic-embed-text-v1.5 (MRL) |
|
|
233
|
+
| **Inference** | transformers.js + ONNX Runtime |
|
|
234
|
+
| **Chunking** | Smart regex / Tree-sitter AST |
|
|
235
|
+
| **Search** | Cosine similarity + exact match boost |
|
|
175
236
|
|
|
176
|
-
|
|
237
|
+
### Search Flow
|
|
177
238
|
|
|
178
|
-
|
|
239
|
+
Query → Vector embedding → Cosine similarity → Ranked results
|
|
179
240
|
|
|
180
241
|
## Examples
|
|
181
242
|
|
|
@@ -214,11 +275,18 @@ Finds all try/catch blocks and error handling patterns.
|
|
|
214
275
|
|
|
215
276
|
## Technical Details
|
|
216
277
|
|
|
217
|
-
**Embedding Model**:
|
|
278
|
+
**Embedding Model**: nomic-embed-text-v1.5 via transformers.js v3
|
|
279
|
+
|
|
280
|
+
- Matryoshka Representation Learning (MRL) for flexible dimensions
|
|
281
|
+
- Configurable output: 64, 128, 256, 512, or 768 dimensions
|
|
282
|
+
- Longer context (8192 tokens vs 256 for MiniLM)
|
|
283
|
+
- Better code understanding through specialized training
|
|
284
|
+
- WebGPU support for up to 100x faster inference (when available)
|
|
285
|
+
|
|
286
|
+
**Legacy Model**: all-MiniLM-L6-v2 (fallback)
|
|
218
287
|
|
|
219
|
-
- Fast inference (
|
|
220
|
-
-
|
|
221
|
-
- Good accuracy for code search
|
|
288
|
+
- Fast inference, small footprint (~100MB)
|
|
289
|
+
- Fixed 384-dimensional output
|
|
222
290
|
|
|
223
291
|
**Vector Similarity**: Cosine similarity
|
|
224
292
|
|
package/config.json
CHANGED
|
@@ -60,7 +60,10 @@
|
|
|
60
60
|
"cacheDirectory": "./.smart-coding-cache",
|
|
61
61
|
"watchFiles": false,
|
|
62
62
|
"verbose": false,
|
|
63
|
-
"embeddingModel": "
|
|
63
|
+
"embeddingModel": "nomic-ai/nomic-embed-text-v1.5",
|
|
64
|
+
"embeddingDimension": 256,
|
|
65
|
+
"device": "auto",
|
|
66
|
+
"chunkingMode": "smart",
|
|
64
67
|
"semanticWeight": 0.7,
|
|
65
68
|
"exactMatchBoost": 1.5,
|
|
66
69
|
"workerThreads": "auto"
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get Status Feature
|
|
3
|
+
*
|
|
4
|
+
* MCP tool to return comprehensive status information about the server.
|
|
5
|
+
* Useful for agents to understand current state and configuration.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import fs from 'fs/promises';
|
|
9
|
+
import path from 'path';
|
|
10
|
+
import { createRequire } from 'module';
|
|
11
|
+
|
|
12
|
+
const require = createRequire(import.meta.url);
|
|
13
|
+
const packageJson = require('../package.json');
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Get tool definition for MCP registration
|
|
17
|
+
*/
|
|
18
|
+
export function getToolDefinition(config) {
|
|
19
|
+
return {
|
|
20
|
+
name: "f_get_status",
|
|
21
|
+
description: "Get comprehensive status information about the Smart Coding MCP server. Returns version, workspace path, model configuration, indexing status, and cache information. Useful for understanding the current state of the semantic search system.",
|
|
22
|
+
inputSchema: {
|
|
23
|
+
type: "object",
|
|
24
|
+
properties: {},
|
|
25
|
+
required: []
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Status Reporter class
|
|
32
|
+
*/
|
|
33
|
+
export class StatusReporter {
|
|
34
|
+
constructor(config, cache, indexer, embedder) {
|
|
35
|
+
this.config = config;
|
|
36
|
+
this.cache = cache;
|
|
37
|
+
this.indexer = indexer;
|
|
38
|
+
this.embedder = embedder;
|
|
39
|
+
this.startTime = Date.now();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Get comprehensive status
|
|
44
|
+
*/
|
|
45
|
+
async getStatus() {
|
|
46
|
+
const vectorStore = this.cache?.getVectorStore() || [];
|
|
47
|
+
|
|
48
|
+
// Get unique files from vector store
|
|
49
|
+
const uniqueFiles = new Set(vectorStore.map(v => v.file));
|
|
50
|
+
|
|
51
|
+
// Get cache size
|
|
52
|
+
let cacheSizeBytes = 0;
|
|
53
|
+
try {
|
|
54
|
+
const cachePath = path.join(this.config.cacheDirectory, 'embeddings.json');
|
|
55
|
+
const stats = await fs.stat(cachePath);
|
|
56
|
+
cacheSizeBytes = stats.size;
|
|
57
|
+
} catch {
|
|
58
|
+
// Cache file doesn't exist yet
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Determine index status
|
|
62
|
+
let indexStatus = 'empty';
|
|
63
|
+
if (this.indexer?.isIndexing) {
|
|
64
|
+
indexStatus = 'indexing';
|
|
65
|
+
} else if (vectorStore.length > 0) {
|
|
66
|
+
indexStatus = 'ready';
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return {
|
|
70
|
+
version: packageJson.version,
|
|
71
|
+
uptime: Math.floor((Date.now() - this.startTime) / 1000),
|
|
72
|
+
|
|
73
|
+
workspace: {
|
|
74
|
+
path: this.config.searchDirectory,
|
|
75
|
+
cacheDirectory: this.config.cacheDirectory
|
|
76
|
+
},
|
|
77
|
+
|
|
78
|
+
model: {
|
|
79
|
+
name: this.embedder?.modelName || this.config.embeddingModel,
|
|
80
|
+
dimension: this.embedder?.dimension || this.config.embeddingDimension,
|
|
81
|
+
device: this.embedder?.device || this.config.device
|
|
82
|
+
},
|
|
83
|
+
|
|
84
|
+
index: {
|
|
85
|
+
status: indexStatus,
|
|
86
|
+
filesIndexed: uniqueFiles.size,
|
|
87
|
+
chunksCount: vectorStore.length,
|
|
88
|
+
chunkingMode: this.config.chunkingMode
|
|
89
|
+
},
|
|
90
|
+
|
|
91
|
+
cache: {
|
|
92
|
+
enabled: this.config.enableCache,
|
|
93
|
+
path: this.config.cacheDirectory,
|
|
94
|
+
sizeBytes: cacheSizeBytes,
|
|
95
|
+
sizeFormatted: formatBytes(cacheSizeBytes)
|
|
96
|
+
},
|
|
97
|
+
|
|
98
|
+
config: {
|
|
99
|
+
maxResults: this.config.maxResults,
|
|
100
|
+
chunkSize: this.config.chunkSize,
|
|
101
|
+
semanticWeight: this.config.semanticWeight,
|
|
102
|
+
exactMatchBoost: this.config.exactMatchBoost,
|
|
103
|
+
workerThreads: this.config.workerThreads
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Format bytes to human readable
|
|
111
|
+
*/
|
|
112
|
+
function formatBytes(bytes) {
|
|
113
|
+
if (bytes === 0) return '0 B';
|
|
114
|
+
const k = 1024;
|
|
115
|
+
const sizes = ['B', 'KB', 'MB', 'GB'];
|
|
116
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
117
|
+
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Handle MCP tool call
|
|
122
|
+
*/
|
|
123
|
+
export async function handleToolCall(request, instance) {
|
|
124
|
+
const status = await instance.getStatus();
|
|
125
|
+
|
|
126
|
+
return {
|
|
127
|
+
content: [{
|
|
128
|
+
type: "text",
|
|
129
|
+
text: JSON.stringify(status, null, 2)
|
|
130
|
+
}]
|
|
131
|
+
};
|
|
132
|
+
}
|
|
@@ -25,6 +25,13 @@ export class CodebaseIndexer {
|
|
|
25
25
|
* Initialize worker thread pool for parallel embedding
|
|
26
26
|
*/
|
|
27
27
|
async initializeWorkers() {
|
|
28
|
+
// Force single-threaded mode for nomic models (transformers.js v3 worker thread issue)
|
|
29
|
+
const isNomicModel = this.config.embeddingModel?.includes('nomic');
|
|
30
|
+
if (isNomicModel) {
|
|
31
|
+
console.error("[Indexer] Single-threaded mode (nomic model - workers disabled for stability)");
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
28
35
|
const numWorkers = this.config.workerThreads === "auto"
|
|
29
36
|
? Math.max(1, os.cpus().length - 1)
|
|
30
37
|
: (this.config.workerThreads || 1);
|
|
@@ -48,6 +55,7 @@ export class CodebaseIndexer {
|
|
|
48
55
|
const worker = new Worker(workerPath, {
|
|
49
56
|
workerData: {
|
|
50
57
|
embeddingModel: this.config.embeddingModel,
|
|
58
|
+
embeddingDimension: this.config.embeddingDimension,
|
|
51
59
|
verbose: this.config.verbose
|
|
52
60
|
}
|
|
53
61
|
});
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Set Workspace Feature
|
|
3
|
+
*
|
|
4
|
+
* MCP tool to change the project workspace path at runtime.
|
|
5
|
+
* Useful when agent detects it's in a different directory.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import fs from 'fs/promises';
|
|
9
|
+
import path from 'path';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Get tool definition for MCP registration
|
|
13
|
+
*/
|
|
14
|
+
export function getToolDefinition(config) {
|
|
15
|
+
return {
|
|
16
|
+
name: "e_set_workspace",
|
|
17
|
+
description: "Change the project workspace path at runtime. Use this when you detect the current workspace is incorrect or you need to switch to a different project directory. Creates cache folder automatically and optionally re-indexes the new workspace.",
|
|
18
|
+
inputSchema: {
|
|
19
|
+
type: "object",
|
|
20
|
+
properties: {
|
|
21
|
+
path: {
|
|
22
|
+
type: "string",
|
|
23
|
+
description: "Absolute path to the new workspace directory"
|
|
24
|
+
},
|
|
25
|
+
clearCache: {
|
|
26
|
+
type: "boolean",
|
|
27
|
+
description: "Whether to clear existing cache before switching (default: false)"
|
|
28
|
+
},
|
|
29
|
+
reindex: {
|
|
30
|
+
type: "boolean",
|
|
31
|
+
description: "Whether to trigger re-indexing after switching (default: true)"
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
required: ["path"]
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Workspace Manager class
|
|
41
|
+
*/
|
|
42
|
+
export class WorkspaceManager {
|
|
43
|
+
constructor(config, cache, indexer) {
|
|
44
|
+
this.config = config;
|
|
45
|
+
this.cache = cache;
|
|
46
|
+
this.indexer = indexer;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Set new workspace path
|
|
51
|
+
*/
|
|
52
|
+
async setWorkspace(newPath, options = {}) {
|
|
53
|
+
const { clearCache = false, reindex = true } = options;
|
|
54
|
+
|
|
55
|
+
// Validate path
|
|
56
|
+
try {
|
|
57
|
+
const stats = await fs.stat(newPath);
|
|
58
|
+
if (!stats.isDirectory()) {
|
|
59
|
+
return {
|
|
60
|
+
success: false,
|
|
61
|
+
error: `Path is not a directory: ${newPath}`
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
} catch (err) {
|
|
65
|
+
return {
|
|
66
|
+
success: false,
|
|
67
|
+
error: `Path does not exist: ${newPath}`
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const oldPath = this.config.searchDirectory;
|
|
72
|
+
|
|
73
|
+
// Update config
|
|
74
|
+
this.config.searchDirectory = newPath;
|
|
75
|
+
|
|
76
|
+
// Update cache directory
|
|
77
|
+
const newCacheDir = path.join(newPath, '.smart-coding-cache');
|
|
78
|
+
this.config.cacheDirectory = newCacheDir;
|
|
79
|
+
|
|
80
|
+
// Ensure cache directory exists
|
|
81
|
+
try {
|
|
82
|
+
await fs.mkdir(newCacheDir, { recursive: true });
|
|
83
|
+
} catch (err) {
|
|
84
|
+
// Ignore if already exists
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Clear cache if requested
|
|
88
|
+
if (clearCache && this.cache) {
|
|
89
|
+
this.cache.setVectorStore([]);
|
|
90
|
+
this.cache.fileHashes = new Map();
|
|
91
|
+
console.error(`[Workspace] Cache cleared for new workspace`);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Update cache path and reload
|
|
95
|
+
if (this.cache) {
|
|
96
|
+
this.cache.config = this.config;
|
|
97
|
+
await this.cache.load();
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Update indexer config
|
|
101
|
+
if (this.indexer) {
|
|
102
|
+
this.indexer.config = this.config;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
console.error(`[Workspace] Changed from ${oldPath} to ${newPath}`);
|
|
106
|
+
|
|
107
|
+
// Trigger re-indexing if requested
|
|
108
|
+
let indexResult = null;
|
|
109
|
+
if (reindex && this.indexer) {
|
|
110
|
+
console.error(`[Workspace] Starting re-indexing...`);
|
|
111
|
+
try {
|
|
112
|
+
indexResult = await this.indexer.indexAll(clearCache);
|
|
113
|
+
} catch (err) {
|
|
114
|
+
console.error(`[Workspace] Re-indexing error: ${err.message}`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return {
|
|
119
|
+
success: true,
|
|
120
|
+
oldPath,
|
|
121
|
+
newPath,
|
|
122
|
+
cacheDirectory: newCacheDir,
|
|
123
|
+
reindexed: reindex,
|
|
124
|
+
indexResult
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Handle MCP tool call
|
|
131
|
+
*/
|
|
132
|
+
export async function handleToolCall(request, instance) {
|
|
133
|
+
const { path: newPath, clearCache, reindex } = request.params.arguments || {};
|
|
134
|
+
|
|
135
|
+
if (!newPath) {
|
|
136
|
+
return {
|
|
137
|
+
content: [{
|
|
138
|
+
type: "text",
|
|
139
|
+
text: JSON.stringify({
|
|
140
|
+
success: false,
|
|
141
|
+
error: "Missing required parameter: path"
|
|
142
|
+
}, null, 2)
|
|
143
|
+
}]
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const result = await instance.setWorkspace(newPath, { clearCache, reindex });
|
|
148
|
+
|
|
149
|
+
return {
|
|
150
|
+
content: [{
|
|
151
|
+
type: "text",
|
|
152
|
+
text: JSON.stringify(result, null, 2)
|
|
153
|
+
}]
|
|
154
|
+
};
|
|
155
|
+
}
|
package/index.js
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
3
3
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
4
|
import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
5
|
-
import { pipeline } from "@xenova/transformers";
|
|
6
5
|
import fs from "fs/promises";
|
|
7
6
|
import { createRequire } from "module";
|
|
8
7
|
|
|
@@ -12,6 +11,7 @@ const packageJson = require("./package.json");
|
|
|
12
11
|
|
|
13
12
|
import { loadConfig } from "./lib/config.js";
|
|
14
13
|
import { EmbeddingsCache } from "./lib/cache.js";
|
|
14
|
+
import { createEmbedder } from "./lib/mrl-embedder.js";
|
|
15
15
|
import { CodebaseIndexer } from "./features/index-codebase.js";
|
|
16
16
|
import { HybridSearch } from "./features/hybrid-search.js";
|
|
17
17
|
|
|
@@ -19,6 +19,8 @@ import * as IndexCodebaseFeature from "./features/index-codebase.js";
|
|
|
19
19
|
import * as HybridSearchFeature from "./features/hybrid-search.js";
|
|
20
20
|
import * as ClearCacheFeature from "./features/clear-cache.js";
|
|
21
21
|
import * as CheckLastVersionFeature from "./features/check-last-version.js";
|
|
22
|
+
import * as SetWorkspaceFeature from "./features/set-workspace.js";
|
|
23
|
+
import * as GetStatusFeature from "./features/get-status.js";
|
|
22
24
|
|
|
23
25
|
// Parse workspace from command line arguments
|
|
24
26
|
const args = process.argv.slice(2);
|
|
@@ -78,6 +80,16 @@ const features = [
|
|
|
78
80
|
module: CheckLastVersionFeature,
|
|
79
81
|
instance: null,
|
|
80
82
|
handler: CheckLastVersionFeature.handleToolCall
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
module: SetWorkspaceFeature,
|
|
86
|
+
instance: null,
|
|
87
|
+
handler: SetWorkspaceFeature.handleToolCall
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
module: GetStatusFeature,
|
|
91
|
+
instance: null,
|
|
92
|
+
handler: GetStatusFeature.handleToolCall
|
|
81
93
|
}
|
|
82
94
|
];
|
|
83
95
|
|
|
@@ -94,9 +106,10 @@ async function initialize() {
|
|
|
94
106
|
process.exit(1);
|
|
95
107
|
}
|
|
96
108
|
|
|
97
|
-
// Load AI model
|
|
109
|
+
// Load AI model using MRL embedder factory
|
|
98
110
|
console.error("[Server] Loading AI embedding model (this may take time on first run)...");
|
|
99
|
-
embedder = await
|
|
111
|
+
embedder = await createEmbedder(config);
|
|
112
|
+
console.error(`[Server] Model: ${embedder.modelName} (${embedder.dimension}d, device: ${embedder.device})`);
|
|
100
113
|
|
|
101
114
|
// Initialize cache
|
|
102
115
|
cache = new EmbeddingsCache(config);
|
|
@@ -113,6 +126,12 @@ async function initialize() {
|
|
|
113
126
|
features[1].instance = indexer;
|
|
114
127
|
features[2].instance = cacheClearer;
|
|
115
128
|
features[3].instance = versionChecker;
|
|
129
|
+
|
|
130
|
+
// Initialize new tools
|
|
131
|
+
const workspaceManager = new SetWorkspaceFeature.WorkspaceManager(config, cache, indexer);
|
|
132
|
+
const statusReporter = new GetStatusFeature.StatusReporter(config, cache, indexer, embedder);
|
|
133
|
+
features[4].instance = workspaceManager;
|
|
134
|
+
features[5].instance = statusReporter;
|
|
116
135
|
|
|
117
136
|
// Start indexing in background (non-blocking)
|
|
118
137
|
console.error("[Server] Starting background indexing...");
|