@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.
- package/README.md +27 -29
- package/codegraph-skill/codegraph/SKILL.md +27 -26
- package/dist/agent/artifact.d.ts.map +1 -1
- package/dist/agent/artifact.js +105 -14
- package/dist/agent/artifact.js.map +1 -1
- package/dist/agent/candidateTests.d.ts +12 -0
- package/dist/agent/candidateTests.d.ts.map +1 -0
- package/dist/agent/candidateTests.js +17 -0
- package/dist/agent/candidateTests.js.map +1 -0
- package/dist/agent/explain.d.ts +3 -0
- package/dist/agent/explain.d.ts.map +1 -1
- package/dist/agent/explain.js +8 -0
- package/dist/agent/explain.js.map +1 -1
- package/dist/agent/explore.d.ts.map +1 -1
- package/dist/agent/explore.js +11 -6
- package/dist/agent/explore.js.map +1 -1
- package/dist/agent/fileView.d.ts.map +1 -1
- package/dist/agent/fileView.js +113 -120
- package/dist/agent/fileView.js.map +1 -1
- package/dist/agent/orient.d.ts.map +1 -1
- package/dist/agent/orient.js +7 -4
- package/dist/agent/orient.js.map +1 -1
- package/dist/agent/packet.d.ts.map +1 -1
- package/dist/agent/packet.js +5 -12
- package/dist/agent/packet.js.map +1 -1
- package/dist/agent/query-index/candidates.d.ts +13 -2
- package/dist/agent/query-index/candidates.d.ts.map +1 -1
- package/dist/agent/query-index/candidates.js +28 -39
- package/dist/agent/query-index/candidates.js.map +1 -1
- package/dist/agent/query-index/content.d.ts +1 -1
- package/dist/agent/query-index/content.js +4 -4
- package/dist/agent/query-index/content.js.map +1 -1
- package/dist/agent/query-index/schema.d.ts.map +1 -1
- package/dist/agent/query-index/schema.js.map +1 -1
- package/dist/agent/query-index/sessionStore.d.ts.map +1 -1
- package/dist/agent/query-index/sessionStore.js +42 -26
- package/dist/agent/query-index/sessionStore.js.map +1 -1
- package/dist/agent/query-index/store.d.ts +10 -4
- package/dist/agent/query-index/store.d.ts.map +1 -1
- package/dist/agent/query-index/store.js +115 -10
- package/dist/agent/query-index/store.js.map +1 -1
- package/dist/agent/query-index/update.d.ts.map +1 -1
- package/dist/agent/query-index/update.js +24 -9
- package/dist/agent/query-index/update.js.map +1 -1
- package/dist/agent/refactorPlan.d.ts.map +1 -1
- package/dist/agent/refactorPlan.js +6 -14
- package/dist/agent/refactorPlan.js.map +1 -1
- package/dist/agent/renamePreview.d.ts +2 -5
- package/dist/agent/renamePreview.d.ts.map +1 -1
- package/dist/agent/renamePreview.js +133 -80
- package/dist/agent/renamePreview.js.map +1 -1
- package/dist/agent/search.d.ts +3 -1
- package/dist/agent/search.d.ts.map +1 -1
- package/dist/agent/search.js +103 -35
- package/dist/agent/search.js.map +1 -1
- package/dist/agent/semanticSymbols.d.ts.map +1 -1
- package/dist/agent/semanticSymbols.js +2 -1
- package/dist/agent/semanticSymbols.js.map +1 -1
- package/dist/agent/session.d.ts +4 -0
- package/dist/agent/session.d.ts.map +1 -1
- package/dist/agent/session.js +20 -7
- package/dist/agent/session.js.map +1 -1
- package/dist/agent-tools.d.ts +1 -1
- package/dist/agent-tools.d.ts.map +1 -1
- package/dist/agent-tools.js +12 -21
- package/dist/agent-tools.js.map +1 -1
- package/dist/bin/cli.js +29242 -25373
- package/dist/bin/queryIndexWorker.js +131 -42
- package/dist/bin/rawQueryWorker.js +270 -0
- package/dist/chunking/chunkFile.d.ts +5 -0
- package/dist/chunking/chunkFile.d.ts.map +1 -1
- package/dist/chunking/chunkFile.js +14 -15
- package/dist/chunking/chunkFile.js.map +1 -1
- package/dist/cli/affected.d.ts.map +1 -1
- package/dist/cli/affected.js +17 -10
- package/dist/cli/affected.js.map +1 -1
- package/dist/cli/callHierarchy.d.ts.map +1 -1
- package/dist/cli/callHierarchy.js +9 -2
- package/dist/cli/callHierarchy.js.map +1 -1
- package/dist/cli/commandTable.d.ts.map +1 -1
- package/dist/cli/commandTable.js +16 -4
- package/dist/cli/commandTable.js.map +1 -1
- package/dist/cli/doctor.d.ts +7 -0
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +166 -0
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/graph.d.ts +2 -1
- package/dist/cli/graph.d.ts.map +1 -1
- package/dist/cli/graph.js +60 -16
- package/dist/cli/graph.js.map +1 -1
- package/dist/cli/graphDelta.d.ts +2 -1
- package/dist/cli/graphDelta.d.ts.map +1 -1
- package/dist/cli/graphDelta.js +5 -0
- package/dist/cli/graphDelta.js.map +1 -1
- package/dist/cli/grep.d.ts +1 -1
- package/dist/cli/grep.d.ts.map +1 -1
- package/dist/cli/grep.js +14 -4
- package/dist/cli/grep.js.map +1 -1
- package/dist/cli/help.d.ts +34 -34
- package/dist/cli/help.d.ts.map +1 -1
- package/dist/cli/help.js +17 -8
- package/dist/cli/help.js.map +1 -1
- package/dist/cli/impact.d.ts +2 -1
- package/dist/cli/impact.d.ts.map +1 -1
- package/dist/cli/impact.js +5 -0
- package/dist/cli/impact.js.map +1 -1
- package/dist/cli/index.d.ts +2 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +3 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/indexPolicy.d.ts.map +1 -1
- package/dist/cli/indexPolicy.js.map +1 -1
- package/dist/cli/inspect.d.ts +2 -1
- package/dist/cli/inspect.d.ts.map +1 -1
- package/dist/cli/inspect.js +25 -13
- package/dist/cli/inspect.js.map +1 -1
- package/dist/cli/install.js +1 -1
- package/dist/cli/install.js.map +1 -1
- package/dist/cli/invocationContext.d.ts.map +1 -1
- package/dist/cli/invocationContext.js +3 -0
- package/dist/cli/invocationContext.js.map +1 -1
- package/dist/cli/links.d.ts +2 -0
- package/dist/cli/links.d.ts.map +1 -1
- package/dist/cli/links.js +1 -1
- package/dist/cli/links.js.map +1 -1
- package/dist/cli/navigation.d.ts +41 -1
- package/dist/cli/navigation.d.ts.map +1 -1
- package/dist/cli/navigation.js +4 -1
- package/dist/cli/navigation.js.map +1 -1
- package/dist/cli/options.d.ts.map +1 -1
- package/dist/cli/options.js +32 -11
- package/dist/cli/options.js.map +1 -1
- package/dist/cli/renamePreview.d.ts.map +1 -1
- package/dist/cli/renamePreview.js +7 -1
- package/dist/cli/renamePreview.js.map +1 -1
- package/dist/cli/review.d.ts +2 -1
- package/dist/cli/review.d.ts.map +1 -1
- package/dist/cli/review.js +5 -0
- package/dist/cli/review.js.map +1 -1
- package/dist/cli/rootPolicy.d.ts.map +1 -1
- package/dist/cli/rootPolicy.js +36 -3
- package/dist/cli/rootPolicy.js.map +1 -1
- package/dist/cli/skill.js +2 -2
- package/dist/cli/skill.js.map +1 -1
- package/dist/cli/sql.js +1 -1
- package/dist/cli/symbols.d.ts.map +1 -1
- package/dist/cli/symbols.js +4 -2
- package/dist/cli/symbols.js.map +1 -1
- package/dist/cli/viewer.d.ts.map +1 -1
- package/dist/cli/viewer.js +46 -34
- package/dist/cli/viewer.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +36 -16
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +3 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +35 -3
- package/dist/config.js.map +1 -1
- package/dist/documentLinks/check.d.ts +2 -1
- package/dist/documentLinks/check.d.ts.map +1 -1
- package/dist/documentLinks/check.js +22 -11
- package/dist/documentLinks/check.js.map +1 -1
- package/dist/duplicate-token-normalization.d.ts.map +1 -1
- package/dist/duplicate-token-normalization.js +10 -2
- package/dist/duplicate-token-normalization.js.map +1 -1
- package/dist/duplicates/scoring.d.ts +0 -10
- package/dist/duplicates/scoring.d.ts.map +1 -1
- package/dist/duplicates/scoring.js +9 -9
- package/dist/duplicates/scoring.js.map +1 -1
- package/dist/duplicates/types.d.ts +2 -0
- package/dist/duplicates/types.d.ts.map +1 -1
- package/dist/duplicates/unitCache.d.ts +15 -9
- package/dist/duplicates/unitCache.d.ts.map +1 -1
- package/dist/duplicates/unitCache.js +184 -33
- package/dist/duplicates/unitCache.js.map +1 -1
- package/dist/duplicates/units.d.ts +6 -15
- package/dist/duplicates/units.d.ts.map +1 -1
- package/dist/duplicates/units.js +42 -20
- package/dist/duplicates/units.js.map +1 -1
- package/dist/duplicates.d.ts.map +1 -1
- package/dist/duplicates.js +59 -0
- package/dist/duplicates.js.map +1 -1
- package/dist/frameworks/angularjs.d.ts.map +1 -1
- package/dist/frameworks/angularjs.js +18 -12
- package/dist/frameworks/angularjs.js.map +1 -1
- package/dist/graph-builder.d.ts.map +1 -1
- package/dist/graph-builder.js +12 -9
- package/dist/graph-builder.js.map +1 -1
- package/dist/graph-edge-collector.d.ts +1 -0
- package/dist/graph-edge-collector.d.ts.map +1 -1
- package/dist/graph-edge-collector.js +1 -1
- package/dist/graph-edge-collector.js.map +1 -1
- package/dist/graphs/grep.d.ts.map +1 -1
- package/dist/graphs/grep.js +7 -2
- package/dist/graphs/grep.js.map +1 -1
- package/dist/graphs/specifiers.d.ts.map +1 -1
- package/dist/graphs/specifiers.js +8 -2
- package/dist/graphs/specifiers.js.map +1 -1
- package/dist/graphs/symbol-graph-detailed.d.ts +10 -1
- package/dist/graphs/symbol-graph-detailed.d.ts.map +1 -1
- package/dist/graphs/symbol-graph-detailed.js +21 -5
- package/dist/graphs/symbol-graph-detailed.js.map +1 -1
- package/dist/impact/analyzer.d.ts.map +1 -1
- package/dist/impact/analyzer.js +19 -2
- package/dist/impact/analyzer.js.map +1 -1
- package/dist/impact/budgets.d.ts.map +1 -1
- package/dist/impact/budgets.js +5 -3
- package/dist/impact/budgets.js.map +1 -1
- package/dist/impact/call-compatibility/textScanner.d.ts +23 -0
- package/dist/impact/call-compatibility/textScanner.d.ts.map +1 -0
- package/dist/impact/call-compatibility/textScanner.js +615 -0
- package/dist/impact/call-compatibility/textScanner.js.map +1 -0
- package/dist/impact/callCompatibility.d.ts +8 -1
- package/dist/impact/callCompatibility.d.ts.map +1 -1
- package/dist/impact/callCompatibility.js +64 -587
- package/dist/impact/callCompatibility.js.map +1 -1
- package/dist/impact/context.d.ts.map +1 -1
- package/dist/impact/context.js +4 -1
- package/dist/impact/context.js.map +1 -1
- package/dist/impact/direct.d.ts +1 -1
- package/dist/impact/direct.d.ts.map +1 -1
- package/dist/impact/direct.js +7 -6
- package/dist/impact/direct.js.map +1 -1
- package/dist/impact/index.d.ts +6 -0
- package/dist/impact/index.d.ts.map +1 -1
- package/dist/impact/index.js +0 -8
- package/dist/impact/index.js.map +1 -1
- package/dist/impact/map.js +2 -2
- package/dist/impact/map.js.map +1 -1
- package/dist/impact/memberResolutionCoverage.d.ts.map +1 -1
- package/dist/impact/memberResolutionCoverage.js +5 -1
- package/dist/impact/memberResolutionCoverage.js.map +1 -1
- package/dist/impact/parse.d.ts.map +1 -1
- package/dist/impact/parse.js +108 -37
- package/dist/impact/parse.js.map +1 -1
- package/dist/impact/referenceCache.js +1 -1
- package/dist/impact/referenceCache.js.map +1 -1
- package/dist/impact/report-suggestions.d.ts.map +1 -1
- package/dist/impact/report-suggestions.js +347 -72
- package/dist/impact/report-suggestions.js.map +1 -1
- package/dist/impact/report.d.ts.map +1 -1
- package/dist/impact/report.js +13 -2
- package/dist/impact/report.js.map +1 -1
- package/dist/impact/reportCompact.d.ts.map +1 -1
- package/dist/impact/reportCompact.js +8 -0
- package/dist/impact/reportCompact.js.map +1 -1
- package/dist/impact/reportFull.d.ts.map +1 -1
- package/dist/impact/reportFull.js +1 -0
- package/dist/impact/reportFull.js.map +1 -1
- package/dist/impact/reportParts.d.ts +9 -0
- package/dist/impact/reportParts.d.ts.map +1 -1
- package/dist/impact/severity.d.ts +3 -2
- package/dist/impact/severity.d.ts.map +1 -1
- package/dist/impact/severity.js +16 -5
- package/dist/impact/severity.js.map +1 -1
- package/dist/impact/streaming.d.ts +32 -2
- package/dist/impact/streaming.d.ts.map +1 -1
- package/dist/impact/streaming.js +62 -3
- package/dist/impact/streaming.js.map +1 -1
- package/dist/impact/suggestions.d.ts.map +1 -1
- package/dist/impact/suggestions.js +1 -1
- package/dist/impact/suggestions.js.map +1 -1
- package/dist/impact/transitive.d.ts.map +1 -1
- package/dist/impact/transitive.js +13 -5
- package/dist/impact/transitive.js.map +1 -1
- package/dist/impact/types.d.ts +21 -20
- package/dist/impact/types.d.ts.map +1 -1
- package/dist/impact/types.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/indexer/build-cache/location.d.ts +19 -0
- package/dist/indexer/build-cache/location.d.ts.map +1 -0
- package/dist/indexer/build-cache/location.js +132 -0
- package/dist/indexer/build-cache/location.js.map +1 -0
- package/dist/indexer/build-cache/manifest.d.ts +14 -6
- package/dist/indexer/build-cache/manifest.d.ts.map +1 -1
- package/dist/indexer/build-cache/manifest.js +194 -30
- package/dist/indexer/build-cache/manifest.js.map +1 -1
- package/dist/indexer/build-cache/module-cache.d.ts +24 -2
- package/dist/indexer/build-cache/module-cache.d.ts.map +1 -1
- package/dist/indexer/build-cache/module-cache.js +98 -32
- package/dist/indexer/build-cache/module-cache.js.map +1 -1
- package/dist/indexer/build-cache/options.d.ts +3 -1
- package/dist/indexer/build-cache/options.d.ts.map +1 -1
- package/dist/indexer/build-cache/options.js +10 -2
- package/dist/indexer/build-cache/options.js.map +1 -1
- package/dist/indexer/build-cache/project-snapshot.d.ts +33 -13
- package/dist/indexer/build-cache/project-snapshot.d.ts.map +1 -1
- package/dist/indexer/build-cache/project-snapshot.js +472 -91
- package/dist/indexer/build-cache/project-snapshot.js.map +1 -1
- package/dist/indexer/build-cache/reports.d.ts.map +1 -1
- package/dist/indexer/build-cache/reports.js +10 -1
- package/dist/indexer/build-cache/reports.js.map +1 -1
- package/dist/indexer/build-cache/resolver-environment.d.ts +9 -0
- package/dist/indexer/build-cache/resolver-environment.d.ts.map +1 -0
- package/dist/indexer/build-cache/resolver-environment.js +160 -0
- package/dist/indexer/build-cache/resolver-environment.js.map +1 -0
- package/dist/indexer/build-cache.d.ts +4 -3
- package/dist/indexer/build-cache.d.ts.map +1 -1
- package/dist/indexer/build-cache.js +4 -3
- package/dist/indexer/build-cache.js.map +1 -1
- package/dist/indexer/build-index.d.ts.map +1 -1
- package/dist/indexer/build-index.js +268 -96
- package/dist/indexer/build-index.js.map +1 -1
- package/dist/indexer/build-manifest.d.ts +1 -0
- package/dist/indexer/build-manifest.d.ts.map +1 -1
- package/dist/indexer/build-manifest.js +15 -5
- package/dist/indexer/build-manifest.js.map +1 -1
- package/dist/indexer/build-workers.d.ts +1 -1
- package/dist/indexer/build-workers.d.ts.map +1 -1
- package/dist/indexer/build-workers.js +57 -42
- package/dist/indexer/build-workers.js.map +1 -1
- package/dist/indexer/call-hierarchy.d.ts.map +1 -1
- package/dist/indexer/call-hierarchy.js.map +1 -1
- package/dist/indexer/finalize.d.ts.map +1 -1
- package/dist/indexer/finalize.js +7 -4
- package/dist/indexer/finalize.js.map +1 -1
- package/dist/indexer/import-types.d.ts +8 -0
- package/dist/indexer/import-types.d.ts.map +1 -1
- package/dist/indexer/imports/jsTextImports.d.ts.map +1 -1
- package/dist/indexer/imports/jsTextImports.js +14 -6
- package/dist/indexer/imports/jsTextImports.js.map +1 -1
- package/dist/indexer/imports/languageSpecific.d.ts.map +1 -1
- package/dist/indexer/imports/languageSpecific.js +10 -5
- package/dist/indexer/imports/languageSpecific.js.map +1 -1
- package/dist/indexer/imports/nativeCaptures.d.ts.map +1 -1
- package/dist/indexer/imports/nativeCaptures.js +4 -1
- package/dist/indexer/imports/nativeCaptures.js.map +1 -1
- package/dist/indexer/imports/python.d.ts.map +1 -1
- package/dist/indexer/imports/python.js +19 -9
- package/dist/indexer/imports/python.js.map +1 -1
- package/dist/indexer/incremental-plan.d.ts +2 -1
- package/dist/indexer/incremental-plan.d.ts.map +1 -1
- package/dist/indexer/incremental-plan.js +7 -4
- package/dist/indexer/incremental-plan.js.map +1 -1
- package/dist/indexer/load-current-index.d.ts.map +1 -1
- package/dist/indexer/load-current-index.js.map +1 -1
- package/dist/indexer/locals-and-exports.d.ts.map +1 -1
- package/dist/indexer/locals-and-exports.js +77 -22
- package/dist/indexer/locals-and-exports.js.map +1 -1
- package/dist/indexer/navigation-goto.d.ts.map +1 -1
- package/dist/indexer/navigation-goto.js +26 -16
- package/dist/indexer/navigation-goto.js.map +1 -1
- package/dist/indexer/navigation-local.d.ts.map +1 -1
- package/dist/indexer/navigation-local.js +7 -4
- package/dist/indexer/navigation-local.js.map +1 -1
- package/dist/indexer/navigation-references.d.ts +1 -1
- package/dist/indexer/navigation-references.d.ts.map +1 -1
- package/dist/indexer/navigation-references.js +34 -17
- package/dist/indexer/navigation-references.js.map +1 -1
- package/dist/indexer/navigation-resolve.d.ts.map +1 -1
- package/dist/indexer/navigation-resolve.js +116 -53
- package/dist/indexer/navigation-resolve.js.map +1 -1
- package/dist/indexer/navigation.d.ts +2 -1
- package/dist/indexer/navigation.d.ts.map +1 -1
- package/dist/indexer/navigation.js +34 -20
- package/dist/indexer/navigation.js.map +1 -1
- package/dist/indexer/parse-context.d.ts +2 -2
- package/dist/indexer/parse-context.d.ts.map +1 -1
- package/dist/indexer/parse-context.js +25 -4
- package/dist/indexer/parse-context.js.map +1 -1
- package/dist/indexer/reference-context.d.ts +2 -2
- package/dist/indexer/reference-context.d.ts.map +1 -1
- package/dist/indexer/reference-context.js +4 -2
- package/dist/indexer/reference-context.js.map +1 -1
- package/dist/indexer/scope-types.d.ts +3 -0
- package/dist/indexer/scope-types.d.ts.map +1 -1
- package/dist/indexer/scope.js +37 -38
- package/dist/indexer/scope.js.map +1 -1
- package/dist/indexer/shared.d.ts.map +1 -1
- package/dist/indexer/shared.js +3 -1
- package/dist/indexer/shared.js.map +1 -1
- package/dist/indexer/type-hierarchy.d.ts.map +1 -1
- package/dist/indexer/type-hierarchy.js +12 -8
- package/dist/indexer/type-hierarchy.js.map +1 -1
- package/dist/indexer/types.d.ts +27 -1
- package/dist/indexer/types.d.ts.map +1 -1
- package/dist/indexer/workspace-symbols.d.ts.map +1 -1
- package/dist/indexer/workspace-symbols.js +5 -3
- package/dist/indexer/workspace-symbols.js.map +1 -1
- package/dist/installer/locks.d.ts +10 -0
- package/dist/installer/locks.d.ts.map +1 -0
- package/dist/installer/locks.js +232 -0
- package/dist/installer/locks.js.map +1 -0
- package/dist/installer/registry.d.ts.map +1 -1
- package/dist/installer/registry.js +75 -235
- package/dist/installer/registry.js.map +1 -1
- package/dist/languages/definitions/csharp.d.ts.map +1 -1
- package/dist/languages/definitions/csharp.js +8 -0
- package/dist/languages/definitions/csharp.js.map +1 -1
- package/dist/languages/definitions/java.d.ts.map +1 -1
- package/dist/languages/definitions/java.js +3 -0
- package/dist/languages/definitions/java.js.map +1 -1
- package/dist/languages/definitions/python.d.ts.map +1 -1
- package/dist/languages/definitions/python.js +2 -0
- package/dist/languages/definitions/python.js.map +1 -1
- package/dist/languages/definitions/rust.d.ts.map +1 -1
- package/dist/languages/definitions/rust.js +2 -0
- package/dist/languages/definitions/rust.js.map +1 -1
- package/dist/languages/importStatementParsers.d.ts +2 -0
- package/dist/languages/importStatementParsers.d.ts.map +1 -1
- package/dist/languages/importStatementParsers.js +24 -10
- package/dist/languages/importStatementParsers.js.map +1 -1
- package/dist/mcp/http.d.ts +3 -1
- package/dist/mcp/http.d.ts.map +1 -1
- package/dist/mcp/http.js +69 -20
- package/dist/mcp/http.js.map +1 -1
- package/dist/mcp/server.d.ts +58 -16
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +447 -140
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tools.d.ts +51 -1
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +129 -3
- package/dist/mcp/tools.js.map +1 -1
- package/dist/native/byteIndex.d.ts +26 -0
- package/dist/native/byteIndex.d.ts.map +1 -0
- package/dist/native/byteIndex.js +70 -0
- package/dist/native/byteIndex.js.map +1 -0
- package/dist/native/projectedTree.d.ts +3 -2
- package/dist/native/projectedTree.d.ts.map +1 -1
- package/dist/native/projectedTree.js +6 -50
- package/dist/native/projectedTree.js.map +1 -1
- package/dist/native/queryResults.d.ts +7 -1
- package/dist/native/queryResults.d.ts.map +1 -1
- package/dist/native/queryResults.js +13 -5
- package/dist/native/queryResults.js.map +1 -1
- package/dist/review/candidates.d.ts.map +1 -1
- package/dist/review/candidates.js +4 -1
- package/dist/review/candidates.js.map +1 -1
- package/dist/review/changes.d.ts +2 -0
- package/dist/review/changes.d.ts.map +1 -1
- package/dist/review/changes.js +10 -0
- package/dist/review/changes.js.map +1 -1
- package/dist/review/deleted.d.ts.map +1 -1
- package/dist/review/deleted.js +20 -2
- package/dist/review/deleted.js.map +1 -1
- package/dist/review/summaries.d.ts +5 -0
- package/dist/review/summaries.d.ts.map +1 -1
- package/dist/review/summaries.js +32 -21
- package/dist/review/summaries.js.map +1 -1
- package/dist/review/types.d.ts +3 -1
- package/dist/review/types.d.ts.map +1 -1
- package/dist/review/types.js +8 -1
- package/dist/review/types.js.map +1 -1
- package/dist/review.d.ts.map +1 -1
- package/dist/review.js +14 -5
- package/dist/review.js.map +1 -1
- package/dist/session.d.ts +20 -4
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +76 -16
- package/dist/session.js.map +1 -1
- package/dist/sql/types.d.ts.map +1 -1
- package/dist/sqlite/query.d.ts +29 -0
- package/dist/sqlite/query.d.ts.map +1 -1
- package/dist/sqlite/query.js +98 -11
- package/dist/sqlite/query.js.map +1 -1
- package/dist/sqlite/rawQueryWorker.d.ts +22 -0
- package/dist/sqlite/rawQueryWorker.d.ts.map +1 -0
- package/dist/sqlite/rawQueryWorker.js +31 -0
- package/dist/sqlite/rawQueryWorker.js.map +1 -0
- package/dist/sqlite/rawQueryWorkerPool.d.ts +66 -0
- package/dist/sqlite/rawQueryWorkerPool.d.ts.map +1 -0
- package/dist/sqlite/rawQueryWorkerPool.js +142 -0
- package/dist/sqlite/rawQueryWorkerPool.js.map +1 -0
- package/dist/sqlite/schema.d.ts +2 -1
- package/dist/sqlite/schema.d.ts.map +1 -1
- package/dist/sqlite/schema.js +15 -1
- package/dist/sqlite/schema.js.map +1 -1
- package/dist/sqlite/write.d.ts.map +1 -1
- package/dist/sqlite/write.js +15 -0
- package/dist/sqlite/write.js.map +1 -1
- package/dist/sqlite-driver.d.ts +11 -0
- package/dist/sqlite-driver.d.ts.map +1 -1
- package/dist/sqlite-driver.js +28 -2
- package/dist/sqlite-driver.js.map +1 -1
- package/dist/sqlite.d.ts +1 -1
- package/dist/sqlite.d.ts.map +1 -1
- package/dist/sqlite.js +1 -1
- package/dist/sqlite.js.map +1 -1
- package/dist/util/bloomFilter.d.ts +3 -2
- package/dist/util/bloomFilter.d.ts.map +1 -1
- package/dist/util/bloomFilter.js +8 -8
- package/dist/util/bloomFilter.js.map +1 -1
- package/dist/util/concurrency.d.ts +1 -0
- package/dist/util/concurrency.d.ts.map +1 -1
- package/dist/util/concurrency.js +9 -2
- package/dist/util/concurrency.js.map +1 -1
- package/dist/util/confinedFile.d.ts +42 -2
- package/dist/util/confinedFile.d.ts.map +1 -1
- package/dist/util/confinedFile.js +114 -3
- package/dist/util/confinedFile.js.map +1 -1
- package/dist/util/errors.d.ts +2 -0
- package/dist/util/errors.d.ts.map +1 -1
- package/dist/util/errors.js +18 -0
- package/dist/util/errors.js.map +1 -1
- package/dist/util/git.d.ts +2 -0
- package/dist/util/git.d.ts.map +1 -1
- package/dist/util/git.js +174 -26
- package/dist/util/git.js.map +1 -1
- package/dist/util/identifiers.d.ts +75 -0
- package/dist/util/identifiers.d.ts.map +1 -0
- package/dist/util/identifiers.js +82 -0
- package/dist/util/identifiers.js.map +1 -0
- package/dist/util/paths.d.ts.map +1 -1
- package/dist/util/paths.js +45 -9
- package/dist/util/paths.js.map +1 -1
- package/dist/util/projectFiles.d.ts.map +1 -1
- package/dist/util/projectFiles.js +43 -14
- package/dist/util/projectFiles.js.map +1 -1
- package/dist/util/resolution/jvm.d.ts.map +1 -1
- package/dist/util/resolution/jvm.js +20 -9
- package/dist/util/resolution/jvm.js.map +1 -1
- package/dist/util/resolution/php.d.ts.map +1 -1
- package/dist/util/resolution/php.js +6 -5
- package/dist/util/resolution/php.js.map +1 -1
- package/dist/util/resolution/tsconfig.d.ts.map +1 -1
- package/dist/util/resolution/tsconfig.js +26 -12
- package/dist/util/resolution/tsconfig.js.map +1 -1
- package/dist/util/rustTestModules.d.ts.map +1 -1
- package/dist/util/rustTestModules.js +4 -2
- package/dist/util/rustTestModules.js.map +1 -1
- package/dist/util/specifiers.d.ts.map +1 -1
- package/dist/util/specifiers.js +10 -3
- package/dist/util/specifiers.js.map +1 -1
- package/dist/util/sqliteSchema.d.ts.map +1 -1
- package/dist/util/sqliteSchema.js +10 -1
- package/dist/util/sqliteSchema.js.map +1 -1
- package/dist/worker/nativeExtractWorker.d.ts +4 -2
- package/dist/worker/nativeExtractWorker.d.ts.map +1 -1
- package/dist/worker/nativeExtractWorker.js +12 -11
- package/dist/worker/nativeExtractWorker.js.map +1 -1
- package/docs/mcp.md +35 -14
- package/package.json +3 -3
package/dist/mcp/server.js
CHANGED
|
@@ -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 {
|
|
6
|
-
import {
|
|
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,
|
|
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,
|
|
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
|
-
|
|
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
|
|
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
|
|
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:
|
|
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
|
-
|
|
129
|
-
|
|
130
|
-
|
|
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
|
|
306
|
-
const
|
|
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 {
|
|
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
|
|
337
|
-
const
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
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
|
|
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 { ...
|
|
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
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
647
|
-
|
|
648
|
-
|
|
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
|
-
|
|
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
|
|
871
|
+
const { handlers, session } = await createWarmedCodegraphMcpResources(options);
|
|
675
872
|
const runtimeIdentity = options.runtimeIdentity ?? captureCodegraphRuntimeIdentity(getCurrentNativeBindingOrigin());
|
|
676
|
-
const
|
|
677
|
-
const
|
|
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
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
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
|
|
903
|
+
const { handlers, session } = await createWarmedCodegraphMcpResources(options);
|
|
696
904
|
const runtimeIdentity = options.runtimeIdentity ?? captureCodegraphRuntimeIdentity(getCurrentNativeBindingOrigin());
|
|
697
|
-
const
|
|
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(
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
1155
|
+
return await legacyRequestAbortStorage.run(abortController.signal, operation);
|
|
900
1156
|
}
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
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
|
|
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
|
-
|
|
1023
|
-
|
|
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,
|
|
1340
|
+
return await handlers.search(parseMcpToolInput(searchSchema, input, name), signal);
|
|
1026
1341
|
case "workspace_symbols":
|
|
1027
|
-
return await handlers.workspace_symbols(parseMcpToolInput(workspaceSymbolsSchema, input,
|
|
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,
|
|
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,
|
|
1346
|
+
return await handlers.refactor_plan(parseMcpToolInput(refactorPlanSchema, input, name), signal);
|
|
1032
1347
|
case "calls":
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
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
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
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,
|
|
1358
|
+
return await handlers.implementations(parseMcpToolInput(implementationsSchema, input, name), signal);
|
|
1052
1359
|
case "explore":
|
|
1053
|
-
return await handlers.explore(parseMcpToolInput(exploreSchema, input,
|
|
1360
|
+
return await handlers.explore(parseMcpToolInput(exploreSchema, input, name), signal);
|
|
1054
1361
|
case "orient":
|
|
1055
|
-
return await handlers.orient(parseMcpToolInput(orientSchema, input,
|
|
1362
|
+
return await handlers.orient(parseMcpToolInput(orientSchema, input, name), signal);
|
|
1056
1363
|
case "packet_get":
|
|
1057
|
-
return await handlers.packet_get(parseMcpToolInput(packetGetSchema, input,
|
|
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,
|
|
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,
|
|
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
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
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,
|
|
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,
|
|
1383
|
+
return await handlers.review(parseMcpToolInput(reviewSchema, input, name), signal);
|
|
1078
1384
|
case "query_sqlite":
|
|
1079
|
-
return await handlers.query_sqlite(parseMcpToolInput(querySqliteSchema, input,
|
|
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,
|
|
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,
|
|
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
|
|
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
|
|
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
|
|
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();
|