@lzehrung/codegraph 2.1.0 → 2.1.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.
Files changed (536) hide show
  1. package/README.md +27 -29
  2. package/codegraph-skill/codegraph/SKILL.md +27 -26
  3. package/dist/agent/artifact.d.ts.map +1 -1
  4. package/dist/agent/artifact.js +105 -14
  5. package/dist/agent/artifact.js.map +1 -1
  6. package/dist/agent/candidateTests.d.ts +12 -0
  7. package/dist/agent/candidateTests.d.ts.map +1 -0
  8. package/dist/agent/candidateTests.js +17 -0
  9. package/dist/agent/candidateTests.js.map +1 -0
  10. package/dist/agent/explain.d.ts +3 -0
  11. package/dist/agent/explain.d.ts.map +1 -1
  12. package/dist/agent/explain.js +8 -0
  13. package/dist/agent/explain.js.map +1 -1
  14. package/dist/agent/explore.d.ts.map +1 -1
  15. package/dist/agent/explore.js +11 -6
  16. package/dist/agent/explore.js.map +1 -1
  17. package/dist/agent/fileView.d.ts.map +1 -1
  18. package/dist/agent/fileView.js +113 -120
  19. package/dist/agent/fileView.js.map +1 -1
  20. package/dist/agent/orient.d.ts.map +1 -1
  21. package/dist/agent/orient.js +7 -4
  22. package/dist/agent/orient.js.map +1 -1
  23. package/dist/agent/packet.d.ts.map +1 -1
  24. package/dist/agent/packet.js +5 -12
  25. package/dist/agent/packet.js.map +1 -1
  26. package/dist/agent/query-index/candidates.d.ts +13 -2
  27. package/dist/agent/query-index/candidates.d.ts.map +1 -1
  28. package/dist/agent/query-index/candidates.js +28 -39
  29. package/dist/agent/query-index/candidates.js.map +1 -1
  30. package/dist/agent/query-index/content.d.ts +1 -1
  31. package/dist/agent/query-index/content.js +4 -4
  32. package/dist/agent/query-index/content.js.map +1 -1
  33. package/dist/agent/query-index/schema.d.ts.map +1 -1
  34. package/dist/agent/query-index/schema.js.map +1 -1
  35. package/dist/agent/query-index/sessionStore.d.ts.map +1 -1
  36. package/dist/agent/query-index/sessionStore.js +42 -26
  37. package/dist/agent/query-index/sessionStore.js.map +1 -1
  38. package/dist/agent/query-index/store.d.ts +10 -4
  39. package/dist/agent/query-index/store.d.ts.map +1 -1
  40. package/dist/agent/query-index/store.js +115 -10
  41. package/dist/agent/query-index/store.js.map +1 -1
  42. package/dist/agent/query-index/update.d.ts.map +1 -1
  43. package/dist/agent/query-index/update.js +24 -9
  44. package/dist/agent/query-index/update.js.map +1 -1
  45. package/dist/agent/refactorPlan.d.ts.map +1 -1
  46. package/dist/agent/refactorPlan.js +6 -14
  47. package/dist/agent/refactorPlan.js.map +1 -1
  48. package/dist/agent/renamePreview.d.ts +2 -5
  49. package/dist/agent/renamePreview.d.ts.map +1 -1
  50. package/dist/agent/renamePreview.js +133 -80
  51. package/dist/agent/renamePreview.js.map +1 -1
  52. package/dist/agent/search.d.ts +3 -1
  53. package/dist/agent/search.d.ts.map +1 -1
  54. package/dist/agent/search.js +103 -35
  55. package/dist/agent/search.js.map +1 -1
  56. package/dist/agent/semanticSymbols.d.ts.map +1 -1
  57. package/dist/agent/semanticSymbols.js +2 -1
  58. package/dist/agent/semanticSymbols.js.map +1 -1
  59. package/dist/agent/session.d.ts +4 -0
  60. package/dist/agent/session.d.ts.map +1 -1
  61. package/dist/agent/session.js +20 -7
  62. package/dist/agent/session.js.map +1 -1
  63. package/dist/agent-tools.d.ts +1 -1
  64. package/dist/agent-tools.d.ts.map +1 -1
  65. package/dist/agent-tools.js +12 -21
  66. package/dist/agent-tools.js.map +1 -1
  67. package/dist/bin/cli.js +29242 -25373
  68. package/dist/bin/queryIndexWorker.js +131 -42
  69. package/dist/bin/rawQueryWorker.js +270 -0
  70. package/dist/chunking/chunkFile.d.ts +5 -0
  71. package/dist/chunking/chunkFile.d.ts.map +1 -1
  72. package/dist/chunking/chunkFile.js +14 -15
  73. package/dist/chunking/chunkFile.js.map +1 -1
  74. package/dist/cli/affected.d.ts.map +1 -1
  75. package/dist/cli/affected.js +17 -10
  76. package/dist/cli/affected.js.map +1 -1
  77. package/dist/cli/callHierarchy.d.ts.map +1 -1
  78. package/dist/cli/callHierarchy.js +9 -2
  79. package/dist/cli/callHierarchy.js.map +1 -1
  80. package/dist/cli/commandTable.d.ts.map +1 -1
  81. package/dist/cli/commandTable.js +16 -4
  82. package/dist/cli/commandTable.js.map +1 -1
  83. package/dist/cli/doctor.d.ts +7 -0
  84. package/dist/cli/doctor.d.ts.map +1 -1
  85. package/dist/cli/doctor.js +166 -0
  86. package/dist/cli/doctor.js.map +1 -1
  87. package/dist/cli/graph.d.ts +2 -1
  88. package/dist/cli/graph.d.ts.map +1 -1
  89. package/dist/cli/graph.js +60 -16
  90. package/dist/cli/graph.js.map +1 -1
  91. package/dist/cli/graphDelta.d.ts +2 -1
  92. package/dist/cli/graphDelta.d.ts.map +1 -1
  93. package/dist/cli/graphDelta.js +5 -0
  94. package/dist/cli/graphDelta.js.map +1 -1
  95. package/dist/cli/grep.d.ts +1 -1
  96. package/dist/cli/grep.d.ts.map +1 -1
  97. package/dist/cli/grep.js +14 -4
  98. package/dist/cli/grep.js.map +1 -1
  99. package/dist/cli/help.d.ts +34 -34
  100. package/dist/cli/help.d.ts.map +1 -1
  101. package/dist/cli/help.js +17 -8
  102. package/dist/cli/help.js.map +1 -1
  103. package/dist/cli/impact.d.ts +2 -1
  104. package/dist/cli/impact.d.ts.map +1 -1
  105. package/dist/cli/impact.js +5 -0
  106. package/dist/cli/impact.js.map +1 -1
  107. package/dist/cli/index.d.ts +2 -1
  108. package/dist/cli/index.d.ts.map +1 -1
  109. package/dist/cli/index.js +3 -0
  110. package/dist/cli/index.js.map +1 -1
  111. package/dist/cli/indexPolicy.d.ts.map +1 -1
  112. package/dist/cli/indexPolicy.js.map +1 -1
  113. package/dist/cli/inspect.d.ts +2 -1
  114. package/dist/cli/inspect.d.ts.map +1 -1
  115. package/dist/cli/inspect.js +25 -13
  116. package/dist/cli/inspect.js.map +1 -1
  117. package/dist/cli/install.js +1 -1
  118. package/dist/cli/install.js.map +1 -1
  119. package/dist/cli/invocationContext.d.ts.map +1 -1
  120. package/dist/cli/invocationContext.js +3 -0
  121. package/dist/cli/invocationContext.js.map +1 -1
  122. package/dist/cli/links.d.ts +2 -0
  123. package/dist/cli/links.d.ts.map +1 -1
  124. package/dist/cli/links.js +1 -1
  125. package/dist/cli/links.js.map +1 -1
  126. package/dist/cli/navigation.d.ts +41 -1
  127. package/dist/cli/navigation.d.ts.map +1 -1
  128. package/dist/cli/navigation.js +4 -1
  129. package/dist/cli/navigation.js.map +1 -1
  130. package/dist/cli/options.d.ts.map +1 -1
  131. package/dist/cli/options.js +32 -11
  132. package/dist/cli/options.js.map +1 -1
  133. package/dist/cli/renamePreview.d.ts.map +1 -1
  134. package/dist/cli/renamePreview.js +7 -1
  135. package/dist/cli/renamePreview.js.map +1 -1
  136. package/dist/cli/review.d.ts +2 -1
  137. package/dist/cli/review.d.ts.map +1 -1
  138. package/dist/cli/review.js +5 -0
  139. package/dist/cli/review.js.map +1 -1
  140. package/dist/cli/rootPolicy.d.ts.map +1 -1
  141. package/dist/cli/rootPolicy.js +36 -3
  142. package/dist/cli/rootPolicy.js.map +1 -1
  143. package/dist/cli/skill.js +2 -2
  144. package/dist/cli/skill.js.map +1 -1
  145. package/dist/cli/sql.js +1 -1
  146. package/dist/cli/symbols.d.ts.map +1 -1
  147. package/dist/cli/symbols.js +4 -2
  148. package/dist/cli/symbols.js.map +1 -1
  149. package/dist/cli/viewer.d.ts.map +1 -1
  150. package/dist/cli/viewer.js +46 -34
  151. package/dist/cli/viewer.js.map +1 -1
  152. package/dist/cli.d.ts.map +1 -1
  153. package/dist/cli.js +36 -16
  154. package/dist/cli.js.map +1 -1
  155. package/dist/config.d.ts +3 -0
  156. package/dist/config.d.ts.map +1 -1
  157. package/dist/config.js +35 -3
  158. package/dist/config.js.map +1 -1
  159. package/dist/documentLinks/check.d.ts +2 -1
  160. package/dist/documentLinks/check.d.ts.map +1 -1
  161. package/dist/documentLinks/check.js +22 -11
  162. package/dist/documentLinks/check.js.map +1 -1
  163. package/dist/duplicate-token-normalization.d.ts.map +1 -1
  164. package/dist/duplicate-token-normalization.js +10 -2
  165. package/dist/duplicate-token-normalization.js.map +1 -1
  166. package/dist/duplicates/scoring.d.ts +0 -10
  167. package/dist/duplicates/scoring.d.ts.map +1 -1
  168. package/dist/duplicates/scoring.js +9 -9
  169. package/dist/duplicates/scoring.js.map +1 -1
  170. package/dist/duplicates/types.d.ts +2 -0
  171. package/dist/duplicates/types.d.ts.map +1 -1
  172. package/dist/duplicates/unitCache.d.ts +15 -9
  173. package/dist/duplicates/unitCache.d.ts.map +1 -1
  174. package/dist/duplicates/unitCache.js +184 -33
  175. package/dist/duplicates/unitCache.js.map +1 -1
  176. package/dist/duplicates/units.d.ts +6 -15
  177. package/dist/duplicates/units.d.ts.map +1 -1
  178. package/dist/duplicates/units.js +42 -20
  179. package/dist/duplicates/units.js.map +1 -1
  180. package/dist/duplicates.d.ts.map +1 -1
  181. package/dist/duplicates.js +59 -0
  182. package/dist/duplicates.js.map +1 -1
  183. package/dist/frameworks/angularjs.d.ts.map +1 -1
  184. package/dist/frameworks/angularjs.js +18 -12
  185. package/dist/frameworks/angularjs.js.map +1 -1
  186. package/dist/graph-builder.d.ts.map +1 -1
  187. package/dist/graph-builder.js +12 -9
  188. package/dist/graph-builder.js.map +1 -1
  189. package/dist/graph-edge-collector.d.ts +1 -0
  190. package/dist/graph-edge-collector.d.ts.map +1 -1
  191. package/dist/graph-edge-collector.js +1 -1
  192. package/dist/graph-edge-collector.js.map +1 -1
  193. package/dist/graphs/grep.d.ts.map +1 -1
  194. package/dist/graphs/grep.js +7 -2
  195. package/dist/graphs/grep.js.map +1 -1
  196. package/dist/graphs/specifiers.d.ts.map +1 -1
  197. package/dist/graphs/specifiers.js +8 -2
  198. package/dist/graphs/specifiers.js.map +1 -1
  199. package/dist/graphs/symbol-graph-detailed.d.ts +10 -1
  200. package/dist/graphs/symbol-graph-detailed.d.ts.map +1 -1
  201. package/dist/graphs/symbol-graph-detailed.js +21 -5
  202. package/dist/graphs/symbol-graph-detailed.js.map +1 -1
  203. package/dist/impact/analyzer.d.ts.map +1 -1
  204. package/dist/impact/analyzer.js +19 -2
  205. package/dist/impact/analyzer.js.map +1 -1
  206. package/dist/impact/budgets.d.ts.map +1 -1
  207. package/dist/impact/budgets.js +5 -3
  208. package/dist/impact/budgets.js.map +1 -1
  209. package/dist/impact/call-compatibility/textScanner.d.ts +23 -0
  210. package/dist/impact/call-compatibility/textScanner.d.ts.map +1 -0
  211. package/dist/impact/call-compatibility/textScanner.js +615 -0
  212. package/dist/impact/call-compatibility/textScanner.js.map +1 -0
  213. package/dist/impact/callCompatibility.d.ts +8 -1
  214. package/dist/impact/callCompatibility.d.ts.map +1 -1
  215. package/dist/impact/callCompatibility.js +64 -587
  216. package/dist/impact/callCompatibility.js.map +1 -1
  217. package/dist/impact/context.d.ts.map +1 -1
  218. package/dist/impact/context.js +4 -1
  219. package/dist/impact/context.js.map +1 -1
  220. package/dist/impact/direct.d.ts +1 -1
  221. package/dist/impact/direct.d.ts.map +1 -1
  222. package/dist/impact/direct.js +7 -6
  223. package/dist/impact/direct.js.map +1 -1
  224. package/dist/impact/index.d.ts +6 -0
  225. package/dist/impact/index.d.ts.map +1 -1
  226. package/dist/impact/index.js +0 -8
  227. package/dist/impact/index.js.map +1 -1
  228. package/dist/impact/map.js +2 -2
  229. package/dist/impact/map.js.map +1 -1
  230. package/dist/impact/memberResolutionCoverage.d.ts.map +1 -1
  231. package/dist/impact/memberResolutionCoverage.js +5 -1
  232. package/dist/impact/memberResolutionCoverage.js.map +1 -1
  233. package/dist/impact/parse.d.ts.map +1 -1
  234. package/dist/impact/parse.js +108 -37
  235. package/dist/impact/parse.js.map +1 -1
  236. package/dist/impact/referenceCache.js +1 -1
  237. package/dist/impact/referenceCache.js.map +1 -1
  238. package/dist/impact/report-suggestions.d.ts.map +1 -1
  239. package/dist/impact/report-suggestions.js +347 -72
  240. package/dist/impact/report-suggestions.js.map +1 -1
  241. package/dist/impact/report.d.ts.map +1 -1
  242. package/dist/impact/report.js +13 -2
  243. package/dist/impact/report.js.map +1 -1
  244. package/dist/impact/reportCompact.d.ts.map +1 -1
  245. package/dist/impact/reportCompact.js +8 -0
  246. package/dist/impact/reportCompact.js.map +1 -1
  247. package/dist/impact/reportFull.d.ts.map +1 -1
  248. package/dist/impact/reportFull.js +1 -0
  249. package/dist/impact/reportFull.js.map +1 -1
  250. package/dist/impact/reportParts.d.ts +9 -0
  251. package/dist/impact/reportParts.d.ts.map +1 -1
  252. package/dist/impact/severity.d.ts +3 -2
  253. package/dist/impact/severity.d.ts.map +1 -1
  254. package/dist/impact/severity.js +16 -5
  255. package/dist/impact/severity.js.map +1 -1
  256. package/dist/impact/streaming.d.ts +32 -2
  257. package/dist/impact/streaming.d.ts.map +1 -1
  258. package/dist/impact/streaming.js +62 -3
  259. package/dist/impact/streaming.js.map +1 -1
  260. package/dist/impact/suggestions.d.ts.map +1 -1
  261. package/dist/impact/suggestions.js +1 -1
  262. package/dist/impact/suggestions.js.map +1 -1
  263. package/dist/impact/transitive.d.ts.map +1 -1
  264. package/dist/impact/transitive.js +13 -5
  265. package/dist/impact/transitive.js.map +1 -1
  266. package/dist/impact/types.d.ts +21 -20
  267. package/dist/impact/types.d.ts.map +1 -1
  268. package/dist/impact/types.js.map +1 -1
  269. package/dist/index.d.ts +2 -2
  270. package/dist/index.d.ts.map +1 -1
  271. package/dist/index.js +1 -1
  272. package/dist/index.js.map +1 -1
  273. package/dist/indexer/build-cache/location.d.ts +19 -0
  274. package/dist/indexer/build-cache/location.d.ts.map +1 -0
  275. package/dist/indexer/build-cache/location.js +132 -0
  276. package/dist/indexer/build-cache/location.js.map +1 -0
  277. package/dist/indexer/build-cache/manifest.d.ts +14 -6
  278. package/dist/indexer/build-cache/manifest.d.ts.map +1 -1
  279. package/dist/indexer/build-cache/manifest.js +194 -30
  280. package/dist/indexer/build-cache/manifest.js.map +1 -1
  281. package/dist/indexer/build-cache/module-cache.d.ts +24 -2
  282. package/dist/indexer/build-cache/module-cache.d.ts.map +1 -1
  283. package/dist/indexer/build-cache/module-cache.js +98 -32
  284. package/dist/indexer/build-cache/module-cache.js.map +1 -1
  285. package/dist/indexer/build-cache/options.d.ts +3 -1
  286. package/dist/indexer/build-cache/options.d.ts.map +1 -1
  287. package/dist/indexer/build-cache/options.js +10 -2
  288. package/dist/indexer/build-cache/options.js.map +1 -1
  289. package/dist/indexer/build-cache/project-snapshot.d.ts +33 -13
  290. package/dist/indexer/build-cache/project-snapshot.d.ts.map +1 -1
  291. package/dist/indexer/build-cache/project-snapshot.js +472 -91
  292. package/dist/indexer/build-cache/project-snapshot.js.map +1 -1
  293. package/dist/indexer/build-cache/reports.d.ts.map +1 -1
  294. package/dist/indexer/build-cache/reports.js +10 -1
  295. package/dist/indexer/build-cache/reports.js.map +1 -1
  296. package/dist/indexer/build-cache/resolver-environment.d.ts +9 -0
  297. package/dist/indexer/build-cache/resolver-environment.d.ts.map +1 -0
  298. package/dist/indexer/build-cache/resolver-environment.js +160 -0
  299. package/dist/indexer/build-cache/resolver-environment.js.map +1 -0
  300. package/dist/indexer/build-cache.d.ts +4 -3
  301. package/dist/indexer/build-cache.d.ts.map +1 -1
  302. package/dist/indexer/build-cache.js +4 -3
  303. package/dist/indexer/build-cache.js.map +1 -1
  304. package/dist/indexer/build-index.d.ts.map +1 -1
  305. package/dist/indexer/build-index.js +268 -96
  306. package/dist/indexer/build-index.js.map +1 -1
  307. package/dist/indexer/build-manifest.d.ts +1 -0
  308. package/dist/indexer/build-manifest.d.ts.map +1 -1
  309. package/dist/indexer/build-manifest.js +15 -5
  310. package/dist/indexer/build-manifest.js.map +1 -1
  311. package/dist/indexer/build-workers.d.ts +1 -1
  312. package/dist/indexer/build-workers.d.ts.map +1 -1
  313. package/dist/indexer/build-workers.js +57 -42
  314. package/dist/indexer/build-workers.js.map +1 -1
  315. package/dist/indexer/call-hierarchy.d.ts.map +1 -1
  316. package/dist/indexer/call-hierarchy.js.map +1 -1
  317. package/dist/indexer/finalize.d.ts.map +1 -1
  318. package/dist/indexer/finalize.js +7 -4
  319. package/dist/indexer/finalize.js.map +1 -1
  320. package/dist/indexer/import-types.d.ts +8 -0
  321. package/dist/indexer/import-types.d.ts.map +1 -1
  322. package/dist/indexer/imports/jsTextImports.d.ts.map +1 -1
  323. package/dist/indexer/imports/jsTextImports.js +14 -6
  324. package/dist/indexer/imports/jsTextImports.js.map +1 -1
  325. package/dist/indexer/imports/languageSpecific.d.ts.map +1 -1
  326. package/dist/indexer/imports/languageSpecific.js +10 -5
  327. package/dist/indexer/imports/languageSpecific.js.map +1 -1
  328. package/dist/indexer/imports/nativeCaptures.d.ts.map +1 -1
  329. package/dist/indexer/imports/nativeCaptures.js +4 -1
  330. package/dist/indexer/imports/nativeCaptures.js.map +1 -1
  331. package/dist/indexer/imports/python.d.ts.map +1 -1
  332. package/dist/indexer/imports/python.js +19 -9
  333. package/dist/indexer/imports/python.js.map +1 -1
  334. package/dist/indexer/incremental-plan.d.ts +2 -1
  335. package/dist/indexer/incremental-plan.d.ts.map +1 -1
  336. package/dist/indexer/incremental-plan.js +7 -4
  337. package/dist/indexer/incremental-plan.js.map +1 -1
  338. package/dist/indexer/load-current-index.d.ts.map +1 -1
  339. package/dist/indexer/load-current-index.js.map +1 -1
  340. package/dist/indexer/locals-and-exports.d.ts.map +1 -1
  341. package/dist/indexer/locals-and-exports.js +77 -22
  342. package/dist/indexer/locals-and-exports.js.map +1 -1
  343. package/dist/indexer/navigation-goto.d.ts.map +1 -1
  344. package/dist/indexer/navigation-goto.js +26 -16
  345. package/dist/indexer/navigation-goto.js.map +1 -1
  346. package/dist/indexer/navigation-local.d.ts.map +1 -1
  347. package/dist/indexer/navigation-local.js +7 -4
  348. package/dist/indexer/navigation-local.js.map +1 -1
  349. package/dist/indexer/navigation-references.d.ts +1 -1
  350. package/dist/indexer/navigation-references.d.ts.map +1 -1
  351. package/dist/indexer/navigation-references.js +34 -17
  352. package/dist/indexer/navigation-references.js.map +1 -1
  353. package/dist/indexer/navigation-resolve.d.ts.map +1 -1
  354. package/dist/indexer/navigation-resolve.js +116 -53
  355. package/dist/indexer/navigation-resolve.js.map +1 -1
  356. package/dist/indexer/navigation.d.ts +2 -1
  357. package/dist/indexer/navigation.d.ts.map +1 -1
  358. package/dist/indexer/navigation.js +34 -20
  359. package/dist/indexer/navigation.js.map +1 -1
  360. package/dist/indexer/parse-context.d.ts +2 -2
  361. package/dist/indexer/parse-context.d.ts.map +1 -1
  362. package/dist/indexer/parse-context.js +25 -4
  363. package/dist/indexer/parse-context.js.map +1 -1
  364. package/dist/indexer/reference-context.d.ts +2 -2
  365. package/dist/indexer/reference-context.d.ts.map +1 -1
  366. package/dist/indexer/reference-context.js +4 -2
  367. package/dist/indexer/reference-context.js.map +1 -1
  368. package/dist/indexer/scope-types.d.ts +3 -0
  369. package/dist/indexer/scope-types.d.ts.map +1 -1
  370. package/dist/indexer/scope.js +37 -38
  371. package/dist/indexer/scope.js.map +1 -1
  372. package/dist/indexer/shared.d.ts.map +1 -1
  373. package/dist/indexer/shared.js +3 -1
  374. package/dist/indexer/shared.js.map +1 -1
  375. package/dist/indexer/type-hierarchy.d.ts.map +1 -1
  376. package/dist/indexer/type-hierarchy.js +12 -8
  377. package/dist/indexer/type-hierarchy.js.map +1 -1
  378. package/dist/indexer/types.d.ts +27 -1
  379. package/dist/indexer/types.d.ts.map +1 -1
  380. package/dist/indexer/workspace-symbols.d.ts.map +1 -1
  381. package/dist/indexer/workspace-symbols.js +5 -3
  382. package/dist/indexer/workspace-symbols.js.map +1 -1
  383. package/dist/installer/locks.d.ts +10 -0
  384. package/dist/installer/locks.d.ts.map +1 -0
  385. package/dist/installer/locks.js +232 -0
  386. package/dist/installer/locks.js.map +1 -0
  387. package/dist/installer/registry.d.ts.map +1 -1
  388. package/dist/installer/registry.js +75 -235
  389. package/dist/installer/registry.js.map +1 -1
  390. package/dist/languages/definitions/csharp.d.ts.map +1 -1
  391. package/dist/languages/definitions/csharp.js +8 -0
  392. package/dist/languages/definitions/csharp.js.map +1 -1
  393. package/dist/languages/definitions/java.d.ts.map +1 -1
  394. package/dist/languages/definitions/java.js +3 -0
  395. package/dist/languages/definitions/java.js.map +1 -1
  396. package/dist/languages/definitions/python.d.ts.map +1 -1
  397. package/dist/languages/definitions/python.js +2 -0
  398. package/dist/languages/definitions/python.js.map +1 -1
  399. package/dist/languages/definitions/rust.d.ts.map +1 -1
  400. package/dist/languages/definitions/rust.js +2 -0
  401. package/dist/languages/definitions/rust.js.map +1 -1
  402. package/dist/languages/importStatementParsers.d.ts +2 -0
  403. package/dist/languages/importStatementParsers.d.ts.map +1 -1
  404. package/dist/languages/importStatementParsers.js +24 -10
  405. package/dist/languages/importStatementParsers.js.map +1 -1
  406. package/dist/mcp/http.d.ts +3 -1
  407. package/dist/mcp/http.d.ts.map +1 -1
  408. package/dist/mcp/http.js +69 -20
  409. package/dist/mcp/http.js.map +1 -1
  410. package/dist/mcp/server.d.ts +58 -16
  411. package/dist/mcp/server.d.ts.map +1 -1
  412. package/dist/mcp/server.js +447 -140
  413. package/dist/mcp/server.js.map +1 -1
  414. package/dist/mcp/tools.d.ts +51 -1
  415. package/dist/mcp/tools.d.ts.map +1 -1
  416. package/dist/mcp/tools.js +129 -3
  417. package/dist/mcp/tools.js.map +1 -1
  418. package/dist/native/byteIndex.d.ts +26 -0
  419. package/dist/native/byteIndex.d.ts.map +1 -0
  420. package/dist/native/byteIndex.js +70 -0
  421. package/dist/native/byteIndex.js.map +1 -0
  422. package/dist/native/projectedTree.d.ts +3 -2
  423. package/dist/native/projectedTree.d.ts.map +1 -1
  424. package/dist/native/projectedTree.js +6 -50
  425. package/dist/native/projectedTree.js.map +1 -1
  426. package/dist/native/queryResults.d.ts +7 -1
  427. package/dist/native/queryResults.d.ts.map +1 -1
  428. package/dist/native/queryResults.js +13 -5
  429. package/dist/native/queryResults.js.map +1 -1
  430. package/dist/review/candidates.d.ts.map +1 -1
  431. package/dist/review/candidates.js +4 -1
  432. package/dist/review/candidates.js.map +1 -1
  433. package/dist/review/changes.d.ts +2 -0
  434. package/dist/review/changes.d.ts.map +1 -1
  435. package/dist/review/changes.js +10 -0
  436. package/dist/review/changes.js.map +1 -1
  437. package/dist/review/deleted.d.ts.map +1 -1
  438. package/dist/review/deleted.js +20 -2
  439. package/dist/review/deleted.js.map +1 -1
  440. package/dist/review/summaries.d.ts +5 -0
  441. package/dist/review/summaries.d.ts.map +1 -1
  442. package/dist/review/summaries.js +32 -21
  443. package/dist/review/summaries.js.map +1 -1
  444. package/dist/review/types.d.ts +3 -1
  445. package/dist/review/types.d.ts.map +1 -1
  446. package/dist/review/types.js +8 -1
  447. package/dist/review/types.js.map +1 -1
  448. package/dist/review.d.ts.map +1 -1
  449. package/dist/review.js +14 -5
  450. package/dist/review.js.map +1 -1
  451. package/dist/session.d.ts +20 -4
  452. package/dist/session.d.ts.map +1 -1
  453. package/dist/session.js +76 -16
  454. package/dist/session.js.map +1 -1
  455. package/dist/sql/types.d.ts.map +1 -1
  456. package/dist/sqlite/query.d.ts +29 -0
  457. package/dist/sqlite/query.d.ts.map +1 -1
  458. package/dist/sqlite/query.js +98 -11
  459. package/dist/sqlite/query.js.map +1 -1
  460. package/dist/sqlite/rawQueryWorker.d.ts +22 -0
  461. package/dist/sqlite/rawQueryWorker.d.ts.map +1 -0
  462. package/dist/sqlite/rawQueryWorker.js +31 -0
  463. package/dist/sqlite/rawQueryWorker.js.map +1 -0
  464. package/dist/sqlite/rawQueryWorkerPool.d.ts +66 -0
  465. package/dist/sqlite/rawQueryWorkerPool.d.ts.map +1 -0
  466. package/dist/sqlite/rawQueryWorkerPool.js +142 -0
  467. package/dist/sqlite/rawQueryWorkerPool.js.map +1 -0
  468. package/dist/sqlite/schema.d.ts +2 -1
  469. package/dist/sqlite/schema.d.ts.map +1 -1
  470. package/dist/sqlite/schema.js +15 -1
  471. package/dist/sqlite/schema.js.map +1 -1
  472. package/dist/sqlite/write.d.ts.map +1 -1
  473. package/dist/sqlite/write.js +15 -0
  474. package/dist/sqlite/write.js.map +1 -1
  475. package/dist/sqlite-driver.d.ts +11 -0
  476. package/dist/sqlite-driver.d.ts.map +1 -1
  477. package/dist/sqlite-driver.js +28 -2
  478. package/dist/sqlite-driver.js.map +1 -1
  479. package/dist/sqlite.d.ts +1 -1
  480. package/dist/sqlite.d.ts.map +1 -1
  481. package/dist/sqlite.js +1 -1
  482. package/dist/sqlite.js.map +1 -1
  483. package/dist/util/bloomFilter.d.ts +3 -2
  484. package/dist/util/bloomFilter.d.ts.map +1 -1
  485. package/dist/util/bloomFilter.js +8 -8
  486. package/dist/util/bloomFilter.js.map +1 -1
  487. package/dist/util/concurrency.d.ts +1 -0
  488. package/dist/util/concurrency.d.ts.map +1 -1
  489. package/dist/util/concurrency.js +9 -2
  490. package/dist/util/concurrency.js.map +1 -1
  491. package/dist/util/confinedFile.d.ts +42 -2
  492. package/dist/util/confinedFile.d.ts.map +1 -1
  493. package/dist/util/confinedFile.js +114 -3
  494. package/dist/util/confinedFile.js.map +1 -1
  495. package/dist/util/errors.d.ts +2 -0
  496. package/dist/util/errors.d.ts.map +1 -1
  497. package/dist/util/errors.js +18 -0
  498. package/dist/util/errors.js.map +1 -1
  499. package/dist/util/git.d.ts +2 -0
  500. package/dist/util/git.d.ts.map +1 -1
  501. package/dist/util/git.js +174 -26
  502. package/dist/util/git.js.map +1 -1
  503. package/dist/util/identifiers.d.ts +75 -0
  504. package/dist/util/identifiers.d.ts.map +1 -0
  505. package/dist/util/identifiers.js +82 -0
  506. package/dist/util/identifiers.js.map +1 -0
  507. package/dist/util/paths.d.ts.map +1 -1
  508. package/dist/util/paths.js +45 -9
  509. package/dist/util/paths.js.map +1 -1
  510. package/dist/util/projectFiles.d.ts.map +1 -1
  511. package/dist/util/projectFiles.js +43 -14
  512. package/dist/util/projectFiles.js.map +1 -1
  513. package/dist/util/resolution/jvm.d.ts.map +1 -1
  514. package/dist/util/resolution/jvm.js +20 -9
  515. package/dist/util/resolution/jvm.js.map +1 -1
  516. package/dist/util/resolution/php.d.ts.map +1 -1
  517. package/dist/util/resolution/php.js +6 -5
  518. package/dist/util/resolution/php.js.map +1 -1
  519. package/dist/util/resolution/tsconfig.d.ts.map +1 -1
  520. package/dist/util/resolution/tsconfig.js +26 -12
  521. package/dist/util/resolution/tsconfig.js.map +1 -1
  522. package/dist/util/rustTestModules.d.ts.map +1 -1
  523. package/dist/util/rustTestModules.js +4 -2
  524. package/dist/util/rustTestModules.js.map +1 -1
  525. package/dist/util/specifiers.d.ts.map +1 -1
  526. package/dist/util/specifiers.js +10 -3
  527. package/dist/util/specifiers.js.map +1 -1
  528. package/dist/util/sqliteSchema.d.ts.map +1 -1
  529. package/dist/util/sqliteSchema.js +10 -1
  530. package/dist/util/sqliteSchema.js.map +1 -1
  531. package/dist/worker/nativeExtractWorker.d.ts +4 -2
  532. package/dist/worker/nativeExtractWorker.d.ts.map +1 -1
  533. package/dist/worker/nativeExtractWorker.js +12 -11
  534. package/dist/worker/nativeExtractWorker.js.map +1 -1
  535. package/docs/mcp.md +35 -14
  536. package/package.json +3 -3
