purecontext-mcp 1.5.2 → 1.11.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 (196) hide show
  1. package/AGENT_INSTRUCTIONS.md +18 -10
  2. package/AGENT_REFERENCE.md +684 -561
  3. package/CHANGELOG.md +567 -445
  4. package/CODE-HISTORY.md +29 -1
  5. package/FRAMEWORK-ADAPTERS.md +368 -351
  6. package/FULL-INSTALLATION-GUIDE.md +351 -341
  7. package/README.md +411 -339
  8. package/REFACTORING-SAFELY.md +338 -279
  9. package/SAFE-CHANGES.md +208 -156
  10. package/USER-GUIDE.md +3 -1
  11. package/WHY-PURECONTEXT.md +103 -73
  12. package/WORKFLOW-PR-REVIEW.md +245 -199
  13. package/dist/adapters/astro-preprocessor.d.ts +25 -0
  14. package/dist/adapters/astro-preprocessor.d.ts.map +1 -0
  15. package/dist/adapters/astro-preprocessor.js +50 -0
  16. package/dist/adapters/astro-preprocessor.js.map +1 -0
  17. package/dist/adapters/astro.d.ts +13 -0
  18. package/dist/adapters/astro.d.ts.map +1 -0
  19. package/dist/adapters/astro.js +83 -0
  20. package/dist/adapters/astro.js.map +1 -0
  21. package/dist/adapters/detect-utils.d.ts +38 -0
  22. package/dist/adapters/detect-utils.d.ts.map +1 -0
  23. package/dist/adapters/detect-utils.js +95 -0
  24. package/dist/adapters/detect-utils.js.map +1 -0
  25. package/dist/adapters/nuxt.d.ts +20 -0
  26. package/dist/adapters/nuxt.d.ts.map +1 -1
  27. package/dist/adapters/nuxt.js +128 -13
  28. package/dist/adapters/nuxt.js.map +1 -1
  29. package/dist/adapters/svelte-preprocessor.d.ts +29 -0
  30. package/dist/adapters/svelte-preprocessor.d.ts.map +1 -0
  31. package/dist/adapters/svelte-preprocessor.js +83 -0
  32. package/dist/adapters/svelte-preprocessor.js.map +1 -0
  33. package/dist/adapters/svelte.d.ts +13 -0
  34. package/dist/adapters/svelte.d.ts.map +1 -0
  35. package/dist/adapters/svelte.js +96 -0
  36. package/dist/adapters/svelte.js.map +1 -0
  37. package/dist/adapters/vue.d.ts.map +1 -1
  38. package/dist/adapters/vue.js +87 -20
  39. package/dist/adapters/vue.js.map +1 -1
  40. package/dist/bin.d.ts +16 -0
  41. package/dist/bin.d.ts.map +1 -0
  42. package/dist/bin.js +21 -0
  43. package/dist/bin.js.map +1 -0
  44. package/dist/cli/hooks.d.ts +2 -2
  45. package/dist/cli/hooks.d.ts.map +1 -1
  46. package/dist/cli/hooks.js +123 -135
  47. package/dist/cli/hooks.js.map +1 -1
  48. package/dist/cli/install-writers.d.ts.map +1 -1
  49. package/dist/cli/install-writers.js +281 -36
  50. package/dist/cli/install-writers.js.map +1 -1
  51. package/dist/cli/resolve-node.d.ts +53 -0
  52. package/dist/cli/resolve-node.d.ts.map +1 -0
  53. package/dist/cli/resolve-node.js +84 -0
  54. package/dist/cli/resolve-node.js.map +1 -0
  55. package/dist/config/config-loader.js +24 -0
  56. package/dist/config/config-loader.js.map +1 -1
  57. package/dist/config/config-schema.d.ts +71 -0
  58. package/dist/config/config-schema.d.ts.map +1 -1
  59. package/dist/config/config-schema.js +102 -0
  60. package/dist/config/config-schema.js.map +1 -1
  61. package/dist/core/db/api-keys.d.ts +1 -1
  62. package/dist/core/db/api-keys.d.ts.map +1 -1
  63. package/dist/core/db/api-keys.js +39 -39
  64. package/dist/core/db/api-keys.js.map +1 -1
  65. package/dist/core/db/co-change-store.d.ts +34 -0
  66. package/dist/core/db/co-change-store.d.ts.map +1 -0
  67. package/dist/core/db/co-change-store.js +78 -0
  68. package/dist/core/db/co-change-store.js.map +1 -0
  69. package/dist/core/db/schema.d.ts +3 -3
  70. package/dist/core/db/schema.d.ts.map +1 -1
  71. package/dist/core/db/schema.js +12 -30
  72. package/dist/core/db/schema.js.map +1 -1
  73. package/dist/core/db/sqlite-loader.d.ts +51 -0
  74. package/dist/core/db/sqlite-loader.d.ts.map +1 -0
  75. package/dist/core/db/sqlite-loader.js +94 -0
  76. package/dist/core/db/sqlite-loader.js.map +1 -0
  77. package/dist/core/db/wasm-sqlite.d.ts +4 -0
  78. package/dist/core/db/wasm-sqlite.d.ts.map +1 -0
  79. package/dist/core/db/wasm-sqlite.js +270 -0
  80. package/dist/core/db/wasm-sqlite.js.map +1 -0
  81. package/dist/core/diff-parser.d.ts.map +1 -1
  82. package/dist/core/diff-parser.js +6 -1
  83. package/dist/core/diff-parser.js.map +1 -1
  84. package/dist/core/git-log-reader.d.ts +28 -0
  85. package/dist/core/git-log-reader.d.ts.map +1 -1
  86. package/dist/core/git-log-reader.js +74 -3
  87. package/dist/core/git-log-reader.js.map +1 -1
  88. package/dist/core/index-manager.d.ts.map +1 -1
  89. package/dist/core/index-manager.js +29 -3
  90. package/dist/core/index-manager.js.map +1 -1
  91. package/dist/core/indexing-worker.d.ts +2 -0
  92. package/dist/core/indexing-worker.d.ts.map +1 -1
  93. package/dist/core/indexing-worker.js +2 -0
  94. package/dist/core/indexing-worker.js.map +1 -1
  95. package/dist/core/watcher/file-watcher.d.ts +6 -0
  96. package/dist/core/watcher/file-watcher.d.ts.map +1 -1
  97. package/dist/core/watcher/file-watcher.js +11 -1
  98. package/dist/core/watcher/file-watcher.js.map +1 -1
  99. package/dist/graph/path-resolver.js +86 -17
  100. package/dist/graph/path-resolver.js.map +1 -1
  101. package/dist/index.d.ts +3 -0
  102. package/dist/index.d.ts.map +1 -1
  103. package/dist/index.js +11 -1
  104. package/dist/index.js.map +1 -1
  105. package/dist/node-guard.d.ts +15 -0
  106. package/dist/node-guard.d.ts.map +1 -0
  107. package/dist/node-guard.js +33 -0
  108. package/dist/node-guard.js.map +1 -0
  109. package/dist/server/admin-api.d.ts +1 -1
  110. package/dist/server/admin-api.d.ts.map +1 -1
  111. package/dist/server/admin-api.js +2 -2
  112. package/dist/server/admin-api.js.map +1 -1
  113. package/dist/server/auth/api-key.d.ts +1 -1
  114. package/dist/server/auth/api-key.d.ts.map +1 -1
  115. package/dist/server/mcp-server.d.ts.map +1 -1
  116. package/dist/server/mcp-server.js +25 -0
  117. package/dist/server/mcp-server.js.map +1 -1
  118. package/dist/server/tools/analyze-diff.d.ts +8 -0
  119. package/dist/server/tools/analyze-diff.d.ts.map +1 -1
  120. package/dist/server/tools/analyze-diff.js +80 -16
  121. package/dist/server/tools/analyze-diff.js.map +1 -1
  122. package/dist/server/tools/change-synthesis.d.ts +90 -0
  123. package/dist/server/tools/change-synthesis.d.ts.map +1 -0
  124. package/dist/server/tools/change-synthesis.js +236 -0
  125. package/dist/server/tools/change-synthesis.js.map +1 -0
  126. package/dist/server/tools/co-change.d.ts +65 -0
  127. package/dist/server/tools/co-change.d.ts.map +1 -0
  128. package/dist/server/tools/co-change.js +146 -0
  129. package/dist/server/tools/co-change.js.map +1 -0
  130. package/dist/server/tools/compare-change-impact.d.ts +58 -0
  131. package/dist/server/tools/compare-change-impact.d.ts.map +1 -0
  132. package/dist/server/tools/compare-change-impact.js +0 -0
  133. package/dist/server/tools/compare-change-impact.js.map +1 -0
  134. package/dist/server/tools/find-refactoring-opportunities.d.ts +1 -1
  135. package/dist/server/tools/get-architecture-snapshot.d.ts.map +1 -1
  136. package/dist/server/tools/get-architecture-snapshot.js +28 -14
  137. package/dist/server/tools/get-architecture-snapshot.js.map +1 -1
  138. package/dist/server/tools/get-churn-metrics.d.ts.map +1 -1
  139. package/dist/server/tools/get-churn-metrics.js +1 -12
  140. package/dist/server/tools/get-churn-metrics.js.map +1 -1
  141. package/dist/server/tools/get-co-change.d.ts +37 -0
  142. package/dist/server/tools/get-co-change.d.ts.map +1 -0
  143. package/dist/server/tools/get-co-change.js +120 -0
  144. package/dist/server/tools/get-co-change.js.map +1 -0
  145. package/dist/server/tools/get-context-bundle.d.ts.map +1 -1
  146. package/dist/server/tools/get-context-bundle.js +56 -3
  147. package/dist/server/tools/get-context-bundle.js.map +1 -1
  148. package/dist/server/tools/get-entry-points.d.ts +1 -1
  149. package/dist/server/tools/get-symbol-risk.d.ts +25 -0
  150. package/dist/server/tools/get-symbol-risk.d.ts.map +1 -0
  151. package/dist/server/tools/get-symbol-risk.js +60 -0
  152. package/dist/server/tools/get-symbol-risk.js.map +1 -0
  153. package/dist/server/tools/get-symbol-source.d.ts +2 -0
  154. package/dist/server/tools/get-symbol-source.d.ts.map +1 -1
  155. package/dist/server/tools/get-symbol-source.js +18 -1
  156. package/dist/server/tools/get-symbol-source.js.map +1 -1
  157. package/dist/server/tools/index-repo.d.ts.map +1 -1
  158. package/dist/server/tools/index-repo.js +8 -2
  159. package/dist/server/tools/index-repo.js.map +1 -1
  160. package/dist/server/tools/prepare-change.d.ts +61 -0
  161. package/dist/server/tools/prepare-change.d.ts.map +1 -0
  162. package/dist/server/tools/prepare-change.js +262 -0
  163. package/dist/server/tools/prepare-change.js.map +1 -0
  164. package/dist/server/tools/search-symbols.d.ts +2 -0
  165. package/dist/server/tools/search-symbols.d.ts.map +1 -1
  166. package/dist/server/tools/search-symbols.js +33 -0
  167. package/dist/server/tools/search-symbols.js.map +1 -1
  168. package/dist/server/tools/symbol-lines.d.ts +25 -0
  169. package/dist/server/tools/symbol-lines.d.ts.map +1 -0
  170. package/dist/server/tools/symbol-lines.js +40 -0
  171. package/dist/server/tools/symbol-lines.js.map +1 -0
  172. package/dist/server/tools/symbol-risk.d.ts +109 -0
  173. package/dist/server/tools/symbol-risk.d.ts.map +1 -0
  174. package/dist/server/tools/symbol-risk.js +251 -0
  175. package/dist/server/tools/symbol-risk.js.map +1 -0
  176. package/dist/server/tools/verify-change.d.ts +40 -0
  177. package/dist/server/tools/verify-change.d.ts.map +1 -0
  178. package/dist/server/tools/verify-change.js +149 -0
  179. package/dist/server/tools/verify-change.js.map +1 -0
  180. package/dist/version.d.ts +1 -1
  181. package/dist/version.d.ts.map +1 -1
  182. package/dist/version.js +1 -1
  183. package/dist/version.js.map +1 -1
  184. package/docs/01-introduction.md +2 -2
  185. package/docs/02-installation.md +97 -89
  186. package/docs/03-quick-start.md +138 -135
  187. package/docs/04-configuration.md +247 -214
  188. package/docs/05-cli-reference.md +236 -219
  189. package/docs/06-tools-reference.md +902 -499
  190. package/docs/14-transport-modes.md +170 -167
  191. package/docs/18-git-history.md +43 -0
  192. package/docs/23-performance.md +123 -121
  193. package/docs/26-troubleshooting.md +249 -234
  194. package/grammars/README.md +88 -0
  195. package/package.json +7 -25
  196. package/AGENT_INSTRUCTIONS_SHORT.md +0 -150
