@phoenixaihub/graphrag 0.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.
Files changed (48) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.md +17 -0
  2. package/.github/ISSUE_TEMPLATE/feature_request.md +12 -0
  3. package/.github/pull_request_template.md +5 -0
  4. package/.github/workflows/ci.yml +22 -0
  5. package/LICENSE +21 -0
  6. package/README.md +103 -0
  7. package/dist/cli.d.ts +3 -0
  8. package/dist/cli.d.ts.map +1 -0
  9. package/dist/cli.js +47 -0
  10. package/dist/cli.js.map +1 -0
  11. package/dist/commands/index-repo.d.ts +8 -0
  12. package/dist/commands/index-repo.d.ts.map +1 -0
  13. package/dist/commands/index-repo.js +79 -0
  14. package/dist/commands/index-repo.js.map +1 -0
  15. package/dist/commands/query.d.ts +7 -0
  16. package/dist/commands/query.d.ts.map +1 -0
  17. package/dist/commands/query.js +32 -0
  18. package/dist/commands/query.js.map +1 -0
  19. package/dist/commands/serve.d.ts +7 -0
  20. package/dist/commands/serve.d.ts.map +1 -0
  21. package/dist/commands/serve.js +65 -0
  22. package/dist/commands/serve.js.map +1 -0
  23. package/dist/db.d.ts +46 -0
  24. package/dist/db.d.ts.map +1 -0
  25. package/dist/db.js +117 -0
  26. package/dist/db.js.map +1 -0
  27. package/dist/embeddings.d.ts +4 -0
  28. package/dist/embeddings.d.ts.map +1 -0
  29. package/dist/embeddings.js +35 -0
  30. package/dist/embeddings.js.map +1 -0
  31. package/dist/index.d.ts +6 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +6 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/parser.d.ts +12 -0
  36. package/dist/parser.d.ts.map +1 -0
  37. package/dist/parser.js +152 -0
  38. package/dist/parser.js.map +1 -0
  39. package/package.json +54 -0
  40. package/src/cli.ts +52 -0
  41. package/src/commands/index-repo.ts +96 -0
  42. package/src/commands/query.ts +43 -0
  43. package/src/commands/serve.ts +90 -0
  44. package/src/db.ts +168 -0
  45. package/src/embeddings.ts +39 -0
  46. package/src/index.ts +5 -0
  47. package/src/parser.ts +162 -0
  48. package/tsconfig.json +19 -0
