magector 1.7.1 → 2.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/README.md +55 -5
- package/package.json +9 -7
- package/src/cli.js +41 -7
- package/src/init.js +3 -0
- package/src/mcp-server.js +1168 -31
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
**Technology-aware MCP server for Magento 2 and Adobe Commerce with intelligent indexing and search.**
|
|
4
4
|
|
|
5
|
-
Magector is a Model Context Protocol (MCP) server that deeply understands Magento 2 and Adobe Commerce. It builds a semantic vector index of your entire codebase — 18,000+ files across hundreds of modules — and exposes
|
|
5
|
+
Magector is a Model Context Protocol (MCP) server that deeply understands Magento 2 and Adobe Commerce. It builds a semantic vector index of your entire codebase — 18,000+ files across hundreds of modules — and exposes 28 tools that let AI assistants search, navigate, and understand the code with domain-specific intelligence. Instead of grepping for keywords, your AI asks *"how are checkout totals calculated?"* and gets ranked, relevant results in under 50ms, enriched with Magento pattern detection (plugins, observers, controllers, DI preferences, layout XML, and 20+ more).
|
|
6
6
|
|
|
7
7
|
[](https://www.rust-lang.org)
|
|
8
8
|
[](https://nodejs.org)
|
|
@@ -58,7 +58,7 @@ The result: your AI assistant calls one MCP tool and gets ranked, pattern-enrich
|
|
|
58
58
|
- **Complexity analysis** -- cyclomatic complexity, function count, and hotspot detection across modules
|
|
59
59
|
- **Fast** -- 10-45ms queries via persistent serve process, batched ONNX embedding with adaptive thread scaling
|
|
60
60
|
- **LLM description enrichment** -- generate natural-language descriptions of di.xml files using Claude, stored in SQLite, and prepend them to embedding text so descriptions influence vector search ranking (not just post-retrieval display)
|
|
61
|
-
- **MCP server** --
|
|
61
|
+
- **MCP server** -- 28 tools integrating with Claude Code, Cursor, and any MCP-compatible AI tool
|
|
62
62
|
- **Clean architecture** -- Rust core handles all indexing/search, Node.js MCP server delegates to it
|
|
63
63
|
|
|
64
64
|
---
|
|
@@ -70,7 +70,7 @@ flowchart LR
|
|
|
70
70
|
subgraph node ["Node.js Layer"]
|
|
71
71
|
direction TB
|
|
72
72
|
G["CLI<br/>init · index · search · describe"]
|
|
73
|
-
E["MCP Server<br/>
|
|
73
|
+
E["MCP Server<br/>28 tools · LRU cache"]
|
|
74
74
|
F["Persistent Serve Process"]
|
|
75
75
|
G --> F
|
|
76
76
|
E --> F
|
|
@@ -347,11 +347,29 @@ For very large or CPU-constrained runs, you may also need to extend the wall-clo
|
|
|
347
347
|
MAGECTOR_INDEX_TIMEOUT=28800000 npx magector index --threads 2 # 8 h timeout, 2 threads
|
|
348
348
|
```
|
|
349
349
|
|
|
350
|
+
### Resume after timeout or interrupt
|
|
351
|
+
|
|
352
|
+
Indexing writes a crash-safe checkpoint to disk every 50 batches (~12,800 files). If the process is killed or times out mid-run, **just re-run `npx magector index`** — it auto-resumes from the last checkpoint:
|
|
353
|
+
|
|
354
|
+
```bash
|
|
355
|
+
npx magector index
|
|
356
|
+
# ♻️ Resuming from previous run: 38400 vectors across 12200 files already indexed
|
|
357
|
+
# ✓ Found 79771 total files; 12200 already indexed, 67571 remaining to process
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
The indexer collects already-embedded file paths from the existing DB, filters them out of file discovery, preserves the existing HNSW state, and only parses/embeds the files that aren't in the DB yet. Partial resume also picks up new files added to the tree since the previous run.
|
|
361
|
+
|
|
362
|
+
To force a full rebuild (e.g. after a schema change or if you want to discard stale vectors), pass `--force`:
|
|
363
|
+
|
|
364
|
+
```bash
|
|
365
|
+
npx magector index --force
|
|
366
|
+
```
|
|
367
|
+
|
|
350
368
|
---
|
|
351
369
|
|
|
352
370
|
## MCP Server Tools
|
|
353
371
|
|
|
354
|
-
The MCP server exposes
|
|
372
|
+
The MCP server exposes 28 tools for AI-assisted Magento 2 and Adobe Commerce development. All search tools return **structured JSON** with file paths, class names, methods, role badges, and content snippets -- enabling AI clients to parse results programmatically and minimize file-read round-trips.
|
|
355
373
|
|
|
356
374
|
### Output Format
|
|
357
375
|
|
|
@@ -407,14 +425,31 @@ All search tools return structured JSON:
|
|
|
407
425
|
| `magento_find_cron` | Find cron job definitions in crontab.xml |
|
|
408
426
|
| `magento_find_db_schema` | Find database table definitions in db_schema.xml (declarative schema) |
|
|
409
427
|
|
|
410
|
-
### Flow Tracing
|
|
428
|
+
### Flow & Dependency Tracing
|
|
411
429
|
|
|
412
430
|
| Tool | Description |
|
|
413
431
|
|------|-------------|
|
|
414
432
|
| `magento_trace_flow` | Trace execution flow from an entry point (route, API, GraphQL, event, cron) -- maps controller → plugins → observers → templates in one call |
|
|
433
|
+
| `magento_trace_dependency` | Trace DI graph for a class/interface -- preferences, plugins, virtualTypes, argument overrides (parses all di.xml, no index needed) |
|
|
434
|
+
| `magento_find_event_flow` | Trace complete event chain: dispatchers → observers → handler PHP classes (parses events.xml + vector search) |
|
|
435
|
+
| `magento_find_layout` | Find layout XML files by handle or content -- lists blocks, containers, and referenceBlock declarations |
|
|
415
436
|
|
|
416
437
|
Auto-detects entry type from pattern (`/V1/...` → API, `snake_case` → event, `camelCase` → GraphQL, `path/segments` → route), or override with `entryType`. Use `depth: "shallow"` (entry + config + plugins) or `depth: "deep"` (adds observers, layout, templates, DI preferences).
|
|
417
438
|
|
|
439
|
+
### Impact & Testing
|
|
440
|
+
|
|
441
|
+
| Tool | Description |
|
|
442
|
+
|------|-------------|
|
|
443
|
+
| `magento_impact_analysis` | Analyze impact of changing a class -- finds use statements, DI references, direct instantiations, and type hints across the codebase |
|
|
444
|
+
| `magento_find_test` | Find PHPUnit tests for a given class/method -- searches Test/ directories for coverage, mocks, and assertions |
|
|
445
|
+
|
|
446
|
+
### Diagnostics
|
|
447
|
+
|
|
448
|
+
| Tool | Description |
|
|
449
|
+
|------|-------------|
|
|
450
|
+
| `magento_error_parser` | Parse Magento error messages and map to root cause, affected files, and fix suggestions (10 known patterns) |
|
|
451
|
+
| `magento_performance_profile` | Profile a Magento subsystem (checkout_totals, order_place, product_save, etc.) for performance bottlenecks -- plugins, observers, and complexity hotspots |
|
|
452
|
+
|
|
418
453
|
### Analysis Tools
|
|
419
454
|
|
|
420
455
|
| Tool | Description |
|
|
@@ -431,6 +466,13 @@ Auto-detects entry type from pattern (`/V1/...` → API, `snake_case` → event,
|
|
|
431
466
|
| `magento_describe` | Generate LLM descriptions for di.xml files (requires `ANTHROPIC_API_KEY`), stored in SQLite, auto-reindexes affected files |
|
|
432
467
|
| `magento_stats` | View index statistics |
|
|
433
468
|
|
|
469
|
+
### Search Enhancements (v2.1)
|
|
470
|
+
|
|
471
|
+
- **Hybrid BM25+vector search** -- combines text frequency scoring with semantic vector similarity for better exact class name matches
|
|
472
|
+
- **Query expansion** -- automatically expands queries with Magento domain synonyms (plugin → interceptor, checkout → cart/quote/totals, etc.)
|
|
473
|
+
- **Module filtering** -- `moduleFilter` parameter on `magento_search` to limit results by vendor/module pattern (supports wildcards, e.g., `"Vendor_*"`)
|
|
474
|
+
- **Non-blocking reindex** -- old index stays usable during background rebuild; new index is built to a temp path and swapped in atomically on completion
|
|
475
|
+
|
|
434
476
|
### Tool Cross-References
|
|
435
477
|
|
|
436
478
|
Each tool description includes "See also" hints to help AI clients chain tools effectively:
|
|
@@ -458,6 +500,14 @@ graph LR
|
|
|
458
500
|
trc -.-> tpl
|
|
459
501
|
trc -.-> api
|
|
460
502
|
trc -.-> gql
|
|
503
|
+
dep["trace_dependency"] --> prf
|
|
504
|
+
dep --> plg
|
|
505
|
+
evf["find_event_flow"] --> obs
|
|
506
|
+
imp["impact_analysis"] --> dep
|
|
507
|
+
imp --> cls
|
|
508
|
+
tst["find_test"] --> cls
|
|
509
|
+
err["error_parser"] --> dep
|
|
510
|
+
lay["find_layout"] --> blk
|
|
461
511
|
|
|
462
512
|
style cls fill:#4a90d9,color:#fff
|
|
463
513
|
style mtd fill:#4a90d9,color:#fff
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "magector",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "Semantic code search for Magento 2 — index, search, MCP server",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/mcp-server.js",
|
|
@@ -20,7 +20,9 @@
|
|
|
20
20
|
"validate:verbose": "node src/cli.js validate --verbose",
|
|
21
21
|
"validate:keep": "node src/cli.js validate --verbose --keep",
|
|
22
22
|
"benchmark": "node src/cli.js benchmark",
|
|
23
|
-
"test": "node tests/mcp-server.test.js",
|
|
23
|
+
"test": "node tests/unit.test.js && node tests/mcp-server.test.js",
|
|
24
|
+
"test:unit": "node tests/unit.test.js",
|
|
25
|
+
"test:integration": "node tests/mcp-server.test.js",
|
|
24
26
|
"test:no-index": "node tests/mcp-server.test.js --no-index",
|
|
25
27
|
"test:accuracy": "node tests/mcp-accuracy.test.js",
|
|
26
28
|
"test:accuracy:verbose": "node tests/mcp-accuracy.test.js --verbose",
|
|
@@ -32,15 +34,15 @@
|
|
|
32
34
|
"dependencies": {
|
|
33
35
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
34
36
|
"chalk": "^5.3.0",
|
|
35
|
-
"glob": "^
|
|
37
|
+
"glob": "^13.0.0",
|
|
36
38
|
"ora": "^8.0.1",
|
|
37
39
|
"ruvector": "^0.1.96"
|
|
38
40
|
},
|
|
39
41
|
"optionalDependencies": {
|
|
40
|
-
"@magector/cli-darwin-arm64": "1.
|
|
41
|
-
"@magector/cli-linux-x64": "1.
|
|
42
|
-
"@magector/cli-linux-arm64": "1.
|
|
43
|
-
"@magector/cli-win32-x64": "1.
|
|
42
|
+
"@magector/cli-darwin-arm64": "2.1.0",
|
|
43
|
+
"@magector/cli-linux-x64": "2.1.0",
|
|
44
|
+
"@magector/cli-linux-arm64": "2.1.0",
|
|
45
|
+
"@magector/cli-win32-x64": "2.1.0"
|
|
44
46
|
},
|
|
45
47
|
"keywords": [
|
|
46
48
|
"magento",
|
package/src/cli.js
CHANGED
|
@@ -40,7 +40,9 @@ Index options:
|
|
|
40
40
|
system responsive during indexing.
|
|
41
41
|
--batch-size <n> Embedding batch size (default: 256). Higher = faster
|
|
42
42
|
but more RAM.
|
|
43
|
-
--force
|
|
43
|
+
--force Discard any existing index and rebuild from scratch.
|
|
44
|
+
Without --force, indexing auto-resumes from the last
|
|
45
|
+
incremental save (written every ~50 batches).
|
|
44
46
|
|
|
45
47
|
Environment Variables:
|
|
46
48
|
MAGENTO_ROOT Path to Magento installation (default: cwd)
|
|
@@ -122,6 +124,12 @@ async function runIndex(targetPath, opts = {}) {
|
|
|
122
124
|
if (opts.batchSize != null) {
|
|
123
125
|
indexArgs.push('--batch-size', String(opts.batchSize));
|
|
124
126
|
}
|
|
127
|
+
// --force discards any existing partial index and rebuilds from scratch.
|
|
128
|
+
// Without it, the Rust indexer auto-resumes from the last incremental
|
|
129
|
+
// save on disk and only re-embeds files that aren't in the DB yet.
|
|
130
|
+
if (opts.force) {
|
|
131
|
+
indexArgs.push('--force');
|
|
132
|
+
}
|
|
125
133
|
// Pass descriptions DB if it exists
|
|
126
134
|
const descDbPath = path.resolve(root, '.magector', 'sqlite.db');
|
|
127
135
|
if (existsSync(descDbPath)) {
|
|
@@ -137,10 +145,12 @@ async function runIndex(targetPath, opts = {}) {
|
|
|
137
145
|
if (err.message && err.message.includes('ETIMEDOUT')) {
|
|
138
146
|
console.error(
|
|
139
147
|
`Indexing timed out after ${indexTimeout / 1000}s.\n` +
|
|
140
|
-
`
|
|
148
|
+
`Partial progress was saved to disk every ~50 batches — re-run\n` +
|
|
149
|
+
`'npx magector index' to auto-resume from the last checkpoint.\n` +
|
|
150
|
+
`\n` +
|
|
151
|
+
`For large codebases or CPU-constrained environments, also consider:\n` +
|
|
141
152
|
` MAGECTOR_INDEX_TIMEOUT=28800000 npx magector index # 8 hours\n` +
|
|
142
|
-
`
|
|
143
|
-
` npx magector index --threads 2`
|
|
153
|
+
` npx magector index --threads 2 # lower CPU usage`
|
|
144
154
|
);
|
|
145
155
|
} else {
|
|
146
156
|
console.error(`Indexing error: ${err.message}`);
|
|
@@ -247,20 +257,44 @@ async function main() {
|
|
|
247
257
|
|
|
248
258
|
case 'index': {
|
|
249
259
|
// First non-flag arg after `index` is the path; everything else is options.
|
|
260
|
+
// Must skip values belonging to flags (e.g., "4" in "--threads 4").
|
|
250
261
|
const indexArgv = args.slice(1);
|
|
251
|
-
const targetPath = indexArgv.find(a => !a.startsWith('-'));
|
|
252
262
|
const indexOpts = parseArgs(indexArgv);
|
|
263
|
+
let targetPath = undefined;
|
|
264
|
+
for (let i = 0; i < indexArgv.length; i++) {
|
|
265
|
+
if (indexArgv[i] === '--threads' || indexArgv[i] === '--batch-size') {
|
|
266
|
+
i++; // skip the flag's value
|
|
267
|
+
} else if (indexArgv[i].startsWith('-')) {
|
|
268
|
+
// skip boolean flags like --force, --verbose
|
|
269
|
+
} else {
|
|
270
|
+
targetPath = indexArgv[i];
|
|
271
|
+
break; // first non-flag, non-value arg is the path
|
|
272
|
+
}
|
|
273
|
+
}
|
|
253
274
|
await runIndex(targetPath, indexOpts);
|
|
254
275
|
break;
|
|
255
276
|
}
|
|
256
277
|
|
|
257
278
|
case 'search': {
|
|
258
|
-
|
|
279
|
+
// Build query from non-flag arguments, skipping values that belong to flags
|
|
280
|
+
const searchArgv = args.slice(1);
|
|
281
|
+
const queryParts = [];
|
|
282
|
+
for (let i = 0; i < searchArgv.length; i++) {
|
|
283
|
+
if (searchArgv[i] === '-l' || searchArgv[i] === '--limit' ||
|
|
284
|
+
searchArgv[i] === '-f' || searchArgv[i] === '--format') {
|
|
285
|
+
i++; // skip the flag's value
|
|
286
|
+
} else if (searchArgv[i].startsWith('-')) {
|
|
287
|
+
// skip boolean flags like -v, --verbose
|
|
288
|
+
} else {
|
|
289
|
+
queryParts.push(searchArgv[i]);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
const query = queryParts.join(' ');
|
|
259
293
|
if (!query) {
|
|
260
294
|
console.error('Usage: npx magector search <query>');
|
|
261
295
|
process.exit(1);
|
|
262
296
|
}
|
|
263
|
-
const opts = parseArgs(
|
|
297
|
+
const opts = parseArgs(searchArgv);
|
|
264
298
|
runSearch(query, opts);
|
|
265
299
|
break;
|
|
266
300
|
}
|
package/src/init.js
CHANGED
|
@@ -265,6 +265,9 @@ export async function init(projectPath, opts = {}) {
|
|
|
265
265
|
if (opts.batchSize != null) {
|
|
266
266
|
indexArgs.push('--batch-size', String(opts.batchSize));
|
|
267
267
|
}
|
|
268
|
+
if (opts.force) {
|
|
269
|
+
indexArgs.push('--force');
|
|
270
|
+
}
|
|
268
271
|
execFileSync(binary, indexArgs, { timeout: initTimeout, stdio: 'inherit' });
|
|
269
272
|
} catch (err) {
|
|
270
273
|
if (err.status) {
|