purecontext-mcp 1.5.0 → 1.5.2

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/user-manual.md DELETED
@@ -1,2466 +0,0 @@
1
- # PureContext MCP — User Manual
2
-
3
- ## Table of Contents
4
-
5
- 1. [What is PureContext MCP?](#1-what-is-purecontext-mcp)
6
- 2. [Installation](#2-installation)
7
- 3. [Connecting to Claude Code (Quick Start)](#3-connecting-to-claude-code-quick-start)
8
- 4. [Configuration](#4-configuration)
9
- 5. [CLI Commands](#5-cli-commands)
10
- 6. [MCP Tools Reference](#6-mcp-tools-reference)
11
- 7. [Language Support](#7-language-support)
12
- 8. [Framework Adapters](#8-framework-adapters)
13
- 9. [Transport Modes](#9-transport-modes)
14
- 10. [AI Summarization](#10-ai-summarization)
15
- 11. [Semantic Search (HNSW)](#11-semantic-search-hnsw)
16
- 12. [Token Savings Tracker](#12-token-savings-tracker)
17
- 13. [Multi-Tenant Hosting](#13-multi-tenant-hosting)
18
- 14. [Web UI](#14-web-ui)
19
- 15. [Security](#15-security)
20
- 16. [Architecture Overview](#16-architecture-overview)
21
- 17. [Troubleshooting](#17-troubleshooting)
22
- 18. [Advanced Relationship Analysis](#18-advanced-relationship-analysis)
23
- 19. [Architectural Visualization](#19-architectural-visualization)
24
- 20. [Refactoring Safety Checks](#20-refactoring-safety-checks)
25
- 21. [Health Dashboards & Debt Reporting](#21-health-dashboards--debt-reporting)
26
- 22. [AST-Level Search](#22-ast-level-search)
27
- 23. [Code Intelligence Helpers](#23-code-intelligence-helpers)
28
-
29
- ---
30
-
31
- ## 1. What is PureContext MCP?
32
-
33
- PureContext MCP is a **token-efficient source code navigation server** for AI agents. Instead of reading entire files, AI agents can retrieve exactly the symbols they need — functions, classes, methods, routes, and more — saving 90–98% of context tokens.
34
-
35
- It implements the **Model Context Protocol (MCP)** so it works natively with Claude Code and any other MCP-compatible AI client.
36
-
37
- **Key capabilities:**
38
- - Index TypeScript, JavaScript, Python, Go, Rust, Java, C#, PHP, Ruby, Kotlin, C, C++, Lua, Dart, Swift, Elixir, Haskell, Scala, and R
39
- - Framework-aware extraction: Vue, React, Nuxt, Next.js, Angular, NestJS, Express, Fastify, Django, Flask, FastAPI, Gin, Rails, Laravel, and more
40
- - Dependency graph: find what a symbol depends on and what depends on it
41
- - Semantic search: find symbols by meaning, not just keywords
42
- - Advanced relationship analysis: call hierarchies, class hierarchies, interface implementations, import cycles, coupling maps
43
- - Architectural visualization: Mermaid/DOT diagrams for call graphs, import graphs, class hierarchies, and dependency matrices
44
- - Refactoring safety checks: pre-flight analysis before renaming, deleting, or moving symbols
45
- - Health dashboards: multi-axis health radar, debt reports, and before/after diff comparisons
46
- - AST-level search: find any node type, signature pattern, decorator, or complexity threshold
47
- - Code intelligence: entry points, public API surface, TODO inventory, complexity hotspots, type graphs, and coverage mapping
48
- - Web UI for visual codebase exploration
49
- - Multi-tenant hosting for team deployments
50
-
51
- ---
52
-
53
- ## 2. Installation
54
-
55
- ### Prerequisites
56
-
57
- - **Node.js** >= 18.0.0
58
- - **npm** >= 9.0.0
59
- - **Git** (required for `index_repo` to clone remote repositories)
60
-
61
- ### Install from source
62
-
63
- ```bash
64
- git clone <repository-url> purecontext-mcp
65
- cd purecontext-mcp
66
- npm install
67
- npm run build
68
- ```
69
-
70
- ### Install globally
71
-
72
- ```bash
73
- npm install -g .
74
- ```
75
-
76
- After this, `purecontext-mcp` is available as a command globally.
77
-
78
- ### Verify installation
79
-
80
- ```bash
81
- purecontext-mcp config --check
82
- ```
83
-
84
- This validates your installation and checks that all prerequisites (tree-sitter grammars, SQLite) are working.
85
-
86
- ---
87
-
88
- ## 3. Connecting to Claude Code (Quick Start)
89
-
90
- ### Step 1 — Add PureContext as an MCP server
91
-
92
- ```bash
93
- claude mcp add purecontext-mcp npx purecontext-mcp
94
- ```
95
-
96
- Or, if installed globally:
97
-
98
- ```bash
99
- claude mcp add purecontext-mcp purecontext-mcp
100
- ```
101
-
102
- ### Step 2 — Index your project
103
-
104
- In Claude Code, ask:
105
-
106
- > "Index this project so I can search its symbols."
107
-
108
- Claude will call the `index_folder` tool. Or explicitly:
109
-
110
- > "Use index_folder to index /path/to/your/project."
111
-
112
- ### Step 3 — Start navigating
113
-
114
- ```
115
- search_symbols → find functions/classes by name
116
- get_file_outline → see all symbols in a file
117
- get_symbol_source → retrieve a symbol's source code
118
- get_blast_radius → see what a symbol affects
119
- get_context_bundle → get a symbol + everything it depends on
120
- ```
121
-
122
- ### Workflow example
123
-
124
- ```
125
- User: "Find the authentication logic in this project."
126
-
127
- Claude:
128
- 1. search_symbols(query: "auth", kind: "function")
129
- → Returns: validateToken, hashPassword, verifySession (3 matches)
130
-
131
- 2. get_symbol_source(id: "validateToken-id")
132
- → Returns: 45 lines of source (instead of the entire 800-line file)
133
-
134
- Token cost: ~150 tokens instead of ~2,000 tokens → 93% savings
135
- ```
136
-
137
- ---
138
-
139
- ## 4. Configuration
140
-
141
- The configuration file lives at `~/.purecontext/config.json`. Generate a default one with:
142
-
143
- ```bash
144
- purecontext-mcp config --init
145
- ```
146
-
147
- View the effective configuration with:
148
-
149
- ```bash
150
- purecontext-mcp config
151
- ```
152
-
153
- ### Complete configuration reference
154
-
155
- ```json
156
- {
157
- "indexDir": "~/.purecontext/indexes",
158
- "fileLimit": 1000,
159
- "watchDebounceMs": 2000,
160
- "excludePatterns": [],
161
- "adapters": "auto",
162
- "maxFileSizeBytes": 1048576,
163
- "allowSymlinks": false,
164
- "transport": "stdio",
165
-
166
- "ai": {
167
- "provider": "none",
168
- "allowRemoteAI": false,
169
- "apiKey": "",
170
- "endpoint": null,
171
- "model": "claude-haiku-4-5-20251001",
172
- "batchSize": 50,
173
- "embeddingModel": null,
174
- "embeddingProvider": null,
175
- "openaiApiKey": ""
176
- },
177
-
178
- "semantic": {
179
- "enabled": false,
180
- "provider": "none",
181
- "localEmbeddingEndpoint": null,
182
- "dimension": null,
183
- "threshold": 50000,
184
- "batchSize": 500,
185
- "concurrency": 2
186
- },
187
-
188
- "http": {
189
- "port": 3000,
190
- "host": "127.0.0.1",
191
- "corsOrigins": ["http://localhost:*"],
192
- "auth": {
193
- "enabled": false,
194
- "token": ""
195
- }
196
- },
197
-
198
- "rateLimit": {
199
- "enabled": true,
200
- "maxTokens": 100,
201
- "refillRate": 10,
202
- "perToolLimits": {
203
- "index_folder": 10,
204
- "index_repo": 10,
205
- "get_context_bundle": 3,
206
- "get_blast_radius": 3,
207
- "get_repo_outline": 2,
208
- "find_dead_code": 5
209
- }
210
- },
211
-
212
- "layers": {
213
- "definitions": [
214
- { "name": "core", "paths": ["src/core/**"] },
215
- { "name": "handlers", "paths": ["src/handlers/**"] },
216
- { "name": "adapters", "paths": ["src/adapters/**"] },
217
- { "name": "server", "paths": ["src/server/**"] }
218
- ],
219
- "rules": [
220
- { "from": "core", "to": "handlers", "allowed": false },
221
- { "from": "core", "to": "adapters", "allowed": false },
222
- { "from": "handlers", "to": "adapters", "allowed": false }
223
- ]
224
- }
225
- }
226
- ```
227
-
228
- ### Key configuration options explained
229
-
230
- | Option | Default | Description |
231
- |--------|---------|-------------|
232
- | `indexDir` | `~/.purecontext/indexes` | Where SQLite databases are stored |
233
- | `fileLimit` | `1000` | Max files to index per project. Increase for large repos. |
234
- | `watchDebounceMs` | `2000` | Delay in ms before re-indexing after file changes |
235
- | `excludePatterns` | `[]` | Additional glob patterns to exclude (on top of built-ins like `node_modules/`, `.git/`) |
236
- | `adapters` | `"auto"` | `"auto"` detects frameworks automatically; `"none"` disables; or `["vue", "nuxt"]` for explicit list |
237
- | `maxFileSizeBytes` | `1048576` | Files larger than 1 MB are skipped. Increase if needed. |
238
- | `allowSymlinks` | `false` | When false, symlinks that resolve outside the project root are blocked |
239
- | `transport` | `"stdio"` | `"stdio"` for Claude Code; `"http"` for browser/remote; `"both"` for both simultaneously |
240
-
241
- ### Environment variable support in config
242
-
243
- API keys can reference environment variables:
244
-
245
- ```json
246
- {
247
- "ai": {
248
- "apiKey": "${ANTHROPIC_API_KEY}"
249
- }
250
- }
251
- ```
252
-
253
- ---
254
-
255
- ## 5. CLI Commands
256
-
257
- ### Start the MCP server (default)
258
-
259
- ```bash
260
- purecontext-mcp
261
- ```
262
-
263
- Starts in stdio transport mode — the default for Claude Code integration.
264
-
265
- ### HTTP transport
266
-
267
- ```bash
268
- purecontext-mcp --transport http
269
- purecontext-mcp --transport http --port 3001
270
- purecontext-mcp --transport both
271
- ```
272
-
273
- CLI flags override `config.json` values.
274
-
275
- ### Configuration commands
276
-
277
- ```bash
278
- # Generate a default config.json
279
- purecontext-mcp config --init
280
-
281
- # Validate config + check prerequisites
282
- purecontext-mcp config --check
283
-
284
- # Show effective configuration (merged with defaults)
285
- purecontext-mcp config
286
- ```
287
-
288
- ### API key management (for hosted deployments)
289
-
290
- ```bash
291
- # Create an API key for a tenant
292
- purecontext-mcp keys create --tenant <tenantId> --permissions read,write
293
-
294
- # List API keys for a tenant
295
- purecontext-mcp keys list --tenant <tenantId>
296
-
297
- # Revoke an API key
298
- purecontext-mcp keys revoke <key-prefix>
299
- ```
300
-
301
- ---
302
-
303
- ## 6. MCP Tools Reference
304
-
305
- All tools return a `_meta` envelope with:
306
- - `timing_ms` — how long the call took
307
- - `tokens_saved` — tokens saved vs. reading raw files (where applicable)
308
- - `total_tokens_saved` — cumulative session total
309
- - `cost_avoided` — estimated USD saved at current model rates
310
- - `powered_by: "PureContext MCP"`
311
-
312
- ---
313
-
314
- ### `index_folder`
315
-
316
- Index a local project directory.
317
-
318
- ```json
319
- {
320
- "path": "/path/to/your/project",
321
- "fileLimit": 1000
322
- }
323
- ```
324
-
325
- **Returns:** `{ repoId, symbolCount, fileCount, duration, languages }`
326
-
327
- Subsequent calls are incremental — only changed files are re-indexed. The file watcher automatically triggers re-indexing on file changes.
328
-
329
- ---
330
-
331
- ### `index_repo`
332
-
333
- Clone and index a remote Git repository.
334
-
335
- ```json
336
- {
337
- "url": "https://github.com/owner/repo",
338
- "branch": "main",
339
- "token": "ghp_...",
340
- "fileLimit": 5000
341
- }
342
- ```
343
-
344
- **Returns:** Same as `index_folder`. The clone is stored under `~/.purecontext/clones/`. Use `delete_index` to remove it.
345
-
346
- Requires `git` on your `PATH`. Shallow clones (`--depth=1`) are used for efficiency.
347
-
348
- ---
349
-
350
- ### `list_repos`
351
-
352
- List all indexed repositories.
353
-
354
- ```json
355
- {}
356
- ```
357
-
358
- **Returns:** Array of `{ repoId, rootPath, symbolCount, fileCount, languages, indexedAt }`
359
-
360
- ---
361
-
362
- ### `resolve_repo`
363
-
364
- Get metadata for a specific repository.
365
-
366
- ```json
367
- {
368
- "path": "/path/to/project"
369
- }
370
- ```
371
-
372
- **Returns:** Repo metadata, or a hint to call `index_folder` if not indexed.
373
-
374
- ---
375
-
376
- ### `search_symbols`
377
-
378
- Search for symbols by name, kind, or file pattern. The primary tool for code navigation.
379
-
380
- ```json
381
- {
382
- "repo": "repoId or path",
383
- "query": "validateToken",
384
- "kind": "function",
385
- "file": "src/auth/**",
386
- "limit": 20,
387
- "mode": "keyword"
388
- }
389
- ```
390
-
391
- | Parameter | Type | Description |
392
- |-----------|------|-------------|
393
- | `query` | string | Name to search for (substring match) |
394
- | `kind` | string | Filter by symbol kind (see [Symbol Kinds](#symbol-kinds)) |
395
- | `file` | string | Glob pattern to restrict to specific files |
396
- | `limit` | number | Max results (default 20) |
397
- | `mode` | string | `"keyword"` (default), `"semantic"`, or `"hybrid"` |
398
-
399
- **Returns:** Array of `{ id, name, kind, filePath, signature, summary, score }`
400
-
401
- Does **not** return source code — use `get_symbol_source` for that.
402
-
403
- ---
404
-
405
- ### `get_symbol_source`
406
-
407
- Retrieve the full source code of a symbol by ID.
408
-
409
- ```json
410
- {
411
- "id": "abc123def456"
412
- }
413
- ```
414
-
415
- **Returns:** `{ symbol, source, filePath, startLine, endLine }`
416
-
417
- Extremely token-efficient: returns only the specific symbol's bytes, not the entire file.
418
-
419
- ---
420
-
421
- ### `get_file_outline`
422
-
423
- List all symbols in a file with signatures and summaries.
424
-
425
- ```json
426
- {
427
- "repo": "repoId or path",
428
- "file": "src/auth/validator.ts"
429
- }
430
- ```
431
-
432
- **Returns:** `{ file, symbols: [{ name, kind, signature, summary, startLine }] }`
433
-
434
- ---
435
-
436
- ### `get_repo_outline`
437
-
438
- High-level view of all files and their top-level symbols.
439
-
440
- ```json
441
- {
442
- "repo": "repoId or path",
443
- "maxDepth": 2
444
- }
445
- ```
446
-
447
- **Returns:** Nested structure of directories → files → top-level symbols.
448
-
449
- ---
450
-
451
- ### `get_file_tree`
452
-
453
- Directory structure with file counts. Useful for understanding project layout.
454
-
455
- ```json
456
- {
457
- "repo": "repoId or path",
458
- "maxDepth": 3
459
- }
460
- ```
461
-
462
- **Returns:** Nested directory/file tree with symbol counts per file.
463
-
464
- ---
465
-
466
- ### `get_context_bundle`
467
-
468
- Get a symbol plus all of its forward dependencies (what it imports/calls).
469
-
470
- ```json
471
- {
472
- "repo": "repoId or path",
473
- "symbolId": "abc123",
474
- "depth": 2
475
- }
476
- ```
477
-
478
- **Returns:** `{ symbol, dependencies: SymbolRecord[], _tokenEstimate }`
479
-
480
- Ideal for understanding a symbol in context without reading entire files.
481
-
482
- ---
483
-
484
- ### `get_blast_radius`
485
-
486
- Reverse dependency analysis — find everything that depends on a symbol.
487
-
488
- ```json
489
- {
490
- "repo": "repoId or path",
491
- "symbolId": "abc123",
492
- "depth": 3
493
- }
494
- ```
495
-
496
- **Returns:** `{ symbol, dependents: SymbolRecord[], _tokenEstimate }`
497
-
498
- Use before changing a function to understand the impact scope.
499
-
500
- ---
501
-
502
- ### `find_importers`
503
-
504
- Find all files that import a specific module.
505
-
506
- ```json
507
- {
508
- "repo": "repoId or path",
509
- "file": "src/utils/auth.ts"
510
- }
511
- ```
512
-
513
- **Returns:** `{ importers: [{ file, symbols }] }`
514
-
515
- ---
516
-
517
- ### `find_dead_code`
518
-
519
- Find exported symbols with zero importers — potential dead code.
520
-
521
- ```json
522
- {
523
- "repo": "repoId or path"
524
- }
525
- ```
526
-
527
- **Returns:** `{ deadSymbols: SymbolRecord[] }`
528
-
529
- ---
530
-
531
- ### `search_text`
532
-
533
- Full-text search across raw file content (like grep, but from the index).
534
-
535
- ```json
536
- {
537
- "repo": "repoId or path",
538
- "query": "validateToken(",
539
- "is_regex": false,
540
- "file_pattern": "**/*.ts",
541
- "context_lines": 2,
542
- "max_results": 50
543
- }
544
- ```
545
-
546
- **Returns:** `{ matches: [{ file, line, column, match, context }], truncated }`
547
-
548
- Uses cached content — no live file reads. Supports regular expressions when `is_regex: true`.
549
-
550
- ---
551
-
552
- ### `search_semantic`
553
-
554
- Semantic (meaning-based) search using embeddings. Finds conceptually related symbols even when no literal string matches.
555
-
556
- ```json
557
- {
558
- "repo": "repoId or path",
559
- "query": "functions that validate user credentials",
560
- "mode": "hybrid",
561
- "semantic_weight": 0.6,
562
- "keyword_weight": 0.4,
563
- "max_results": 10,
564
- "kind": "function"
565
- }
566
- ```
567
-
568
- **Returns:** `{ results: [{ ...symbol, scores: { keyword, semantic, combined } }] }`
569
-
570
- Requires semantic search to be enabled and an embedding provider configured. Falls back to FTS keyword search if no semantic index exists.
571
-
572
- ---
573
-
574
- ### `get_layer_violations`
575
-
576
- Analyze architectural dependency violations based on configured layer rules.
577
-
578
- ```json
579
- {
580
- "repo": "repoId or path",
581
- "layers": [
582
- { "name": "core", "paths": ["src/core/**"] },
583
- { "name": "handlers", "paths": ["src/handlers/**"] }
584
- ]
585
- }
586
- ```
587
-
588
- **Returns:** `{ violations: [{ from_layer, to_layer, from_file, to_file, import_spec }], summary }`
589
-
590
- If `layers` is omitted, reads from `config.json`. Useful for enforcing clean architecture.
591
-
592
- ---
593
-
594
- ### `get_savings_stats`
595
-
596
- View cumulative token savings across all PureContext tool calls.
597
-
598
- ```json
599
- {
600
- "reset": false
601
- }
602
- ```
603
-
604
- **Returns:**
605
- ```json
606
- {
607
- "total_tokens_saved": 123456,
608
- "equivalent_context_windows": { "claude_200k": 0.62, "gpt4_128k": 0.96 },
609
- "total_cost_avoided": {
610
- "claude_opus_4": 1.85,
611
- "claude_sonnet_4": 0.37,
612
- "claude_haiku_4": 0.10,
613
- "gpt4o": 0.31,
614
- "gpt4o_mini": 0.02
615
- }
616
- }
617
- ```
618
-
619
- Set `reset: true` to clear the counter.
620
-
621
- ---
622
-
623
- ### Symbol Kinds
624
-
625
- The `kind` parameter in search accepts any of these values:
626
-
627
- | Kind | Description |
628
- |------|-------------|
629
- | `function` | Standalone function / top-level def |
630
- | `class` | Class, struct (Go/Rust), or OOP type |
631
- | `method` | Method inside a class/struct/impl |
632
- | `const` | Constant, exported variable, field |
633
- | `type` | Type alias, typedef, newtype |
634
- | `interface` | Interface or protocol |
635
- | `enum` | Enumeration |
636
- | `component` | UI component (Vue, React, Angular) |
637
- | `composable` | Vue composable (`useXxx`) |
638
- | `hook` | React hook (`useXxx`) |
639
- | `route` | HTTP route (any framework) |
640
- | `middleware` | Middleware or guard |
641
- | `decorator` | Decorator / annotation |
642
- | `model` | ORM model (Django, Rails, Laravel, Hibernate, SQLAlchemy) |
643
- | `view` | Request handler / controller action |
644
- | `struct` | C/C++ struct (distinct from class) |
645
- | `macro` | C/C++ `#define` macro |
646
- | `signal` | Django signal receiver |
647
- | `namespace` | C++ namespace |
648
- | `widget` | Flutter widget |
649
-
650
- ---
651
-
652
- ## 7. Language Support
653
-
654
- PureContext supports 19 languages via tree-sitter AST parsing.
655
-
656
- ### Full symbol extraction
657
-
658
- | Language | Extensions | Symbol Types | Doc Comments |
659
- |----------|-----------|--------------|--------------|
660
- | **TypeScript** | `.ts`, `.tsx`, `.mts`, `.cts` | function, class, method, const, type, interface, enum | JSDoc `/** */` |
661
- | **JavaScript** | `.js`, `.jsx`, `.mjs`, `.cjs` | function, class, method, const | JSDoc `/** */` |
662
- | **Python** | `.py` | function, class, method, const | Docstrings `"""` |
663
- | **Go** | `.go` | function, method, class (struct), interface, const, type | `//` preceding comments |
664
- | **Rust** | `.rs` | function, method, class (struct), enum, interface (trait), const, type | `///` doc comments |
665
- | **Java** | `.java` | class, interface, enum, method, const | Javadoc `/** */` |
666
- | **C#** | `.cs` | class, interface, enum, struct, record, method, const, property | XML docs `/// <summary>` |
667
- | **PHP** | `.php` | function, class, interface, trait, enum, method, const | PHPDoc `/** */` |
668
- | **Ruby** | `.rb` | function, class, method, module, const | `#` comments |
669
- | **Kotlin** | `.kt`, `.kts` | function, class, interface, enum, method, typealias, object | KDoc `/**` |
670
- | **C** | `.c`, `.h` | function, struct, enum, macro, type | `//` and `/* */` |
671
- | **C++** | `.cpp`, `.cxx`, `.cc`, `.hpp`, `.hxx`, `.hh` | All C types + namespace, template | `///` Doxygen |
672
- | **Lua** | `.lua` | function, method, const | `--` comments |
673
- | **Dart** | `.dart` | class, mixin, extension, enum, function, method, const, type | `///` doc comments |
674
- | **Swift** | `.swift` | class, struct, protocol, actor, extension, method, enum, type | `///` DocC |
675
- | **Elixir** | `.ex`, `.exs` | module (class), function, macro, struct, protocol | `@doc` attribute |
676
- | **Haskell** | `.hs`, `.lhs` | function, data (class), typeclass (interface), instance, type, newtype | Haddock `-- \|` |
677
- | **Scala** | `.scala`, `.sc` | class, trait, object, case class, function, method, type, enum | Scaladoc `/** */` |
678
- | **R** | `.r`, `.R`, `.Rmd` | function, const, S3/S4/R6 class | Roxygen2 `#'` |
679
-
680
- ### What gets indexed
681
-
682
- - **All non-private symbols** by default (exact visibility rules vary by language)
683
- - **Byte offsets** for precise source retrieval
684
- - **Import/dependency edges** for the dependency graph
685
- - **Docstrings** as symbol summaries (stage 1 of the summarizer pipeline)
686
-
687
- ### What is excluded automatically
688
-
689
- - `node_modules/`, `.git/`, `dist/`, `build/`, `.claude/`
690
- - `*.lock` files, `.env*` files
691
- - Binary files (detected by null-byte scanning)
692
- - Files > 1 MB (configurable)
693
- - Secret files: `*.pem`, `*.key`, `id_rsa`, `credentials.json`, etc.
694
- - `private` methods in Java, C#, PHP (language-specific visibility rules)
695
- - Unexported symbols in Go (lowercase names)
696
- - `static` functions in C (translation-unit internal)
697
- - Private (`_`-prefixed) symbols in Dart
698
-
699
- ---
700
-
701
- ## 8. Framework Adapters
702
-
703
- Framework adapters run on top of language handlers and extract framework-specific metadata. They are auto-detected from project config files.
704
-
705
- ### JavaScript / TypeScript Frameworks
706
-
707
- #### Vue 3
708
- **Detected by:** `vue` in `package.json`, or any `.vue` files present.
709
-
710
- Extracts from `.vue` Single File Components:
711
- - `component` — the component itself (from filename or `defineComponent`)
712
- - `composable` — exported `use*` functions
713
-
714
- `frameworkMeta` includes: `vue_component`, `vue_composable`.
715
-
716
- #### Nuxt
717
- **Detected by:** `nuxt.config.ts` (or `.js`/`.mts`/`.mjs`) in project root.
718
-
719
- Extracts:
720
- - `route` from `pages/**/*.vue` (with derived route path like `/blog/:slug`)
721
- - `route` from `server/api/**/*.ts` (with HTTP method from filename suffix)
722
- - `middleware` from `plugins/**` and `middleware/**`
723
- - Enriches composables in `composables/**` with `nuxt_auto_import: true`
724
-
725
- #### React
726
- **Detected by:** `react` in `package.json` dependencies.
727
-
728
- Enriches TypeScript handler symbols:
729
- - PascalCase functions returning JSX → `component`
730
- - `use*` functions → `hook`
731
-
732
- #### Next.js
733
- **Detected by:** `next.config.*` or `next` in `package.json`.
734
-
735
- Extracts:
736
- - **Pages Router** (`pages/**`): `route` symbols with path derivation
737
- - `pages/blog/[slug].tsx` → `/blog/:slug`
738
- - Detects `getServerSideProps` (SSR), `getStaticProps` (SSG)
739
- - **App Router** (`app/**/page.tsx`): `route` symbols
740
- - `app/(marketing)/about/page.tsx` → `/about` (route groups stripped)
741
- - Detects `'use client'` directive
742
- - **API routes**: `pages/api/**` and `app/**/route.ts` (with HTTP method exports)
743
- - **Middleware** (`middleware.ts`): `middleware` symbol with matcher
744
-
745
- #### Angular
746
- **Detected by:** `@angular/core` in `package.json`.
747
-
748
- Extracts from decorated classes:
749
- - `@Component` → `component` (with `selector`)
750
- - `@Injectable` → `class` (service)
751
- - `@NgModule` → `class` (module)
752
- - `@Directive` → `component` (with `selector`)
753
- - `@Pipe` → `component` (with pipe name)
754
- - `RouterModule.forRoot/forChild` → `route` symbols
755
-
756
- #### NestJS
757
- **Detected by:** `@nestjs/core` in `package.json`.
758
-
759
- Extracts from decorated controllers:
760
- - `@Controller('prefix')` + `@Get(':id')` → `route` with combined path (`GET /prefix/:id`)
761
- - `@Injectable` → `class` with `nestjs_provider: true`
762
- - `@Module` → `class` with `nestjs_module: true`
763
- - `@Guard` / `CanActivate` → `middleware`
764
-
765
- #### Express
766
- **Detected by:** `express` in `package.json`.
767
-
768
- Extracts string-literal route registrations:
769
- - `app.get('/path', ...)` → `route`
770
- - `router.post('/path', ...)` → `route`
771
- - `app.use('/path', ...)` → `middleware`
772
-
773
- Dynamic paths (variables, template literals) are skipped.
774
-
775
- #### Fastify
776
- **Detected by:** `fastify` in `package.json`.
777
-
778
- Same pattern as Express: `fastify.get(path, ...)` → `route`.
779
-
780
- ---
781
-
782
- ### Python Frameworks
783
-
784
- #### Flask
785
- **Detected by:** `Flask` in `requirements.txt` or `pyproject.toml`.
786
-
787
- Extracts:
788
- - `@app.route('/path')` → `route`
789
- - `@app.get('/path')`, `@app.post(...)` → `route`
790
- - Blueprint routes: `@bp.route(...)` → `route`
791
- - Class-based views (inheriting `MethodView`) → `view`
792
-
793
- Flask path parameters (`<int:user_id>`) are preserved as-is.
794
-
795
- #### FastAPI
796
- **Detected by:** `fastapi` in `requirements.txt` or `pyproject.toml`.
797
-
798
- Extracts:
799
- - `@app.get('/items/{id}')` → `route`
800
- - `@router.post(...)` (APIRouter) → `route`
801
-
802
- FastAPI path parameters (`{param}`) are preserved as-is.
803
-
804
- #### Django
805
- **Detected by:** `manage.py` at project root, or `django` in requirements.
806
-
807
- Extracts:
808
- - `models.Model` subclasses → `model`
809
- - Class-based views (`APIView`, `ViewSet`, etc.) → `view`
810
- - Function-based views (with `@login_required`, `@api_view`) → `view`
811
- - `path(...)` / `re_path(...)` in `urls.py` → `route`
812
- - `@receiver(post_save)` → `signal`
813
-
814
- ---
815
-
816
- ### Go Frameworks
817
-
818
- #### Gin
819
- **Detected by:** `github.com/gin-gonic/gin` in `go.mod`.
820
-
821
- Extracts: `r.GET("/path", handler)`, `r.POST(...)`, etc. → `route`
822
- Groups: `r.Group("/api")` prefix applied to child routes.
823
-
824
- #### Echo
825
- **Detected by:** `github.com/labstack/echo` in `go.mod`.
826
-
827
- Same pattern as Gin: `e.GET("/path", handler)` → `route`.
828
-
829
- #### Fiber
830
- **Detected by:** `github.com/gofiber/fiber` in `go.mod`.
831
-
832
- Uses title-case methods: `app.Get("/path", handler)` → `route`.
833
-
834
- ---
835
-
836
- ### PHP Frameworks
837
-
838
- #### Laravel
839
- **Detected by:** `laravel/framework` in `composer.json`.
840
-
841
- Extracts:
842
- - `Route::get('/path', ...)` → `route`
843
- - `Route::resource('users', Controller::class)` → multiple CRUD routes
844
- - `Route::group(['prefix' => '/api'], ...)` → prefix applied to children
845
- - `User extends Model` → `model`
846
- - Controller public methods → `view`
847
- - Middleware classes → `middleware`
848
-
849
- #### Symfony
850
- **Detected by:** `symfony/framework-bundle` in `composer.json`.
851
-
852
- Extracts:
853
- - `#[Route('/path', methods: ['GET'])]` → `route` (PHP 8 attributes)
854
- - `@Route('/path')` in docblock → `route` (annotation style)
855
- - `#[AsController]` or `AbstractController` subclasses → controller
856
-
857
- ---
858
-
859
- ### Ruby Frameworks
860
-
861
- #### Rails
862
- **Detected by:** `gem 'rails'` in `Gemfile`.
863
-
864
- Extracts:
865
- - `ApplicationRecord` subclasses → `model` (with `has_many` associations)
866
- - `ApplicationController` subclasses → `class` (controller)
867
- - Controller public methods → `view` (action)
868
- - `get '/path'`, `resources :users` in `routes.rb` → `route`
869
-
870
- #### Sinatra
871
- **Detected by:** `gem 'sinatra'` in `Gemfile` or `require 'sinatra'` in source.
872
-
873
- Extracts: `get '/path' do ... end` → `route`
874
-
875
- ---
876
-
877
- ### Kotlin Frameworks
878
-
879
- #### Ktor
880
- **Detected by:** `io.ktor` in `build.gradle` / `pom.xml`.
881
-
882
- Extracts from routing DSL:
883
- - `get("/path") { ... }` → `route`
884
- - `route("/api") { get("/users") }` → combined path `/api/users`
885
- - `authenticate { ... }` → `frameworkMeta.authenticated: true`
886
-
887
- #### Spring (Kotlin)
888
- **Detected by:** `org.springframework.boot` in `build.gradle` / `pom.xml`.
889
-
890
- Extracts:
891
- - `@RestController` + `@GetMapping("/path")` → `route`
892
- - `@Service`, `@Component`, `@Repository` → class with metadata
893
-
894
- ---
895
-
896
- ### Rust Frameworks
897
-
898
- #### Axum
899
- **Detected by:** `axum` in `Cargo.toml` dependencies.
900
-
901
- Extracts: `.route("/path", get(handler))` chains → `route`
902
- Layers: `.layer(...)` → `middleware`
903
-
904
- #### Actix-web
905
- **Detected by:** `actix-web` in `Cargo.toml`.
906
-
907
- Extracts:
908
- - `#[get("/path")]` attribute macro → `route`
909
- - `web::resource("/path").route(web::get().to(handler))` → `route`
910
- - `.wrap(...)` → `middleware`
911
-
912
- #### Rocket
913
- **Detected by:** `rocket` in `Cargo.toml`.
914
-
915
- Extracts:
916
- - `#[get("/path")]` → `route`
917
- - `#[catch(404)]` → error catcher
918
- - `Fairing` implementations → `middleware`
919
-
920
- ---
921
-
922
- ### Java Frameworks
923
-
924
- #### Spring Boot
925
- **Detected by:** `spring-boot-starter` in `pom.xml` / `build.gradle`.
926
-
927
- Extracts:
928
- - `@GetMapping`, `@PostMapping`, etc. (combined with `@RequestMapping` prefix) → `route`
929
- - `@Service`, `@Component`, `@Repository` → bean classes
930
- - `@Bean` methods → bean symbols
931
- - `@Scheduled` methods → scheduled tasks
932
-
933
- #### Micronaut
934
- **Detected by:** `io.micronaut` in build files.
935
-
936
- Extracts: `@Get("/path")`, `@Post(...)` → `route`; `@Client` interfaces → `interface`.
937
-
938
- #### Quarkus
939
- **Detected by:** `io.quarkus` in build files.
940
-
941
- Extracts: JAX-RS `@GET` / `@Path` → `route`; `@ApplicationScoped` → bean.
942
-
943
- ---
944
-
945
- ### ORM Adapters
946
-
947
- #### Hibernate (Java)
948
- **Detected by:** `hibernate-core` or `jakarta.persistence` in dependencies.
949
-
950
- Extracts from `@Entity` classes:
951
- - Table name (from `@Table(name = "...")` or class name)
952
- - Columns with types and nullability
953
- - Relationships (`@OneToMany`, `@ManyToOne`, etc.)
954
- - Named queries (`@NamedQuery`)
955
-
956
- #### SQLAlchemy (Python)
957
- **Detected by:** `sqlalchemy` in requirements.
958
-
959
- Extracts from `Base` / `DeclarativeBase` subclasses:
960
- - `__tablename__` attribute
961
- - `Column(Type)` fields with types and constraints
962
- - `relationship()` associations
963
- - `@hybrid_property` methods
964
-
965
- Supports both SQLAlchemy 1.x and 2.0 (`mapped_column`) styles.
966
-
967
- #### Django ORM
968
- **Detected by:** Django project with `manage.py`.
969
-
970
- Extracts from `models.py` files:
971
- - `models.Model` subclasses with table names
972
- - Field types: `CharField`, `IntegerField`, `ForeignKey`, `ManyToManyField`, etc.
973
- - `on_delete` constraint metadata
974
- - Custom managers
975
-
976
- ---
977
-
978
- ### Mobile Frameworks
979
-
980
- #### Flutter
981
- **Detected by:** `sdk: flutter` in `pubspec.yaml`.
982
-
983
- Extracts from `.dart` files:
984
- - `StatelessWidget` subclasses → `widget` (with `flutter_widget_type: 'stateless'`)
985
- - `StatefulWidget` subclasses → `widget` (with linked State class)
986
- - `ChangeNotifier` subclasses → `class` (with `flutter_notifier: true`)
987
-
988
- Test files (`*_test.dart`) are excluded from widget extraction.
989
-
990
- ---
991
-
992
- ## 9. Transport Modes
993
-
994
- ### stdio (default)
995
-
996
- The standard transport for Claude Code and other MCP-native clients.
997
-
998
- ```bash
999
- purecontext-mcp
1000
- ```
1001
-
1002
- No network exposure. Communication happens via stdin/stdout.
1003
-
1004
- **Claude Code configuration:**
1005
- ```bash
1006
- claude mcp add purecontext-mcp purecontext-mcp
1007
- ```
1008
-
1009
- ### HTTP / Streamable HTTP
1010
-
1011
- For browser-based clients, remote development, or multi-client setups.
1012
-
1013
- ```bash
1014
- purecontext-mcp --transport http --port 3000
1015
- ```
1016
-
1017
- ```json
1018
- // config.json
1019
- {
1020
- "transport": "http",
1021
- "http": {
1022
- "port": 3000,
1023
- "host": "127.0.0.1",
1024
- "corsOrigins": ["http://localhost:*"]
1025
- }
1026
- }
1027
- ```
1028
-
1029
- **Endpoints:**
1030
- - `GET /health` — Server health check (always public)
1031
- - `GET /sse` — MCP SSE stream
1032
- - `POST /message` — MCP message handler
1033
- - `GET /` — Web UI (when built)
1034
-
1035
- **Claude Code + HTTP:**
1036
- Add to your Claude Code MCP config:
1037
- ```json
1038
- {
1039
- "mcpServers": {
1040
- "purecontext": {
1041
- "transport": "http",
1042
- "url": "http://localhost:3000/sse"
1043
- }
1044
- }
1045
- }
1046
- ```
1047
-
1048
- ### Both (development mode)
1049
-
1050
- Runs stdio and HTTP simultaneously:
1051
-
1052
- ```bash
1053
- purecontext-mcp --transport both
1054
- ```
1055
-
1056
- ### HTTP Authentication
1057
-
1058
- When deploying on a non-loopback address, enable bearer token authentication:
1059
-
1060
- ```json
1061
- {
1062
- "http": {
1063
- "host": "0.0.0.0",
1064
- "auth": {
1065
- "enabled": true,
1066
- "token": "${PURECONTEXT_API_TOKEN}"
1067
- }
1068
- }
1069
- }
1070
- ```
1071
-
1072
- If `token` is empty with `enabled: true`, a random 32-byte hex token is generated at startup and printed to stderr. Save it.
1073
-
1074
- All MCP requests must include: `Authorization: Bearer <token>`
1075
-
1076
- ---
1077
-
1078
- ## 10. AI Summarization
1079
-
1080
- PureContext can generate natural-language summaries for symbols that have no docstring, using a multi-stage fallback:
1081
-
1082
- 1. **Stage 1** — Docstring (JSDoc, Python docstring, `///`, `@doc`, etc.)
1083
- 2. **Stage 2** — Framework-derived: `"Vue component UserCard"`, `"GET /api/users server route"`
1084
- 3. **Stage 3** — AI batch summarization (optional, requires config)
1085
- 4. **Stage 4** — Signature fallback: `"function validateToken(token: string): boolean"`
1086
-
1087
- ### Enable AI summarization
1088
-
1089
- **Using Anthropic (Claude Haiku):**
1090
-
1091
- ```json
1092
- {
1093
- "ai": {
1094
- "provider": "anthropic",
1095
- "allowRemoteAI": true,
1096
- "apiKey": "${ANTHROPIC_API_KEY}",
1097
- "model": "claude-haiku-4-5-20251001",
1098
- "batchSize": 50
1099
- }
1100
- }
1101
- ```
1102
-
1103
- **Using a local Ollama model:**
1104
-
1105
- ```json
1106
- {
1107
- "ai": {
1108
- "provider": "openai-compatible",
1109
- "allowRemoteAI": true,
1110
- "endpoint": "http://localhost:11434",
1111
- "model": "llama3.2",
1112
- "batchSize": 10
1113
- }
1114
- }
1115
- ```
1116
-
1117
- AI summarization is **always optional**. With `allowRemoteAI: false` (the default), no network calls are made and all tests pass.
1118
-
1119
- Summaries are generated post-indexing in batches. On incremental re-index, changed symbols get their summaries refreshed.
1120
-
1121
- ---
1122
-
1123
- ## 11. Semantic Search (HNSW)
1124
-
1125
- Semantic search uses embedding vectors and HNSW (Hierarchical Navigable Small Worlds) indexing to find symbols by meaning, not just keywords.
1126
-
1127
- **When is it active?**
1128
- - `semantic.enabled: true` in config
1129
- - Repository has more than `semantic.threshold` symbols (default: 50,000)
1130
- - An embedding provider is configured
1131
-
1132
- **Below the threshold**, all search uses SQLite FTS5 keyword search.
1133
-
1134
- ### Enable semantic search
1135
-
1136
- **Using OpenAI embeddings:**
1137
-
1138
- ```json
1139
- {
1140
- "semantic": {
1141
- "enabled": true,
1142
- "provider": "openai",
1143
- "threshold": 50000
1144
- },
1145
- "ai": {
1146
- "openaiApiKey": "${OPENAI_API_KEY}"
1147
- }
1148
- }
1149
- ```
1150
-
1151
- **Using local Ollama embeddings:**
1152
-
1153
- ```json
1154
- {
1155
- "semantic": {
1156
- "enabled": true,
1157
- "provider": "local",
1158
- "localEmbeddingEndpoint": "http://localhost:11434",
1159
- "threshold": 1000
1160
- }
1161
- }
1162
- ```
1163
-
1164
- Set `threshold` low (e.g., 100) to test on small repos.
1165
-
1166
- ### Using semantic search
1167
-
1168
- Via `search_semantic` tool:
1169
-
1170
- ```json
1171
- {
1172
- "repo": "my-project",
1173
- "query": "functions that validate user credentials",
1174
- "mode": "hybrid",
1175
- "semantic_weight": 0.6,
1176
- "keyword_weight": 0.4
1177
- }
1178
- ```
1179
-
1180
- Via `search_symbols` tool (automatic hybrid mode when index exists):
1181
-
1182
- ```json
1183
- {
1184
- "repo": "my-project",
1185
- "query": "auth validate",
1186
- "mode": "hybrid"
1187
- }
1188
- ```
1189
-
1190
- ### How hybrid search works
1191
-
1192
- 1. Run FTS keyword search → top N results
1193
- 2. Embed the query → run HNSW vector search → top N results
1194
- 3. Merge using Reciprocal Rank Fusion (RRF):
1195
- `score = keywordWeight × (1/(60+rank)) + semanticWeight × (1/(60+rank))`
1196
- 4. Return top results sorted by combined score
1197
-
1198
- ### Performance
1199
-
1200
- - HNSW search: < 10ms for k=10 in a 100k vector index
1201
- - Embedding generation: batched, ~50ms per symbol
1202
- - Indexes are persisted to `~/.purecontext/indexes/{repoId}/hnsw.idx`
1203
-
1204
- ---
1205
-
1206
- ## 12. Token Savings Tracker
1207
-
1208
- Every retrieval tool call automatically tracks how many tokens were saved compared to reading full files.
1209
-
1210
- ### How savings are calculated
1211
-
1212
- ```
1213
- tokens_saved = max(0, (rawFileBytes - responseBytes) / 4)
1214
- ```
1215
-
1216
- The `4 bytes/token` ratio is the cl100k_base encoding approximation.
1217
-
1218
- ### Viewing savings
1219
-
1220
- Use the `get_savings_stats` tool:
1221
-
1222
- ```json
1223
- {}
1224
- ```
1225
-
1226
- ```json
1227
- {
1228
- "total_tokens_saved": 1234567,
1229
- "equivalent_context_windows": {
1230
- "claude_200k": 6.17,
1231
- "gpt4_128k": 9.64
1232
- },
1233
- "total_cost_avoided": {
1234
- "claude_opus_4": 18.52,
1235
- "claude_sonnet_4": 3.70,
1236
- "claude_haiku_4": 0.99,
1237
- "gpt4o": 3.09,
1238
- "gpt4o_mini": 0.19
1239
- }
1240
- }
1241
- ```
1242
-
1243
- Savings are included in the `_meta` field of every retrieval tool response:
1244
-
1245
- ```json
1246
- {
1247
- "symbol": { ... },
1248
- "source": "...",
1249
- "_meta": {
1250
- "timing_ms": 3,
1251
- "tokens_saved": 1842,
1252
- "total_tokens_saved": 45231,
1253
- "cost_avoided": { "claude_opus_4": 0.028 },
1254
- "powered_by": "PureContext MCP"
1255
- }
1256
- }
1257
- ```
1258
-
1259
- Savings persist to `~/.purecontext/_savings.json` across sessions. Reset with `get_savings_stats(reset: true)`.
1260
-
1261
- ---
1262
-
1263
- ## 13. Multi-Tenant Hosting
1264
-
1265
- PureContext supports hosting as a shared service for teams or organizations.
1266
-
1267
- ### Rate Limiting
1268
-
1269
- Enabled automatically when using HTTP transport. Uses a token bucket algorithm:
1270
- - Each client gets a bucket with capacity `maxTokens` (default 100)
1271
- - Tokens refill at `refillRate` per second (default 10)
1272
- - Expensive operations cost more tokens (indexing costs 10 tokens by default)
1273
-
1274
- When rate limited, responses return `429 Too Many Requests` with a `Retry-After` header.
1275
-
1276
- Configure in `config.json`:
1277
-
1278
- ```json
1279
- {
1280
- "rateLimit": {
1281
- "enabled": true,
1282
- "maxTokens": 100,
1283
- "refillRate": 10,
1284
- "perToolLimits": {
1285
- "index_folder": 10,
1286
- "search_symbols": 1
1287
- }
1288
- }
1289
- }
1290
- ```
1291
-
1292
- ### API Key Authentication
1293
-
1294
- Create and manage API keys for tenant identification:
1295
-
1296
- ```bash
1297
- # Create a key
1298
- purecontext-mcp keys create --tenant myorg --permissions read,write
1299
-
1300
- # Output: cl_live_a1b2c3d4_<random>_<checksum>
1301
- # Save this — it's shown only once
1302
-
1303
- # List keys
1304
- purecontext-mcp keys list --tenant myorg
1305
-
1306
- # Revoke a key
1307
- purecontext-mcp keys revoke cl_live_a1b2c3
1308
- ```
1309
-
1310
- **Key format:** `cl_live_{tenantId}_{24-char-random}_{checksum}`
1311
-
1312
- Keys include a checksum for fast format validation without a database hit. Raw keys are never stored — only SHA-256 hashes.
1313
-
1314
- **Permissions:**
1315
- - `read` — query tools (search, retrieval)
1316
- - `write` — indexing tools (index_folder, index_repo)
1317
- - `admin` — tenant management, stats
1318
-
1319
- ### Tenant Data Isolation
1320
-
1321
- When running multi-tenant:
1322
- - Each tenant's repositories, symbols, and embeddings are isolated
1323
- - Queries across tenants are prevented at the data layer
1324
- - Separate HNSW indexes per tenant
1325
- - Storage quotas per tenant
1326
-
1327
- ### Admin API
1328
-
1329
- Accessible at `http://localhost:3000/admin/*` with `admin` permission:
1330
-
1331
- | Endpoint | Description |
1332
- |----------|-------------|
1333
- | `GET /admin/stats` | Server-wide statistics |
1334
- | `POST /admin/tenants` | Create a tenant |
1335
- | `GET /admin/tenants` | List all tenants |
1336
- | `GET /admin/tenants/:id/stats` | Tenant-specific stats |
1337
- | `DELETE /admin/tenants/:id` | Delete tenant and all data |
1338
- | `POST /admin/tenants/:id/keys` | Create API key for tenant |
1339
-
1340
- ---
1341
-
1342
- ## 14. Web UI
1343
-
1344
- A browser-based interface for visual codebase exploration. Served at `http://localhost:3000` when HTTP transport is active.
1345
-
1346
- ### Building the UI
1347
-
1348
- ```bash
1349
- npm run build:ui
1350
- ```
1351
-
1352
- Or include it in the full build:
1353
-
1354
- ```bash
1355
- npm run build
1356
- ```
1357
-
1358
- ### Features
1359
-
1360
- #### Repository Browser
1361
- - List all indexed repositories with symbol counts and languages
1362
- - Collapsible file tree with file type icons
1363
- - File outline: all symbols in a file, grouped by kind
1364
-
1365
- #### Symbol Search
1366
- - Real-time search with 300ms debounce
1367
- - Filter by: kind, language, file pattern
1368
- - Keyboard navigation (arrow keys + Enter)
1369
- - Term highlighting in results
1370
-
1371
- #### Symbol Source Viewer
1372
- - Syntax-highlighted source code (via Shiki — VS Code accuracy)
1373
- - Line numbers with anchors
1374
- - Light/dark theme toggle (persisted in localStorage)
1375
- - Related symbols panel: importers, dependencies, same-file symbols
1376
-
1377
- #### Dependency Graph
1378
- - Interactive force-directed graph of file/symbol dependencies
1379
- - Pan, zoom, fit-to-view controls
1380
- - Layout options: force-directed, hierarchical, radial
1381
- - Depth slider (1-hop to N-hop)
1382
- - Powered by React Flow + D3
1383
-
1384
- #### Blast Radius Visualization
1385
- - Radial layout: affected symbols radiate from the source
1386
- - Color gradient: red (direct impact) → yellow (indirect)
1387
- - Impact statistics: files affected, symbols affected
1388
- - Toggle between graph and list view
1389
-
1390
- ### Development mode
1391
-
1392
- ```bash
1393
- npm run dev
1394
- ```
1395
-
1396
- Runs TypeScript compiler in watch mode alongside Vite dev server with hot reload.
1397
-
1398
- ---
1399
-
1400
- ## 15. Security
1401
-
1402
- ### Path Traversal Prevention
1403
-
1404
- All file paths are validated before reading:
1405
- - Resolved to absolute paths
1406
- - Verified to start within the project root
1407
- - Symlinks that escape the root are blocked (unless `allowSymlinks: true`)
1408
-
1409
- ### Secret File Exclusion
1410
-
1411
- The following files are automatically excluded from indexing:
1412
- - `.env`, `.env.*`, `.env.local`, `.env.production`
1413
- - `*.pem`, `*.key`, `*.p12`, `*.pfx`, `*.crt`, `*.cer`
1414
- - `id_rsa`, `id_ed25519`, `id_ecdsa`, `id_dsa`
1415
- - `credentials.json`, `credentials.yaml`, `secrets.json`
1416
- - `serviceAccountKey*.json`, `*-service-account.json`
1417
- - `*.token`, `*.secret`
1418
-
1419
- ### Binary File Detection
1420
-
1421
- Files with null bytes in the first 8 KB are treated as binary and skipped.
1422
-
1423
- ### HTTP Security
1424
-
1425
- - Default host: `127.0.0.1` (loopback only) — not exposed on the network
1426
- - Warning logged if `host` is not loopback and `auth.enabled` is false
1427
- - Token comparison uses `crypto.timingSafeEqual()` (timing-attack resistant)
1428
- - Request bodies limited to 1 MB
1429
- - CORS origins whitelist-controlled
1430
-
1431
- ### Remote Repository Cloning
1432
-
1433
- - Only `https://`, `http://`, and `git@` URL schemes are accepted
1434
- - Clone tokens are never logged
1435
- - Clones are isolated under `~/.purecontext/clones/`
1436
-
1437
- ---
1438
-
1439
- ## 16. Architecture Overview
1440
-
1441
- PureContext uses a strict three-layer architecture:
1442
-
1443
- ```
1444
- Adapters → Handlers → Core
1445
- ```
1446
-
1447
- - **Core** (`src/core/`) — File discovery, hashing, tree-sitter dispatch, SQLite storage, MCP transport, file watcher. Language-agnostic.
1448
- - **Handlers** (`src/handlers/`) — One handler per language. Implements `LanguageHandler`: parse with tree-sitter, extract symbols and imports.
1449
- - **Adapters** (`src/adapters/`) — One adapter per framework. Implements `FrameworkAdapter`: auto-detect from project files, extract framework-specific symbols, enrich metadata.
1450
-
1451
- The dependency graph, semantic indexer, summarizer, and MCP server all build on Core without violating the layer boundary. Use `get_layer_violations` to verify your own projects follow similar rules.
1452
-
1453
- ### Data flow
1454
-
1455
- ```
1456
- index_folder(path)
1457
- → FileDiscovery (scan, priority order, exclude patterns, secret detection)
1458
- → HashCache (skip unchanged files)
1459
- → LanguageHandler.parseFile(buffer) → AST
1460
- → LanguageHandler.extractSymbols(AST) → SymbolRecord[]
1461
- → LanguageHandler.extractImports(AST) → ImportRecord[]
1462
- → FrameworkAdapter.extractFrameworkSymbols(AST) → SymbolRecord[]
1463
- → FrameworkAdapter.enrichMetadata(symbol) → SymbolRecord
1464
- → Summarizer (docstring → framework-derived → AI → signature)
1465
- → SymbolStore.insertSymbols(batch) → SQLite
1466
- → PathResolver.resolve(imports) → DepEdge[]
1467
- → DepStore.insertEdges(batch) → SQLite
1468
- → SemanticIndexer.index(symbols) → HNSW (if enabled)
1469
- ```
1470
-
1471
- ### Storage locations
1472
-
1473
- | Path | Contents |
1474
- |------|----------|
1475
- | `~/.purecontext/indexes/` | SQLite databases (one per project) |
1476
- | `~/.purecontext/indexes/{repoId}/hnsw.idx` | HNSW vector index |
1477
- | `~/.purecontext/clones/` | Remote repo clones |
1478
- | `~/.purecontext/config.json` | Configuration file |
1479
- | `~/.purecontext/_savings.json` | Cumulative token savings |
1480
-
1481
- ---
1482
-
1483
- ## 17. Troubleshooting
1484
-
1485
- ### "Repo not indexed" error
1486
-
1487
- The repository has not been indexed yet. Call `index_folder` first.
1488
-
1489
- ### Incremental re-index not triggered
1490
-
1491
- The file watcher has a 2-second debounce. For manual force re-index: call `index_folder` again — it skips unchanged files using content hashing.
1492
-
1493
- ### Missing symbols after indexing
1494
-
1495
- Check if the file is excluded:
1496
- 1. File may be in `node_modules/`, `dist/`, or another built-in exclusion
1497
- 2. File may match a `excludePatterns` glob
1498
- 3. File may exceed `maxFileSizeBytes`
1499
- 4. File may be a secret file (matched by security patterns)
1500
- 5. For some languages: private symbols are skipped by design (e.g., Go unexported, C static functions)
1501
-
1502
- ### Adapter not activating
1503
-
1504
- Run `purecontext-mcp config --check` and look at the detected adapters. Adapter detection:
1505
- - Vue: requires `vue` in `package.json`
1506
- - Nuxt: requires `nuxt.config.ts`
1507
- - Django: requires `manage.py` at project root
1508
- - Gin: requires `github.com/gin-gonic/gin` in `go.mod`
1509
-
1510
- Force a specific adapter by setting `adapters` in config:
1511
- ```json
1512
- { "adapters": ["vue", "nuxt"] }
1513
- ```
1514
-
1515
- ### HTTP transport not accessible from browser
1516
-
1517
- 1. Check `http.host` — default is `127.0.0.1` (loopback). Set to `0.0.0.0` for network access.
1518
- 2. Check `http.corsOrigins` — must include the browser's origin.
1519
- 3. Check `http.auth` — if enabled, all requests need `Authorization: Bearer <token>`.
1520
-
1521
- ### Semantic search not working
1522
-
1523
- 1. Verify `semantic.enabled: true` in config
1524
- 2. Verify a provider is configured (`semantic.provider`)
1525
- 3. Check if the repo meets the threshold: `semantic.threshold` (default 50,000 symbols — lower it for small repos)
1526
- 4. Check API key environment variables
1527
-
1528
- ### Config validation errors
1529
-
1530
- ```bash
1531
- purecontext-mcp config --check
1532
- ```
1533
-
1534
- This validates `~/.purecontext/config.json` and reports any schema errors.
1535
-
1536
- ### Performance — indexing is slow
1537
-
1538
- - Increase `fileLimit` if you want more files indexed
1539
- - The first index is always slower; subsequent runs are incremental
1540
- - AI summarization (`allowRemoteAI: true`) adds network latency
1541
- - Semantic indexing also adds API call time
1542
-
1543
- ### "git not found" when using index_repo
1544
-
1545
- Install Git and ensure it is on `PATH`. Verify with `git --version`.
1546
-
1547
- ---
1548
-
1549
- ---
1550
-
1551
- ## 18. Advanced Relationship Analysis
1552
-
1553
- Tools for understanding deep structural relationships between symbols and files.
1554
-
1555
- ---
1556
-
1557
- ### `find_implementations`
1558
-
1559
- Find all concrete implementations of a TypeScript interface or abstract class, and all method overrides for a given base method.
1560
-
1561
- ```json
1562
- {
1563
- "repoId": "a1b2c3d4e5f60001",
1564
- "symbolId": "abc123def456",
1565
- "includeAbstract": false,
1566
- "limit": 50
1567
- }
1568
- ```
1569
-
1570
- | Parameter | Type | Description |
1571
- |-----------|------|-------------|
1572
- | `symbolId` | string | ID of the interface or abstract class (from `search_symbols`) |
1573
- | `includeAbstract` | boolean | Include abstract subclasses in results (default false) |
1574
- | `limit` | number | Max implementations to return (default 50) |
1575
-
1576
- **Returns:** `{ interfaceName, interfaceFilePath, implementations: [{ symbolId, name, kind, filePath, startLine, signature, summary, implementedMethods, missingMethods }], totalFound }`
1577
-
1578
- Each implementation records which interface methods it has implemented and which are missing.
1579
-
1580
- ---
1581
-
1582
- ### `get_call_hierarchy`
1583
-
1584
- Return the callers and callees of a function, N levels deep, as a tree structure. Unlike `get_blast_radius` (file-level, reverse-only), this tool returns a hierarchical view of the call stack.
1585
-
1586
- ```json
1587
- {
1588
- "repoId": "...",
1589
- "symbolId": "abc123",
1590
- "direction": "callees",
1591
- "maxDepth": 3,
1592
- "maxNodes": 50
1593
- }
1594
- ```
1595
-
1596
- | Parameter | Type | Description |
1597
- |-----------|------|-------------|
1598
- | `direction` | string | `"callees"` — what this function calls; `"callers"` — what calls it; `"both"` — bidirectional |
1599
- | `maxDepth` | number | Maximum tree depth (default 3, max 6) |
1600
- | `maxNodes` | number | Stop expanding once this many nodes are reached (default 50) |
1601
- | `maxTokens` | number | Soft cap on response size in tokens |
1602
-
1603
- **Returns:** `{ root: CallNode, direction, totalNodes, truncated }` where each `CallNode` has `children`, `callCount`, and `cyclic: true` for recursive calls.
1604
-
1605
- ---
1606
-
1607
- ### `get_class_hierarchy`
1608
-
1609
- Return the full inheritance chain for a class or interface — ancestors (extends chain upward) and/or descendants (all subclasses downward). External base classes not indexed in the repo appear as leaf nodes with `symbolId: null`.
1610
-
1611
- ```json
1612
- {
1613
- "repoId": "...",
1614
- "symbolId": "abc123",
1615
- "direction": "both",
1616
- "maxDepth": 5,
1617
- "includeInterfaces": true
1618
- }
1619
- ```
1620
-
1621
- | Parameter | Type | Description |
1622
- |-----------|------|-------------|
1623
- | `direction` | string | `"ancestors"`, `"descendants"`, or `"both"` (default) |
1624
- | `maxDepth` | number | Maximum traversal depth in each direction (default 5) |
1625
- | `includeInterfaces` | boolean | Include implemented interfaces in the chain (default true) |
1626
-
1627
- **Returns:** `{ root: HierarchyNode, direction, totalNodes }` as a tree with `ancestors` and `descendants` sub-trees.
1628
-
1629
- ---
1630
-
1631
- ### `find_cycles`
1632
-
1633
- Detect all import cycles in the dependency graph and return them as ordered file paths. Unlike `detect_antipatterns` (which only counts cycles), this tool returns the actual cycle paths so you can resolve them.
1634
-
1635
- ```json
1636
- {
1637
- "repoId": "...",
1638
- "filePath": "src/auth/",
1639
- "maxCycles": 20,
1640
- "minLength": 2
1641
- }
1642
- ```
1643
-
1644
- | Parameter | Type | Description |
1645
- |-----------|------|-------------|
1646
- | `filePath` | string | Scope to cycles involving this file/directory |
1647
- | `maxCycles` | number | Stop after finding this many cycles (default 20) |
1648
- | `minLength` | number | Minimum cycle length to report (default 2). Raise to skip direct mutual imports. |
1649
-
1650
- **Returns:** `{ cycles: [{ files: string[], length, severity }], totalFound, truncated }`
1651
-
1652
- Severity: `"error"` for tight 2–3-node cycles; `"warning"` for longer chains.
1653
-
1654
- ---
1655
-
1656
- ### `get_coupling_map`
1657
-
1658
- Return per-file coupling scores using Martin's instability metric. Goes beyond `get_quality_metrics` to show exactly which files each file imports and which files import it.
1659
-
1660
- ```json
1661
- {
1662
- "repoId": "...",
1663
- "topN": 20,
1664
- "minScore": 3,
1665
- "direction": "both"
1666
- }
1667
- ```
1668
-
1669
- | Parameter | Type | Description |
1670
- |-----------|------|-------------|
1671
- | `filePath` | string | Scope to a single file. Omit for top-N across the whole repo. |
1672
- | `topN` | number | Max files to return when `filePath` is omitted (default 20) |
1673
- | `minScore` | number | Only include files whose total coupling ≥ this value |
1674
- | `direction` | string | `"efferent"`, `"afferent"`, or `"both"` (default) |
1675
-
1676
- **Returns:** `{ files: [{ filePath, efferentCoupling, afferentCoupling, instability, efferentDeps, afferentDeps }] }`
1677
-
1678
- - `instability = efferentCoupling / (efferentCoupling + afferentCoupling)`
1679
- - Score near `0` = stable hub (risky to change)
1680
- - Score near `1` = leaf node (safe to change)
1681
-
1682
- ---
1683
-
1684
- ## 19. Architectural Visualization
1685
-
1686
- Generate diagrams of your codebase structure. All diagram tools support Mermaid format (renders natively in GitHub, VS Code, and Claude) and DOT format (for Graphviz).
1687
-
1688
- ---
1689
-
1690
- ### `render_diagram`
1691
-
1692
- The general-purpose diagram generator. Produces file-level import graphs, call graphs, or class hierarchy diagrams.
1693
-
1694
- ```json
1695
- {
1696
- "repoId": "...",
1697
- "type": "module",
1698
- "filePath": "src/core/",
1699
- "maxNodes": 30,
1700
- "maxDepth": 3,
1701
- "format": "mermaid"
1702
- }
1703
- ```
1704
-
1705
- | Parameter | Type | Description |
1706
- |-----------|------|-------------|
1707
- | `type` | string | `"module"`/`"import"` — file-level import graph; `"call"` — call graph; `"class"` — class hierarchy |
1708
- | `rootSymbolId` | string | Anchor for `call` and `class` diagrams (required for those types) |
1709
- | `filePath` | string | Scope to a directory/file prefix |
1710
- | `maxNodes` | number | Stop adding nodes at this count (default 30) |
1711
- | `maxDepth` | number | Maximum traversal depth (default 3) |
1712
- | `format` | string | `"mermaid"` (default) or `"dot"` |
1713
-
1714
- **Returns:** `{ diagram: string, format, nodeCount, edgeCount, truncated }`
1715
-
1716
- ---
1717
-
1718
- ### `render_call_graph`
1719
-
1720
- Render a call graph rooted at a symbol as a Mermaid flowchart or DOT diagram. A focused alternative to `render_diagram` with type `"call"`.
1721
-
1722
- ```json
1723
- {
1724
- "repoId": "...",
1725
- "symbolId": "abc123",
1726
- "direction": "both",
1727
- "maxDepth": 3,
1728
- "format": "mermaid"
1729
- }
1730
- ```
1731
-
1732
- The root node is styled distinctly. Recursive/cyclic calls are shown as dashed arrows.
1733
-
1734
- ---
1735
-
1736
- ### `render_import_graph`
1737
-
1738
- Render a file-level import graph for a directory or the whole repo. A focused alternative to `render_diagram` with type `"module"`.
1739
-
1740
- ```json
1741
- {
1742
- "repoId": "...",
1743
- "filePath": "src/",
1744
- "maxNodes": 40,
1745
- "format": "mermaid"
1746
- }
1747
- ```
1748
-
1749
- Files are clustered by directory. Use `filePath` to restrict the graph to a subtree.
1750
-
1751
- ---
1752
-
1753
- ### `render_class_hierarchy`
1754
-
1755
- Render a class inheritance diagram as a Mermaid `classDiagram`. A focused alternative to `render_diagram` with type `"class"`.
1756
-
1757
- ```json
1758
- {
1759
- "repoId": "...",
1760
- "symbolId": "abc123",
1761
- "direction": "both",
1762
- "maxDepth": 4,
1763
- "format": "mermaid"
1764
- }
1765
- ```
1766
-
1767
- ---
1768
-
1769
- ### `render_dep_matrix`
1770
-
1771
- Render a dependency matrix (coupling heatmap) for the top-N most coupled files.
1772
-
1773
- ```json
1774
- {
1775
- "repoId": "...",
1776
- "topN": 10,
1777
- "filePath": "src/core/",
1778
- "format": "ascii"
1779
- }
1780
- ```
1781
-
1782
- | Parameter | Type | Description |
1783
- |-----------|------|-------------|
1784
- | `topN` | number | Number of files in the matrix (default 10) |
1785
- | `filePath` | string | Scope file selection to a directory |
1786
- | `format` | string | `"ascii"` (default, token-efficient) or `"mermaid"` (graph diagram) |
1787
-
1788
- **Returns:** `{ matrix: string, files: string[], format }`
1789
-
1790
- Cell `[row][col]` is `1` when the row file imports the column file, `—` on the diagonal.
1791
-
1792
- ---
1793
-
1794
- ### `get_architecture_snapshot`
1795
-
1796
- Freeze the current architecture state into a named snapshot, then diff two snapshots to measure structural change over time.
1797
-
1798
- ```json
1799
- {
1800
- "repoId": "...",
1801
- "action": "create",
1802
- "label": "before-auth-refactor"
1803
- }
1804
- ```
1805
-
1806
- | `action` | Description |
1807
- |----------|-------------|
1808
- | `"create"` | Compute and store a snapshot (fileCount, symbolCount, edgeCount, cycleCount, avgCoupling, avgComplexity) |
1809
- | `"list"` | Return all snapshots for the repo, newest first |
1810
- | `"diff"` | Compare two snapshots — requires `snapshotId` (base) and `compareId` (head) |
1811
- | `"delete"` | Remove a snapshot by `snapshotId` |
1812
-
1813
- **Diff returns:** `{ base, head, deltas: { cycleCountDelta, avgCouplingDelta, ... }, trend }` — a negative `cycleCountDelta` means fewer cycles (improvement).
1814
-
1815
- **Workflow:**
1816
- ```
1817
- 1. get_architecture_snapshot(action: "create", label: "before")
1818
- 2. [make changes, re-index]
1819
- 3. get_architecture_snapshot(action: "create", label: "after")
1820
- 4. get_architecture_snapshot(action: "diff", snapshotId: "before-id", compareId: "after-id")
1821
- ```
1822
-
1823
- ---
1824
-
1825
- ## 20. Refactoring Safety Checks
1826
-
1827
- Pre-flight tools that return a verdict and an impact map before you make a destructive change.
1828
-
1829
- ---
1830
-
1831
- ### `check_rename_safe`
1832
-
1833
- Pre-flight check for renaming a symbol. Returns a verdict, all affected files, and the specific lines that need updating.
1834
-
1835
- ```json
1836
- {
1837
- "repoId": "...",
1838
- "symbolId": "abc123",
1839
- "newName": "validateCredentials",
1840
- "checkConflicts": true
1841
- }
1842
- ```
1843
-
1844
- **Returns:** `{ safe: boolean, verdict, oldName, newName, affectedFiles: [{ filePath, line, column, changeType, snippet }], blockers: string[] }`
1845
-
1846
- `safe: false` when:
1847
- - `newName` already exists in the same file (name conflict)
1848
- - Any references are string literals (require manual updates — a rename tool can't fix these)
1849
-
1850
- `changeType` values: `"import"`, `"call"`, `"type-reference"`, `"string-literal"`, `"comment"`
1851
-
1852
- ---
1853
-
1854
- ### `check_delete_safe`
1855
-
1856
- Pre-flight check for deleting a symbol or an entire file.
1857
-
1858
- ```json
1859
- {
1860
- "repoId": "...",
1861
- "symbolId": "abc123",
1862
- "includeExternalRisk": true
1863
- }
1864
- ```
1865
-
1866
- | Parameter | Type | Description |
1867
- |-----------|------|-------------|
1868
- | `symbolId` | string | Single symbol to check |
1869
- | `filePath` | string | All symbols in a file (aggregate verdict) — use instead of `symbolId` |
1870
- | `includeExternalRisk` | boolean | Flag exported symbols as risky (external npm consumers; default true) |
1871
-
1872
- **Returns:** `{ safe: boolean, verdict, risks: [{ kind, filePath, line, snippet }] }`
1873
-
1874
- Risk kinds: `"live-reference"`, `"exported-symbol"`, `"entry-point"`, `"test-subject"`
1875
-
1876
- ---
1877
-
1878
- ### `check_move_safe`
1879
-
1880
- Pre-flight check for moving a file to a new path. Identifies all import statements that reference the current path and reports which will break.
1881
-
1882
- ```json
1883
- {
1884
- "repoId": "...",
1885
- "filePath": "src/utils/auth.ts",
1886
- "newFilePath": "src/auth/utils.ts"
1887
- }
1888
- ```
1889
-
1890
- **Returns:** `{ safe: boolean, verdict, affectedImports: [{ filePath, line, currentSpecifier, updatedSpecifier }], manualUpdatesRequired: boolean }`
1891
-
1892
- `safe: false` when any import uses a non-relative specifier (path alias, bare module name) that can't be automatically updated.
1893
-
1894
- ---
1895
-
1896
- ### `plan_refactoring`
1897
-
1898
- Generate a sequenced, risk-annotated refactoring plan for a symbol or file. Synthesizes the outputs of `check_rename_safe`, `check_delete_safe`, `check_move_safe`, `find_cycles`, `get_coupling_map`, `detect_antipatterns`, and `get_quality_metrics` into a prioritized action list.
1899
-
1900
- ```json
1901
- {
1902
- "repoId": "...",
1903
- "goal": "rename-symbol",
1904
- "symbolId": "abc123",
1905
- "newName": "validateCredentials"
1906
- }
1907
- ```
1908
-
1909
- | `goal` | Description |
1910
- |--------|-------------|
1911
- | `"rename-symbol"` | Rename a symbol everywhere — requires `symbolId` + `newName` |
1912
- | `"delete-symbol"` | Safely remove a symbol — requires `symbolId` |
1913
- | `"break-cycle"` | Resolve a circular import — requires `filePath` or `symbolId` |
1914
- | `"extract-module"` | Move a file to a new location — requires `filePath` + `newFilePath` |
1915
- | `"reduce-coupling"` | Split a highly-coupled file — requires `filePath` or `symbolId` |
1916
- | `"general"` | Open-ended analysis — surfaces top findings |
1917
-
1918
- **Returns:** `{ goal, steps: [{ order, action, target, risk, rationale }], summary, estimatedFiles, warnings }`
1919
-
1920
- Steps are ordered bottom-up: leaf files before hub files, reference updates before declaration changes.
1921
-
1922
- ---
1923
-
1924
- ## 21. Health Dashboards & Debt Reporting
1925
-
1926
- Tools for measuring, tracking, and comparing codebase health over time.
1927
-
1928
- ---
1929
-
1930
- ### `health_radar`
1931
-
1932
- Compute a multi-axis health radar for an indexed repo. Each axis is scored 0–100 (100 = perfectly healthy).
1933
-
1934
- ```json
1935
- {
1936
- "repoId": "...",
1937
- "scope": "src/core/",
1938
- "includeStability": true
1939
- }
1940
- ```
1941
-
1942
- | Parameter | Type | Description |
1943
- |-----------|------|-------------|
1944
- | `scope` | string | Directory prefix to narrow analysis |
1945
- | `includeStability` | boolean | Include churn-based stability axis (requires git metadata; default true) |
1946
-
1947
- **Returns:**
1948
- ```json
1949
- {
1950
- "axes": {
1951
- "complexity": { "score": 72, "label": "Good", "rationale": "..." },
1952
- "coupling": { "score": 58, "label": "Warning", "rationale": "..." },
1953
- "maintainability": { "score": 81, "label": "Good", "rationale": "..." },
1954
- "documentation": { "score": 44, "label": "Poor", "rationale": "..." },
1955
- "stability": { "score": 65, "label": "Fair", "rationale": "..." }
1956
- },
1957
- "overallHealth": 64,
1958
- "grade": "C",
1959
- "summary": { "totalFiles": 120, "symbolCount": 1840, "highRiskFiles": 7 }
1960
- }
1961
- ```
1962
-
1963
- Five axes:
1964
- - **complexity** — inverse of average/peak cyclomatic complexity
1965
- - **coupling** — inverse of high-coupling file density
1966
- - **maintainability** — inverse of dead-code and god-class density
1967
- - **documentation** — percentage of symbols with non-trivial summaries
1968
- - **stability** — inverse of churn-hotspot density (requires git metadata)
1969
-
1970
- ---
1971
-
1972
- ### `diff_health_radar`
1973
-
1974
- Compare health radar scores between two indexed repos (or two states of the same codebase). Positive delta = improvement; negative delta = regression.
1975
-
1976
- ```json
1977
- {
1978
- "baseRepoId": "main-branch-id",
1979
- "headRepoId": "feature-branch-id",
1980
- "scope": "src/"
1981
- }
1982
- ```
1983
-
1984
- **Primary use cases:**
1985
- - PR review: index `main` branch → index feature branch → compare
1986
- - Refactoring validation: re-index before/after changes → compare
1987
- - Cross-repo benchmarking
1988
-
1989
- **Returns:** `{ base, head, axes: { complexity: { base, head, delta, trend }, ... }, overallDelta, trend, regressions, improvements }`
1990
-
1991
- A delta ≥ +5 is a meaningful improvement; ≤ −5 is a meaningful regression.
1992
-
1993
- ---
1994
-
1995
- ### `get_debt_report`
1996
-
1997
- Generate a comprehensive technical debt report aggregating complexity, structural, maintainability, and volatility signals.
1998
-
1999
- ```json
2000
- {
2001
- "repoId": "...",
2002
- "scope": "src/",
2003
- "topN": 10,
2004
- "includeChurn": true
2005
- }
2006
- ```
2007
-
2008
- | Parameter | Type | Description |
2009
- |-----------|------|-------------|
2010
- | `scope` | string | Directory prefix to narrow analysis |
2011
- | `topN` | number | Number of top debt files to return (default 10) |
2012
- | `includeChurn` | boolean | Include churn-based volatility debt (requires git metadata; default true) |
2013
-
2014
- **Returns:**
2015
- ```json
2016
- {
2017
- "overallDebt": 43,
2018
- "grade": "C",
2019
- "categories": {
2020
- "complexity": { "score": 38, "topIssues": [...] },
2021
- "structural": { "score": 61, "topIssues": [...] },
2022
- "maintainability": { "score": 29, "topIssues": [...] },
2023
- "volatility": { "score": 44, "topIssues": [...] }
2024
- },
2025
- "topDebtFiles": [{ "filePath": "...", "score": 87, "reasons": [...] }],
2026
- "actionItems": [{ "priority": "high", "action": "...", "estimatedROI": "..." }]
2027
- }
2028
- ```
2029
-
2030
- Debt score 0–100: higher = more debt. Use periodically for debt reviews, CI gates, and architecture planning.
2031
-
2032
- **Differs from `health_radar`:** Debt scores are inverted (100 = bad); adds a Documentation axis; no per-file breakdown in `health_radar`.
2033
-
2034
- ---
2035
-
2036
- ## 22. AST-Level Search
2037
-
2038
- Tools for searching source code at the structural (AST) level rather than by symbol name or text.
2039
-
2040
- ---
2041
-
2042
- ### `search_ast`
2043
-
2044
- Find every occurrence of a specific tree-sitter AST node type across all indexed files — without reading files manually.
2045
-
2046
- ```json
2047
- {
2048
- "repoId": "...",
2049
- "nodeType": "arrow_function",
2050
- "language": "typescript",
2051
- "filePath": "src/",
2052
- "limit": 50
2053
- }
2054
- ```
2055
-
2056
- | Parameter | Type | Description |
2057
- |-----------|------|-------------|
2058
- | `nodeType` | string | Tree-sitter node type name (exact, case-sensitive) |
2059
- | `language` | string | Restrict to a specific language handler |
2060
- | `filePath` | string | Restrict to a file or directory prefix |
2061
- | `limit` | number | Max results (default 50) |
2062
-
2063
- **Common node types:**
2064
-
2065
- | Language | Node Types |
2066
- |----------|-----------|
2067
- | TypeScript / JS | `arrow_function`, `function_declaration`, `class_declaration`, `interface_declaration`, `try_statement`, `await_expression`, `call_expression`, `import_statement`, `jsx_element`, `template_string`, `throw_statement`, `type_alias_declaration` |
2068
- | Python | `function_definition`, `class_definition`, `for_statement`, `with_statement`, `decorated_definition`, `lambda` |
2069
- | Rust | `function_item`, `struct_item`, `impl_item`, `match_expression`, `closure_expression`, `trait_item` |
2070
- | Go | `function_declaration`, `method_declaration`, `go_statement`, `defer_statement`, `type_declaration`, `interface_type` |
2071
- | Java/Kotlin | `method_declaration`, `class_declaration`, `try_statement`, `lambda_expression`, `annotation` |
2072
-
2073
- **Returns:** `{ matches: [{ filePath, startLine, endLine, text, nodeType }], totalFound, skippedFiles }`
2074
-
2075
- Note: only files backed by a WASM grammar are searched. Regex-only handlers (Terraform, Protobuf, GraphQL, etc.) are silently skipped and reported in `skippedFiles`.
2076
-
2077
- ---
2078
-
2079
- ### `search_by_signature`
2080
-
2081
- Find all symbols whose type signature matches a pattern. Operates on the stored one-line signature string — no AST re-parsing needed.
2082
-
2083
- ```json
2084
- {
2085
- "repoId": "...",
2086
- "pattern": "Promise<void>",
2087
- "mode": "contains",
2088
- "kind": "function",
2089
- "limit": 50
2090
- }
2091
- ```
2092
-
2093
- | Parameter | Type | Description |
2094
- |-----------|------|-------------|
2095
- | `pattern` | string | Pattern to match against the signature |
2096
- | `mode` | string | `"contains"` (default), `"startsWith"`, or `"regex"` |
2097
- | `kind` | string | Filter by symbol kind |
2098
- | `filePath` | string | Restrict to a file or directory prefix |
2099
-
2100
- **Pattern examples:**
2101
- ```
2102
- "Promise<void>" → all functions returning Promise<void>
2103
- "async" → all async functions
2104
- "(req: Request" → all functions accepting a Request parameter
2105
- ": string[]" → all functions returning string[]
2106
- "export async" → all exported async symbols (use startsWith mode)
2107
- ```
2108
-
2109
- **Returns:** `{ matches: [{ ...symbol, signature }], totalFound }`
2110
-
2111
- ---
2112
-
2113
- ### `search_by_decorator`
2114
-
2115
- Find all symbols annotated with a specific decorator. Re-parses stored file content via tree-sitter to locate decorator nodes.
2116
-
2117
- ```json
2118
- {
2119
- "repoId": "...",
2120
- "decoratorName": "Injectable",
2121
- "matchMode": "exact",
2122
- "filePath": "src/services/"
2123
- }
2124
- ```
2125
-
2126
- | Parameter | Type | Description |
2127
- |-----------|------|-------------|
2128
- | `decoratorName` | string | Decorator name without the `@` prefix |
2129
- | `matchMode` | string | `"exact"` (default), `"contains"`, or `"prefix"` |
2130
- | `filePath` | string | Restrict to a file or directory prefix |
2131
-
2132
- **Examples:**
2133
- ```
2134
- decoratorName: "Injectable" → all @Injectable classes
2135
- decoratorName: "Controller" → all @Controller route handlers
2136
- decoratorName: "Column", matchMode: "prefix" → @Column, @ColumnType, etc.
2137
- decoratorName: "test", matchMode: "contains" → anything with "test" in decorator
2138
- ```
2139
-
2140
- **Returns:** `{ matches: [{ ...symbol, decoratorName, decoratorArgs }], totalFound, skippedFiles }`
2141
-
2142
- ---
2143
-
2144
- ### `search_by_complexity`
2145
-
2146
- Find all symbols whose complexity metrics match a set of min/max filters. Covers six dimensions stored at index time.
2147
-
2148
- ```json
2149
- {
2150
- "repoId": "...",
2151
- "minCyclomaticComplexity": 8,
2152
- "minParamCount": 5,
2153
- "kind": "function",
2154
- "limit": 50
2155
- }
2156
- ```
2157
-
2158
- **Available filters** (all optional, combined with AND):
2159
-
2160
- | Filter | Description |
2161
- |--------|-------------|
2162
- | `minCyclomaticComplexity` / `maxCyclomaticComplexity` | Branching complexity |
2163
- | `minCognitiveComplexity` / `maxCognitiveComplexity` | Cognitive load |
2164
- | `minLineCount` / `maxLineCount` | Function body size |
2165
- | `minNestingDepth` / `maxNestingDepth` | Maximum nesting level |
2166
- | `minParamCount` / `maxParamCount` | Number of parameters |
2167
- | `minReturnCount` / `maxReturnCount` | Number of return statements |
2168
-
2169
- **Use cases:**
2170
- ```
2171
- minCyclomaticComplexity: 8 → dangerously complex functions
2172
- minParamCount: 5 → functions with too many arguments
2173
- minLineCount: 100 → long functions to split
2174
- minNestingDepth: 4 → deeply nested, hard-to-read code
2175
- maxCyclomaticComplexity: 2, maxLineCount: 15 → simple utility functions
2176
- ```
2177
-
2178
- **Returns:** `{ matches: [{ ...symbol, metrics: { cyclomaticComplexity, cognitiveComplexity, lineCount, nestingDepth, paramCount, returnCount } }], totalFound }`
2179
-
2180
- ---
2181
-
2182
- ## 23. Code Intelligence Helpers
2183
-
2184
- Higher-level tools that answer specific questions about a codebase without requiring manual navigation.
2185
-
2186
- ---
2187
-
2188
- ### `get_entry_points`
2189
-
2190
- Identify the runnable entry points of a repository: main functions, CLI handlers, HTTP server startups, Lambda/serverless handlers, test suites, and standalone scripts.
2191
-
2192
- ```json
2193
- {
2194
- "repoId": "...",
2195
- "kind": "server_startup",
2196
- "minConfidence": "high",
2197
- "filePath": "src/cmd/"
2198
- }
2199
- ```
2200
-
2201
- | Parameter | Type | Description |
2202
- |-----------|------|-------------|
2203
- | `kind` | string | Filter: `"main_function"`, `"cli_handler"`, `"server_startup"`, `"lambda_handler"`, `"test_suite"`, `"script"` |
2204
- | `filePath` | string | Restrict to a file or directory prefix |
2205
- | `minConfidence` | string | `"high"`, `"medium"`, or `"low"` (default: `"low"` — returns all candidates) |
2206
-
2207
- **Returns:** `{ entryPoints: [{ symbolId, name, kind, filePath, confidence, reason, signature }], totalFound }`
2208
-
2209
- **Use with:**
2210
- - `get_context_bundle` to follow the full dependency chain from an entry point
2211
- - `get_call_hierarchy` for a callee tree rooted at an entry point
2212
- - `find_dead_code` to discover unreachable code relative to entry points
2213
-
2214
- ---
2215
-
2216
- ### `get_public_api`
2217
-
2218
- Return the public API surface of a repository: all exported symbols, grouped by file.
2219
-
2220
- ```json
2221
- {
2222
- "repoId": "...",
2223
- "filePath": "src/",
2224
- "kind": "function",
2225
- "includeMembers": false,
2226
- "groupByFile": true,
2227
- "limit": 200
2228
- }
2229
- ```
2230
-
2231
- | Parameter | Type | Description |
2232
- |-----------|------|-------------|
2233
- | `filePath` | string | Restrict to a file or directory prefix |
2234
- | `kind` | string | Filter by symbol kind |
2235
- | `includeMembers` | boolean | Also include public methods of exported classes (default false) |
2236
- | `groupByFile` | boolean | Group results by file path (default true) |
2237
- | `limit` | number | Max symbols to return |
2238
-
2239
- **Returns:** `{ files: [{ filePath, exports: [{ symbolId, name, kind, signature, summary, isDefault }] }], totalExports }`
2240
-
2241
- A symbol is considered public when its signature begins with the `export` keyword.
2242
-
2243
- **Use with:**
2244
- - `find_dead_code` to find exported symbols that nobody imports
2245
- - `get_blast_radius` before removing an export
2246
-
2247
- ---
2248
-
2249
- ### `get_todos`
2250
-
2251
- Scan all indexed source files for comment tags and return a structured inventory.
2252
-
2253
- ```json
2254
- {
2255
- "repoId": "...",
2256
- "tags": ["TODO", "FIXME"],
2257
- "assignee": "alice",
2258
- "filePath": "src/",
2259
- "groupByFile": true,
2260
- "limit": 100
2261
- }
2262
- ```
2263
-
2264
- | Parameter | Type | Description |
2265
- |-----------|------|-------------|
2266
- | `tags` | array | Tags to scan for (default: all 7 — `TODO`, `FIXME`, `HACK`, `NOTE`, `OPTIMIZE`, `BUG`, `XXX`) |
2267
- | `filePath` | string | Restrict to a file or directory prefix |
2268
- | `assignee` | string | Filter by assignee — matches `TODO(alice):` when `assignee: "alice"` (case-insensitive) |
2269
- | `groupByFile` | boolean | Group results by file (default false) |
2270
- | `limit` | number | Max results to return |
2271
-
2272
- **Returns:** `{ todos: [{ filePath, line, tag, assignee, text }], totalFound, byTag: { TODO: 12, FIXME: 3, ... } }`
2273
-
2274
- ---
2275
-
2276
- ### `get_complexity_hotspots`
2277
-
2278
- Aggregate per-symbol complexity metrics to the file level and return a ranked list of the files with the highest complexity concentration.
2279
-
2280
- ```json
2281
- {
2282
- "repoId": "...",
2283
- "scope": "src/core/",
2284
- "topN": 10,
2285
- "minComplexity": 3
2286
- }
2287
- ```
2288
-
2289
- | Parameter | Type | Description |
2290
- |-----------|------|-------------|
2291
- | `scope` | string | Restrict to a directory prefix |
2292
- | `topN` | number | Number of hotspot files to return (default 10) |
2293
- | `minComplexity` | number | Only count symbols with cyclomatic complexity ≥ this (default 1) |
2294
-
2295
- **Returns:** `{ hotspots: [{ filePath, hotspotScore, avgComplexity, maxComplexity, symbolCount, topOffenders: [{ name, kind, complexity }] }] }`
2296
-
2297
- `hotspotScore` is 0–100 (higher = more complex). Use this to answer "where should I focus refactoring effort?"
2298
-
2299
- **Differs from related tools:**
2300
- - `get_quality_metrics` — per-symbol composite score
2301
- - `search_by_complexity` — threshold/range filter for individual symbols
2302
- - `get_debt_report` — broader tech-debt summary including structural issues
2303
-
2304
- ---
2305
-
2306
- ### `get_type_graph`
2307
-
2308
- Return the type dependency graph for a repository, showing how interfaces, classes, type aliases, and enums relate to each other through inheritance (`extends`), implementation (`implements`), and usage.
2309
-
2310
- ```json
2311
- {
2312
- "repoId": "...",
2313
- "rootSymbol": "UserRepository",
2314
- "maxDepth": 3,
2315
- "scope": "src/domain/",
2316
- "format": "mermaid"
2317
- }
2318
- ```
2319
-
2320
- | Parameter | Type | Description |
2321
- |-----------|------|-------------|
2322
- | `rootSymbol` | string | Name or ID of a type to root the graph at. Omit to return the full graph for the scope. |
2323
- | `maxDepth` | number | Maximum traversal depth from `rootSymbol` (default 3) |
2324
- | `scope` | string | Restrict to a directory prefix |
2325
- | `includeExternal` | boolean | Include types that extend non-indexed base classes (default false) |
2326
- | `format` | string | `"json"` (default) or `"mermaid"` |
2327
-
2328
- **Returns (`json`):** `{ nodes: [{ id, name, kind, filePath }], edges: [{ source, target, relationship }] }` where `relationship` is `"extends"`, `"implements"`, or `"uses"`.
2329
-
2330
- **Returns (`mermaid`):** A `classDiagram` block ready to paste into any Mermaid renderer.
2331
-
2332
- **Differs from related tools:**
2333
- - `get_class_hierarchy` — single-root ancestor/descendant tree for one class
2334
- - `find_implementations` — all concrete implementations of one interface
2335
- - `get_type_graph` — full multi-root graph of all type relationships in a scope
2336
-
2337
- ---
2338
-
2339
- ### `find_untested_symbols`
2340
-
2341
- Identify symbols that do not appear to have test coverage by scanning test files for references to each symbol name. Returns a prioritized list ranked by cyclomatic complexity.
2342
-
2343
- ```json
2344
- {
2345
- "repoId": "...",
2346
- "scope": "src/services/",
2347
- "kinds": ["function", "method"],
2348
- "minComplexity": 2,
2349
- "limit": 50
2350
- }
2351
- ```
2352
-
2353
- | Parameter | Type | Description |
2354
- |-----------|------|-------------|
2355
- | `scope` | string | Restrict to a directory prefix |
2356
- | `kinds` | array | Symbol kinds to check (default: `function`, `method`, `class`, `interface`, `middleware`, `route`) |
2357
- | `minComplexity` | number | Only include symbols with cyclomatic complexity ≥ this (default 1) |
2358
- | `limit` | number | Max symbols to return |
2359
-
2360
- **Returns:** `{ untestedSymbols: [{ symbolId, name, kind, filePath, complexity, priority }], totalUntested, totalChecked }`
2361
-
2362
- Priority: `"high"` (complexity ≥ 5 or ≥ 20 lines), `"medium"` (complexity ≥ 2 or ≥ 8 lines), `"low"` (all others).
2363
-
2364
- **Detection strategy:** Static heuristic — a symbol's name must appear as an identifier in at least one test file. Not a coverage-report parser; use `get_test_coverage_map` for line-level accuracy.
2365
-
2366
- ---
2367
-
2368
- ### `get_test_coverage_map`
2369
-
2370
- Parse a coverage JSON report (Istanbul/NYC or V8/c8 format) and map line-level coverage data to symbols in the indexed codebase.
2371
-
2372
- ```json
2373
- {
2374
- "repoId": "...",
2375
- "coveragePath": "/project/coverage/coverage-final.json",
2376
- "scope": "src/",
2377
- "includeUncoveredOnly": false
2378
- }
2379
- ```
2380
-
2381
- | Parameter | Type | Description |
2382
- |-----------|------|-------------|
2383
- | `coveragePath` | string | Absolute path to the coverage JSON file |
2384
- | `scope` | string | Restrict to a directory prefix |
2385
- | `includeUncoveredOnly` | boolean | Return only uncovered symbols (default false) |
2386
- | `format` | string | Auto-detected: `"istanbul"` or `"v8"` |
2387
-
2388
- **Returns:** `{ files: [{ filePath, statements, functions, branches, lines, symbols: [{ name, kind, covered, callCount }] }], summary: { totalSymbols, coveredSymbols, coveragePercent } }`
2389
-
2390
- **Supported report formats:**
2391
- - **Istanbul/NYC:** `coverage-final.json` produced by `nyc`, `jest --coverage`, `vitest --coverage.reporter=json`, `c8`
2392
- - **V8:** Array of `{ url, functions }` objects produced by `node --experimental-vm-modules` or `c8 --reporter=json`
2393
-
2394
- **Differs from `find_untested_symbols`:** This tool requires a coverage file and delivers line-level accuracy. `find_untested_symbols` uses name-based heuristics and needs no coverage file.
2395
-
2396
- ---
2397
-
2398
- ## Quick Reference Card
2399
-
2400
- ```
2401
- # Install
2402
- npm install -g .
2403
-
2404
- # Connect to Claude Code
2405
- claude mcp add purecontext-mcp purecontext-mcp
2406
-
2407
- # Generate config
2408
- purecontext-mcp config --init
2409
-
2410
- # Start HTTP server with Web UI
2411
- purecontext-mcp --transport http --port 3000
2412
-
2413
- # In Claude Code — core navigation
2414
- index_folder → index a project
2415
- search_symbols → find code by name or kind
2416
- get_file_outline → see all symbols in a file
2417
- get_symbol_source → retrieve a symbol's source
2418
- get_context_bundle → symbol + what it depends on
2419
- get_blast_radius → symbol + what depends on it
2420
- search_text → grep-style text search
2421
- search_semantic → meaning-based search
2422
- find_dead_code → unused exports
2423
- get_layer_violations → architecture rule checking
2424
- get_savings_stats → view token savings
2425
-
2426
- # Advanced relationship analysis (Phase 28)
2427
- find_implementations → all classes implementing an interface
2428
- get_call_hierarchy → callers/callees tree, N levels deep
2429
- get_class_hierarchy → full inheritance chain (up and down)
2430
- find_cycles → all import cycles with file paths
2431
- get_coupling_map → per-file coupling scores (Martin's instability)
2432
-
2433
- # Architectural visualization (Phase 29)
2434
- render_diagram → Mermaid/DOT: import graph, call graph, class diagram
2435
- render_call_graph → call graph rooted at a symbol
2436
- render_import_graph → file-level import graph for a directory
2437
- render_class_hierarchy → class inheritance diagram
2438
- render_dep_matrix → dependency matrix heatmap (ASCII or Mermaid)
2439
- get_architecture_snapshot → snapshot + diff of architecture state over time
2440
-
2441
- # Refactoring safety checks (Phase 30)
2442
- check_rename_safe → pre-flight: rename a symbol everywhere
2443
- check_delete_safe → pre-flight: delete a symbol or file
2444
- check_move_safe → pre-flight: move a file to a new path
2445
- plan_refactoring → sequenced, risk-annotated refactoring plan
2446
-
2447
- # Health dashboards & debt reporting (Phase 31)
2448
- health_radar → 5-axis health score (0–100) with letter grade
2449
- diff_health_radar → compare health between two repo states (PR review)
2450
- get_debt_report → comprehensive debt report with action items
2451
-
2452
- # AST-level search (Phase 32)
2453
- search_ast → find any tree-sitter node type across all files
2454
- search_by_signature → find symbols by type signature pattern
2455
- search_by_decorator → find all symbols with a specific decorator
2456
- search_by_complexity → find symbols matching complexity thresholds
2457
-
2458
- # Code intelligence helpers (Phase 33)
2459
- get_entry_points → find main functions, CLI handlers, Lambda, server startups
2460
- get_public_api → all exported symbols grouped by file
2461
- get_todos → TODO/FIXME/HACK/BUG inventory from comment tags
2462
- get_complexity_hotspots → file-level complexity ranking for refactoring focus
2463
- get_type_graph → full type/interface dependency graph (Mermaid or JSON)
2464
- find_untested_symbols → symbols with no test coverage, ranked by complexity
2465
- get_test_coverage_map → map Istanbul/V8 coverage JSON to indexed symbols
2466
- ```