code-graph-context 1.1.0 → 2.0.1
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 +221 -101
- package/dist/core/config/fairsquare-framework-schema.js +47 -60
- package/dist/core/config/nestjs-framework-schema.js +71 -44
- package/dist/core/config/schema.js +1 -1
- package/dist/core/config/timeouts.js +27 -0
- package/dist/core/embeddings/embeddings.service.js +122 -2
- package/dist/core/embeddings/natural-language-to-cypher.service.js +416 -17
- package/dist/core/parsers/parser-factory.js +5 -3
- package/dist/core/parsers/typescript-parser.js +618 -50
- package/dist/core/parsers/workspace-parser.js +554 -0
- package/dist/core/utils/edge-factory.js +37 -0
- package/dist/core/utils/file-change-detection.js +105 -0
- package/dist/core/utils/file-utils.js +20 -0
- package/dist/core/utils/index.js +3 -0
- package/dist/core/utils/path-utils.js +75 -0
- package/dist/core/utils/progress-reporter.js +112 -0
- package/dist/core/utils/project-id.js +176 -0
- package/dist/core/utils/retry.js +41 -0
- package/dist/core/workspace/index.js +4 -0
- package/dist/core/workspace/workspace-detector.js +221 -0
- package/dist/mcp/constants.js +153 -5
- package/dist/mcp/handlers/cross-file-edge.helpers.js +19 -0
- package/dist/mcp/handlers/file-change-detection.js +105 -0
- package/dist/mcp/handlers/graph-generator.handler.js +97 -32
- package/dist/mcp/handlers/incremental-parse.handler.js +146 -0
- package/dist/mcp/handlers/streaming-import.handler.js +210 -0
- package/dist/mcp/handlers/traversal.handler.js +130 -71
- package/dist/mcp/mcp.server.js +45 -6
- package/dist/mcp/service-init.js +79 -0
- package/dist/mcp/services/job-manager.js +165 -0
- package/dist/mcp/services/watch-manager.js +376 -0
- package/dist/mcp/services.js +2 -2
- package/dist/mcp/tools/check-parse-status.tool.js +64 -0
- package/dist/mcp/tools/impact-analysis.tool.js +84 -18
- package/dist/mcp/tools/index.js +13 -1
- package/dist/mcp/tools/list-projects.tool.js +62 -0
- package/dist/mcp/tools/list-watchers.tool.js +51 -0
- package/dist/mcp/tools/natural-language-to-cypher.tool.js +34 -8
- package/dist/mcp/tools/parse-typescript-project.tool.js +318 -58
- package/dist/mcp/tools/search-codebase.tool.js +56 -16
- package/dist/mcp/tools/start-watch-project.tool.js +100 -0
- package/dist/mcp/tools/stop-watch-project.tool.js +49 -0
- package/dist/mcp/tools/traverse-from-node.tool.js +68 -9
- package/dist/mcp/utils.js +35 -13
- package/dist/mcp/workers/parse-worker.js +198 -0
- package/dist/storage/neo4j/neo4j.service.js +147 -48
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/code-graph-context)
|
|
4
4
|
[](LICENSE)
|
|
5
5
|
[](https://typescriptlang.org/)
|
|
6
|
-
[](https://neo4j.com/)
|
|
7
7
|
[](https://nestjs.com/)
|
|
8
8
|
[](https://openai.com/)
|
|
9
9
|
[](https://modelcontextprotocol.io/)
|
|
@@ -14,11 +14,18 @@ A Model Context Protocol (MCP) server that builds rich code graphs to provide de
|
|
|
14
14
|
|
|
15
15
|
## Features
|
|
16
16
|
|
|
17
|
+
- **Multi-Project Support**: Parse and query multiple projects in a single database with complete isolation via `projectId`
|
|
17
18
|
- **Rich Code Graph Generation**: Parses TypeScript projects and creates detailed graph representations with AST-level precision
|
|
18
19
|
- **Semantic Search**: Vector-based semantic search using OpenAI embeddings to find relevant code patterns and implementations
|
|
19
20
|
- **Natural Language Querying**: Convert natural language questions into Cypher queries using OpenAI assistants API
|
|
20
21
|
- **Framework-Aware & Customizable**: Built-in NestJS schema with ability to define custom framework patterns via configuration
|
|
21
22
|
- **Weighted Graph Traversal**: Intelligent traversal that scores paths based on relationship importance, query relevance, and depth
|
|
23
|
+
- **Workspace & Monorepo Support**: Auto-detects Turborepo, pnpm, Yarn, and npm workspaces
|
|
24
|
+
- **Async Parsing**: Background parsing with Worker threads for large codebases without blocking the MCP server
|
|
25
|
+
- **Streaming Import**: Chunked processing for projects with 100+ files to prevent memory issues
|
|
26
|
+
- **Incremental Parsing**: Only reparse changed files for faster updates
|
|
27
|
+
- **File Watching**: Real-time monitoring with automatic incremental graph updates on file changes
|
|
28
|
+
- **Impact Analysis**: Assess refactoring risk with dependency analysis (LOW/MEDIUM/HIGH/CRITICAL scoring)
|
|
22
29
|
- **High Performance**: Optimized Neo4j storage with vector indexing for fast retrieval
|
|
23
30
|
- **MCP Integration**: Seamless integration with Claude Code and other MCP-compatible tools
|
|
24
31
|
|
|
@@ -45,7 +52,7 @@ The system uses a dual-schema approach:
|
|
|
45
52
|
### Prerequisites
|
|
46
53
|
|
|
47
54
|
- **Node.js** >= 18
|
|
48
|
-
- **Neo4j** >= 5.
|
|
55
|
+
- **Neo4j** >= 5.23 with APOC plugin
|
|
49
56
|
- **OpenAI API Key** (for embeddings and natural language processing)
|
|
50
57
|
- **Docker** (recommended for Neo4j setup)
|
|
51
58
|
|
|
@@ -112,7 +119,7 @@ docker run -d \
|
|
|
112
119
|
-p 7474:7474 -p 7687:7687 \
|
|
113
120
|
-e NEO4J_AUTH=neo4j/PASSWORD \
|
|
114
121
|
-e NEO4J_PLUGINS='["apoc"]' \
|
|
115
|
-
neo4j:5.
|
|
122
|
+
neo4j:5.23
|
|
116
123
|
```
|
|
117
124
|
|
|
118
125
|
**Option B: Neo4j Desktop**
|
|
@@ -226,9 +233,67 @@ node /path/to/code-graph-context/dist/mcp/mcp.server.js
|
|
|
226
233
|
npm run build
|
|
227
234
|
```
|
|
228
235
|
|
|
229
|
-
## Tool Usage Guide
|
|
236
|
+
## Tool Usage Guide
|
|
230
237
|
|
|
231
|
-
###
|
|
238
|
+
### Available Tools
|
|
239
|
+
|
|
240
|
+
| Tool | Description | Best For |
|
|
241
|
+
|------|-------------|----------|
|
|
242
|
+
| `list_projects` | List all parsed projects in database | **Discovery** - see available projects and their status |
|
|
243
|
+
| `search_codebase` | Semantic search using vector embeddings | **Starting point** - find code by describing what you need |
|
|
244
|
+
| `traverse_from_node` | Explore relationships from a specific node | **Deep dive** - understand dependencies and connections |
|
|
245
|
+
| `impact_analysis` | Analyze what depends on a node | **Pre-refactoring** - assess blast radius (LOW/MEDIUM/HIGH/CRITICAL) |
|
|
246
|
+
| `parse_typescript_project` | Parse project and build the graph | **Initial setup** - supports async mode for large projects |
|
|
247
|
+
| `check_parse_status` | Monitor async parsing job progress | **Monitoring** - track background parsing jobs |
|
|
248
|
+
| `start_watch_project` | Start file watching for a project | **Live updates** - auto-update graph on file changes |
|
|
249
|
+
| `stop_watch_project` | Stop file watching for a project | **Resource management** - stop monitoring |
|
|
250
|
+
| `list_watchers` | List all active file watchers | **Monitoring** - see what's being watched |
|
|
251
|
+
| `natural_language_to_cypher` | Convert natural language to Cypher | **Advanced queries** - complex graph queries |
|
|
252
|
+
| `test_neo4j_connection` | Verify database connectivity | **Health check** - troubleshooting |
|
|
253
|
+
|
|
254
|
+
> **Note**: All query tools (`search_codebase`, `traverse_from_node`, `impact_analysis`, `natural_language_to_cypher`) require a `projectId` parameter. Use `list_projects` to discover available projects.
|
|
255
|
+
|
|
256
|
+
### Tool Selection Guide
|
|
257
|
+
|
|
258
|
+
- **`list_projects`**: First step - discover what projects are available
|
|
259
|
+
- **`search_codebase`**: Find code by describing what you're looking for
|
|
260
|
+
- **`traverse_from_node`**: Use node IDs from search results to explore relationships
|
|
261
|
+
- **`impact_analysis`**: Before refactoring - understand what depends on the code you're changing
|
|
262
|
+
|
|
263
|
+
### Multi-Project Workflow
|
|
264
|
+
|
|
265
|
+
All query tools require a `projectId` parameter to ensure project isolation. You can provide:
|
|
266
|
+
|
|
267
|
+
1. **Project ID**: `proj_a1b2c3d4e5f6` (auto-generated from path)
|
|
268
|
+
2. **Project Name**: `my-backend` (extracted from package.json or directory name)
|
|
269
|
+
3. **Project Path**: `/path/to/my-backend` (resolved to project ID)
|
|
270
|
+
|
|
271
|
+
**Typical Workflow:**
|
|
272
|
+
|
|
273
|
+
```typescript
|
|
274
|
+
// Step 1: Discover available projects
|
|
275
|
+
list_projects()
|
|
276
|
+
// Returns: project names, IDs, status, node/edge counts
|
|
277
|
+
|
|
278
|
+
// Step 2: Parse a new project (if not already parsed)
|
|
279
|
+
parse_typescript_project({
|
|
280
|
+
projectPath: '/path/to/project',
|
|
281
|
+
tsconfigPath: '/path/to/project/tsconfig.json'
|
|
282
|
+
})
|
|
283
|
+
// Returns: projectId for use in queries
|
|
284
|
+
|
|
285
|
+
// Step 3: Query the project using any of these ID formats
|
|
286
|
+
search_codebase({ projectId: "my-backend", query: "authentication" })
|
|
287
|
+
search_codebase({ projectId: "proj_a1b2c3d4e5f6", query: "authentication" })
|
|
288
|
+
search_codebase({ projectId: "/path/to/my-backend", query: "authentication" })
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
**Pro Tips:**
|
|
292
|
+
- Use project names instead of full IDs for convenience
|
|
293
|
+
- Run `list_projects` first to see what's available
|
|
294
|
+
- Each project is completely isolated - queries never cross project boundaries
|
|
295
|
+
|
|
296
|
+
### Sequential Workflow Patterns
|
|
232
297
|
|
|
233
298
|
The MCP tools are designed to work together in powerful workflows. Here are the most effective patterns:
|
|
234
299
|
|
|
@@ -419,24 +484,71 @@ traverse_from_node({
|
|
|
419
484
|
```
|
|
420
485
|
|
|
421
486
|
#### 3. `parse_typescript_project` - Graph Generation
|
|
422
|
-
**Purpose**: Parse a TypeScript/NestJS project and build the
|
|
487
|
+
**Purpose**: Parse a TypeScript/NestJS project and build the graph database.
|
|
488
|
+
|
|
489
|
+
**Parameters:**
|
|
490
|
+
| Parameter | Type | Default | Description |
|
|
491
|
+
|-----------|------|---------|-------------|
|
|
492
|
+
| `projectPath` | string | required | Path to project root directory |
|
|
493
|
+
| `tsconfigPath` | string | required | Path to tsconfig.json |
|
|
494
|
+
| `projectId` | string | auto | Override auto-generated project ID |
|
|
495
|
+
| `clearExisting` | boolean | true | Clear existing data (false = incremental) |
|
|
496
|
+
| `async` | boolean | false | Run in background Worker thread |
|
|
497
|
+
| `useStreaming` | enum | "auto" | "auto", "always", or "never" |
|
|
498
|
+
| `chunkSize` | number | 50 | Files per chunk for streaming |
|
|
499
|
+
| `projectType` | enum | "auto" | "auto", "nestjs", "vanilla" |
|
|
500
|
+
| `watch` | boolean | false | Start file watching after parse (requires `async: false`) |
|
|
501
|
+
| `watchDebounceMs` | number | 1000 | Debounce delay for watch mode in ms |
|
|
423
502
|
|
|
424
503
|
```typescript
|
|
425
|
-
//
|
|
504
|
+
// Standard parsing (blocking)
|
|
505
|
+
await mcp.call('parse_typescript_project', {
|
|
506
|
+
projectPath: '/path/to/project',
|
|
507
|
+
tsconfigPath: '/path/to/project/tsconfig.json'
|
|
508
|
+
});
|
|
509
|
+
// Returns: projectId for use in queries
|
|
510
|
+
|
|
511
|
+
// Async parsing for large projects (non-blocking)
|
|
512
|
+
await mcp.call('parse_typescript_project', {
|
|
513
|
+
projectPath: '/path/to/large-project',
|
|
514
|
+
tsconfigPath: '/path/to/large-project/tsconfig.json',
|
|
515
|
+
async: true // Returns immediately with job ID
|
|
516
|
+
});
|
|
517
|
+
// Returns: "Job ID: job_abc123... Use check_parse_status to monitor."
|
|
518
|
+
|
|
519
|
+
// Check async job progress
|
|
520
|
+
await mcp.call('check_parse_status', { jobId: 'job_abc123' });
|
|
521
|
+
// Returns: progress %, phase, nodes/edges imported
|
|
522
|
+
|
|
523
|
+
// Incremental parsing (only changed files)
|
|
426
524
|
await mcp.call('parse_typescript_project', {
|
|
427
|
-
projectPath: '/path/to/
|
|
428
|
-
tsconfigPath: '/path/to/
|
|
429
|
-
clearExisting:
|
|
525
|
+
projectPath: '/path/to/project',
|
|
526
|
+
tsconfigPath: '/path/to/project/tsconfig.json',
|
|
527
|
+
clearExisting: false // Keep existing, only reparse changed files
|
|
430
528
|
});
|
|
431
529
|
|
|
432
|
-
//
|
|
433
|
-
|
|
530
|
+
// Parse and start file watching
|
|
531
|
+
await mcp.call('parse_typescript_project', {
|
|
532
|
+
projectPath: '/path/to/project',
|
|
533
|
+
tsconfigPath: '/path/to/project/tsconfig.json',
|
|
534
|
+
watch: true, // Start watching after parse completes
|
|
535
|
+
watchDebounceMs: 1000 // Wait 1s after last change before updating
|
|
536
|
+
});
|
|
537
|
+
// File changes now automatically trigger incremental graph updates
|
|
434
538
|
```
|
|
435
539
|
|
|
540
|
+
**Modes:**
|
|
541
|
+
- **Standard**: Blocks until complete, best for small-medium projects
|
|
542
|
+
- **Async**: Returns immediately, use `check_parse_status` to monitor
|
|
543
|
+
- **Streaming**: Auto-enabled for projects >100 files, prevents OOM
|
|
544
|
+
- **Incremental**: Set `clearExisting: false` to only reparse changed files
|
|
545
|
+
- **Watch**: Set `watch: true` to automatically update graph on file changes (requires sync mode)
|
|
546
|
+
|
|
436
547
|
**Performance Notes**:
|
|
437
|
-
- Large projects (>1000 files)
|
|
438
|
-
-
|
|
439
|
-
-
|
|
548
|
+
- Large projects (>1000 files) should use `async: true`
|
|
549
|
+
- Streaming is auto-enabled for projects >100 files
|
|
550
|
+
- Incremental mode detects changes via mtime, size, and content hash
|
|
551
|
+
- Worker threads have 30-minute timeout and 8GB heap limit
|
|
440
552
|
|
|
441
553
|
#### 4. `test_neo4j_connection` - Health Check
|
|
442
554
|
**Purpose**: Verify database connectivity and APOC plugin availability.
|
|
@@ -450,65 +562,104 @@ await mcp.call('test_neo4j_connection');
|
|
|
450
562
|
APOC plugin available with 438 functions"
|
|
451
563
|
```
|
|
452
564
|
|
|
565
|
+
#### 5. File Watching Tools
|
|
566
|
+
**Purpose**: Monitor file changes and automatically update the graph.
|
|
567
|
+
|
|
568
|
+
```typescript
|
|
569
|
+
// Option 1: Start watching during parse
|
|
570
|
+
await mcp.call('parse_typescript_project', {
|
|
571
|
+
projectPath: '/path/to/project',
|
|
572
|
+
tsconfigPath: '/path/to/project/tsconfig.json',
|
|
573
|
+
watch: true // Starts watching after parse completes
|
|
574
|
+
});
|
|
575
|
+
|
|
576
|
+
// Option 2: Start watching a previously parsed project
|
|
577
|
+
await mcp.call('start_watch_project', {
|
|
578
|
+
projectId: 'my-backend', // Project name, ID, or path
|
|
579
|
+
debounceMs: 2000 // Optional: wait 2s after last change (default: 1000)
|
|
580
|
+
});
|
|
581
|
+
|
|
582
|
+
// List all active watchers
|
|
583
|
+
await mcp.call('list_watchers');
|
|
584
|
+
// Returns: watcher status, pending changes, last update time
|
|
585
|
+
|
|
586
|
+
// Stop watching a project
|
|
587
|
+
await mcp.call('stop_watch_project', {
|
|
588
|
+
projectId: 'my-backend'
|
|
589
|
+
});
|
|
590
|
+
```
|
|
591
|
+
|
|
592
|
+
**How It Works:**
|
|
593
|
+
1. File watcher monitors `.ts` and `.tsx` files using native OS events
|
|
594
|
+
2. Changes are debounced to batch rapid edits
|
|
595
|
+
3. Only modified files are re-parsed (incremental)
|
|
596
|
+
4. Cross-file edges are preserved during updates
|
|
597
|
+
5. Graph updates happen automatically in the background
|
|
598
|
+
|
|
599
|
+
**Resource Limits:**
|
|
600
|
+
- Maximum 10 concurrent watchers
|
|
601
|
+
- 1000 pending events per watcher
|
|
602
|
+
- Graceful cleanup on server shutdown
|
|
603
|
+
|
|
453
604
|
### Workflow Examples
|
|
454
605
|
|
|
455
606
|
#### Example 1: Understanding Authentication Flow
|
|
456
607
|
```typescript
|
|
457
608
|
// Step 1: Find authentication-related code
|
|
458
609
|
const searchResult = await mcp.call('search_codebase', {
|
|
459
|
-
|
|
460
|
-
|
|
610
|
+
projectId: 'my-backend', // Required: project name, ID, or path
|
|
611
|
+
query: 'JWT token validation authentication'
|
|
461
612
|
});
|
|
462
613
|
|
|
463
614
|
// Step 2: Extract node ID from most relevant result
|
|
464
|
-
const nodeId = "MethodDeclaration:697d2c96
|
|
615
|
+
const nodeId = "proj_abc123:MethodDeclaration:697d2c96";
|
|
465
616
|
|
|
466
617
|
// Step 3: Explore immediate relationships
|
|
467
618
|
const immediateConnections = await mcp.call('traverse_from_node', {
|
|
619
|
+
projectId: 'my-backend',
|
|
468
620
|
nodeId,
|
|
469
|
-
maxDepth: 2
|
|
470
|
-
skip: 0
|
|
621
|
+
maxDepth: 2
|
|
471
622
|
});
|
|
472
623
|
|
|
473
624
|
// Step 4: Go deeper to understand full authentication chain
|
|
474
625
|
const deepConnections = await mcp.call('traverse_from_node', {
|
|
626
|
+
projectId: 'my-backend',
|
|
475
627
|
nodeId,
|
|
476
|
-
maxDepth: 4
|
|
477
|
-
skip: 0
|
|
628
|
+
maxDepth: 4
|
|
478
629
|
});
|
|
479
630
|
|
|
480
|
-
// Step 5:
|
|
481
|
-
const
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
skip: 10 // Skip first 10 to see different connections
|
|
631
|
+
// Step 5: Assess refactoring impact
|
|
632
|
+
const impact = await mcp.call('impact_analysis', {
|
|
633
|
+
projectId: 'my-backend',
|
|
634
|
+
nodeId
|
|
485
635
|
});
|
|
636
|
+
// Returns: risk level (LOW/MEDIUM/HIGH/CRITICAL), dependents, affected files
|
|
486
637
|
```
|
|
487
638
|
|
|
488
639
|
#### Example 2: API Endpoint Analysis
|
|
489
640
|
```typescript
|
|
490
641
|
// Step 1: Search for controller endpoints
|
|
491
642
|
const controllerSearch = await mcp.call('search_codebase', {
|
|
492
|
-
|
|
493
|
-
|
|
643
|
+
projectId: 'my-backend',
|
|
644
|
+
query: 'HTTP controller endpoints routes POST GET'
|
|
494
645
|
});
|
|
495
646
|
|
|
496
647
|
// Step 2: Find a controller node ID from results
|
|
497
|
-
const controllerNodeId = "ClassDeclaration:controller-uuid";
|
|
648
|
+
const controllerNodeId = "proj_abc123:ClassDeclaration:controller-uuid";
|
|
498
649
|
|
|
499
650
|
// Step 3: Explore what endpoints this controller exposes
|
|
500
651
|
const endpoints = await mcp.call('traverse_from_node', {
|
|
652
|
+
projectId: 'my-backend',
|
|
501
653
|
nodeId: controllerNodeId,
|
|
502
|
-
maxDepth: 2
|
|
503
|
-
skip: 0
|
|
654
|
+
maxDepth: 2
|
|
504
655
|
});
|
|
505
656
|
|
|
506
657
|
// Step 4: For each endpoint found, explore its dependencies
|
|
507
|
-
const endpointNodeId = "MethodDeclaration:endpoint-uuid";
|
|
658
|
+
const endpointNodeId = "proj_abc123:MethodDeclaration:endpoint-uuid";
|
|
508
659
|
const endpointDeps = await mcp.call('traverse_from_node', {
|
|
660
|
+
projectId: 'my-backend',
|
|
509
661
|
nodeId: endpointNodeId,
|
|
510
|
-
maxDepth: 3
|
|
511
|
-
skip: 0
|
|
662
|
+
maxDepth: 3
|
|
512
663
|
});
|
|
513
664
|
```
|
|
514
665
|
|
|
@@ -516,22 +667,24 @@ const endpointDeps = await mcp.call('traverse_from_node', {
|
|
|
516
667
|
```typescript
|
|
517
668
|
// Step 1: Find a specific service
|
|
518
669
|
const serviceSearch = await mcp.call('search_codebase', {
|
|
519
|
-
|
|
520
|
-
|
|
670
|
+
projectId: 'my-backend',
|
|
671
|
+
query: 'UserService injectable dependency injection'
|
|
521
672
|
});
|
|
522
673
|
|
|
523
674
|
// Step 2: Map all its dependencies (what it injects)
|
|
524
675
|
const serviceDeps = await mcp.call('traverse_from_node', {
|
|
525
|
-
|
|
676
|
+
projectId: 'my-backend',
|
|
677
|
+
nodeId: "proj_abc123:ClassDeclaration:user-service-uuid",
|
|
526
678
|
maxDepth: 2,
|
|
527
|
-
|
|
679
|
+
direction: "OUTGOING" // What this service depends on
|
|
528
680
|
});
|
|
529
681
|
|
|
530
|
-
// Step 3:
|
|
531
|
-
const
|
|
532
|
-
|
|
533
|
-
|
|
682
|
+
// Step 3: Impact analysis - what depends on this service
|
|
683
|
+
const impact = await mcp.call('impact_analysis', {
|
|
684
|
+
projectId: 'my-backend',
|
|
685
|
+
nodeId: "proj_abc123:ClassDeclaration:user-service-uuid"
|
|
534
686
|
});
|
|
687
|
+
// Returns: risk level, all dependents, affected files
|
|
535
688
|
```
|
|
536
689
|
|
|
537
690
|
### Advanced Usage Tips
|
|
@@ -548,7 +701,10 @@ const serviceDependents = await mcp.call('search_codebase', {
|
|
|
548
701
|
|
|
549
702
|
**Example Reading Pattern**:
|
|
550
703
|
```typescript
|
|
551
|
-
const response = await search_codebase({
|
|
704
|
+
const response = await search_codebase({
|
|
705
|
+
projectId: "my-backend",
|
|
706
|
+
query: "authentication"
|
|
707
|
+
});
|
|
552
708
|
|
|
553
709
|
// 1. Get overview statistics
|
|
554
710
|
console.log(`Found ${response.totalConnections} connections across ${response.uniqueFiles} files`);
|
|
@@ -571,7 +727,6 @@ firstDepth.chains.forEach(chain => {
|
|
|
571
727
|
```
|
|
572
728
|
|
|
573
729
|
#### Managing Large Responses
|
|
574
|
-
- **Start Small**: Use `limit: 1-3` for initial searches
|
|
575
730
|
- **Relationship Filtering**: Use `relationshipTypes` to focus on specific connections
|
|
576
731
|
- **Structure-Only View**: Set `includeCode: false` to exclude source code snippets
|
|
577
732
|
- **Summary Mode**: Use `summaryOnly: true` for just file paths and statistics
|
|
@@ -607,6 +762,7 @@ Each potential path is scored using three factors multiplied together:
|
|
|
607
762
|
```typescript
|
|
608
763
|
// Use standard traversal for exhaustive exploration
|
|
609
764
|
search_codebase({
|
|
765
|
+
projectId: "my-backend",
|
|
610
766
|
query: "...",
|
|
611
767
|
useWeightedTraversal: false
|
|
612
768
|
})
|
|
@@ -618,46 +774,6 @@ search_codebase({
|
|
|
618
774
|
- **Memory**: Large traversals may hit Neo4j memory limits (increase heap size if needed)
|
|
619
775
|
- **Caching**: Node IDs are persistent; save interesting ones for later exploration
|
|
620
776
|
|
|
621
|
-
## Available MCP Tools
|
|
622
|
-
|
|
623
|
-
### Core Tools
|
|
624
|
-
|
|
625
|
-
| Tool | Description | Parameters | Use Case |
|
|
626
|
-
|------|-------------|------------|----------|
|
|
627
|
-
| `hello` | Test tool that says hello | None | Verify MCP connection |
|
|
628
|
-
| `test_neo4j_connection` | Test Neo4j connection and APOC plugin | None | Health check before operations |
|
|
629
|
-
|
|
630
|
-
### Parsing Tools
|
|
631
|
-
|
|
632
|
-
| Tool | Description | Parameters | Use Case |
|
|
633
|
-
|------|-------------|------------|----------|
|
|
634
|
-
| `parse_typescript_project` | Parse TypeScript/NestJS project into graph | `projectPath`, `tsconfigPath`, `clearExisting?` | Initial setup: build the graph database |
|
|
635
|
-
|
|
636
|
-
### Search & Exploration Tools
|
|
637
|
-
|
|
638
|
-
| Tool | Description | Parameters | Best For |
|
|
639
|
-
|------|-------------|------------|----------|
|
|
640
|
-
| `search_codebase` | **Vector-based semantic search** - Find most relevant code using OpenAI embeddings | `query`, `limit?`, `useWeightedTraversal?` (default: true) | **Starting point** for code exploration. Uses weighted scoring for intelligent traversal |
|
|
641
|
-
| `traverse_from_node` | **Focused graph traversal** - Explore specific relationships from a known node | `nodeId` (string), `maxDepth?` (1-10, default: 3), `skip?` (default: 0) | **Deep diving** into specific code relationships. Pagination for large graphs |
|
|
642
|
-
| `natural_language_to_cypher` | **AI-powered query generation** - Convert natural language to Cypher queries using GPT-4 | `query` (string) | **Advanced queries** - currently requires OpenAI assistant setup |
|
|
643
|
-
|
|
644
|
-
### Tool Selection Guide
|
|
645
|
-
|
|
646
|
-
**Start Here**: `search_codebase`
|
|
647
|
-
- Use when you don't know specific node IDs
|
|
648
|
-
- Best for exploring new codebases
|
|
649
|
-
- Returns rich context with code snippets
|
|
650
|
-
|
|
651
|
-
**Go Deeper**: `traverse_from_node`
|
|
652
|
-
- Use when you have specific node IDs from search results
|
|
653
|
-
- Perfect for understanding relationships and dependencies
|
|
654
|
-
- Use `skip` parameter for pagination through large result sets
|
|
655
|
-
|
|
656
|
-
**Advanced**: `natural_language_to_cypher`
|
|
657
|
-
- Requires additional OpenAI assistant configuration
|
|
658
|
-
- Best for complex queries beyond simple search/traversal
|
|
659
|
-
- Currently in development - may require setup
|
|
660
|
-
|
|
661
777
|
## Claude Code Integration Tips
|
|
662
778
|
|
|
663
779
|
### Guiding Tool Usage with claude.md
|
|
@@ -687,12 +803,12 @@ You can add a `claude.md` file to your repository root to help Claude Code under
|
|
|
687
803
|
```markdown
|
|
688
804
|
**Use `useWeightedTraversal: true` for:**
|
|
689
805
|
- Service/Controller classes with many dependencies
|
|
690
|
-
- Queries with depth > 3
|
|
806
|
+
- Queries with depth > 3
|
|
691
807
|
- Cleaner, more relevant results
|
|
692
808
|
|
|
693
809
|
**Recommended settings:**
|
|
694
|
-
- Default: `
|
|
695
|
-
- Simple lookups: `
|
|
810
|
+
- Default: `maxDepth: 5, snippetLength: 900`
|
|
811
|
+
- Simple lookups: `maxDepth: 2`
|
|
696
812
|
```
|
|
697
813
|
|
|
698
814
|
#### Framework-Specific Patterns
|
|
@@ -713,13 +829,13 @@ Document your custom node types and relationships so Claude knows what to search
|
|
|
713
829
|
|
|
714
830
|
```markdown
|
|
715
831
|
**Finding authentication:**
|
|
716
|
-
search_codebase({ query: "JWT authentication middleware" })
|
|
832
|
+
search_codebase({ projectId: "my-project", query: "JWT authentication middleware" })
|
|
717
833
|
|
|
718
834
|
**Tracing dependencies:**
|
|
719
|
-
traverse_from_node({ nodeId: "...", direction: "OUTGOING", maxDepth: 5 })
|
|
835
|
+
traverse_from_node({ projectId: "my-project", nodeId: "...", direction: "OUTGOING", maxDepth: 5 })
|
|
720
836
|
|
|
721
837
|
**Impact analysis:**
|
|
722
|
-
|
|
838
|
+
impact_analysis({ projectId: "my-project", nodeId: "..." })
|
|
723
839
|
```
|
|
724
840
|
|
|
725
841
|
## Framework Support
|
|
@@ -778,6 +894,10 @@ The server provides deep understanding of NestJS patterns:
|
|
|
778
894
|
| `NEO4J_URI` | Neo4j database URI | `bolt://localhost:7687` |
|
|
779
895
|
| `NEO4J_USER` | Neo4j username | `neo4j` |
|
|
780
896
|
| `NEO4J_PASSWORD` | Neo4j password | `PASSWORD` |
|
|
897
|
+
| `NEO4J_QUERY_TIMEOUT_MS` | Neo4j query timeout | `30000` (30s) |
|
|
898
|
+
| `NEO4J_CONNECTION_TIMEOUT_MS` | Neo4j connection timeout | `10000` (10s) |
|
|
899
|
+
| `OPENAI_EMBEDDING_TIMEOUT_MS` | Embedding API timeout | `60000` (60s) |
|
|
900
|
+
| `OPENAI_ASSISTANT_TIMEOUT_MS` | Assistant API timeout | `120000` (120s) |
|
|
781
901
|
|
|
782
902
|
### Parse Options
|
|
783
903
|
|
|
@@ -804,27 +924,27 @@ const parseOptions = {
|
|
|
804
924
|
### Current Limitations
|
|
805
925
|
|
|
806
926
|
1. **Language Support**: Currently supports TypeScript/NestJS only
|
|
807
|
-
2. **Framework Support**: Primary focus on NestJS patterns
|
|
927
|
+
2. **Framework Support**: Primary focus on NestJS patterns (React, Angular, Vue planned)
|
|
808
928
|
3. **File Size**: Large files (>10MB) may cause parsing performance issues
|
|
809
|
-
4. **Memory Usage**:
|
|
929
|
+
4. **Memory Usage**: Mitigated by streaming import for large projects
|
|
810
930
|
5. **Vector Search**: Requires OpenAI API for semantic search functionality
|
|
811
|
-
6. **
|
|
812
|
-
7. **
|
|
813
|
-
8. **Neo4j Memory**: Database memory limits can cause query failures on large graphs
|
|
931
|
+
6. **Response Size**: Large graph traversals can exceed token limits (25,000 tokens max)
|
|
932
|
+
7. **Neo4j Memory**: Database memory limits can cause query failures on large graphs
|
|
814
933
|
|
|
815
934
|
### Performance Considerations
|
|
816
935
|
|
|
817
|
-
- **Large Projects**:
|
|
936
|
+
- **Large Projects**: Use `async: true` for projects with >1000 files
|
|
937
|
+
- **Streaming**: Auto-enabled for >100 files to prevent memory issues
|
|
818
938
|
- **Graph Traversal**: Deep traversals (>5 levels) may be slow for highly connected graphs
|
|
819
939
|
- **Embedding Generation**: Initial parsing with embeddings can take several minutes for large codebases
|
|
820
940
|
- **Neo4j Memory**: Recommend at least 4GB RAM allocation for Neo4j with large graphs
|
|
941
|
+
- **Worker Timeout**: Async parsing has 30-minute timeout for safety
|
|
821
942
|
|
|
822
943
|
### Known Issues
|
|
823
944
|
|
|
824
945
|
1. **Complex Type Inference**: Advanced TypeScript type gymnastics may not be fully captured
|
|
825
946
|
2. **Dynamic Imports**: Runtime module loading not tracked in static analysis
|
|
826
947
|
3. **Decorator Arguments**: Complex decorator argument patterns may not be fully parsed
|
|
827
|
-
4. **Monorepo Support**: Limited support for complex monorepo structures
|
|
828
948
|
|
|
829
949
|
## Troubleshooting
|
|
830
950
|
|
|
@@ -858,11 +978,11 @@ docker-compose restart neo4j
|
|
|
858
978
|
```
|
|
859
979
|
|
|
860
980
|
#### Token Limit Exceeded
|
|
861
|
-
If responses exceed
|
|
981
|
+
If responses exceed token limits:
|
|
862
982
|
|
|
863
983
|
```typescript
|
|
864
|
-
// Reduce
|
|
865
|
-
|
|
984
|
+
// Reduce depth or use structure-only view
|
|
985
|
+
traverse_from_node({ nodeId: "...", maxDepth: 2, includeCode: false })
|
|
866
986
|
|
|
867
987
|
// Use pagination with skip
|
|
868
988
|
traverse_from_node({ nodeId: "...", maxDepth: 2, skip: 0 })
|
|
@@ -76,6 +76,45 @@ const extractInjectableDependencies = (parsedNode, _allNodes, _sharedContext) =>
|
|
|
76
76
|
}
|
|
77
77
|
return {};
|
|
78
78
|
};
|
|
79
|
+
/**
|
|
80
|
+
* Extract class property types for edge detection.
|
|
81
|
+
* This allows INTERNAL_API_CALL detection to work without AST access.
|
|
82
|
+
* Extracts both typed properties and instantiated properties.
|
|
83
|
+
*/
|
|
84
|
+
const extractPropertyTypes = (parsedNode, _allNodes, _sharedContext) => {
|
|
85
|
+
const node = parsedNode.sourceNode;
|
|
86
|
+
if (!node || !Node.isClassDeclaration(node))
|
|
87
|
+
return {};
|
|
88
|
+
const propertyTypes = [];
|
|
89
|
+
const properties = node.getProperties();
|
|
90
|
+
for (const prop of properties) {
|
|
91
|
+
// Get type from type annotation (e.g., `private client: PaymentsClient`)
|
|
92
|
+
const typeNode = prop.getTypeNode();
|
|
93
|
+
if (typeNode) {
|
|
94
|
+
propertyTypes.push(typeNode.getText());
|
|
95
|
+
}
|
|
96
|
+
// Get type from initializer (e.g., `private client = new PaymentsClient()`)
|
|
97
|
+
const initializer = prop.getInitializer();
|
|
98
|
+
if (initializer && Node.isNewExpression(initializer)) {
|
|
99
|
+
const expression = initializer.getExpression();
|
|
100
|
+
propertyTypes.push(expression.getText());
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
// Also check constructor parameters for injected dependencies
|
|
104
|
+
const constructors = node.getConstructors();
|
|
105
|
+
for (const ctor of constructors) {
|
|
106
|
+
for (const param of ctor.getParameters()) {
|
|
107
|
+
const typeNode = param.getTypeNode();
|
|
108
|
+
if (typeNode) {
|
|
109
|
+
propertyTypes.push(typeNode.getText());
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return {
|
|
114
|
+
propertyTypes,
|
|
115
|
+
hasVendorClient: propertyTypes.some((t) => t.endsWith('Client')),
|
|
116
|
+
};
|
|
117
|
+
};
|
|
79
118
|
/**
|
|
80
119
|
* Extract repository DAL dependencies
|
|
81
120
|
* Uses the dependencies array from @Injectable([...]) decorator
|
|
@@ -332,6 +371,11 @@ export const FAIRSQUARE_FRAMEWORK_SCHEMA = {
|
|
|
332
371
|
extractor: extractInjectableDependencies,
|
|
333
372
|
priority: 10,
|
|
334
373
|
},
|
|
374
|
+
{
|
|
375
|
+
nodeType: CoreNodeType.CLASS_DECLARATION,
|
|
376
|
+
extractor: extractPropertyTypes,
|
|
377
|
+
priority: 9, // Run after extractInjectableDependencies
|
|
378
|
+
},
|
|
335
379
|
],
|
|
336
380
|
additionalRelationships: [FairSquareSemanticEdgeType.FS_INJECTS],
|
|
337
381
|
neo4j: {
|
|
@@ -508,49 +552,6 @@ export const FAIRSQUARE_FRAMEWORK_SCHEMA = {
|
|
|
508
552
|
primaryLabel: FairSquareSemanticNodeType.FS_ROUTE_DEFINITION,
|
|
509
553
|
},
|
|
510
554
|
},
|
|
511
|
-
// HTTP Endpoint (Controller methods)
|
|
512
|
-
// fairsquareHttpEndpoint: {
|
|
513
|
-
// name: 'FairSquare HTTP Endpoint',
|
|
514
|
-
// targetCoreType: CoreNodeType.METHOD_DECLARATION,
|
|
515
|
-
// semanticType: FairSquareSemanticNodeType.FS_HTTP_ENDPOINT as any,
|
|
516
|
-
// priority: 100,
|
|
517
|
-
//
|
|
518
|
-
// detectionPatterns: [
|
|
519
|
-
// {
|
|
520
|
-
// type: 'function',
|
|
521
|
-
// pattern: (node: Node) => {
|
|
522
|
-
// if (!Node.isMethodDeclaration(node)) return false;
|
|
523
|
-
// const methodName = node.getName().toLowerCase();
|
|
524
|
-
// const httpMethods = ['get', 'post', 'put', 'delete', 'patch'];
|
|
525
|
-
//
|
|
526
|
-
// // Check if method is HTTP verb AND parent is Controller
|
|
527
|
-
// const parent = node.getParent();
|
|
528
|
-
// const isController =
|
|
529
|
-
// Node.isClassDeclaration(parent) &&
|
|
530
|
-
// (parent.getName()?.endsWith('Controller') || parent.getExtends()?.getText() === 'Controller');
|
|
531
|
-
//
|
|
532
|
-
// return httpMethods.includes(methodName) && isController;
|
|
533
|
-
// },
|
|
534
|
-
// confidence: 1.0,
|
|
535
|
-
// priority: 10,
|
|
536
|
-
// },
|
|
537
|
-
// ],
|
|
538
|
-
//
|
|
539
|
-
// contextExtractors: [
|
|
540
|
-
// {
|
|
541
|
-
// nodeType: CoreNodeType.METHOD_DECLARATION,
|
|
542
|
-
// extractor: extractHttpEndpoint,
|
|
543
|
-
// priority: 10,
|
|
544
|
-
// },
|
|
545
|
-
// ],
|
|
546
|
-
//
|
|
547
|
-
// additionalRelationships: [FairSquareSemanticEdgeType.FS_EXPOSES_HTTP as any],
|
|
548
|
-
//
|
|
549
|
-
// neo4j: {
|
|
550
|
-
// additionalLabels: ['FairSquare', 'HttpEndpoint', 'API'],
|
|
551
|
-
// primaryLabel: 'FairSquareHttpEndpoint',
|
|
552
|
-
// },
|
|
553
|
-
// },
|
|
554
555
|
},
|
|
555
556
|
// ============================================================================
|
|
556
557
|
// EDGE ENHANCEMENTS (Relationship detection)
|
|
@@ -761,24 +762,10 @@ export const FAIRSQUARE_FRAMEWORK_SCHEMA = {
|
|
|
761
762
|
if (!vendorName)
|
|
762
763
|
return false;
|
|
763
764
|
// Check if service uses the corresponding VendorClient
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
return false;
|
|
765
|
+
// Use pre-extracted propertyTypes to avoid AST dependency (allows cross-chunk/cross-package detection)
|
|
766
|
+
const propertyTypes = parsedSourceNode.properties.context?.propertyTypes ?? [];
|
|
767
767
|
const expectedClientName = `${vendorName.charAt(0).toUpperCase() + vendorName.slice(1)}Client`;
|
|
768
|
-
|
|
769
|
-
for (const prop of properties) {
|
|
770
|
-
const typeNode = prop.getTypeNode();
|
|
771
|
-
if (typeNode?.getText() === expectedClientName) {
|
|
772
|
-
return true;
|
|
773
|
-
}
|
|
774
|
-
const initializer = prop.getInitializer();
|
|
775
|
-
if (initializer && Node.isNewExpression(initializer)) {
|
|
776
|
-
if (initializer.getExpression().getText() === expectedClientName) {
|
|
777
|
-
return true;
|
|
778
|
-
}
|
|
779
|
-
}
|
|
780
|
-
}
|
|
781
|
-
return false;
|
|
768
|
+
return propertyTypes.includes(expectedClientName);
|
|
782
769
|
},
|
|
783
770
|
contextExtractor: (parsedSourceNode, parsedTargetNode, allParsedNodes, sharedContext) => {
|
|
784
771
|
const vendorControllerMap = sharedContext?.get('vendorControllers');
|