@@ -0,0 +1,17 @@
1
+ ---
2
+ name: Bug report
3
+ about: Report a bug
4
+ title: '[Bug] '
5
+ labels: bug
6
+ ---
7
+
8
+ **Describe the bug**
9
+
10
+ **To reproduce**
11
+
12
+ **Expected behavior**
13
+
14
+ **Environment**
15
+ - OS:
16
+ - Node.js version:
17
+ - graphrag version:
@@ -0,0 +1,12 @@
1
+ ---
2
+ name: Feature request
3
+ about: Suggest an idea
4
+ title: '[Feature] '
5
+ labels: enhancement
6
+ ---
7
+
8
+ **Problem**
9
+
10
+ **Proposed solution**
11
+
12
+ **Alternatives considered**
@@ -0,0 +1,5 @@
1
+ ## Description
2
+
3
+ ## Changes
4
+
5
+ ## Testing
@@ -0,0 +1,22 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ build:
11
+ runs-on: ubuntu-latest
12
+ strategy:
13
+ matrix:
14
+ node-version: [18, 20, 22]
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+ - uses: actions/setup-node@v4
18
+ with:
19
+ node-version: ${{ matrix.node-version }}
20
+ - run: npm ci
21
+ - run: npm run build
22
+ - run: npm run lint
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Phoenix AI Hub
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,103 @@
1
+ # @phoenixaihub/graphrag
2
+
3
+ [![npm](https://img.shields.io/npm/v/@phoenixaihub/graphrag)](https://www.npmjs.com/package/@phoenixaihub/graphrag)
4
+ [![CI](https://github.com/phoenix-assistant/graph-rag-private-codebases/actions/workflows/ci.yml/badge.svg)](https://github.com/phoenix-assistant/graph-rag-private-codebases/actions/workflows/ci.yml)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
+
7
+ **Graph RAG for private codebases** — index your code into a knowledge graph with semantic search and an MCP server. Self-hosted, no code leaves your machine.
8
+
9
+ ## Features
10
+
11
+ - 🔍 **Index** TypeScript, JavaScript, and Python codebases into a knowledge graph
12
+ - 🧠 **Semantic search** over code with graph-aware context expansion
13
+ - 🔗 **Graph relationships** — functions, classes, imports, exports, call chains
14
+ - 🤖 **MCP server** — plug into Claude, Cursor, or any MCP-compatible client
15
+ - 🏠 **Self-hosted** — SQLite-backed, runs locally, zero cloud dependencies
16
+ - ⚡ **Optional embeddings** via OpenAI `text-embedding-3-small`
17
+
18
+ ## Quick Start
19
+
20
+ ```bash
21
+ npm install -g @phoenixaihub/graphrag
22
+
23
+ # Index a repo
24
+ graphrag index ./my-project
25
+
26
+ # Search code
27
+ graphrag query "authentication middleware"
28
+
29
+ # Start MCP server
30
+ graphrag serve --db ./my-project/.graphrag/index.db
31
+ ```
32
+
33
+ ## MCP Configuration
34
+
35
+ Add to your Claude Desktop / Cursor config:
36
+
37
+ ```json
38
+ {
39
+ "mcpServers": {
40
+ "graphrag": {
41
+ "command": "graphrag",
42
+ "args": ["serve", "--db", "/path/to/project/.graphrag/index.db"]
43
+ }
44
+ }
45
+ }
46
+ ```
47
+
48
+ ### Available MCP Tools
49
+
50
+ | Tool | Description |
51
+ |------|-------------|
52
+ | `search_codebase` | Semantic search across indexed code entities |
53
+ | `get_function_context` | Get a function/class with full graph context (callers, callees, imports) |
54
+ | `find_usages` | Find all usages of a function, class, or variable |
55
+
56
+ ## With Embeddings
57
+
58
+ Set `OPENAI_API_KEY` and use `--embed`:
59
+
60
+ ```bash
61
+ export OPENAI_API_KEY=sk-...
62
+ graphrag index ./my-project --embed
63
+ ```
64
+
65
+ ## How It Works
66
+
67
+ 1. **Parse** — Extracts functions, classes, imports/exports using regex-based parsing
68
+ 2. **Graph** — Builds entity relationship graph (contains, imports, calls, extends)
69
+ 3. **Store** — Persists to SQLite with full-text search indexes
70
+ 4. **Search** — Text search + graph traversal for context-rich results
71
+ 5. **Serve** — MCP server exposes tools for AI-assisted code exploration
72
+
73
+ ## Comparison
74
+
75
+ | Feature | GraphRAG | Sourcegraph | Codeium |
76
+ |---------|----------|-------------|---------|
77
+ | Self-hosted | ✅ Local SQLite | ❌ Server required | ❌ Cloud |
78
+ | Privacy | ✅ No code leaves machine | ⚠️ Depends on deployment | ❌ Cloud-processed |
79
+ | MCP support | ✅ Built-in | ❌ | ❌ |
80
+ | Setup time | < 1 min | Hours | Minutes |
81
+ | Cost | Free | $$$$ | Free tier limited |
82
+ | Graph relationships | ✅ | ✅ | ❌ |
83
+ | Languages | TS/JS/Python | 30+ | 70+ |
84
+
85
+ ## Programmatic API
86
+
87
+ ```typescript
88
+ import { GraphDB, parseFile } from '@phoenixaihub/graphrag';
89
+
90
+ const db = new GraphDB('.graphrag/index.db');
91
+ const result = parseFile('./src/main.ts');
92
+
93
+ for (const entity of result.entities) {
94
+ db.insertEntity(entity);
95
+ }
96
+
97
+ const results = db.searchEntities('handler', 5);
98
+ console.log(results);
99
+ ```
100
+
101
+ ## License
102
+
103
+ MIT
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,47 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from 'commander';
3
+ import { indexRepo } from './commands/index-repo.js';
4
+ import { queryCode } from './commands/query.js';
5
+ import { serve } from './commands/serve.js';
6
+ const program = new Command();
7
+ program
8
+ .name('graphrag')
9
+ .description('Graph RAG for private codebases — self-hosted code intelligence')
10
+ .version('0.1.0');
11
+ program
12
+ .command('index <repo>')
13
+ .description('Index a codebase into a knowledge graph')
14
+ .option('--extensions <exts>', 'File extensions to index (comma-separated)', 'ts,tsx,js,jsx,py')
15
+ .option('--db <path>', 'Database path', '.graphrag/index.db')
16
+ .option('--embed', 'Generate embeddings (requires OPENAI_API_KEY)', false)
17
+ .action(async (repo, opts) => {
18
+ await indexRepo(repo, {
19
+ extensions: opts.extensions.split(','),
20
+ dbPath: opts.db,
21
+ embed: opts.embed,
22
+ });
23
+ });
24
+ program
25
+ .command('query <question>')
26
+ .description('Semantic search over indexed codebase with graph context')
27
+ .option('--db <path>', 'Database path', '.graphrag/index.db')
28
+ .option('--limit <n>', 'Max results', '5')
29
+ .action(async (question, opts) => {
30
+ await queryCode(question, {
31
+ dbPath: opts.db,
32
+ limit: parseInt(opts.limit, 10),
33
+ });
34
+ });
35
+ program
36
+ .command('serve')
37
+ .description('Start MCP server for code intelligence')
38
+ .option('--db <path>', 'Database path', '.graphrag/index.db')
39
+ .option('--port <n>', 'Port number', '3700')
40
+ .action(async (opts) => {
41
+ await serve({
42
+ dbPath: opts.db,
43
+ port: parseInt(opts.port, 10),
44
+ });
45
+ });
46
+ program.parse();
47
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAE5C,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,UAAU,CAAC;KAChB,WAAW,CAAC,iEAAiE,CAAC;KAC9E,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,OAAO;KACJ,OAAO,CAAC,cAAc,CAAC;KACvB,WAAW,CAAC,yCAAyC,CAAC;KACtD,MAAM,CAAC,qBAAqB,EAAE,4CAA4C,EAAE,kBAAkB,CAAC;KAC/F,MAAM,CAAC,aAAa,EAAE,eAAe,EAAE,oBAAoB,CAAC;KAC5D,MAAM,CAAC,SAAS,EAAE,+CAA+C,EAAE,KAAK,CAAC;KACzE,MAAM,CAAC,KAAK,EAAE,IAAY,EAAE,IAAI,EAAE,EAAE;IACnC,MAAM,SAAS,CAAC,IAAI,EAAE;QACpB,UAAU,EAAE,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC;QACtC,MAAM,EAAE,IAAI,CAAC,EAAE;QACf,KAAK,EAAE,IAAI,CAAC,KAAK;KAClB,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,kBAAkB,CAAC;KAC3B,WAAW,CAAC,0DAA0D,CAAC;KACvE,MAAM,CAAC,aAAa,EAAE,eAAe,EAAE,oBAAoB,CAAC;KAC5D,MAAM,CAAC,aAAa,EAAE,aAAa,EAAE,GAAG,CAAC;KACzC,MAAM,CAAC,KAAK,EAAE,QAAgB,EAAE,IAAI,EAAE,EAAE;IACvC,MAAM,SAAS,CAAC,QAAQ,EAAE;QACxB,MAAM,EAAE,IAAI,CAAC,EAAE;QACf,KAAK,EAAE,QAAQ,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,CAAC;KAChC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,OAAO,CAAC;KAChB,WAAW,CAAC,wCAAwC,CAAC;KACrD,MAAM,CAAC,aAAa,EAAE,eAAe,EAAE,oBAAoB,CAAC;KAC5D,MAAM,CAAC,YAAY,EAAE,aAAa,EAAE,MAAM,CAAC;KAC3C,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;IACrB,MAAM,KAAK,CAAC;QACV,MAAM,EAAE,IAAI,CAAC,EAAE;QACf,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;KAC9B,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEL,OAAO,CAAC,KAAK,EAAE,CAAC"}
@@ -0,0 +1,8 @@
1
+ interface IndexOptions {
2
+ extensions: string[];
3
+ dbPath: string;
4
+ embed: boolean;
5
+ }
6
+ export declare function indexRepo(repoPath: string, opts: IndexOptions): Promise<void>;
7
+ export {};
8
+ //# sourceMappingURL=index-repo.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-repo.d.ts","sourceRoot":"","sources":["../../src/commands/index-repo.ts"],"names":[],"mappings":"AAMA,UAAU,YAAY;IACpB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,wBAAsB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAmFnF"}
@@ -0,0 +1,79 @@
1
+ import path from 'path';
2
+ import { glob } from 'glob';
3
+ import { GraphDB } from '../db.js';
4
+ import { parseFile } from '../parser.js';
5
+ import { getEmbeddings } from '../embeddings.js';
6
+ export async function indexRepo(repoPath, opts) {
7
+ const absRepo = path.resolve(repoPath);
8
+ const dbPath = path.isAbsolute(opts.dbPath) ? opts.dbPath : path.join(absRepo, opts.dbPath);
9
+ const db = new GraphDB(dbPath);
10
+ const patterns = opts.extensions.map(ext => `**/*.${ext}`);
11
+ const files = await glob(patterns, {
12
+ cwd: absRepo,
13
+ ignore: ['**/node_modules/**', '**/dist/**', '**/.git/**', '**/venv/**', '**/__pycache__/**'],
14
+ absolute: true,
15
+ });
16
+ console.log(`Indexing ${files.length} files from ${absRepo}`);
17
+ const entityNameToId = new Map();
18
+ let totalEntities = 0;
19
+ let totalEdges = 0;
20
+ const pendingEdges = [];
21
+ const chunksToEmbed = [];
22
+ for (const file of files) {
23
+ const relPath = path.relative(absRepo, file);
24
+ db.clearFile(relPath);
25
+ const result = parseFile(file);
26
+ for (const entity of result.entities) {
27
+ const e = { ...entity, filePath: relPath };
28
+ const id = db.insertEntity(e);
29
+ entityNameToId.set(e.name, id);
30
+ totalEntities++;
31
+ // Create chunk for non-import entities
32
+ if (e.kind !== 'import') {
33
+ chunksToEmbed.push({ entityId: id, content: `${e.kind} ${e.name}\n${e.code}` });
34
+ }
35
+ }
36
+ pendingEdges.push(...result.edges);
37
+ }
38
+ // Resolve and insert edges
39
+ for (const edge of pendingEdges) {
40
+ const sourceId = entityNameToId.get(edge.sourceName);
41
+ const targetId = entityNameToId.get(edge.targetName);
42
+ if (sourceId && targetId) {
43
+ db.insertEdge({ sourceId, targetId, relation: edge.relation });
44
+ totalEdges++;
45
+ }
46
+ }
47
+ // Generate embeddings in batches
48
+ if (opts.embed && process.env.OPENAI_API_KEY) {
49
+ console.log(`Generating embeddings for ${chunksToEmbed.length} chunks...`);
50
+ const batchSize = 100;
51
+ for (let i = 0; i < chunksToEmbed.length; i += batchSize) {
52
+ const batch = chunksToEmbed.slice(i, i + batchSize);
53
+ const embeddings = await getEmbeddings(batch.map(c => c.content));
54
+ for (let j = 0; j < batch.length; j++) {
55
+ db.insertChunk({
56
+ entityId: batch[j].entityId,
57
+ content: batch[j].content,
58
+ embedding: new Float64Array(embeddings[j]),
59
+ });
60
+ }
61
+ console.log(` Embedded ${Math.min(i + batchSize, chunksToEmbed.length)}/${chunksToEmbed.length}`);
62
+ }
63
+ }
64
+ else {
65
+ // Store chunks without embeddings
66
+ for (const chunk of chunksToEmbed) {
67
+ db.insertChunk({ entityId: chunk.entityId, content: chunk.content });
68
+ }
69
+ }
70
+ const stats = db.getStats();
71
+ console.log(`\nDone! Indexed:`);
72
+ console.log(` Files: ${stats.files}`);
73
+ console.log(` Entities: ${stats.entities}`);
74
+ console.log(` Edges: ${stats.edges}`);
75
+ console.log(` Chunks: ${stats.chunks}`);
76
+ console.log(`\nDatabase: ${dbPath}`);
77
+ db.close();
78
+ }
79
+ //# sourceMappingURL=index-repo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-repo.js","sourceRoot":"","sources":["../../src/commands/index-repo.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ interface QueryOptions {
2
+ dbPath: string;
3
+ limit: number;
4
+ }
5
+ export declare function queryCode(question: string, opts: QueryOptions): Promise<void>;
6
+ export {};
7
+ //# sourceMappingURL=query.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../src/commands/query.ts"],"names":[],"mappings":"AAGA,UAAU,YAAY;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AAED,wBAAsB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAkCnF"}
@@ -0,0 +1,32 @@
1
+ import path from 'path';
2
+ import { GraphDB } from '../db.js';
3
+ export async function queryCode(question, opts) {
4
+ const dbPath = path.resolve(opts.dbPath);
5
+ const db = new GraphDB(dbPath);
6
+ const results = db.searchEntities(question, opts.limit);
7
+ if (results.length === 0) {
8
+ console.log('No results found.');
9
+ db.close();
10
+ return;
11
+ }
12
+ console.log(`Found ${results.length} results:\n`);
13
+ for (const entity of results) {
14
+ const id = entity.id;
15
+ console.log(`━━━ ${entity.kind}: ${entity.name} ━━━`);
16
+ console.log(`File: ${entity.filePath}:${entity.startLine}-${entity.endLine}`);
17
+ // Get related entities for context
18
+ const related = db.getRelated(id);
19
+ if (related.length > 0) {
20
+ console.log(`Relations:`);
21
+ for (const r of related.slice(0, 5)) {
22
+ console.log(` ${r.relation} → ${r.entity.name} (${r.entity.kind})`);
23
+ }
24
+ }
25
+ console.log(`\n${entity.code.substring(0, 300)}`);
26
+ if (entity.code.length > 300)
27
+ console.log(' ...');
28
+ console.log('');
29
+ }
30
+ db.close();
31
+ }
32
+ //# sourceMappingURL=query.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query.js","sourceRoot":"","sources":["../../src/commands/query.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAOnC,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,QAAgB,EAAE,IAAkB;IAClE,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACzC,MAAM,EAAE,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAE/B,MAAM,OAAO,GAAG,EAAE,CAAC,cAAc,CAAC,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;IAExD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;QACjC,EAAE,CAAC,KAAK,EAAE,CAAC;QACX,OAAO;IACT,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,SAAS,OAAO,CAAC,MAAM,aAAa,CAAC,CAAC;IAElD,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,EAAE,GAAI,MAAc,CAAC,EAAY,CAAC;QACxC,OAAO,CAAC,GAAG,CAAC,OAAO,MAAM,CAAC,IAAI,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,CAAC;QACtD,OAAO,CAAC,GAAG,CAAC,SAAS,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,SAAS,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;QAE9E,mCAAmC;QACnC,MAAM,OAAO,GAAG,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;QAClC,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACvB,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;YAC1B,KAAK,MAAM,CAAC,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;gBACpC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,QAAQ,MAAM,CAAC,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,GAAG,CAAC,CAAC;YACvE,CAAC;QACH,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,KAAK,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;QAClD,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,GAAG,GAAG;YAAE,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACnD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAClB,CAAC;IAED,EAAE,CAAC,KAAK,EAAE,CAAC;AACb,CAAC"}
@@ -0,0 +1,7 @@
1
+ interface ServeOptions {
2
+ dbPath: string;
3
+ port: number;
4
+ }
5
+ export declare function serve(opts: ServeOptions): Promise<void>;
6
+ export {};
7
+ //# sourceMappingURL=serve.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../../src/commands/serve.ts"],"names":[],"mappings":"AAMA,UAAU,YAAY;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAsB,KAAK,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CA8E7D"}
@@ -0,0 +1,65 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
3
+ import { z } from 'zod';
4
+ import path from 'path';
5
+ import { GraphDB } from '../db.js';
6
+ export async function serve(opts) {
7
+ const dbPath = path.resolve(opts.dbPath);
8
+ const db = new GraphDB(dbPath);
9
+ const server = new McpServer({
10
+ name: 'graphrag',
11
+ version: '0.1.0',
12
+ });
13
+ server.tool('search_codebase', 'Search the indexed codebase for functions, classes, and code patterns', { query: z.string().describe('Search query'), limit: z.number().optional().describe('Max results (default 5)') }, async ({ query, limit }) => {
14
+ const results = db.searchEntities(query, limit ?? 5);
15
+ return {
16
+ content: [{
17
+ type: 'text',
18
+ text: JSON.stringify(results.map(e => ({
19
+ name: e.name,
20
+ kind: e.kind,
21
+ file: `${e.filePath}:${e.startLine}-${e.endLine}`,
22
+ code: e.code.substring(0, 500),
23
+ })), null, 2),
24
+ }],
25
+ };
26
+ });
27
+ server.tool('get_function_context', 'Get a function/class with its full graph context (callers, callees, imports)', { name: z.string().describe('Function or class name') }, async ({ name }) => {
28
+ const entities = db.findEntitiesByName(name);
29
+ if (entities.length === 0) {
30
+ return { content: [{ type: 'text', text: `No entity found: ${name}` }] };
31
+ }
32
+ const entity = entities[0];
33
+ const id = entity.id;
34
+ const related = db.getRelated(id);
35
+ return {
36
+ content: [{
37
+ type: 'text',
38
+ text: JSON.stringify({
39
+ entity: { name: entity.name, kind: entity.kind, file: entity.filePath, code: entity.code },
40
+ related: related.map(r => ({
41
+ name: r.entity.name, kind: r.entity.kind, relation: r.relation,
42
+ file: r.entity.filePath,
43
+ })),
44
+ }, null, 2),
45
+ }],
46
+ };
47
+ });
48
+ server.tool('find_usages', 'Find all usages of a function, class, or variable', { name: z.string().describe('Entity name to find usages of') }, async ({ name }) => {
49
+ const usages = db.getUsages(name);
50
+ return {
51
+ content: [{
52
+ type: 'text',
53
+ text: JSON.stringify(usages.map(e => ({
54
+ name: e.name, kind: e.kind,
55
+ file: `${e.filePath}:${e.startLine}-${e.endLine}`,
56
+ code: e.code.substring(0, 200),
57
+ })), null, 2),
58
+ }],
59
+ };
60
+ });
61
+ const transport = new StdioServerTransport();
62
+ await server.connect(transport);
63
+ console.error('GraphRAG MCP server running on stdio');
64
+ }
65
+ //# sourceMappingURL=serve.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serve.js","sourceRoot":"","sources":["../../src/commands/serve.ts"],"names":[],"mappings":"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"}
package/dist/db.d.ts ADDED
@@ -0,0 +1,46 @@
1
+ export interface Entity {
2
+ id?: number;
3
+ filePath: string;
4
+ name: string;
5
+ kind: 'file' | 'function' | 'class' | 'method' | 'variable' | 'import' | 'export';
6
+ startLine: number;
7
+ endLine: number;
8
+ code: string;
9
+ language: string;
10
+ }
11
+ export interface Edge {
12
+ id?: number;
13
+ sourceId: number;
14
+ targetId: number;
15
+ relation: 'contains' | 'imports' | 'exports' | 'calls' | 'extends' | 'implements';
16
+ }
17
+ export interface Chunk {
18
+ id?: number;
19
+ entityId: number;
20
+ content: string;
21
+ embedding?: Float64Array | null;
22
+ }
23
+ export declare class GraphDB {
24
+ private db;
25
+ constructor(dbPath: string);
26
+ insertEntity(e: Entity): number;
27
+ insertEdge(e: Edge): number;
28
+ insertChunk(c: Chunk): number;
29
+ getEntity(id: number): Entity | undefined;
30
+ findEntitiesByName(name: string): Entity[];
31
+ searchEntities(query: string, limit?: number): Entity[];
32
+ getRelated(entityId: number, direction?: 'outgoing' | 'incoming' | 'both'): Array<{
33
+ entity: Entity;
34
+ relation: string;
35
+ }>;
36
+ getUsages(name: string): Entity[];
37
+ clearFile(filePath: string): void;
38
+ getStats(): {
39
+ entities: number;
40
+ edges: number;
41
+ chunks: number;
42
+ files: number;
43
+ };
44
+ close(): void;
45
+ }
46
+ //# sourceMappingURL=db.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../src/db.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,MAAM;IACrB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,OAAO,GAAG,QAAQ,GAAG,UAAU,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAClF,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,IAAI;IACnB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,UAAU,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,GAAG,YAAY,CAAC;CACnF;AAED,MAAM,WAAW,KAAK;IACpB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;CACjC;AAoCD,qBAAa,OAAO;IAClB,OAAO,CAAC,EAAE,CAAoB;gBAElB,MAAM,EAAE,MAAM;IAQ1B,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM;IAQ/B,UAAU,CAAC,CAAC,EAAE,IAAI,GAAG,MAAM;IAQ3B,WAAW,CAAC,CAAC,EAAE,KAAK,GAAG,MAAM;IAS7B,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAIzC,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE;IAM1C,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,SAAI,GAAG,MAAM,EAAE;IAWlD,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,GAAE,UAAU,GAAG,UAAU,GAAG,MAAe,GAAG,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IAiB/H,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE;IASjC,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAUjC,QAAQ,IAAI;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE;IAQ9E,KAAK,IAAI,IAAI;CAGd"}
package/dist/db.js ADDED
@@ -0,0 +1,117 @@
1
+ import Database from 'better-sqlite3';
2
+ import path from 'path';
3
+ import fs from 'fs';
4
+ const SCHEMA = `
5
+ CREATE TABLE IF NOT EXISTS entities (
6
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
7
+ file_path TEXT NOT NULL,
8
+ name TEXT NOT NULL,
9
+ kind TEXT NOT NULL,
10
+ start_line INTEGER NOT NULL,
11
+ end_line INTEGER NOT NULL,
12
+ code TEXT NOT NULL,
13
+ language TEXT NOT NULL
14
+ );
15
+
16
+ CREATE TABLE IF NOT EXISTS edges (
17
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
18
+ source_id INTEGER NOT NULL REFERENCES entities(id),
19
+ target_id INTEGER NOT NULL REFERENCES entities(id),
20
+ relation TEXT NOT NULL
21
+ );
22
+
23
+ CREATE TABLE IF NOT EXISTS chunks (
24
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
25
+ entity_id INTEGER NOT NULL REFERENCES entities(id),
26
+ content TEXT NOT NULL,
27
+ embedding BLOB
28
+ );
29
+
30
+ CREATE INDEX IF NOT EXISTS idx_entities_name ON entities(name);
31
+ CREATE INDEX IF NOT EXISTS idx_entities_kind ON entities(kind);
32
+ CREATE INDEX IF NOT EXISTS idx_entities_file ON entities(file_path);
33
+ CREATE INDEX IF NOT EXISTS idx_edges_source ON edges(source_id);
34
+ CREATE INDEX IF NOT EXISTS idx_edges_target ON edges(target_id);
35
+ CREATE INDEX IF NOT EXISTS idx_chunks_entity ON chunks(entity_id);
36
+ `;
37
+ export class GraphDB {
38
+ db;
39
+ constructor(dbPath) {
40
+ const dir = path.dirname(dbPath);
41
+ if (!fs.existsSync(dir))
42
+ fs.mkdirSync(dir, { recursive: true });
43
+ this.db = new Database(dbPath);
44
+ this.db.pragma('journal_mode = WAL');
45
+ this.db.exec(SCHEMA);
46
+ }
47
+ insertEntity(e) {
48
+ const stmt = this.db.prepare('INSERT INTO entities (file_path, name, kind, start_line, end_line, code, language) VALUES (?, ?, ?, ?, ?, ?, ?)');
49
+ const result = stmt.run(e.filePath, e.name, e.kind, e.startLine, e.endLine, e.code, e.language);
50
+ return Number(result.lastInsertRowid);
51
+ }
52
+ insertEdge(e) {
53
+ const stmt = this.db.prepare('INSERT INTO edges (source_id, target_id, relation) VALUES (?, ?, ?)');
54
+ const result = stmt.run(e.sourceId, e.targetId, e.relation);
55
+ return Number(result.lastInsertRowid);
56
+ }
57
+ insertChunk(c) {
58
+ const stmt = this.db.prepare('INSERT INTO chunks (entity_id, content, embedding) VALUES (?, ?, ?)');
59
+ const embeddingBlob = c.embedding ? Buffer.from(c.embedding.buffer) : null;
60
+ const result = stmt.run(c.entityId, c.content, embeddingBlob);
61
+ return Number(result.lastInsertRowid);
62
+ }
63
+ getEntity(id) {
64
+ return this.db.prepare('SELECT * FROM entities WHERE id = ?').get(id);
65
+ }
66
+ findEntitiesByName(name) {
67
+ return this.db.prepare('SELECT * FROM entities WHERE name LIKE ?').all(`%${name}%`);
68
+ }
69
+ searchEntities(query, limit = 5) {
70
+ // Text-based search across name and code
71
+ const terms = query.toLowerCase().split(/\s+/).filter(Boolean);
72
+ if (terms.length === 0)
73
+ return [];
74
+ const conditions = terms.map(() => '(LOWER(name) LIKE ? OR LOWER(code) LIKE ?)').join(' AND ');
75
+ const params = terms.flatMap(t => [`%${t}%`, `%${t}%`]);
76
+ return this.db.prepare(`SELECT * FROM entities WHERE ${conditions} ORDER BY kind, name LIMIT ?`).all(...params, limit);
77
+ }
78
+ getRelated(entityId, direction = 'both') {
79
+ const results = [];
80
+ if (direction === 'outgoing' || direction === 'both') {
81
+ const rows = this.db.prepare('SELECT e.*, ed.relation FROM entities e JOIN edges ed ON e.id = ed.target_id WHERE ed.source_id = ?').all(entityId);
82
+ results.push(...rows.map(r => ({ entity: r, relation: r.relation })));
83
+ }
84
+ if (direction === 'incoming' || direction === 'both') {
85
+ const rows = this.db.prepare('SELECT e.*, ed.relation FROM entities e JOIN edges ed ON e.id = ed.source_id WHERE ed.target_id = ?').all(entityId);
86
+ results.push(...rows.map(r => ({ entity: r, relation: r.relation })));
87
+ }
88
+ return results;
89
+ }
90
+ getUsages(name) {
91
+ return this.db.prepare(`SELECT DISTINCT e2.* FROM entities e1
92
+ JOIN edges ed ON e1.id = ed.target_id
93
+ JOIN entities e2 ON e2.id = ed.source_id
94
+ WHERE e1.name = ? AND ed.relation IN ('calls', 'imports')`).all(name);
95
+ }
96
+ clearFile(filePath) {
97
+ const entities = this.db.prepare('SELECT id FROM entities WHERE file_path = ?').all(filePath);
98
+ const ids = entities.map(e => e.id);
99
+ if (ids.length === 0)
100
+ return;
101
+ const placeholders = ids.map(() => '?').join(',');
102
+ this.db.prepare(`DELETE FROM chunks WHERE entity_id IN (${placeholders})`).run(...ids);
103
+ this.db.prepare(`DELETE FROM edges WHERE source_id IN (${placeholders}) OR target_id IN (${placeholders})`).run(...ids, ...ids);
104
+ this.db.prepare(`DELETE FROM entities WHERE file_path = ?`).run(filePath);
105
+ }
106
+ getStats() {
107
+ const entities = this.db.prepare('SELECT COUNT(*) as c FROM entities').get().c;
108
+ const edges = this.db.prepare('SELECT COUNT(*) as c FROM edges').get().c;
109
+ const chunks = this.db.prepare('SELECT COUNT(*) as c FROM chunks').get().c;
110
+ const files = this.db.prepare('SELECT COUNT(DISTINCT file_path) as c FROM entities').get().c;
111
+ return { entities, edges, chunks, files };
112
+ }
113
+ close() {
114
+ this.db.close();
115
+ }
116
+ }
117
+ //# sourceMappingURL=db.js.map