@@ -1,499 +1,902 @@
1
- # MCP Tools Reference
2
-
3
-
4
- All tools return JSON. Most responses include a `_tokenEstimate` field so agents can gauge context size before loading full source. Every retrieval tool also includes a `_meta` envelope with timing and token savings.
5
-
6
- ```json
7
- "_meta": {
8
- "timing_ms": 3,
9
- "tokens_saved": 1842,
10
- "total_tokens_saved": 45231,
11
- "cost_avoided": { "claude_opus_4": 0.028 },
12
- "powered_by": "PureContext MCP"
13
- }
14
- ```
15
-
16
- ---
17
-
18
- ## Indexing
19
-
20
- ### `index_folder`
21
-
22
- Index a local project directory.
23
-
24
- **Parameters:**
25
-
26
- | Parameter | Type | Required | Description |
27
- |-----------|------|----------|-------------|
28
- | `path` | `string` | yes | Absolute path to the project root |
29
- | `fileLimit` | `number` | no | Override config `fileLimit` for this run |
30
- | `force` | `boolean` | no | Re-index even unchanged files (default: `false`) |
31
-
32
- **Returns:** `{ repoId, filesIndexed, symbolsExtracted, durationMs, languages, adapters }`
33
-
34
- Subsequent calls are incremental — only changed files (by content hash) are re-parsed. The file watcher also triggers incremental re-indexing automatically on file changes.
35
-
36
- ---
37
-
38
- ### `index_repo`
39
-
40
- Clone and index a remote Git repository.
41
-
42
- **Parameters:**
43
-
44
- | Parameter | Type | Required | Description |
45
- |-----------|------|----------|-------------|
46
- | `url` | `string` | yes | Repository URL (`https://`, `http://`, or `git@`) |
47
- | `branch` | `string` | no | Branch to clone (default: default branch) |
48
- | `token` | `string` | no | Personal access token for private repos |
49
- | `fileLimit` | `number` | no | Max files to index |
50
-
51
- **Returns:** Same as `index_folder`. Clones are stored at `~/.purecontext/clones/`.
52
-
53
- ---
54
-
55
- ### `resolve_repo`
56
-
57
- Resolve a local path to its `repoId` and check if it is indexed.
58
-
59
- **Parameters:** `{ path: string }`
60
-
61
- **Returns:** `{ repoId, indexed, lastIndexed, filesIndexed, symbolCount }`
62
-
63
- ---
64
-
65
- ### `list_repos`
66
-
67
- List all indexed repositories.
68
-
69
- **Parameters:** `{}`
70
-
71
- **Returns:** `{ repos: [{ repoId, path, filesIndexed, lastIndexed, languages }] }`
72
-
73
- ---
74
-
75
- ### `invalidate_cache`
76
-
77
- Force a full re-index of a repo or a single file, clearing all content hashes.
78
-
79
- **Parameters:**
80
-
81
- | Parameter | Type | Required | Description |
82
- |-----------|------|----------|-------------|
83
- | `repoId` | `string` | yes | Repository to invalidate |
84
- | `filePath` | `string` | no | If given, invalidate only this file (relative path) |
85
-
86
- **Returns:** `{ invalidated: number }` — number of files whose cache was cleared.
87
-
88
- ---
89
-
90
- ## Symbol Search & Retrieval
91
-
92
- ### `search_symbols`
93
-
94
- Search symbols by name fragment. The primary navigation tool.
95
-
96
- **Parameters:**
97
-
98
- | Parameter | Type | Required | Description |
99
- |-----------|------|----------|-------------|
100
- | `repoId` | `string` | yes | Target repository |
101
- | `query` | `string` | yes | Name fragment or FTS5 query |
102
- | `kind` | `string` | no | Filter by symbol kind (see [Symbol Kinds](#symbol-kinds)) |
103
- | `filePath` | `string` | no | Filter to a specific file |
104
- | `limit` | `number` | no | Max results (default: 20) |
105
- | `mode` | `string` | no | `"keyword"` (default), `"semantic"`, or `"hybrid"` |
106
- | `debug` | `boolean` | no | Include relevance scoring breakdown in response |
107
-
108
- **Returns:** `{ symbols: SymbolSummary[], _tokenEstimate }`
109
-
110
- Does **not** return source code — use `get_symbol_source` for that.
111
-
112
- ---
113
-
114
- ### `search_text`
115
-
116
- Full-text search across cached file content (grep-like).
117
-
118
- **Parameters:**
119
-
120
- | Parameter | Type | Required | Description |
121
- |-----------|------|----------|-------------|
122
- | `repoId` | `string` | yes | Target repository |
123
- | `query` | `string` | yes | Search term or regex |
124
- | `is_regex` | `boolean` | no | Treat query as a regular expression (default: `false`) |
125
- | `file_pattern` | `string` | no | Glob pattern to restrict to specific files |
126
- | `context_lines` | `number` | no | Lines of context around each match (default: 2) |
127
- | `max_results` | `number` | no | Max matches (default: 50) |
128
- | `debug` | `boolean` | no | Include relevance scoring breakdown |
129
-
130
- **Returns:** `{ matches: [{ file, line, column, match, context }], truncated }`
131
-
132
- ---
133
-
134
- ### `search_semantic`
135
-
136
- Semantic (meaning-based) search using HNSW vector index.
137
-
138
- **Parameters:**
139
-
140
- | Parameter | Type | Required | Description |
141
- |-----------|------|----------|-------------|
142
- | `repoId` | `string` | yes | Target repository |
143
- | `query` | `string` | yes | Natural language description |
144
- | `mode` | `string` | no | `"semantic"` (default) or `"hybrid"` |
145
- | `semantic_weight` | `number` | no | Weight for semantic score in hybrid mode (default: 0.6) |
146
- | `keyword_weight` | `number` | no | Weight for keyword score in hybrid mode (default: 0.4) |
147
- | `max_results` | `number` | no | Max results (default: 10) |
148
- | `kind` | `string` | no | Filter by symbol kind |
149
-
150
- **Returns:** `{ results: [{ ...symbol, scores: { keyword, semantic, combined } }] }`
151
-
152
- Requires semantic search enabled and an embedding provider configured. Falls back to FTS5 when no HNSW index exists.
153
-
154
- ---
155
-
156
- ### `get_symbol_source`
157
-
158
- Retrieve the raw source code of a symbol.
159
-
160
- **Parameters:**
161
-
162
- | Parameter | Type | Required | Description |
163
- |-----------|------|----------|-------------|
164
- | `repoId` | `string` | yes | Target repository |
165
- | `symbolId` | `string` | yes | Symbol ID from `search_symbols` |
166
- | `context_lines` | `number` | no | Extra lines of context above/below (default: 0) |
167
- | `verify` | `boolean` | no | Re-read file from disk to verify source hasn't changed |
168
-
169
- **Returns:** `{ source, filePath, startByte, endByte, startLine, endLine, _tokenEstimate }`
170
-
171
- ---
172
-
173
- ### `get_symbols`
174
-
175
- Batch-fetch multiple symbols by ID.
176
-
177
- **Parameters:**
178
-
179
- | Parameter | Type | Required | Description |
180
- |-----------|------|----------|-------------|
181
- | `repoId` | `string` | yes | Target repository |
182
- | `symbolIds` | `string[]` | yes | Array of symbol IDs |
183
-
184
- **Returns:** `{ symbols: [{ ...symbolSummary, source }] }`
185
-
186
- ---
187
-
188
- ### `get_file_content`
189
-
190
- Retrieve raw cached file content, with optional line range.
191
-
192
- **Parameters:**
193
-
194
- | Parameter | Type | Required | Description |
195
- |-----------|------|----------|-------------|
196
- | `repoId` | `string` | yes | Target repository |
197
- | `filePath` | `string` | yes | Relative file path |
198
- | `startLine` | `number` | no | Start line (1-based, default: 1) |
199
- | `endLine` | `number` | no | End line (inclusive, default: end of file) |
200
-
201
- **Returns:** `{ content, filePath, startLine, endLine, totalLines, _tokenEstimate }`
202
-
203
- ---
204
-
205
- ### `get_file_outline`
206
-
207
- All symbols in a file with signatures and summaries.
208
-
209
- **Parameters:** `{ repoId, filePath }`
210
-
211
- **Returns:** `{ filePath, symbols: SymbolSummary[], _tokenEstimate }`
212
-
213
- ---
214
-
215
- ### `get_repo_outline`
216
-
217
- All files with their top-level symbols — a project map.
218
-
219
- **Parameters:** `{ repoId, limit? }` (default limit: 100 files)
220
-
221
- **Returns:** `{ files: [{ filePath, symbols: SymbolSummary[] }], _tokenEstimate }`
222
-
223
- ---
224
-
225
- ### `get_file_tree`
226
-
227
- Directory tree with file counts per directory.
228
-
229
- **Parameters:** `{ repoId, maxDepth? }` (default maxDepth: 5)
230
-
231
- **Returns:** Nested `{ name, type: 'dir'|'file', children?, symbolCount? }`
232
-
233
- ---
234
-
235
- ### `find_references`
236
-
237
- Find all usage sites (call sites, references) for a symbol across the repo.
238
-
239
- **Parameters:**
240
-
241
- | Parameter | Type | Required | Description |
242
- |-----------|------|----------|-------------|
243
- | `repoId` | `string` | yes | Target repository |
244
- | `symbolId` | `string` | yes | Symbol to find references for |
245
- | `limit` | `number` | no | Max results (default: 50) |
246
-
247
- **Returns:** `{ references: [{ filePath, line, column, snippet }], count }`
248
-
249
- ---
250
-
251
- ## Dependency Graph
252
-
253
- ### `get_context_bundle`
254
-
255
- Forward-walk from a symbol — returns everything needed to understand it (transitive imports).
256
-
257
- **Parameters:**
258
-
259
- | Parameter | Type | Required | Description |
260
- |-----------|------|----------|-------------|
261
- | `repoId` | `string` | yes | Target repository |
262
- | `symbolId` | `string` | yes | Starting symbol |
263
- | `maxDepth` | `number` | no | Max traversal depth (default: 3) |
264
- | `maxTokens` | `number` | no | Stop collecting when estimate exceeds this |
265
-
266
- **Returns:** `{ symbols: SymbolSummary[], files: string[], _tokenEstimate }`
267
-
268
- ---
269
-
270
- ### `get_blast_radius`
271
-
272
- Reverse-walk — all files that (transitively) import a symbol. Use before modifying or deleting a symbol.
273
-
274
- **Parameters:**
275
-
276
- | Parameter | Type | Required | Description |
277
- |-----------|------|----------|-------------|
278
- | `repoId` | `string` | yes | Target repository |
279
- | `symbolId` | `string` | yes | Starting symbol |
280
- | `maxDepth` | `number` | no | Max traversal depth (default: 5) |
281
-
282
- **Returns:** `{ importers: string[], count, _tokenEstimate }`
283
-
284
- ---
285
-
286
- ### `find_importers`
287
-
288
- Direct (one-hop) importers of a file.
289
-
290
- **Parameters:** `{ repoId, filePath }`
291
-
292
- **Returns:** `{ importers: [{ filePath, importedNames: string[] }], _tokenEstimate }`
293
-
294
- ---
295
-
296
- ### `find_dead_code`
297
-
298
- Exported symbols in files that nothing else imports.
299
-
300
- **Parameters:**
301
-
302
- | Parameter | Type | Required | Description |
303
- |-----------|------|----------|-------------|
304
- | `repoId` | `string` | yes | Target repository |
305
- | `limit` | `number` | no | Max results (default: 50) |
306
-
307
- **Returns:** `{ symbols: SymbolSummary[], _tokenEstimate }`
308
-
309
- **Note:** May produce false positives for: dynamic imports, side-effect imports, symbols used by external packages (npm consumers).
310
-
311
- ---
312
-
313
- ### `get_layer_violations`
314
-
315
- Detect architectural import boundary violations.
316
-
317
- **Parameters:**
318
-
319
- | Parameter | Type | Required | Description |
320
- |-----------|------|----------|-------------|
321
- | `repoId` | `string` | yes | Target repository |
322
- | `layers` | `LayerDef[]` | no | Layer definitions (reads from config if omitted) |
323
-
324
- **Returns:** `{ violations: [{ from_layer, to_layer, from_file, to_file, import_spec }], summary }`
325
-
326
- ---
327
-
328
- ## Token Savings
329
-
330
- ### `get_savings_stats`
331
-
332
- View cumulative token savings across all PureContext tool calls.
333
-
334
- **Parameters:** `{ reset?: boolean }` — set `reset: true` to clear counters.
335
-
336
- **Returns:**
337
-
338
- ```json
339
- {
340
- "total_tokens_saved": 1234567,
341
- "equivalent_context_windows": {
342
- "claude_200k": 6.17,
343
- "gpt4_128k": 9.64
344
- },
345
- "total_cost_avoided": {
346
- "claude_opus_4": 18.52,
347
- "claude_sonnet_4": 3.70,
348
- "claude_haiku_4": 0.99,
349
- "gpt4o": 3.09,
350
- "gpt4o_mini": 0.19
351
- }
352
- }
353
- ```
354
-
355
- ---
356
-
357
- ## Cross-Repo Tools
358
-
359
- ### `search_cross_repo`
360
-
361
- Search symbols across multiple indexed repositories simultaneously.
362
-
363
- **Parameters:**
364
-
365
- | Parameter | Type | Required | Description |
366
- |-----------|------|----------|-------------|
367
- | `query` | `string` | yes | Name fragment |
368
- | `repoIds` | `string[]` | no | Repos to search (default: all in workspace) |
369
- | `kind` | `string` | no | Symbol kind filter |
370
- | `limit` | `number` | no | Max results (default: 20) |
371
-
372
- **Returns:** `{ symbols: [{ ...symbolSummary, repoId }] }`
373
-
374
- ---
375
-
376
- ### `find_similar`
377
-
378
- Find semantically similar code across repos.
379
-
380
- **Parameters:**
381
-
382
- | Parameter | Type | Required | Description |
383
- |-----------|------|----------|-------------|
384
- | `symbolId` | `string` | yes | Reference symbol |
385
- | `repoId` | `string` | yes | Repo of the reference symbol |
386
- | `searchRepoIds` | `string[]` | no | Repos to search (default: all) |
387
- | `minSimilarity` | `number` | no | Minimum cosine similarity 0–1 (default: 0.8) |
388
- | `limit` | `number` | no | Max results (default: 10) |
389
-
390
- **Returns:** `{ similar: [{ ...symbolSummary, repoId, similarity }] }`
391
-
392
- Requires semantic search enabled.
393
-
394
- ---
395
-
396
- ## Git & History Tools
397
-
398
- ### `get_symbol_history`
399
-
400
- Symbol-level git commit history.
401
-
402
- **Parameters:**
403
-
404
- | Parameter | Type | Required | Description |
405
- |-----------|------|----------|-------------|
406
- | `repoId` | `string` | yes | Target repository |
407
- | `symbolId` | `string` | yes | Symbol to get history for |
408
- | `limit` | `number` | no | Max commits (default: 20) |
409
-
410
- **Returns:** `{ history: [{ hash, author, date, message, diff }] }`
411
-
412
- ---
413
-
414
- ### `get_churn_metrics`
415
-
416
- File or symbol churn metrics.
417
-
418
- **Parameters:**
419
-
420
- | Parameter | Type | Required | Description |
421
- |-----------|------|----------|-------------|
422
- | `repoId` | `string` | yes | Target repository |
423
- | `filePath` | `string` | no | Scope to a single file |
424
- | `since` | `string` | no | ISO 8601 date — look back from this date |
425
-
426
- **Returns:** `{ files: [{ filePath, commits, linesChanged, authors, churnScore }] }`
427
-
428
- ---
429
-
430
- ## Architecture Analysis Tools
431
-
432
- ### `get_quality_metrics`
433
-
434
- Per-file and per-symbol quality scores.
435
-
436
- **Parameters:** `{ repoId, filePath? }`
437
-
438
- **Returns:** `{ files: [{ filePath, complexity, coupling, cohesion, docCoverage, score }] }`
439
-
440
- ---
441
-
442
- ### `detect_antipatterns`
443
-
444
- Detect common architectural anti-patterns.
445
-
446
- **Parameters:** `{ repoId, patterns?: string[] }` omit `patterns` for all checks.
447
-
448
- **Returns:** `{ issues: [{ pattern, filePath, symbolId, severity, description }] }`
449
-
450
- ---
451
-
452
- ### `get_architecture_doc`
453
-
454
- Auto-generate an architecture summary.
455
-
456
- **Parameters:** `{ repoId, format?: 'markdown' | 'mermaid' }` (default: `'markdown'`)
457
-
458
- **Returns:** `{ doc: string }`
459
-
460
- ---
461
-
462
- ## Ecosystem & Data Tools
463
-
464
- ### `search_columns`
465
-
466
- Search dbt/SQL column definitions.
467
-
468
- **Parameters:** `{ repoId, query, modelName? }`
469
-
470
- **Returns:** `{ columns: [{ name, model, dataType, description, lineage }] }`
471
-
472
- ---
473
-
474
- ## Symbol Kinds
475
-
476
- The `kind` parameter accepts any of:
477
-
478
- | Kind | Description |
479
- |------|-------------|
480
- | `function` | Standalone function / top-level def |
481
- | `class` | Class, struct (Go/Rust), or OOP type |
482
- | `method` | Method inside a class/struct/impl |
483
- | `const` | Constant, exported variable, field |
484
- | `type` | Type alias, typedef, newtype |
485
- | `interface` | Interface or protocol |
486
- | `enum` | Enumeration |
487
- | `component` | UI component (Vue, React, Angular) |
488
- | `composable` | Vue composable (`useXxx`) |
489
- | `hook` | React hook (`useXxx`) |
490
- | `route` | HTTP route (any framework) |
491
- | `middleware` | Middleware or guard |
492
- | `decorator` | Decorator / annotation |
493
- | `model` | ORM model |
494
- | `view` | Request handler / controller action |
495
- | `struct` | C/C++ struct |
496
- | `macro` | C/C++ `#define` macro |
497
- | `signal` | Django signal receiver |
498
- | `namespace` | C++ namespace |
499
- | `widget` | Flutter widget |
1
+ # MCP Tools Reference
2
+
3
+
4
+ All tools return JSON. Most responses include a `_tokenEstimate` field so agents can gauge context size before loading full source. Every retrieval tool also includes a `_meta` envelope with timing and token savings.
5
+
6
+ ```json
7
+ "_meta": {
8
+ "timing_ms": 3,
9
+ "tokens_saved": 1842,
10
+ "total_tokens_saved": 45231,
11
+ "cost_avoided": { "claude_opus_4": 0.028 },
12
+ "powered_by": "PureContext MCP"
13
+ }
14
+ ```
15
+
16
+ ---
17
+
18
+ ## Indexing
19
+
20
+ ### `index_folder`
21
+
22
+ Index a local project directory.
23
+
24
+ **Parameters:**
25
+
26
+ | Parameter | Type | Required | Description |
27
+ |-----------|------|----------|-------------|
28
+ | `path` | `string` | yes | Absolute path to the project root |
29
+ | `fileLimit` | `number` | no | Override config `fileLimit` for this run |
30
+ | `force` | `boolean` | no | Re-index even unchanged files (default: `false`) |
31
+
32
+ **Returns:** `{ repoId, filesIndexed, symbolsExtracted, durationMs, languages, adapters }`
33
+
34
+ Subsequent calls are incremental — only changed files (by content hash) are re-parsed. The file watcher also triggers incremental re-indexing automatically on file changes.
35
+
36
+ ---
37
+
38
+ ### `index_repo`
39
+
40
+ Clone and index a remote Git repository.
41
+
42
+ **Parameters:**
43
+
44
+ | Parameter | Type | Required | Description |
45
+ |-----------|------|----------|-------------|
46
+ | `url` | `string` | yes | Repository URL (`https://`, `http://`, or `git@`) |
47
+ | `branch` | `string` | no | Branch to clone (default: default branch) |
48
+ | `token` | `string` | no | Personal access token for private repos |
49
+ | `fileLimit` | `number` | no | Max files to index |
50
+
51
+ **Returns:** Same as `index_folder`. Clones are stored at `~/.purecontext/clones/`.
52
+
53
+ ---
54
+
55
+ ### `resolve_repo`
56
+
57
+ Resolve a local path to its `repoId` and check if it is indexed.
58
+
59
+ **Parameters:** `{ path: string }`
60
+
61
+ **Returns:** `{ repoId, indexed, lastIndexed, filesIndexed, symbolCount }`
62
+
63
+ ---
64
+
65
+ ### `list_repos`
66
+
67
+ List all indexed repositories.
68
+
69
+ **Parameters:** `{}`
70
+
71
+ **Returns:** `{ repos: [{ repoId, path, filesIndexed, lastIndexed, languages }] }`
72
+
73
+ ---
74
+
75
+ ### `invalidate_cache`
76
+
77
+ Force a full re-index of a repo or a single file, clearing all content hashes.
78
+
79
+ **Parameters:**
80
+
81
+ | Parameter | Type | Required | Description |
82
+ |-----------|------|----------|-------------|
83
+ | `repoId` | `string` | yes | Repository to invalidate |
84
+ | `filePath` | `string` | no | If given, invalidate only this file (relative path) |
85
+
86
+ **Returns:** `{ invalidated: number }` — number of files whose cache was cleared.
87
+
88
+ ---
89
+
90
+ ## Symbol Search & Retrieval
91
+
92
+ ### `search_symbols`
93
+
94
+ Search symbols by name fragment. The primary navigation tool.
95
+
96
+ **Parameters:**
97
+
98
+ | Parameter | Type | Required | Description |
99
+ |-----------|------|----------|-------------|
100
+ | `repoId` | `string` | yes | Target repository |
101
+ | `query` | `string` | yes | Name fragment or FTS5 query |
102
+ | `kind` | `string` | no | Filter by symbol kind (see [Symbol Kinds](#symbol-kinds)) |
103
+ | `filePath` | `string` | no | Filter to a specific file |
104
+ | `limit` | `number` | no | Max results (default: 20) |
105
+ | `mode` | `string` | no | `"keyword"` (default), `"semantic"`, or `"hybrid"` |
106
+ | `debug` | `boolean` | no | Include relevance scoring breakdown in response |
107
+ | `includeRisk` | `boolean` | no | Attach a compact `{ band, riskScore }` to each result (default `false`; see [`get_symbol_risk`](#get_symbol_risk)) |
108
+
109
+ **Returns:** `{ symbols: SymbolSummary[], _tokenEstimate }`
110
+
111
+ Does **not** return source code — use `get_symbol_source` for that.
112
+
113
+ ---
114
+
115
+ ### `search_text`
116
+
117
+ Full-text search across cached file content (grep-like).
118
+
119
+ **Parameters:**
120
+
121
+ | Parameter | Type | Required | Description |
122
+ |-----------|------|----------|-------------|
123
+ | `repoId` | `string` | yes | Target repository |
124
+ | `query` | `string` | yes | Search term or regex |
125
+ | `is_regex` | `boolean` | no | Treat query as a regular expression (default: `false`) |
126
+ | `file_pattern` | `string` | no | Glob pattern to restrict to specific files |
127
+ | `context_lines` | `number` | no | Lines of context around each match (default: 2) |
128
+ | `max_results` | `number` | no | Max matches (default: 50) |
129
+ | `debug` | `boolean` | no | Include relevance scoring breakdown |
130
+
131
+ **Returns:** `{ matches: [{ file, line, column, match, context }], truncated }`
132
+
133
+ ---
134
+
135
+ ### `search_semantic`
136
+
137
+ Semantic (meaning-based) search using HNSW vector index.
138
+
139
+ **Parameters:**
140
+
141
+ | Parameter | Type | Required | Description |
142
+ |-----------|------|----------|-------------|
143
+ | `repoId` | `string` | yes | Target repository |
144
+ | `query` | `string` | yes | Natural language description |
145
+ | `mode` | `string` | no | `"semantic"` (default) or `"hybrid"` |
146
+ | `semantic_weight` | `number` | no | Weight for semantic score in hybrid mode (default: 0.6) |
147
+ | `keyword_weight` | `number` | no | Weight for keyword score in hybrid mode (default: 0.4) |
148
+ | `max_results` | `number` | no | Max results (default: 10) |
149
+ | `kind` | `string` | no | Filter by symbol kind |
150
+
151
+ **Returns:** `{ results: [{ ...symbol, scores: { keyword, semantic, combined } }] }`
152
+
153
+ Requires semantic search enabled and an embedding provider configured. Falls back to FTS5 when no HNSW index exists.
154
+
155
+ ---
156
+
157
+ ### `get_symbol_source`
158
+
159
+ Retrieve the raw source code of a symbol.
160
+
161
+ **Parameters:**
162
+
163
+ | Parameter | Type | Required | Description |
164
+ |-----------|------|----------|-------------|
165
+ | `repoId` | `string` | yes | Target repository |
166
+ | `symbolId` | `string` | yes | Symbol ID from `search_symbols` |
167
+ | `context_lines` | `number` | no | Extra lines of context above/below (default: 0) |
168
+ | `verify` | `boolean` | no | Re-read file from disk to verify source hasn't changed |
169
+ | `includeRisk` | `boolean` | no | Attach a compact `{ band, riskScore }` to the symbol (default `false`; see [`get_symbol_risk`](#get_symbol_risk)) |
170
+
171
+ **Returns:** `{ source, filePath, startByte, endByte, startLine, endLine, _tokenEstimate }`
172
+
173
+ ---
174
+
175
+ ### `get_symbols`
176
+
177
+ Batch-fetch multiple symbols by ID.
178
+
179
+ **Parameters:**
180
+
181
+ | Parameter | Type | Required | Description |
182
+ |-----------|------|----------|-------------|
183
+ | `repoId` | `string` | yes | Target repository |
184
+ | `symbolIds` | `string[]` | yes | Array of symbol IDs |
185
+
186
+ **Returns:** `{ symbols: [{ ...symbolSummary, source }] }`
187
+
188
+ ---
189
+
190
+ ### `get_file_content`
191
+
192
+ Retrieve raw cached file content, with optional line range.
193
+
194
+ **Parameters:**
195
+
196
+ | Parameter | Type | Required | Description |
197
+ |-----------|------|----------|-------------|
198
+ | `repoId` | `string` | yes | Target repository |
199
+ | `filePath` | `string` | yes | Relative file path |
200
+ | `startLine` | `number` | no | Start line (1-based, default: 1) |
201
+ | `endLine` | `number` | no | End line (inclusive, default: end of file) |
202
+
203
+ **Returns:** `{ content, filePath, startLine, endLine, totalLines, _tokenEstimate }`
204
+
205
+ ---
206
+
207
+ ### `get_file_outline`
208
+
209
+ All symbols in a file with signatures and summaries.
210
+
211
+ **Parameters:** `{ repoId, filePath }`
212
+
213
+ **Returns:** `{ filePath, symbols: SymbolSummary[], _tokenEstimate }`
214
+
215
+ ---
216
+
217
+ ### `get_repo_outline`
218
+
219
+ All files with their top-level symbols a project map.
220
+
221
+ **Parameters:** `{ repoId, limit? }` (default limit: 100 files)
222
+
223
+ **Returns:** `{ files: [{ filePath, symbols: SymbolSummary[] }], _tokenEstimate }`
224
+
225
+ ---
226
+
227
+ ### `get_file_tree`
228
+
229
+ Directory tree with file counts per directory.
230
+
231
+ **Parameters:** `{ repoId, maxDepth? }` (default maxDepth: 5)
232
+
233
+ **Returns:** Nested `{ name, type: 'dir'|'file', children?, symbolCount? }`
234
+
235
+ ---
236
+
237
+ ### `find_references`
238
+
239
+ Find all usage sites (call sites, references) for a symbol across the repo.
240
+
241
+ **Parameters:**
242
+
243
+ | Parameter | Type | Required | Description |
244
+ |-----------|------|----------|-------------|
245
+ | `repoId` | `string` | yes | Target repository |
246
+ | `symbolId` | `string` | yes | Symbol to find references for |
247
+ | `limit` | `number` | no | Max results (default: 50) |
248
+
249
+ **Returns:** `{ references: [{ filePath, line, column, snippet }], count }`
250
+
251
+ ---
252
+
253
+ ## Dependency Graph
254
+
255
+ ### `get_context_bundle`
256
+
257
+ Forward-walk from a symbol — returns everything needed to understand it (transitive imports).
258
+
259
+ **Parameters:**
260
+
261
+ | Parameter | Type | Required | Description |
262
+ |-----------|------|----------|-------------|
263
+ | `repoId` | `string` | yes | Target repository |
264
+ | `symbolId` | `string` | yes | Starting symbol |
265
+ | `maxDepth` | `number` | no | Max traversal depth (default: 3) |
266
+ | `maxTokens` | `number` | no | Stop collecting when estimate exceeds this |
267
+
268
+ **Returns:** `{ symbols: SymbolSummary[], files: string[], _tokenEstimate }`
269
+
270
+ When git co-change data exists (`git.coChangeDepth > 0`), the response also includes `historicalNeighbors` — files that historically change together with the target but are not reachable through imports, each with a small outline. Absent (and output byte-identical to before) when there is no co-change data.
271
+
272
+ ---
273
+
274
+ ### `get_blast_radius`
275
+
276
+ Reverse-walk all files that (transitively) import a symbol. Use before modifying or deleting a symbol.
277
+
278
+ **Parameters:**
279
+
280
+ | Parameter | Type | Required | Description |
281
+ |-----------|------|----------|-------------|
282
+ | `repoId` | `string` | yes | Target repository |
283
+ | `symbolId` | `string` | yes | Starting symbol |
284
+ | `maxDepth` | `number` | no | Max traversal depth (default: 5) |
285
+
286
+ **Returns:** `{ importers: string[], count, _tokenEstimate }`
287
+
288
+ ---
289
+
290
+ ### `find_importers`
291
+
292
+ Direct (one-hop) importers of a file.
293
+
294
+ **Parameters:** `{ repoId, filePath }`
295
+
296
+ **Returns:** `{ importers: [{ filePath, importedNames: string[] }], _tokenEstimate }`
297
+
298
+ ---
299
+
300
+ ### `find_dead_code`
301
+
302
+ Exported symbols in files that nothing else imports.
303
+
304
+ **Parameters:**
305
+
306
+ | Parameter | Type | Required | Description |
307
+ |-----------|------|----------|-------------|
308
+ | `repoId` | `string` | yes | Target repository |
309
+ | `limit` | `number` | no | Max results (default: 50) |
310
+
311
+ **Returns:** `{ symbols: SymbolSummary[], _tokenEstimate }`
312
+
313
+ **Note:** May produce false positives for: dynamic imports, side-effect imports, symbols used by external packages (npm consumers).
314
+
315
+ ---
316
+
317
+ ### `get_layer_violations`
318
+
319
+ Detect architectural import boundary violations.
320
+
321
+ **Parameters:**
322
+
323
+ | Parameter | Type | Required | Description |
324
+ |-----------|------|----------|-------------|
325
+ | `repoId` | `string` | yes | Target repository |
326
+ | `layers` | `LayerDef[]` | no | Layer definitions (reads from config if omitted) |
327
+
328
+ **Returns:** `{ violations: [{ from_layer, to_layer, from_file, to_file, import_spec }], summary }`
329
+
330
+ ---
331
+
332
+ ## Token Savings
333
+
334
+ ### `get_savings_stats`
335
+
336
+ View cumulative token savings across all PureContext tool calls.
337
+
338
+ **Parameters:** `{ reset?: boolean }` — set `reset: true` to clear counters.
339
+
340
+ **Returns:**
341
+
342
+ ```json
343
+ {
344
+ "total_tokens_saved": 1234567,
345
+ "equivalent_context_windows": {
346
+ "claude_200k": 6.17,
347
+ "gpt4_128k": 9.64
348
+ },
349
+ "total_cost_avoided": {
350
+ "claude_opus_4": 18.52,
351
+ "claude_sonnet_4": 3.70,
352
+ "claude_haiku_4": 0.99,
353
+ "gpt4o": 3.09,
354
+ "gpt4o_mini": 0.19
355
+ }
356
+ }
357
+ ```
358
+
359
+ ---
360
+
361
+ ## Cross-Repo Tools
362
+
363
+ > To search symbol *names* across repositories, use `search_symbols` with `repoIds: [...]`, or omit `repoId`/`repoIds` entirely to search every indexed repo in one call.
364
+
365
+ ### `find_cross_repo_usages`
366
+
367
+ Find where source files in *other* indexed repos reference an identifier defined in a given repo — i.e. which downstream packages/services consume a symbol from a shared library. Word-boundary text search; heuristic, not type-resolved.
368
+
369
+ **Parameters:**
370
+
371
+ | Parameter | Type | Required | Description |
372
+ |-----------|------|----------|-------------|
373
+ | `sourceRepoId` | `string` | yes | Repo that defines the symbol |
374
+ | `symbolName` | `string` | yes | Symbol name to search for in other repos |
375
+ | `symbolKind` | `string` | no | Filter the source-repo lookup by kind (reduces false positives for generic names) |
376
+ | `targetRepoIds` | `string[]` | no | Repos to search (default: all indexed repos except the source) |
377
+ | `limit` | `number` | no | Max usages (default: 50) |
378
+
379
+ **Returns:** `{ usages: [{ repoId, filePath, line, context }] }`
380
+
381
+ ---
382
+
383
+ ### `search_similar`
384
+
385
+ Find semantically similar code across repos (HNSW vector similarity). Before implementing new functionality, call this to check whether equivalent code already exists. Requires semantic search enabled.
386
+
387
+ **Parameters:**
388
+
389
+ | Parameter | Type | Required | Description |
390
+ |-----------|------|----------|-------------|
391
+ | `repoId` | `string` | yes | Repo of the reference symbol |
392
+ | `symbolId` | `string` | yes | Reference symbol |
393
+ | `searchRepoIds` | `string[]` | no | Repos to search (default: all) |
394
+ | `minSimilarity` | `number` | no | Minimum cosine similarity 0–1 (default: 0.8) |
395
+ | `limit` | `number` | no | Max results (default: 10) |
396
+
397
+ **Returns:** `{ similar: [{ ...symbolSummary, repoId, similarity }] }`
398
+
399
+ ---
400
+
401
+ ## Git & History Tools
402
+
403
+ ### `get_symbol_history`
404
+
405
+ Symbol-level git commit history.
406
+
407
+ **Parameters:**
408
+
409
+ | Parameter | Type | Required | Description |
410
+ |-----------|------|----------|-------------|
411
+ | `repoId` | `string` | yes | Target repository |
412
+ | `symbolId` | `string` | yes | Symbol to get history for |
413
+ | `limit` | `number` | no | Max commits (default: 20) |
414
+
415
+ **Returns:** `{ history: [{ hash, author, date, message, diff }] }`
416
+
417
+ ---
418
+
419
+ ### `get_churn_metrics`
420
+
421
+ File or symbol churn metrics.
422
+
423
+ **Parameters:**
424
+
425
+ | Parameter | Type | Required | Description |
426
+ |-----------|------|----------|-------------|
427
+ | `repoId` | `string` | yes | Target repository |
428
+ | `filePath` | `string` | no | Scope to a single file |
429
+ | `since` | `string` | no | ISO 8601 date — look back from this date |
430
+
431
+ **Returns:** `{ files: [{ filePath, commits, linesChanged, authors, churnScore }] }`
432
+
433
+ ---
434
+
435
+ ### `get_co_change`
436
+
437
+ Temporal coupling — files that historically change together with a target file or symbol, derived from the repo-level commit capture. Reveals coupling the import graph cannot (a route and its test; a feature flag and the code it gates). Requires `git.coChangeDepth > 0` at index time.
438
+
439
+ **Parameters:**
440
+
441
+ | Parameter | Type | Required | Description |
442
+ |-----------|------|----------|-------------|
443
+ | `repoId` | `string` | yes | Target repository |
444
+ | `filePath` | `string` | no | Target file path (provide this **or** `symbolId`) |
445
+ | `symbolId` | `string` | no | Target symbol — resolved to its containing file (git is file-granular) |
446
+ | `minSupport` | `number` | no | Drop partners with fewer than N shared commits (default 2) |
447
+ | `dayWindow` | `number` | no | Look back N days (default: entire captured window) |
448
+ | `topN` | `number` | no | Max partners to return (default 20) |
449
+
450
+ **Returns:** `{ targetFilePath, targetCommits, windowCommits, signalQuality, partners: [{ filePath, support, weightedSupport, confidence, lift, coChangeDate }] }`
451
+
452
+ Mega-commits (reformats, lockfile sweeps) are filtered out and down-weighted; `signalQuality: "low"` flags shallow/sparse histories.
453
+
454
+ ---
455
+
456
+ ### `get_symbol_risk`
457
+
458
+ Composite, explainable "how risky is it to change this symbol?" verdict. Blends churn (90 d), centrality (afferent coupling + reverse blast radius), cyclomatic complexity, test-coverage gap, and co-change spread — each normalized repo-relative. Returns a 0–100 score, a band, the per-factor breakdown, and human-readable reasons. Code-centered only — no author/ownership metrics.
459
+
460
+ **Parameters:**
461
+
462
+ | Parameter | Type | Required | Description |
463
+ |-----------|------|----------|-------------|
464
+ | `repoId` | `string` | yes | Target repository |
465
+ | `symbolId` | `string` | yes | Symbol to score |
466
+
467
+ **Returns:** `{ riskScore, band: "low" | "review" | "high", factors: { churn, centrality, complexity, testGap, coChange }, reasons: string[], signalQuality }`
468
+
469
+ > `search_symbols` and `get_symbol_source` accept `includeRisk: true` to attach a compact `{ band, riskScore }` to results (opt-in, default off). `get_context_bundle` returns `historicalNeighbors` — co-changing files not reachable via imports — when co-change data exists. Risk weights are configurable via `risk.weights.*` (see [Configuration](04-configuration.md)).
470
+
471
+ ---
472
+
473
+ ## Architecture Analysis Tools
474
+
475
+ ### `get_quality_metrics`
476
+
477
+ Per-file and per-symbol quality scores.
478
+
479
+ **Parameters:** `{ repoId, filePath? }`
480
+
481
+ **Returns:** `{ files: [{ filePath, complexity, coupling, cohesion, docCoverage, score }] }`
482
+
483
+ ---
484
+
485
+ ### `detect_antipatterns`
486
+
487
+ Detect common architectural anti-patterns.
488
+
489
+ **Parameters:** `{ repoId, patterns?: string[] }` — omit `patterns` for all checks.
490
+
491
+ **Returns:** `{ issues: [{ pattern, filePath, symbolId, severity, description }] }`
492
+
493
+ ---
494
+
495
+ ### `generate_docs`
496
+
497
+ Auto-generate an architecture / module summary in Markdown or Mermaid. Requires `ai.allowRemoteAI: true` for AI-written prose.
498
+
499
+ **Parameters:** `{ repoId, scope?, format?: 'markdown' | 'mermaid' }` (default format: `'markdown'`)
500
+
501
+ **Returns:** `{ doc: string }`
502
+
503
+ ---
504
+
505
+ ### `get_coupling_map`
506
+
507
+ Per-file afferent/efferent coupling and instability (`I = efferent / (afferent + efferent)`).
508
+
509
+ **Parameters:** `{ repoId, filePath?, scope?, limit? }` (limit default 50)
510
+
511
+ **Returns:** `{ files: [{ filePath, efferentCoupling, afferentCoupling, instability, efferentDeps, afferentDeps }] }`
512
+
513
+ ---
514
+
515
+ ### `find_refactoring_opportunities`
516
+
517
+ Surface extract/split/decouple candidates ranked by estimated impact.
518
+
519
+ **Parameters:** `{ repoId, scope?, limit? }`
520
+
521
+ **Returns:** `{ opportunities: [{ filePath, symbolId?, kind, impact, rationale }] }`
522
+
523
+ ---
524
+
525
+ ## Relationship Analysis Tools
526
+
527
+ ### `find_implementations`
528
+
529
+ All concrete implementations of an interface or abstract class. Returns `implementedMethods` / `missingMethods` per class — call before modifying an interface to know every class that must change.
530
+
531
+ **Parameters:** `{ repoId, symbolId, includeAbstract?, limit? }` (limit default 50)
532
+
533
+ ---
534
+
535
+ ### `get_call_hierarchy`
536
+
537
+ Callers and callees of a function, N levels deep, as a tree. Recursive calls are marked `cyclic: true`. Uses the import-edge graph — dynamic dispatch / `eval` / reflection are invisible.
538
+
539
+ **Parameters:** `{ repoId, symbolId, direction?: 'callers' | 'callees' | 'both', maxDepth?, maxNodes? }`
540
+
541
+ ---
542
+
543
+ ### `get_class_hierarchy`
544
+
545
+ Inheritance tree rooted at a class — ancestors (what it extends) and descendants (what extends it).
546
+
547
+ **Parameters:** `{ repoId, symbolId, direction?: 'ancestors' | 'descendants' | 'both', maxDepth? }` (default `both`, depth 5)
548
+
549
+ ---
550
+
551
+ ### `find_cycles`
552
+
553
+ Detect circular import dependencies (strongly-connected components with severity ratings).
554
+
555
+ **Parameters:** `{ repoId, scope?, minCycleLength? }` (default min length 2)
556
+
557
+ **Returns:** `{ cycles: [{ files, length, severity }], totalFound }`
558
+
559
+ ---
560
+
561
+ ### `trace_invocation_chain`
562
+
563
+ Follow call edges from a symbol N hops deep and return the linearised call path(s).
564
+
565
+ **Parameters:** `{ repoId, symbolId, maxDepth? }`
566
+
567
+ ---
568
+
569
+ ### `get_lexical_scope_matches`
570
+
571
+ All symbols accessible from a given file + line: local scope, imports, and module exports.
572
+
573
+ **Parameters:** `{ repoId, filePath, line }`
574
+
575
+ ---
576
+
577
+ ## Visualization Tools
578
+
579
+ ### `render_diagram`
580
+
581
+ Generate a Mermaid or DOT diagram from the dependency graph.
582
+
583
+ **Parameters:**
584
+
585
+ | Parameter | Type | Required | Description |
586
+ |-----------|------|----------|-------------|
587
+ | `repoId` | `string` | yes | Target repository |
588
+ | `type` | `string` | no | `"module"` / `"import"` (file-level), `"call"` (needs `rootSymbolId`), `"class"` (needs `rootSymbolId`) |
589
+ | `format` | `string` | no | `"mermaid"` (default) or `"dot"` |
590
+ | `maxNodes` | `number` | no | Cap nodes (diagrams >50 nodes become unreadable) |
591
+ | `maxDepth` | `number` | no | Max graph depth |
592
+
593
+ **Returns:** `{ diagram: string, format, nodeCount }`
594
+
595
+ `render_call_graph`, `render_import_graph`, `render_class_hierarchy`, and `render_dep_matrix` are specialized variants of `render_diagram` for a single diagram type.
596
+
597
+ ---
598
+
599
+ ### `get_architecture_snapshot`
600
+
601
+ Freeze the architecture state (file/symbol/edge counts, cycle membership, layer violations, coupling/complexity averages) into a named snapshot, then `diff` two snapshots for before/after evidence. The stored cycle/layer data is what `compare_change_impact` diffs against.
602
+
603
+ **Parameters:** `{ repoId, action: 'create' | 'list' | 'diff' | 'delete', snapshotId?, compareId?, label? }`
604
+
605
+ ---
606
+
607
+ ## Refactoring Safety Tools
608
+
609
+ Run the matching `check_*` before any structural change — they give a binary `safe` verdict with the full impact list. (For the impact-aware pre/post loop, see [Change & Refactoring Tools](#change--refactoring-tools).)
610
+
611
+ ### `check_rename_safe`
612
+
613
+ **Parameters:** `{ repoId, symbolId, newName }`
614
+
615
+ **Returns:** `{ safe, verdict, conflicts, affectedSites: [{ filePath, line, column, context, changeType }], affectedFileCount }` — `safe: false` on name conflicts or string-literal references that need human judgment.
616
+
617
+ ---
618
+
619
+ ### `check_delete_safe`
620
+
621
+ **Parameters:** `{ repoId, symbolId }` (or `filePath` for a whole-file aggregate)
622
+
623
+ **Returns:** `{ safe, risks: [{ kind, filePath, line, detail }], liveReferenceCount, isExported, isEntryPoint }`
624
+
625
+ ---
626
+
627
+ ### `check_move_safe`
628
+
629
+ **Parameters:** `{ repoId, filePath, newFilePath }`
630
+
631
+ **Returns:** `{ safe, importUpdates: [{ importerFilePath, currentImportPath, newImportPath, line }], newCycles, wouldIntroduceCycles }`
632
+
633
+ ---
634
+
635
+ ### `plan_refactoring`
636
+
637
+ Sequenced, risk-annotated plan synthesizing the safety checks. Read-only — produces a plan, writes nothing.
638
+
639
+ **Parameters:** `{ repoId, goal: 'rename-symbol' | 'delete-symbol' | 'break-cycle' | 'extract-module' | 'reduce-coupling' | 'general', symbolId?, filePath?, newName?, newFilePath?, contextHint? }`
640
+
641
+ **Returns:** `{ goal, summary, steps: [{ order, action, filePath, line?, detail, automated, risk }], totalSteps, estimatedRisk, warnings }`
642
+
643
+ ---
644
+
645
+ ## Health & Debt Tools
646
+
647
+ ### `health_radar`
648
+
649
+ Five-axis health radar (each axis 0–100, 100 = healthy): complexity, coupling, maintainability, documentation, stability.
650
+
651
+ **Parameters:** `{ repoId, scope?, includeStability? }` (set `includeStability: false` for repos with no git history)
652
+
653
+ ---
654
+
655
+ ### `diff_health_radar`
656
+
657
+ Compare two health snapshots axis-by-axis for before/after evidence.
658
+
659
+ **Parameters:** `{ repoId, scope?, includeStability? }` (compares against the prior snapshot / two commits)
660
+
661
+ ---
662
+
663
+ ### `get_debt_report`
664
+
665
+ Per-file technical-debt report with priority tiers and recommendations.
666
+
667
+ **Parameters:** `{ repoId, scope?, maxFiles?, includeDead? }` (maxFiles default 10)
668
+
669
+ ---
670
+
671
+ ## AST-Level Search Tools
672
+
673
+ These re-parse stored file content with tree-sitter — only files backed by a WASM grammar are searched (regex-only handlers are skipped; use `search_text` there).
674
+
675
+ ### `search_ast`
676
+
677
+ Find every occurrence of a tree-sitter node type (e.g. `try_statement`, `arrow_function`, `impl_item`).
678
+
679
+ **Parameters:** `{ repoId, nodeType, filePath?, limit? }`
680
+
681
+ ---
682
+
683
+ ### `search_by_signature`
684
+
685
+ Search symbols by type-signature pattern (regex or substring).
686
+
687
+ **Parameters:** `{ repoId, pattern, kind? }`
688
+
689
+ ---
690
+
691
+ ### `search_by_decorator`
692
+
693
+ Find all symbols annotated with a given decorator (e.g. `Injectable`, `route`). Combine with set-difference to find symbols *lacking* a decorator.
694
+
695
+ **Parameters:** `{ repoId, decorator, kind? }`
696
+
697
+ ---
698
+
699
+ ### `search_by_complexity`
700
+
701
+ Find symbols above a cyclomatic-complexity threshold.
702
+
703
+ **Parameters:** `{ repoId, minComplexity, kind?, limit? }`
704
+
705
+ ---
706
+
707
+ ## Code Intelligence Tools
708
+
709
+ ### `get_entry_points`
710
+
711
+ Identify runnable entry points (main, CLI, server startup, Lambda, test suites, scripts), each with a `confidence` and reason.
712
+
713
+ **Parameters:** `{ repoId, kind?, minConfidence? }`
714
+
715
+ ---
716
+
717
+ ### `get_public_api`
718
+
719
+ Exported symbols grouped by file — the public API surface of the repo or a module.
720
+
721
+ **Parameters:** `{ repoId, filePath?, kind?, includeMembers?, groupByFile? }` (groupByFile default true)
722
+
723
+ ---
724
+
725
+ ### `get_todos`
726
+
727
+ All TODO / FIXME / HACK / NOTE / XXX comments with file, line, tag, and text.
728
+
729
+ **Parameters:** `{ repoId, tags?, filePath?, limit? }` (limit default 200)
730
+
731
+ ---
732
+
733
+ ### `get_complexity_hotspots`
734
+
735
+ Symbols ranked by complexity, highest first.
736
+
737
+ **Parameters:** `{ repoId, kind?, filePath?, limit?, minComplexity? }` (limit default 20)
738
+
739
+ ---
740
+
741
+ ### `get_type_graph`
742
+
743
+ Type dependency graph — which types reference which.
744
+
745
+ **Parameters:** `{ repoId, symbolId?, maxDepth?, direction?: 'uses' | 'usedBy' | 'both' }` (maxDepth default 3)
746
+
747
+ ---
748
+
749
+ ### `find_untested_symbols`
750
+
751
+ Exported symbols with no corresponding test coverage (import-based heuristic, not runtime coverage).
752
+
753
+ **Parameters:** `{ repoId, filePath?, kind?, limit? }` (limit default 50)
754
+
755
+ ---
756
+
757
+ ### `get_test_coverage_map`
758
+
759
+ Per-file coverage map with `coverageRatio` and aggregated totals.
760
+
761
+ **Parameters:** `{ repoId, filePath?, includeSymbols? }`
762
+
763
+ ---
764
+
765
+ ### `get_task_context`
766
+
767
+ Assemble a focused, token-bounded context bundle for a natural-language task description (the symbols and files most relevant to the work).
768
+
769
+ **Parameters:** `{ repoId, task, maxTokens? }`
770
+
771
+ ---
772
+
773
+ ## Distribution Tools
774
+
775
+ ### `export_index`
776
+
777
+ Serialize a repo's index to a portable archive.
778
+
779
+ **Parameters:** `{ repoId, outputPath? }`
780
+
781
+ ---
782
+
783
+ ### `import_index`
784
+
785
+ Import a previously exported index archive.
786
+
787
+ **Parameters:** `{ archivePath }`
788
+
789
+ ---
790
+
791
+ ### `fetch_public_index`
792
+
793
+ Download a pre-built index from the public registry.
794
+
795
+ **Parameters:** `{ name | url }`
796
+
797
+ ---
798
+
799
+ ## Ecosystem & Data Tools
800
+
801
+ ### `search_columns`
802
+
803
+ Search dbt/SQL column definitions with full upstream/downstream lineage. dbt-only — run `dbt compile` before `index_folder`.
804
+
805
+ **Parameters:** `{ repoId, query, modelName? }`
806
+
807
+ **Returns:** `{ columns: [{ name, model, dataType, description, lineage }] }`
808
+
809
+ ---
810
+
811
+ ## Change & Refactoring Tools
812
+
813
+ PureContext closes a loop around an edit: assess before, reconcile after, and check for architectural regression. These tools are **judgment, not actuation** — they never write files. Each verdict ships with a plain-English `reasons[]`.
814
+
815
+ ### `analyze_diff`
816
+
817
+ Parse a unified git diff and produce an impact-aware change report (CI / PR review). Built on the same synthesis engine as `prepare_change`.
818
+
819
+ **Parameters:** `{ repoId, diff, includeBlastRadius?, blastRadiusDepth?, includeRisk?, includeCoChangeGaps?, includeTests?, includeArchitectureFlags? }` (impact sections default on; switch off for cheap runs).
820
+
821
+ **Returns:** `{ summary, changedSymbols, blastRadius?, risk?, missingCoChange?, recommendedTests?, coverageGaps?, architecturalFlags?, signalQuality?, reviewPriority }`
822
+
823
+ ---
824
+
825
+ ### `prepare_change`
826
+
827
+ Pre-edit verdict for an intended change. Resolves a target and returns the predicted impact **before** you edit.
828
+
829
+ **Parameters:**
830
+
831
+ | Parameter | Type | Required | Description |
832
+ |-----------|------|----------|-------------|
833
+ | `repoId` | `string` | yes | Target repository |
834
+ | `intent` | `"rename" \| "delete" \| "modify" \| "extract"` | yes | What you intend to do |
835
+ | `targetSymbolId` | `string` | one of | Resolve directly by symbol id |
836
+ | `query` | `string` | one of | Resolve by free-text name/description |
837
+ | `includeRisk` / `includeCoChangeGaps` / `includeTests` / `includeArchitectureFlags` | `boolean` | no | Section toggles (default on) |
838
+
839
+ **Returns:** `{ verdict: "ready" | "ambiguous_target" | "no_target", target?, candidates?, predictedChange?: { changedSymbolIds, changedFilePaths }, predictionId?, risk?, missingCoChange?, recommendedTests?, coverageGaps?, architecturalFlags?, signalQuality?, reasons }`
840
+
841
+ > On `ambiguous_target` it returns `candidates[]` and refuses to synthesize — re-call with the chosen `targetSymbolId`. It never guesses.
842
+
843
+ ---
844
+
845
+ ### `verify_change`
846
+
847
+ Post-edit reconciliation of the real diff against a `prepare_change` prediction. Stateless — pass the prediction back inline.
848
+
849
+ **Parameters:**
850
+
851
+ | Parameter | Type | Required | Description |
852
+ |-----------|------|----------|-------------|
853
+ | `repoId` | `string` | yes | Target repository |
854
+ | `diff` | `string` | yes | Unified diff of what you actually changed |
855
+ | `predictedFilePaths` | `string[]` | yes | `predictedChange.changedFilePaths` from prepare_change |
856
+ | `predictedCoChange` | `string[]` | no | `missingCoChange[].filePath` from prepare_change |
857
+ | `predictionId` | `string` | no | Optional echo (label only; not stored) |
858
+
859
+ **Returns:** `{ verdict: "complete" | "incomplete" | "scope_expanded", actualFilePaths, addressedCoChange, unaddressedCoChange, unplannedChanges, coverageGapsRemaining, signalQuality, reasons }`
860
+
861
+ > Co-change reconciliation is suppressed when `signalQuality` is `low` (shallow/squashed history) — it never invents "you forgot X."
862
+
863
+ ---
864
+
865
+ ### `compare_change_impact`
866
+
867
+ Before/after architecture *regression* delta. Distinct from `analyze_diff`'s `architecturalFlags` (which flag pre-existing issues); this reports only what the change introduced or resolved.
868
+
869
+ **Parameters:** `{ repoId, baselineSnapshotId? }` — baseline from `get_architecture_snapshot` (action `create`); omit to use the most recent snapshot.
870
+
871
+ **Returns:** `{ verdict: "regressed" | "improved" | "unchanged" | "no_baseline", baselineSnapshotId?, newCycles, resolvedCycles, newLayerViolations, resolvedLayerViolations, currentCycleCount, currentLayerViolationCount, reasons }`
872
+
873
+ **Workflow:** `get_architecture_snapshot` (create) → edit → reindex → `compare_change_impact`. Snapshots created before v1.11.0 lack the stored cycle/layer data and return `no_baseline`.
874
+
875
+ ---
876
+
877
+ ## Symbol Kinds
878
+
879
+ The `kind` parameter accepts any of:
880
+
881
+ | Kind | Description |
882
+ |------|-------------|
883
+ | `function` | Standalone function / top-level def |
884
+ | `class` | Class, struct (Go/Rust), or OOP type |
885
+ | `method` | Method inside a class/struct/impl |
886
+ | `const` | Constant, exported variable, field |
887
+ | `type` | Type alias, typedef, newtype |
888
+ | `interface` | Interface or protocol |
889
+ | `enum` | Enumeration |
890
+ | `component` | UI component (Vue, React, Angular) |
891
+ | `composable` | Vue composable (`useXxx`) |
892
+ | `hook` | React hook (`useXxx`) |
893
+ | `route` | HTTP route (any framework) |
894
+ | `middleware` | Middleware or guard |
895
+ | `decorator` | Decorator / annotation |
896
+ | `model` | ORM model |
897
+ | `view` | Request handler / controller action |
898
+ | `struct` | C/C++ struct |
899
+ | `macro` | C/C++ `#define` macro |
900
+ | `signal` | Django signal receiver |
901
+ | `namespace` | C++ namespace |
902
+ | `widget` | Flutter widget |