@@ -1,9 +1,11 @@
1
1
  import { randomUUID } from "node:crypto";
2
+ import { AsyncLocalStorage } from "node:async_hooks";
2
3
  import fs from "node:fs/promises";
3
4
  import { createServer } from "node:http";
4
5
  import path from "node:path";
5
- import { createMcpHandler, isInitializeRequest, isLegacyRequest, Server, } from "@modelcontextprotocol/server";
6
- import { serveStdio } from "@modelcontextprotocol/server/stdio";
6
+ import { Transform } from "node:stream";
7
+ import { createMcpHandler, isInitializeRequest, isLegacyRequest, ProtocolError, ProtocolErrorCode, Server, } from "@modelcontextprotocol/server";
8
+ import { StdioServerTransport, serveStdio } from "@modelcontextprotocol/server/stdio";
7
9
  import { NodeStreamableHTTPServerTransport, originValidation, toNodeHandler, toWebRequest, } from "@modelcontextprotocol/node";
8
10
  import { z } from "zod";
9
11
  import { buildCodegraphArtifactWithSession } from "../agent/artifact.js";
@@ -12,7 +14,7 @@ import { getCodegraphFileViewWithSession, MAX_FILE_VIEW_BYTES, MAX_FILE_VIEW_LIN
12
14
  import { exploreCodegraphWithSession } from "../agent/explore.js";
13
15
  import { orientCodegraphWithSession } from "../agent/orient.js";
14
16
  import { getCodegraphPacketWithSession } from "../agent/packet.js";
15
- import { searchCodegraphWithSession } from "../agent/search.js";
17
+ import { MAX_GRAPH_DEPTH, searchCodegraphWithSession } from "../agent/search.js";
16
18
  import { workspaceSymbolsWithSession } from "../agent/workspaceSymbols.js";
17
19
  import { findImplementationsWithSession, findSubtypesWithSession, findSupertypesWithSession, } from "../agent/typeHierarchy.js";
18
20
  import { findCalleesWithSession, findCallersWithSession } from "../agent/callHierarchy.js";
@@ -28,16 +30,17 @@ import { DEFAULT_BOUNDED_IMPACT_BUDGETS } from "../impact/budgets.js";
28
30
  import { buildReviewReport } from "../review.js";
29
31
  import { boundReviewReportForTransport } from "../review/types.js";
30
32
  import { SQLITE_ARTIFACT_FILE_SIGNATURES_METADATA_KEY, queryGraphSqliteRaw } from "../sqlite.js";
33
+ import { boundList, countOmitted } from "../presentation/bounds.js";
31
34
  import { isPlainRecord } from "../util/guards.js";
32
35
  import { toProjectDisplayPath } from "../util/paths.js";
33
36
  import { errorMessage } from "../util/errors.js";
34
- import { createAgentSession, listAgentSessionFiles } from "../agent/session.js";
37
+ import { assertNoPrebuiltSessionWithBuildOptions, createAgentSession, listAgentSessionFiles, } from "../agent/session.js";
35
38
  import { mapLimit } from "../util/concurrency.js";
36
39
  import { assertRealPathCandidateWithinRoot, resolveProjectFile } from "../util/confinedFile.js";
37
40
  import { SymbolKind } from "../indexer/types.js";
38
41
  import { DEFAULT_WORKSPACE_SYMBOL_LIMIT, MAX_WORKSPACE_SYMBOL_LIMIT } from "../indexer/workspace-symbols.js";
39
- import { assertMcpSqliteQueryResourceBounded, boundRawSqlResult, DEFAULT_SQLITE_BYTE_LIMIT, normalizeSqliteRowLimit, } from "./sqliteGuard.js";
40
- import { DEFAULT_CALL_HIERARCHY_LIMIT, MAX_CALL_HIERARCHY_LIMIT, DEFAULT_MCP_COLLECTION_LIMIT, DEFAULT_TYPE_HIERARCHY_LIMIT, listCodegraphMcpTools, MAX_TYPE_HIERARCHY_LIMIT, MAX_MCP_COLLECTION_LIMIT, MAX_RENAME_PREVIEW_EDITS, MCP_TOOLS, MAX_REFACTOR_PLAN_LIMIT, } from "./tools.js";
42
+ import { assertMcpSqliteQueryResourceBounded, DEFAULT_SQLITE_BYTE_LIMIT, normalizeSqliteRowLimit, } from "./sqliteGuard.js";
43
+ import { DEFAULT_CALL_HIERARCHY_LIMIT, MAX_CALL_HIERARCHY_LIMIT, DEFAULT_MCP_COLLECTION_LIMIT, DEFAULT_TYPE_HIERARCHY_LIMIT, listCodegraphMcpTools, MAX_TYPE_HIERARCHY_LIMIT, MAX_MCP_COLLECTION_LIMIT, MAX_RENAME_PREVIEW_EDITS, MCP_TOOL_REGISTRY, MAX_REFACTOR_PLAN_LIMIT, } from "./tools.js";
41
44
  import { buildAllowedHostHeaders, buildAllowedOriginHostnames, closeHttpServer, emptyAllowedHostHeaderRules, formatHostForUrl, getHeaderValue, getHttpServerPort, getRequestPath, isAllowedHostHeader, listenOnHttpServer, readJsonRequestBody, waitForHttpServerClose, writeJsonResponse, writeJsonRpcError, } from "./http.js";
42
45
  import { getCurrentNativeBindingOrigin } from "../native/runtime.js";
43
46
  import { captureCodegraphRuntimeIdentity, createInstalledVersionChecker, } from "../runtimeIdentity.js";
@@ -47,12 +50,35 @@ import { awaitStdioMcpLifecycle, DEFAULT_MCP_STDIO_IDLE_TIMEOUT_MS } from "./std
47
50
  export const DEFAULT_MCP_HTTP_SESSION_IDLE_MS = 30 * 60 * 1000;
48
51
  export const DEFAULT_MCP_HTTP_SESSION_MAX_COUNT = 32;
49
52
  export const DEFAULT_MCP_HTTP_SESSION_EVICTION_INTERVAL_MS = 60_000;
53
+ export const DEFAULT_MCP_HTTP_BODY_TIMEOUT_MS = 30_000;
54
+ export const DEFAULT_MCP_TOOL_TIMEOUT_MS = 30 * 60 * 1000;
55
+ const MAX_MCP_HTTP_BODY_TIMEOUT_MS = 2_147_483_647;
56
+ const MAX_MCP_STDIO_FRAME_BYTES = 10 * 1024 * 1024;
57
+ const MAX_MCP_TOOL_TIMEOUT_MS = 2_147_483_647;
58
+ export const DEFAULT_MCP_TOOL_CONCURRENCY = 4;
59
+ function normalizeMcpToolConcurrency(value) {
60
+ if (!Number.isFinite(value))
61
+ return DEFAULT_MCP_TOOL_CONCURRENCY;
62
+ return Math.max(1, Math.floor(value));
63
+ }
64
+ function assertMcpHttpBodyTimeout(value) {
65
+ if (!Number.isSafeInteger(value) || value < 1 || value > MAX_MCP_HTTP_BODY_TIMEOUT_MS) {
66
+ throw new RangeError(`httpBodyTimeoutMs must be a positive integer no greater than ${MAX_MCP_HTTP_BODY_TIMEOUT_MS}.`);
67
+ }
68
+ return value;
69
+ }
70
+ function assertMcpToolTimeout(value) {
71
+ if (!Number.isSafeInteger(value) || value < 0 || value > MAX_MCP_TOOL_TIMEOUT_MS) {
72
+ throw new RangeError(`mcpToolTimeoutMs must be a whole number from 0 through ${MAX_MCP_TOOL_TIMEOUT_MS}; 0 disables the deadline.`);
73
+ }
74
+ return value;
75
+ }
76
+ const legacyRequestAbortStorage = new AsyncLocalStorage();
50
77
  const MAX_MCP_FRESHNESS_CHANGED_FILES = 25;
78
+ const MAX_MCP_FRESHNESS_RETRIES = 3;
51
79
  const SQLITE_ARTIFACT_STAT_CONCURRENCY = 64;
52
80
  function assertMcpSessionOptions(options) {
53
- if (options.session !== undefined && options.buildOptions !== undefined) {
54
- throw new Error("MCP server options cannot combine a prebuilt session with buildOptions.");
55
- }
81
+ assertNoPrebuiltSessionWithBuildOptions(options, "MCP server options");
56
82
  }
57
83
  function createCodegraphMcpSession(options, root) {
58
84
  assertMcpSessionOptions(options);
@@ -72,7 +98,7 @@ function startCodegraphMcpWarmup(session, warmup) {
72
98
  }
73
99
  return undefined;
74
100
  }
75
- async function createWarmedCodegraphMcpHandlers(options) {
101
+ async function createWarmedCodegraphMcpResources(options) {
76
102
  const root = path.resolve(options.root);
77
103
  const session = createCodegraphMcpSession(options, root);
78
104
  await startCodegraphMcpWarmup(session, options.warmup);
@@ -81,7 +107,10 @@ async function createWarmedCodegraphMcpHandlers(options) {
81
107
  void host;
82
108
  void port;
83
109
  void onHttpListen;
84
- return createCodegraphMcpHandlersForSession({ ...handlerOptions, root }, session);
110
+ return {
111
+ handlers: createCodegraphMcpHandlersForSession({ ...handlerOptions, root }, session),
112
+ session,
113
+ };
85
114
  }
86
115
  const MCP_HTTP_PATH = "/mcp";
87
116
  const MAX_MCP_HTTP_BODY_BYTES = 1_000_000;
@@ -102,6 +131,24 @@ function createCodegraphMcpHandlersForSession(options, session) {
102
131
  let sqlitePath = configuredSqlitePath;
103
132
  let sqliteOutDir = configuredSqliteOutDir;
104
133
  let sqliteCanRefresh = configuredSqliteCanRefresh;
134
+ let refreshPromise;
135
+ let refreshEpoch = 0;
136
+ let artifactWritePromise;
137
+ const withArtifactWriteLock = async (operation) => {
138
+ const previous = artifactWritePromise;
139
+ const complete = Promise.withResolvers();
140
+ artifactWritePromise = complete.promise;
141
+ try {
142
+ if (previous)
143
+ await previous.catch(() => undefined);
144
+ return await operation();
145
+ }
146
+ finally {
147
+ complete.resolve();
148
+ if (artifactWritePromise === complete.promise)
149
+ artifactWritePromise = undefined;
150
+ }
151
+ };
105
152
  const relative = (file) => toProjectDisplayPath(root, file);
106
153
  const boundedLimit = (limit, fallback, max) => {
107
154
  if (typeof limit !== "number" || !Number.isFinite(limit))
@@ -115,7 +162,7 @@ function createCodegraphMcpHandlersForSession(options, session) {
115
162
  state: "stale",
116
163
  changedFiles: boundedChangedFiles,
117
164
  changedFileCount: changedFiles.length,
118
- omittedChangedFileCount: Math.max(0, changedFiles.length - boundedChangedFiles.length),
165
+ omittedChangedFileCount: countOmitted(changedFiles.length, boundedChangedFiles.length),
119
166
  reason,
120
167
  };
121
168
  };
@@ -125,9 +172,16 @@ function createCodegraphMcpHandlersForSession(options, session) {
125
172
  return { state: "fresh" };
126
173
  };
127
174
  const withFreshness = async (run) => {
128
- const freshness = await checkMcpFreshness();
129
- const result = await run();
130
- return { ...result, freshness };
175
+ for (let attempt = 0; attempt < MAX_MCP_FRESHNESS_RETRIES; attempt += 1) {
176
+ if (refreshPromise)
177
+ await refreshPromise;
178
+ const epoch = refreshEpoch;
179
+ const freshness = await checkMcpFreshness();
180
+ const result = await run();
181
+ if (epoch === refreshEpoch && !refreshPromise)
182
+ return { ...result, freshness };
183
+ }
184
+ throw new Error("Workspace refresh changed repeatedly while serving the request; retry after refresh completes.");
131
185
  };
132
186
  const formatSqliteFreshnessError = (freshness) => {
133
187
  if (freshness.state === "fresh")
@@ -151,7 +205,7 @@ function createCodegraphMcpHandlersForSession(options, session) {
151
205
  return false;
152
206
  return path.basename(sqlitePath) === "codegraph.sqlite";
153
207
  };
154
- const rebuildSqliteArtifactForQuery = async () => {
208
+ const rebuildSqliteArtifactForQuery = async () => await withArtifactWriteLock(async () => {
155
209
  if (!sqliteOutDir)
156
210
  throw new Error("SQLite artifact output directory is unavailable.");
157
211
  const outDir = await assertWritableDirectoryRealPathWithinRoot(await realRoot, root, sqliteOutDir, "Artifact output directory");
@@ -167,7 +221,7 @@ function createCodegraphMcpHandlersForSession(options, session) {
167
221
  throw new Error("SQLite artifact refresh did not produce a SQLite file.");
168
222
  sqlitePath = path.join(result.outDir, sqliteArtifact);
169
223
  sqliteOutDir = result.outDir;
170
- };
224
+ });
171
225
  const refreshSqliteArtifactForQuery = async (freshness, refreshOptions) => {
172
226
  if (freshness.state === "fresh")
173
227
  return freshness;
@@ -286,7 +340,7 @@ function createCodegraphMcpHandlersForSession(options, session) {
286
340
  // Probe one entry past the display limit so `truncated` is exact
287
341
  // rather than a `results.length === limit` heuristic (which cannot
288
342
  // tell "exactly limit reachable files" apart from "more exist"),
289
- // without re-walking the whole reachable graph for an exact total
343
+ // without re-walking the whole reachable graph for an exact total -
290
344
  // see finding #44.
291
345
  limit: limit + 1,
292
346
  };
@@ -302,13 +356,18 @@ function createCodegraphMcpHandlersForSession(options, session) {
302
356
  targetFile = await resolveProjectFile(await realRoot, root, request.file);
303
357
  }
304
358
  const collected = collectEntries(snapshot.fileGraph, targetFile, queryOptions);
305
- const totalSeen = collected.length;
306
- const truncated = totalSeen > limit;
307
- const entries = collected.slice(0, limit).map((dependency) => ({
359
+ const { items, omitted } = boundList(collected, limit);
360
+ const entries = items.map((dependency) => ({
308
361
  file: relative(dependency.file),
309
362
  depth: dependency.depth,
310
363
  }));
311
- return { entries, limit, totalSeen, truncated, omitted: truncated ? totalSeen - limit : 0 };
364
+ return {
365
+ entries,
366
+ limit,
367
+ totalSeen: collected.length,
368
+ truncated: Boolean(omitted),
369
+ omitted,
370
+ };
312
371
  };
313
372
  const calls = async (request) => {
314
373
  const findCalls = request.direction === "callers" ? findCallersWithSession : findCalleesWithSession;
@@ -333,12 +392,15 @@ function createCodegraphMcpHandlersForSession(options, session) {
333
392
  if (result.status !== "ok") {
334
393
  return { references: [], limit, totalSeen: 0, truncated: false, omitted: 0 };
335
394
  }
336
- const totalSeen = result.references.length;
337
- const truncated = totalSeen > limit;
338
- const references = result.references
339
- .slice(0, limit)
340
- .map((reference) => ({ file: relative(reference.file), range: reference.range }));
341
- return { references, limit, totalSeen, truncated, omitted: truncated ? totalSeen - limit : 0 };
395
+ const { items, omitted } = boundList(result.references, limit);
396
+ const references = items.map((reference) => ({ file: relative(reference.file), range: reference.range }));
397
+ return {
398
+ references,
399
+ limit,
400
+ totalSeen: result.references.length,
401
+ truncated: Boolean(omitted),
402
+ omitted,
403
+ };
342
404
  };
343
405
  const fileDeps = async (request) => await withFreshness(async () => {
344
406
  const { entries, ...meta } = await collectMcpDependencyEntries(request, request.direction === "deps" ? getDependencies : getReverseDependencies);
@@ -458,7 +520,7 @@ function createCodegraphMcpHandlersForSession(options, session) {
458
520
  if (parseQualifiedSymbolPath(handle)) {
459
521
  const snapshot = await session.loadProject({ symbolGraph: "skip" });
460
522
  const resolved = requireSemanticSymbol(snapshot, handle);
461
- // Probe one reference past the display limit so `truncated` is exact see
523
+ // Probe one reference past the display limit so `truncated` is exact - see
462
524
  // `collectMcpDependencyEntries` for the rationale (finding #44).
463
525
  const result = await findReferences(snapshot.index, { def: resolved.def }, { maxReferences: limit + 1 });
464
526
  return boundedReferencesFromResult(result, limit);
@@ -534,7 +596,7 @@ function createCodegraphMcpHandlersForSession(options, session) {
534
596
  // complete, unbounded report should call `buildReviewReport` directly.
535
597
  return boundReviewReportForTransport(report);
536
598
  }),
537
- query_sqlite: async (request) => {
599
+ query_sqlite: async (request, executionOptions) => {
538
600
  if (!sqlitePath) {
539
601
  throw new Error("No SQLite artifact is available. Run artifact_build first or pass artifactPath.");
540
602
  }
@@ -555,19 +617,35 @@ function createCodegraphMcpHandlersForSession(options, session) {
555
617
  }
556
618
  const result = await queryGraphSqliteRaw(realSqlitePath, request.query, request.params ?? [], {
557
619
  maxRows: normalizeSqliteRowLimit(request.limit),
620
+ maxBytes: DEFAULT_SQLITE_BYTE_LIMIT,
621
+ ...(executionOptions?.signal ? { signal: executionOptions.signal } : {}),
558
622
  });
559
- return { ...boundRawSqlResult(result, DEFAULT_SQLITE_BYTE_LIMIT), freshness: artifactFreshness };
623
+ return { ...result, truncated: Boolean(result.truncated), freshness: artifactFreshness };
560
624
  },
561
- refresh_index: async (request) => {
625
+ refresh_index: async (request) => await withArtifactWriteLock(async () => {
562
626
  const warmup = request.warmup ?? "off";
563
- session.invalidate();
564
- sqlitePath = configuredSqlitePath;
565
- sqliteOutDir = configuredSqliteOutDir;
566
- sqliteCanRefresh = configuredSqliteCanRefresh;
567
- await startCodegraphMcpWarmup(session, warmup);
627
+ const previousRefresh = refreshPromise;
628
+ const refresh = (async () => {
629
+ if (previousRefresh)
630
+ await previousRefresh.catch(() => undefined);
631
+ ++refreshEpoch;
632
+ session.invalidate();
633
+ sqlitePath = configuredSqlitePath;
634
+ sqliteOutDir = configuredSqliteOutDir;
635
+ sqliteCanRefresh = configuredSqliteCanRefresh;
636
+ await startCodegraphMcpWarmup(session, warmup);
637
+ })();
638
+ refreshPromise = refresh;
639
+ try {
640
+ await refresh;
641
+ }
642
+ finally {
643
+ if (refreshPromise === refresh)
644
+ refreshPromise = undefined;
645
+ }
568
646
  return { refreshed: true, warmup };
569
- },
570
- artifact_build: async (request) => {
647
+ }),
648
+ artifact_build: async (request) => await withArtifactWriteLock(async () => {
571
649
  if (readOnly) {
572
650
  throw new Error("artifact_build is disabled in read-only MCP mode.");
573
651
  }
@@ -599,18 +677,60 @@ function createCodegraphMcpHandlersForSession(options, session) {
599
677
  sqliteCanRefresh = true;
600
678
  }
601
679
  return { ...result, freshness };
680
+ }),
681
+ };
682
+ }
683
+ function createMcpToolOperationTracker() {
684
+ let accepting = true;
685
+ const operations = new Set();
686
+ return {
687
+ isAccepting: () => accepting,
688
+ track: (operation) => {
689
+ if (!accepting)
690
+ return undefined;
691
+ const tracked = operation();
692
+ operations.add(tracked);
693
+ void tracked.then(() => operations.delete(tracked), () => operations.delete(tracked));
694
+ return tracked;
695
+ },
696
+ stop: () => {
697
+ accepting = false;
698
+ },
699
+ drain: async () => {
700
+ accepting = false;
701
+ await Promise.allSettled([...operations]);
602
702
  },
603
703
  };
604
704
  }
605
- export function createCodegraphMcpProtocolServer(handlers, runtimeIdentity = captureCodegraphRuntimeIdentity(getCurrentNativeBindingOrigin()), installedVersion = createInstalledVersionChecker(runtimeIdentity), toolCallState = { firstToolCallPending: true }) {
705
+ function createMcpToolConcurrencyTracker(maximum) {
706
+ return { inFlight: 0, maximum: normalizeMcpToolConcurrency(maximum) };
707
+ }
708
+ export function createCodegraphMcpProtocolServer(handlers, runtimeIdentity = captureCodegraphRuntimeIdentity(getCurrentNativeBindingOrigin()), installedVersion = createInstalledVersionChecker(runtimeIdentity), toolCallState = { firstToolCallPending: true }, maxConcurrentToolCalls = DEFAULT_MCP_TOOL_CONCURRENCY, mcpToolTimeoutMs = DEFAULT_MCP_TOOL_TIMEOUT_MS) {
709
+ return createCodegraphMcpProtocolServerWithTracker(handlers, runtimeIdentity, installedVersion, toolCallState, assertMcpToolTimeout(mcpToolTimeoutMs), createMcpToolOperationTracker(), createMcpToolConcurrencyTracker(maxConcurrentToolCalls));
710
+ }
711
+ export function createCodegraphMcpProtocolServerWithTracker(handlers, runtimeIdentity, installedVersion, toolCallState, mcpToolTimeoutMs, toolOperations, toolConcurrency) {
606
712
  const server = new Server({
607
713
  name: "codegraph",
608
714
  version: runtimeIdentity.runningVersion,
609
715
  }, {
610
716
  capabilities: { tools: {}, logging: {} },
611
717
  });
612
- server.setRequestHandler("tools/list", () => ({ tools: MCP_TOOLS }));
718
+ const activeToolCalls = new Map();
719
+ server.setNotificationHandler("notifications/cancelled", (notification) => {
720
+ const requestId = notification.params.requestId;
721
+ if (requestId !== undefined) {
722
+ activeToolCalls.get(requestId)?.abort(new Error("MCP tool call was cancelled."));
723
+ }
724
+ });
725
+ server.setRequestHandler("tools/list", () => ({ tools: listCodegraphMcpTools() }));
613
726
  server.setRequestHandler("tools/call", async (request, ctx) => {
727
+ if (!toolOperations.isAccepting()) {
728
+ throw new Error("MCP server is shutting down.");
729
+ }
730
+ if (toolConcurrency.inFlight >= toolConcurrency.maximum) {
731
+ throw new Error("MCP tool execution is busy; retry shortly.");
732
+ }
733
+ toolConcurrency.inFlight += 1;
614
734
  const isFirstToolCall = toolCallState.firstToolCallPending;
615
735
  toolCallState.firstToolCallPending = false;
616
736
  const progressToken = isFirstToolCall ? getToolCallProgressToken(request.params) : undefined;
@@ -622,12 +742,7 @@ export function createCodegraphMcpProtocolServer(handlers, runtimeIdentity = cap
622
742
  if (progressToken !== undefined) {
623
743
  await ctx.mcpReq.notify({
624
744
  method: "notifications/progress",
625
- params: {
626
- progressToken,
627
- progress,
628
- total: 1,
629
- message,
630
- },
745
+ params: { progressToken, progress, total: 1, message },
631
746
  });
632
747
  }
633
748
  }
@@ -643,9 +758,32 @@ export function createCodegraphMcpProtocolServer(handlers, runtimeIdentity = cap
643
758
  console.error(`[codegraph] installed-version check failed: ${errorMessage(error)}`);
644
759
  }
645
760
  try {
646
- const result = await callMcpTool(handlers, request.params.name, request.params.arguments ?? {});
647
- await emitFirstToolCallVisibility("info", 1, `Codegraph finished warming the first tool call for '${request.params.name}'.`);
648
- return toToolResult(result);
761
+ const toolCallAbort = createMcpToolAbortSignal([ctx.mcpReq.signal, legacyRequestAbortStorage.getStore()], request.params.name, mcpToolTimeoutMs);
762
+ activeToolCalls.set(ctx.mcpReq.id, toolCallAbort);
763
+ try {
764
+ const operation = toolOperations.track(() => callMcpTool(handlers, request.params.name, request.params.arguments ?? {}, toolCallAbort.signal));
765
+ if (operation === undefined) {
766
+ toolConcurrency.inFlight -= 1;
767
+ throw new Error("MCP server is shutting down.");
768
+ }
769
+ const releaseToolCall = () => {
770
+ toolConcurrency.inFlight -= 1;
771
+ };
772
+ try {
773
+ const result = await awaitMcpToolOperation(toolCallAbort.signal, operation, releaseToolCall);
774
+ await emitFirstToolCallVisibility("info", 1, `Codegraph finished warming the first tool call for '${request.params.name}'.`);
775
+ return toToolResult(result);
776
+ }
777
+ catch (error) {
778
+ if (error instanceof ProtocolError || toolCallAbort.signal.aborted)
779
+ throw error;
780
+ return toToolErrorResult(error);
781
+ }
782
+ }
783
+ finally {
784
+ activeToolCalls.delete(ctx.mcpReq.id);
785
+ toolCallAbort.dispose();
786
+ }
649
787
  }
650
788
  catch (error) {
651
789
  await emitFirstToolCallVisibility("error", 1, `Codegraph failed while warming the first tool call for '${request.params.name}'.`);
@@ -654,12 +792,71 @@ export function createCodegraphMcpProtocolServer(handlers, runtimeIdentity = cap
654
792
  });
655
793
  return server;
656
794
  }
657
- function createCodegraphMcpProtocolFactory(handlers, runtimeIdentity) {
795
+ function createCodegraphMcpProtocolFactory(handlers, runtimeIdentity, maxConcurrentToolCalls = DEFAULT_MCP_TOOL_CONCURRENCY, mcpToolTimeoutMs = DEFAULT_MCP_TOOL_TIMEOUT_MS) {
796
+ const toolConcurrency = createMcpToolConcurrencyTracker(maxConcurrentToolCalls);
658
797
  const installedVersion = createInstalledVersionChecker(runtimeIdentity);
659
798
  const toolCallState = { firstToolCallPending: true };
660
- return () => createCodegraphMcpProtocolServer(handlers, runtimeIdentity, installedVersion, toolCallState);
799
+ const toolOperations = createMcpToolOperationTracker();
800
+ const timeout = assertMcpToolTimeout(mcpToolTimeoutMs);
801
+ return {
802
+ create: () => createCodegraphMcpProtocolServerWithTracker(handlers, runtimeIdentity, installedVersion, toolCallState, timeout, toolOperations, toolConcurrency),
803
+ stop: () => toolOperations.stop(),
804
+ drain: () => toolOperations.drain(),
805
+ };
806
+ }
807
+ export function createParseErrorReportingStdin(input, output) {
808
+ let pending = Buffer.alloc(0);
809
+ const processFrame = (rawFrame, stream) => {
810
+ const frame = rawFrame.at(-1) === 13 ? rawFrame.subarray(0, -1) : rawFrame;
811
+ if (!frame.length)
812
+ return;
813
+ if (frame.length > MAX_MCP_STDIO_FRAME_BYTES) {
814
+ return new Error("MCP stdio frame exceeded 10 MiB.");
815
+ }
816
+ try {
817
+ JSON.parse(frame.toString("utf8"));
818
+ stream.push(frame);
819
+ stream.push("\n");
820
+ }
821
+ catch {
822
+ output.write(`${JSON.stringify({
823
+ jsonrpc: "2.0",
824
+ id: null,
825
+ error: { code: ProtocolErrorCode.ParseError, message: "Parse error" },
826
+ })}\n`);
827
+ }
828
+ };
829
+ const filter = new Transform({
830
+ transform(chunk, _encoding, callback) {
831
+ pending = Buffer.concat([pending, chunk]);
832
+ let newline = pending.indexOf(10);
833
+ while (newline >= 0) {
834
+ const error = processFrame(pending.subarray(0, newline), this);
835
+ pending = pending.subarray(newline + 1);
836
+ if (error !== undefined) {
837
+ callback(error);
838
+ return;
839
+ }
840
+ newline = pending.indexOf(10);
841
+ }
842
+ if (pending.length > MAX_MCP_STDIO_FRAME_BYTES) {
843
+ callback(new Error("MCP stdio frame exceeded 10 MiB."));
844
+ return;
845
+ }
846
+ callback();
847
+ },
848
+ flush(callback) {
849
+ const error = processFrame(pending, this);
850
+ pending = Buffer.alloc(0);
851
+ callback(error);
852
+ },
853
+ });
854
+ input.pipe(filter);
855
+ return filter;
661
856
  }
662
857
  export async function serveCodegraphMcp(options) {
858
+ const configuredMcpToolTimeout = options.mcpToolTimeoutMs === undefined ? DEFAULT_MCP_TOOL_TIMEOUT_MS : options.mcpToolTimeoutMs;
859
+ const mcpToolTimeoutMs = assertMcpToolTimeout(configuredMcpToolTimeout);
663
860
  const port = options.port;
664
861
  if (port !== undefined) {
665
862
  const started = await startCodegraphMcpHttpServer({ ...options, port });
@@ -671,36 +868,47 @@ export async function serveCodegraphMcp(options) {
671
868
  await waitForHttpServerClose(started.server);
672
869
  return;
673
870
  }
674
- const handlers = await createWarmedCodegraphMcpHandlers(options);
871
+ const { handlers, session } = await createWarmedCodegraphMcpResources(options);
675
872
  const runtimeIdentity = options.runtimeIdentity ?? captureCodegraphRuntimeIdentity(getCurrentNativeBindingOrigin());
676
- const createProtocolServer = createCodegraphMcpProtocolFactory(handlers, runtimeIdentity);
677
- const handle = serveStdio(createProtocolServer, {
873
+ const protocolFactory = createCodegraphMcpProtocolFactory(handlers, runtimeIdentity, options.mcpToolConcurrency ?? DEFAULT_MCP_TOOL_CONCURRENCY, mcpToolTimeoutMs);
874
+ const transport = new StdioServerTransport(createParseErrorReportingStdin(process.stdin, process.stdout), process.stdout, { maxBufferSize: MAX_MCP_STDIO_FRAME_BYTES });
875
+ const handle = serveStdio(protocolFactory.create, {
876
+ transport,
678
877
  legacy: "serve",
679
878
  onerror: (error) => {
680
879
  console.error(`[codegraph] MCP stdio error: ${error.message}`);
681
880
  },
682
881
  });
683
882
  const idleTimeoutMs = options.idleTimeoutMs ?? DEFAULT_MCP_STDIO_IDLE_TIMEOUT_MS;
684
- await awaitStdioMcpLifecycle(handle, {
685
- idleTimeoutMs,
686
- onShutdown: (shutdownReason) => {
687
- console.error(`[codegraph] MCP stdio shutting down (${shutdownReason})`);
688
- },
689
- });
690
- // Ensure orphaned stdio servers do not linger after the client is gone.
883
+ try {
884
+ await awaitStdioMcpLifecycle(handle, {
885
+ idleTimeoutMs,
886
+ onShutdown: (shutdownReason) => {
887
+ console.error(`[codegraph] MCP stdio shutting down (${shutdownReason})`);
888
+ },
889
+ });
890
+ }
891
+ finally {
892
+ protocolFactory.stop();
893
+ await protocolFactory.drain();
894
+ session.invalidate();
895
+ }
691
896
  process.exitCode = 0;
692
897
  }
693
898
  export async function startCodegraphMcpHttpServer(options) {
899
+ const httpBodyTimeoutMs = assertMcpHttpBodyTimeout(options.httpBodyTimeoutMs === undefined ? DEFAULT_MCP_HTTP_BODY_TIMEOUT_MS : options.httpBodyTimeoutMs);
900
+ const configuredMcpToolTimeout = options.mcpToolTimeoutMs === undefined ? DEFAULT_MCP_TOOL_TIMEOUT_MS : options.mcpToolTimeoutMs;
901
+ const mcpToolTimeoutMs = assertMcpToolTimeout(configuredMcpToolTimeout);
694
902
  const host = options.host ?? "127.0.0.1";
695
- const handlers = await createWarmedCodegraphMcpHandlers(options);
903
+ const { handlers, session } = await createWarmedCodegraphMcpResources(options);
696
904
  const runtimeIdentity = options.runtimeIdentity ?? captureCodegraphRuntimeIdentity(getCurrentNativeBindingOrigin());
697
- const createProtocolServer = createCodegraphMcpProtocolFactory(handlers, runtimeIdentity);
905
+ const protocolFactory = createCodegraphMcpProtocolFactory(handlers, runtimeIdentity, options.mcpToolConcurrency ?? DEFAULT_MCP_TOOL_CONCURRENCY, mcpToolTimeoutMs);
698
906
  const sessionStore = createLegacyMcpSessionStore({
699
907
  idleMs: options.httpSessionIdleMs ?? DEFAULT_MCP_HTTP_SESSION_IDLE_MS,
700
908
  maxCount: options.httpSessionMaxCount ?? DEFAULT_MCP_HTTP_SESSION_MAX_COUNT,
701
909
  evictionIntervalMs: options.httpSessionEvictionIntervalMs ?? DEFAULT_MCP_HTTP_SESSION_EVICTION_INTERVAL_MS,
702
910
  });
703
- const modernHandler = createMcpHandler(createProtocolServer, {
911
+ const modernHandler = createMcpHandler(protocolFactory.create, {
704
912
  legacy: "reject",
705
913
  onerror: (error) => {
706
914
  console.error(`[codegraph] MCP HTTP error: ${error.message}`);
@@ -716,18 +924,31 @@ export async function startCodegraphMcpHttpServer(options) {
716
924
  let closeResourcesPromise;
717
925
  const closeResources = () => {
718
926
  closeResourcesPromise ??= (async () => {
927
+ protocolFactory.stop();
719
928
  sessionStore.stop();
720
- await closeMcpResources(sessionStore.sessions, modernHandler.close);
929
+ try {
930
+ await closeMcpResources(sessionStore.sessions, modernHandler.close);
931
+ }
932
+ finally {
933
+ await protocolFactory.drain();
934
+ session.invalidate();
935
+ }
721
936
  })();
722
937
  return closeResourcesPromise;
723
938
  };
724
939
  const server = createServer((request, response) => {
725
- void handleMcpHttpRequest(request, response, sessionStore, () => allowedHostHeaders, validateOrigin, modernNodeHandler, createProtocolServer);
940
+ void handleMcpHttpRequest(request, response, sessionStore, () => allowedHostHeaders, validateOrigin, modernNodeHandler, protocolFactory.create, httpBodyTimeoutMs);
726
941
  });
727
942
  server.on("close", () => {
728
943
  void closeResources();
729
944
  });
730
- await listenOnHttpServer(server, options.port, host);
945
+ try {
946
+ await listenOnHttpServer(server, options.port, host);
947
+ }
948
+ catch (error) {
949
+ await closeResources();
950
+ throw error;
951
+ }
731
952
  const address = server.address();
732
953
  const actualPort = getHttpServerPort(address);
733
954
  const urlHost = formatHostForUrl(host);
@@ -747,7 +968,11 @@ export async function startCodegraphMcpHttpServer(options) {
747
968
  },
748
969
  };
749
970
  }
750
- async function handleMcpHttpRequest(request, response, sessionStore, getAllowedHostHeaders, validateOrigin, modernNodeHandler, createProtocolServer) {
971
+ async function handleMcpHttpRequest(request, response, sessionStore, getAllowedHostHeaders, validateOrigin, modernNodeHandler, createProtocolServer, bodyTimeoutMs) {
972
+ const writeClosingJsonRpcError = (statusCode, message) => {
973
+ response.setHeader("connection", "close");
974
+ writeJsonRpcError(response, statusCode, message);
975
+ };
751
976
  const requestPath = getRequestPath(request);
752
977
  if (requestPath !== MCP_HTTP_PATH) {
753
978
  writeJsonResponse(response, 404, { error: "Not found" });
@@ -761,11 +986,15 @@ async function handleMcpHttpRequest(request, response, sessionStore, getAllowedH
761
986
  return;
762
987
  try {
763
988
  if (request.method === "POST") {
764
- const parsedBody = await readJsonRequestBody(request, MAX_MCP_HTTP_BODY_BYTES);
989
+ const parsedBody = await readJsonRequestBody(request, MAX_MCP_HTTP_BODY_BYTES, bodyTimeoutMs);
765
990
  if (parsedBody.status === "too_large") {
766
991
  writeJsonRpcError(response, 413, "MCP request body is too large");
767
992
  return;
768
993
  }
994
+ if (parsedBody.status === "timeout") {
995
+ writeClosingJsonRpcError(408, "MCP request body timed out");
996
+ return;
997
+ }
769
998
  if (parsedBody.status === "invalid_json") {
770
999
  writeJsonRpcError(response, 400, "Invalid JSON request body");
771
1000
  return;
@@ -805,13 +1034,7 @@ async function handleLegacyMcpHttpPost(request, response, body, sessionStore, cr
805
1034
  return;
806
1035
  }
807
1036
  sessionStore.touch(sessionId);
808
- try {
809
- await handleLegacyMcpSessionRequest(session, request, response, body);
810
- }
811
- catch (error) {
812
- await sessionStore.delete(sessionId);
813
- throw error;
814
- }
1037
+ await handleLegacyMcpSessionRequest(session, request, response, body);
815
1038
  return;
816
1039
  }
817
1040
  if (!isInitializeRequest(body)) {
@@ -859,10 +1082,16 @@ async function handleLegacyMcpHttpPost(request, response, body, sessionStore, cr
859
1082
  openSseStreams: 0,
860
1083
  };
861
1084
  sessionRef.current = session;
1085
+ // The SDK transport reports every per-request validation rejection through onerror
1086
+ // too (bad Accept header, wrong Content-Type, malformed JSON, an unsupported
1087
+ // protocol version, ...) - each of those already answered its own request with a
1088
+ // 4xx response and left the transport fully usable. Deleting the session here would
1089
+ // tear down an otherwise healthy session over one malformed follow-up request. Only
1090
+ // onclose reflects the transport actually shutting down (an explicit DELETE, an
1091
+ // eviction we triggered, or a real fatal failure), so session teardown is driven by
1092
+ // onclose alone; onerror only logs.
862
1093
  transport.onerror = (error) => {
863
1094
  console.error(`[codegraph] MCP HTTP session transport error: ${error.message}`);
864
- if (initializedSessionId !== undefined)
865
- void sessionStore.delete(initializedSessionId);
866
1095
  };
867
1096
  transport.onclose = () => {
868
1097
  if (initializedSessionId !== undefined)
@@ -871,6 +1100,14 @@ async function handleLegacyMcpHttpPost(request, response, body, sessionStore, cr
871
1100
  try {
872
1101
  await protocolServer.connect(transport);
873
1102
  await handleLegacyMcpSessionRequest(session, request, response, body);
1103
+ if (initializedSessionId === undefined) {
1104
+ // The transport answered a pre-session 4xx (invalid Accept header, wrong
1105
+ // Content-Type, malformed JSON, ...) without throwing and without ever reaching
1106
+ // onsessioninitialized, so nothing else releases this capacity reservation or
1107
+ // closes this ad hoc protocol server/transport pair.
1108
+ releaseCapacityReservation();
1109
+ await closeMcpSession(session);
1110
+ }
874
1111
  }
875
1112
  catch (error) {
876
1113
  if (initializedSessionId !== undefined) {
@@ -895,12 +1132,33 @@ async function handleExistingMcpSessionRequest(request, response, sessionStore)
895
1132
  return;
896
1133
  }
897
1134
  sessionStore.touch(sessionId);
1135
+ await handleLegacyMcpSessionRequest(session, request, response);
1136
+ }
1137
+ /**
1138
+ * Runs one legacy HTTP request with a signal that aborts when its connection closes.
1139
+ * The signal is scoped to this request and is available to nested MCP tool dispatch.
1140
+ */
1141
+ export async function runWithLegacyRequestAbortSignal(request, response, operation) {
1142
+ const abortController = new AbortController();
1143
+ let completed = false;
1144
+ const abortDisconnectedRequest = () => {
1145
+ if (completed)
1146
+ return;
1147
+ if (request.aborted || (!response.writableFinished && response.destroyed)) {
1148
+ abortController.abort(new Error("MCP HTTP request connection closed."));
1149
+ }
1150
+ };
1151
+ request.on("aborted", abortDisconnectedRequest);
1152
+ request.on("close", abortDisconnectedRequest);
1153
+ response.on("close", abortDisconnectedRequest);
898
1154
  try {
899
- await handleLegacyMcpSessionRequest(session, request, response);
1155
+ return await legacyRequestAbortStorage.run(abortController.signal, operation);
900
1156
  }
901
- catch (error) {
902
- await sessionStore.delete(sessionId);
903
- throw error;
1157
+ finally {
1158
+ completed = true;
1159
+ request.off("aborted", abortDisconnectedRequest);
1160
+ request.off("close", abortDisconnectedRequest);
1161
+ response.off("close", abortDisconnectedRequest);
904
1162
  }
905
1163
  }
906
1164
  async function handleLegacyMcpSessionRequest(session, request, response, body) {
@@ -909,12 +1167,15 @@ async function handleLegacyMcpSessionRequest(session, request, response, body) {
909
1167
  if (tracksSseStream)
910
1168
  session.openSseStreams += 1;
911
1169
  try {
912
- await session.transport.handleRequest(request, response, body);
1170
+ await runWithLegacyRequestAbortSignal(request, response, async () => {
1171
+ await session.transport.handleRequest(request, response, body);
1172
+ });
913
1173
  }
914
1174
  finally {
915
1175
  session.inFlightRequests -= 1;
916
1176
  if (tracksSseStream)
917
1177
  session.openSseStreams -= 1;
1178
+ session.lastActivityAt = Date.now();
918
1179
  }
919
1180
  }
920
1181
  function isLegacySseRequest(request) {
@@ -1019,98 +1280,140 @@ async function closeMcpResources(sessions, closeModernHandler) {
1019
1280
  function isMcpNodeRequest(request) {
1020
1281
  return request.method !== undefined && request.url !== undefined;
1021
1282
  }
1022
- async function callMcpTool(handlers, name, input) {
1023
- switch (name) {
1283
+ function createMcpToolAbortSignal(requestSignals, toolName, timeoutMs) {
1284
+ const controller = new AbortController();
1285
+ const listeners = [];
1286
+ for (const requestSignal of requestSignals) {
1287
+ if (requestSignal === undefined)
1288
+ continue;
1289
+ const onAbort = () => {
1290
+ controller.abort(requestSignal.reason);
1291
+ };
1292
+ listeners.push({ signal: requestSignal, onAbort });
1293
+ if (requestSignal.aborted)
1294
+ onAbort();
1295
+ else
1296
+ requestSignal.addEventListener("abort", onAbort, { once: true });
1297
+ }
1298
+ const timeout = timeoutMs > 0
1299
+ ? setTimeout(() => {
1300
+ controller.abort(new Error(`MCP tool '${toolName}' exceeded the configured deadline of ${timeoutMs} ms.`));
1301
+ }, timeoutMs)
1302
+ : undefined;
1303
+ timeout?.unref?.();
1304
+ return {
1305
+ signal: controller.signal,
1306
+ abort: (reason) => controller.abort(reason),
1307
+ dispose: () => {
1308
+ clearTimeout(timeout);
1309
+ for (const listener of listeners)
1310
+ listener.signal.removeEventListener("abort", listener.onAbort);
1311
+ },
1312
+ };
1313
+ }
1314
+ export function awaitMcpToolOperation(signal, operation, onSettled) {
1315
+ void operation.then(onSettled, onSettled);
1316
+ return withAbortSignal(signal, operation);
1317
+ }
1318
+ function withAbortSignal(signal, operation) {
1319
+ if (!signal)
1320
+ return operation;
1321
+ const cancellationError = () => {
1322
+ const reason = signal.reason;
1323
+ if (reason instanceof Error && reason.name !== "AbortError")
1324
+ return reason;
1325
+ return new Error("MCP tool call was cancelled.");
1326
+ };
1327
+ if (signal.aborted)
1328
+ return Promise.reject(cancellationError());
1329
+ const cancellation = Promise.withResolvers();
1330
+ const onAbort = () => cancellation.reject(cancellationError());
1331
+ signal.addEventListener("abort", onAbort, { once: true });
1332
+ return Promise.race([operation, cancellation.promise]).finally(() => signal.removeEventListener("abort", onAbort));
1333
+ }
1334
+ export async function callMcpTool(handlers, name, input, signal) {
1335
+ const tool = MCP_TOOL_REGISTRY.find((entry) => entry.name === name);
1336
+ if (!tool)
1337
+ throw new ProtocolError(ProtocolErrorCode.MethodNotFound, `Unknown MCP tool: ${name}`);
1338
+ switch (tool.dispatch.handler) {
1024
1339
  case "search":
1025
- return await handlers.search(parseMcpToolInput(searchSchema, input, "search"));
1340
+ return await handlers.search(parseMcpToolInput(searchSchema, input, name), signal);
1026
1341
  case "workspace_symbols":
1027
- return await handlers.workspace_symbols(parseMcpToolInput(workspaceSymbolsSchema, input, "workspace_symbols"));
1342
+ return await handlers.workspace_symbols(parseMcpToolInput(workspaceSymbolsSchema, input, name), signal);
1028
1343
  case "rename_preview":
1029
- return await handlers.rename_preview(parseMcpToolInput(renamePreviewSchema, input, "rename_preview"));
1344
+ return await handlers.rename_preview(parseMcpToolInput(renamePreviewSchema, input, name), signal);
1030
1345
  case "refactor_plan":
1031
- return await handlers.refactor_plan(parseMcpToolInput(refactorPlanSchema, input, "refactor_plan"));
1346
+ return await handlers.refactor_plan(parseMcpToolInput(refactorPlanSchema, input, name), signal);
1032
1347
  case "calls":
1033
- return await handlers.calls(parseMcpToolInput(callsSchema, input, "calls"));
1034
- case "callers":
1035
- return await handlers.calls({ ...parseMcpToolInput(callHierarchySchema, input, name), direction: "callers" });
1036
- case "callees":
1037
- return await handlers.calls({ ...parseMcpToolInput(callHierarchySchema, input, name), direction: "callees" });
1348
+ if (tool.dispatch.direction) {
1349
+ return await handlers.calls({ ...parseMcpToolInput(callHierarchySchema, input, name), direction: tool.dispatch.direction }, signal);
1350
+ }
1351
+ return await handlers.calls(parseMcpToolInput(callsSchema, input, name), signal);
1038
1352
  case "type_hierarchy":
1039
- return await handlers.type_hierarchy(parseMcpToolInput(typeHierarchyUnifiedSchema, input, "type_hierarchy"));
1040
- case "supertypes":
1041
- return await handlers.type_hierarchy({
1042
- ...parseMcpToolInput(typeHierarchySchema, input, name),
1043
- direction: "supertypes",
1044
- });
1045
- case "subtypes":
1046
- return await handlers.type_hierarchy({
1047
- ...parseMcpToolInput(typeHierarchySchema, input, name),
1048
- direction: "subtypes",
1049
- });
1353
+ if (tool.dispatch.direction) {
1354
+ return await handlers.type_hierarchy({ ...parseMcpToolInput(typeHierarchySchema, input, name), direction: tool.dispatch.direction }, signal);
1355
+ }
1356
+ return await handlers.type_hierarchy(parseMcpToolInput(typeHierarchyUnifiedSchema, input, name), signal);
1050
1357
  case "implementations":
1051
- return await handlers.implementations(parseMcpToolInput(implementationsSchema, input, "implementations"));
1358
+ return await handlers.implementations(parseMcpToolInput(implementationsSchema, input, name), signal);
1052
1359
  case "explore":
1053
- return await handlers.explore(parseMcpToolInput(exploreSchema, input, "explore"));
1360
+ return await handlers.explore(parseMcpToolInput(exploreSchema, input, name), signal);
1054
1361
  case "orient":
1055
- return await handlers.orient(parseMcpToolInput(orientSchema, input, "orient"));
1362
+ return await handlers.orient(parseMcpToolInput(orientSchema, input, name), signal);
1056
1363
  case "packet_get":
1057
- return await handlers.packet_get(parseMcpToolInput(packetGetSchema, input, "packet_get"));
1364
+ return await handlers.packet_get(parseMcpToolInput(packetGetSchema, input, name), signal);
1058
1365
  case "get_file":
1059
- return await handlers.get_file(parseMcpToolInput(getFileSchema, input, "get_file"));
1366
+ return await handlers.get_file(parseMcpToolInput(getFileSchema, input, name), signal);
1060
1367
  case "get_symbol":
1061
- return await handlers.get_symbol(parseMcpToolInput(handleSchema, input, "get_symbol"));
1368
+ return await handlers.get_symbol(parseMcpToolInput(handleSchema, input, name), signal);
1062
1369
  case "goto":
1063
- return await callGotoTool(handlers, input);
1370
+ return await callGotoTool(handlers, input, signal);
1064
1371
  case "refs":
1065
- return await callRefsTool(handlers, input);
1372
+ return await callRefsTool(handlers, input, signal);
1066
1373
  case "file_deps":
1067
- return await handlers.file_deps(parseMcpToolInput(fileDepsUnifiedSchema, input, "file_deps"));
1068
- case "deps":
1069
- return await handlers.file_deps({ ...parseMcpToolInput(fileGraphSchema, input, name), direction: "deps" });
1070
- case "rdeps":
1071
- return await handlers.file_deps({ ...parseMcpToolInput(fileGraphSchema, input, name), direction: "rdeps" });
1374
+ if (tool.dispatch.direction) {
1375
+ return await handlers.file_deps({ ...parseMcpToolInput(fileGraphSchema, input, name), direction: tool.dispatch.direction }, signal);
1376
+ }
1377
+ return await handlers.file_deps(parseMcpToolInput(fileDepsUnifiedSchema, input, name), signal);
1072
1378
  case "path":
1073
- return await handlers.path(parseMcpToolInput(pathSchema, input, "path"));
1379
+ return await handlers.path(parseMcpToolInput(pathSchema, input, name), signal);
1074
1380
  case "impact":
1075
- return await handlers.impact(parseMcpToolInput(gitRangeSchema, input, name));
1381
+ return await handlers.impact(parseMcpToolInput(gitRangeSchema, input, name), signal);
1076
1382
  case "review":
1077
- return await handlers.review(parseMcpToolInput(reviewSchema, input, "review"));
1383
+ return await handlers.review(parseMcpToolInput(reviewSchema, input, name), signal);
1078
1384
  case "query_sqlite":
1079
- return await handlers.query_sqlite(parseMcpToolInput(querySqliteSchema, input, "query_sqlite"));
1385
+ return await handlers.query_sqlite(parseMcpToolInput(querySqliteSchema, input, name), {
1386
+ ...(signal ? { signal } : {}),
1387
+ });
1080
1388
  case "refresh_index":
1081
- return await handlers.refresh_index(parseMcpToolInput(refreshIndexSchema, input, "refresh_index"));
1389
+ return await handlers.refresh_index(parseMcpToolInput(refreshIndexSchema, input, name), signal);
1082
1390
  case "artifact_build":
1083
- return await handlers.artifact_build(parseMcpToolInput(artifactBuildSchema, input, "artifact_build"));
1084
- default:
1085
- throw new Error(`Unknown MCP tool: ${name}`);
1391
+ return await handlers.artifact_build(parseMcpToolInput(artifactBuildSchema, input, name), signal);
1086
1392
  }
1087
1393
  }
1088
- async function callGotoTool(handlers, input) {
1394
+ async function callGotoTool(handlers, input, signal) {
1089
1395
  const request = parseMcpToolInput(navigationSchema, input, "goto");
1090
1396
  if (request.handle !== undefined)
1091
- return await handlers.goto({ handle: request.handle });
1397
+ return await handlers.goto({ handle: request.handle }, signal);
1092
1398
  if (request.file === undefined || request.line === undefined || request.column === undefined) {
1093
- throw new Error("goto requires either handle or file, line, and column.");
1399
+ throw new ProtocolError(ProtocolErrorCode.InvalidParams, "goto requires either handle or file, line, and column.");
1094
1400
  }
1095
- return await handlers.goto({ file: request.file, line: request.line, column: request.column });
1401
+ return await handlers.goto({ file: request.file, line: request.line, column: request.column }, signal);
1096
1402
  }
1097
- async function callRefsTool(handlers, input) {
1403
+ async function callRefsTool(handlers, input, signal) {
1098
1404
  const request = parseMcpToolInput(refsSchema, input, "refs");
1099
1405
  if (request.handle !== undefined) {
1100
- return await handlers.refs({
1101
- handle: request.handle,
1102
- ...(request.limit !== undefined ? { limit: request.limit } : {}),
1103
- });
1406
+ return await handlers.refs({ handle: request.handle, ...(request.limit !== undefined ? { limit: request.limit } : {}) }, signal);
1104
1407
  }
1105
1408
  if (request.file === undefined || request.line === undefined || request.column === undefined) {
1106
- throw new Error("refs requires either handle or file, line, and column.");
1409
+ throw new ProtocolError(ProtocolErrorCode.InvalidParams, "refs requires either handle or file, line, and column.");
1107
1410
  }
1108
1411
  return await handlers.refs({
1109
1412
  file: request.file,
1110
1413
  line: request.line,
1111
1414
  column: request.column,
1112
1415
  ...(request.limit !== undefined ? { limit: request.limit } : {}),
1113
- });
1416
+ }, signal);
1114
1417
  }
1115
1418
  function toToolResult(value) {
1116
1419
  return {
@@ -1122,6 +1425,10 @@ function toToolResult(value) {
1122
1425
  ],
1123
1426
  };
1124
1427
  }
1428
+ function toToolErrorResult(error) {
1429
+ const message = errorMessage(error).replace(/(?:[A-Za-z]:)?[/\\][^'"\n]*?(?=(?:[/\\][^'"\n]*)?['"]|$)/g, "<path>");
1430
+ return { isError: true, content: [{ type: "text", text: message }] };
1431
+ }
1125
1432
  const mcpProgressTokenSchema = z.union([z.string(), z.number()]);
1126
1433
  const toolCallMetaSchema = z
1127
1434
  .object({
@@ -1148,14 +1455,14 @@ function parseMcpToolInput(schema, input, toolName) {
1148
1455
  const parsed = schema.safeParse(input);
1149
1456
  if (parsed.success)
1150
1457
  return parsed.data;
1151
- throw new Error(formatMcpInvalidParams(toolName, parsed.error));
1458
+ throw new ProtocolError(ProtocolErrorCode.InvalidParams, formatMcpInvalidParams(toolName, parsed.error));
1152
1459
  }
1153
1460
  const searchSchema = z
1154
1461
  .object({
1155
1462
  query: z.string(),
1156
1463
  mode: z.enum(["hybrid", "symbol", "path", "text", "graph", "sql"]).optional(),
1157
1464
  from: z.string().optional(),
1158
- depth: z.number().int().nonnegative().optional(),
1465
+ depth: z.number().int().nonnegative().max(MAX_GRAPH_DEPTH).optional(),
1159
1466
  limit: z.number().int().nonnegative().optional(),
1160
1467
  })
1161
1468
  .strict();