codebase-onboarder 0.5.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +196 -47
- package/bin/build-if-source.js +23 -0
- package/cli/commands.d.ts +26 -0
- package/cli/commands.js +836 -811
- package/cli/commands.js.map +1 -0
- package/cli/explorer/advanced.d.ts +14 -0
- package/cli/explorer/advanced.js +449 -0
- package/cli/explorer/advanced.js.map +1 -0
- package/cli/explorer/app.d.ts +1 -0
- package/cli/explorer/app.js +396 -229
- package/cli/explorer/app.js.map +1 -0
- package/cli/explorer/assistant.d.ts +9 -0
- package/cli/explorer/assistant.js +58 -0
- package/cli/explorer/assistant.js.map +1 -0
- package/cli/explorer/commands.d.ts +17 -0
- package/cli/explorer/commands.js +400 -162
- package/cli/explorer/commands.js.map +1 -0
- package/cli/explorer/featureViews.d.ts +124 -0
- package/cli/explorer/featureViews.js +179 -0
- package/cli/explorer/featureViews.js.map +1 -0
- package/cli/explorer/github.d.ts +21 -0
- package/cli/explorer/github.js +73 -0
- package/cli/explorer/github.js.map +1 -0
- package/cli/explorer/graphs.d.ts +7 -0
- package/cli/explorer/graphs.js +173 -0
- package/cli/explorer/graphs.js.map +1 -0
- package/cli/explorer/picker.d.ts +22 -0
- package/cli/explorer/picker.js +150 -0
- package/cli/explorer/picker.js.map +1 -0
- package/cli/explorer/report.d.ts +85 -0
- package/cli/explorer/report.js +60 -0
- package/cli/explorer/report.js.map +1 -0
- package/cli/explorer/session.d.ts +449 -0
- package/cli/explorer/session.js +184 -95
- package/cli/explorer/session.js.map +1 -0
- package/cli/explorer/views.d.ts +19 -0
- package/cli/explorer/views.js +496 -412
- package/cli/explorer/views.js.map +1 -0
- package/cli/explorer/wrap.d.ts +1 -0
- package/cli/explorer/wrap.js +33 -0
- package/cli/explorer/wrap.js.map +1 -0
- package/cli/main.d.ts +1 -0
- package/cli/main.js +235 -138
- package/cli/main.js.map +1 -0
- package/cli/prompt.d.ts +5 -0
- package/cli/prompt.js +84 -80
- package/cli/prompt.js.map +1 -0
- package/cli/scanOptions.d.ts +2 -0
- package/cli/scanOptions.js +11 -0
- package/cli/scanOptions.js.map +1 -0
- package/cli/ui.d.ts +33 -0
- package/cli/ui.js +55 -35
- package/cli/ui.js.map +1 -0
- package/cli/wizard.d.ts +187 -0
- package/cli/wizard.js +304 -284
- package/cli/wizard.js.map +1 -0
- package/package.json +15 -4
- package/public/app.d.ts +1 -0
- package/public/app.js +1057 -1009
- package/public/app.js.map +1 -0
- package/public/browser.d.ts +68 -0
- package/public/browser.js +2 -0
- package/public/browser.js.map +1 -0
- package/public/index.html +30 -13
- package/public/js/about.d.ts +6 -0
- package/public/js/about.js +165 -172
- package/public/js/about.js.map +1 -0
- package/public/js/aiDraft.d.ts +3 -0
- package/public/js/aiDraft.js +116 -124
- package/public/js/aiDraft.js.map +1 -0
- package/public/js/analysisPanel.d.ts +7 -0
- package/public/js/analysisPanel.js +166 -166
- package/public/js/analysisPanel.js.map +1 -0
- package/public/js/analysisReport.d.ts +38 -0
- package/public/js/analysisReport.js +105 -110
- package/public/js/analysisReport.js.map +1 -0
- package/public/js/api.d.ts +26 -0
- package/public/js/api.js +176 -167
- package/public/js/api.js.map +1 -0
- package/public/js/atlas.d.ts +6 -0
- package/public/js/atlas.js +50 -58
- package/public/js/atlas.js.map +1 -0
- package/public/js/blameView.d.ts +2 -0
- package/public/js/blameView.js +36 -37
- package/public/js/blameView.js.map +1 -0
- package/public/js/codeTab.d.ts +3 -0
- package/public/js/codeTab.js +175 -180
- package/public/js/codeTab.js.map +1 -0
- package/public/js/codeViewer.d.ts +5 -0
- package/public/js/codeViewer.js +162 -150
- package/public/js/codeViewer.js.map +1 -0
- package/public/js/components/FileChip.d.ts +9 -0
- package/public/js/components/FileChip.js +45 -49
- package/public/js/components/FileChip.js.map +1 -0
- package/public/js/components/MetricSparkline.d.ts +7 -0
- package/public/js/components/MetricSparkline.js +35 -44
- package/public/js/components/MetricSparkline.js.map +1 -0
- package/public/js/components/RiskBadge.d.ts +9 -0
- package/public/js/components/RiskBadge.js +55 -63
- package/public/js/components/RiskBadge.js.map +1 -0
- package/public/js/deepAnalysisView.d.ts +99 -0
- package/public/js/deepAnalysisView.js +282 -302
- package/public/js/deepAnalysisView.js.map +1 -0
- package/public/js/diagramPane.d.ts +8 -0
- package/public/js/diagramPane.js +133 -135
- package/public/js/diagramPane.js.map +1 -0
- package/public/js/diffView.d.ts +6 -0
- package/public/js/diffView.js +222 -209
- package/public/js/diffView.js.map +1 -0
- package/public/js/docsView.d.ts +2 -0
- package/public/js/docsView.js +441 -442
- package/public/js/docsView.js.map +1 -0
- package/public/js/dom.d.ts +189 -0
- package/public/js/dom.js +5 -0
- package/public/js/dom.js.map +1 -0
- package/public/js/fileSourceBrowser.d.ts +5 -0
- package/public/js/fileSourceBrowser.js +33 -41
- package/public/js/fileSourceBrowser.js.map +1 -0
- package/public/js/flameGraph.d.ts +5 -0
- package/public/js/flameGraph.js +62 -72
- package/public/js/flameGraph.js.map +1 -0
- package/public/js/forceGraph.d.ts +10 -0
- package/public/js/forceGraph.js +581 -556
- package/public/js/forceGraph.js.map +1 -0
- package/public/js/heatmap.d.ts +4 -0
- package/public/js/heatmap.js +142 -164
- package/public/js/heatmap.js.map +1 -0
- package/public/js/highlight.d.ts +2 -0
- package/public/js/highlight.js +116 -107
- package/public/js/highlight.js.map +1 -0
- package/public/js/html.d.ts +2 -0
- package/public/js/html.js +14 -44
- package/public/js/html.js.map +1 -0
- package/public/js/insightsView.d.ts +5 -0
- package/public/js/insightsView.js +93 -111
- package/public/js/insightsView.js.map +1 -0
- package/public/js/inspector.d.ts +37 -0
- package/public/js/inspector.js +416 -445
- package/public/js/inspector.js.map +1 -0
- package/public/js/llm.d.ts +113 -0
- package/public/js/llm.js +233 -272
- package/public/js/llm.js.map +1 -0
- package/public/js/mapView.d.ts +3 -0
- package/public/js/mapView.js +121 -120
- package/public/js/mapView.js.map +1 -0
- package/public/js/markdown.d.ts +3 -0
- package/public/js/markdown.js +84 -91
- package/public/js/markdown.js.map +1 -0
- package/public/js/mindmap.d.ts +32 -0
- package/public/js/mindmap.js +244 -259
- package/public/js/mindmap.js.map +1 -0
- package/public/js/mobilePanels.d.ts +5 -0
- package/public/js/mobilePanels.js +50 -0
- package/public/js/mobilePanels.js.map +1 -0
- package/public/js/repoFiles.d.ts +12 -0
- package/public/js/repoFiles.js +28 -27
- package/public/js/repoFiles.js.map +1 -0
- package/public/js/reviewView.d.ts +28 -0
- package/public/js/reviewView.js +256 -0
- package/public/js/reviewView.js.map +1 -0
- package/public/js/sbomView.d.ts +3 -0
- package/public/js/sbomView.js +59 -67
- package/public/js/sbomView.js.map +1 -0
- package/public/js/scanCache.d.ts +16 -0
- package/public/js/scanCache.js +67 -65
- package/public/js/scanCache.js.map +1 -0
- package/public/js/search.d.ts +7 -0
- package/public/js/search.js +868 -800
- package/public/js/search.js.map +1 -0
- package/public/js/searchLocal.d.ts +42 -0
- package/public/js/searchLocal.js +87 -0
- package/public/js/searchLocal.js.map +1 -0
- package/public/js/serverSettings.d.ts +5 -0
- package/public/js/serverSettings.js +153 -164
- package/public/js/serverSettings.js.map +1 -0
- package/public/js/state.d.ts +798 -0
- package/public/js/state.js +114 -122
- package/public/js/state.js.map +1 -0
- package/public/js/tour.d.ts +6 -0
- package/public/js/tour.js +5 -7
- package/public/js/tour.js.map +1 -0
- package/public/js/transitions.d.ts +2 -0
- package/public/js/transitions.js +9 -10
- package/public/js/transitions.js.map +1 -0
- package/public/js/tree.d.ts +12 -0
- package/public/js/tree.js +157 -154
- package/public/js/tree.js.map +1 -0
- package/public/js/workflowsView.d.ts +3 -0
- package/public/js/workflowsView.js +15 -22
- package/public/js/workflowsView.js.map +1 -0
- package/public/search.css +495 -0
- package/public/styles.css +163 -346
- package/public/workbench.css +166 -0
- package/server/apiAuth.d.ts +3 -0
- package/server/apiAuth.js +18 -20
- package/server/apiAuth.js.map +1 -0
- package/server/apiDiff.d.ts +2 -0
- package/server/apiDiff.js +20 -18
- package/server/apiDiff.js.map +1 -0
- package/server/apiDocs.d.ts +2 -0
- package/server/apiDocs.js +38 -40
- package/server/apiDocs.js.map +1 -0
- package/server/apiFile.d.ts +1 -0
- package/server/apiFile.js +14 -17
- package/server/apiFile.js.map +1 -0
- package/server/apiGitBlame.d.ts +2 -0
- package/server/apiGitBlame.js +50 -51
- package/server/apiGitBlame.js.map +1 -0
- package/server/apiMcp.d.ts +4 -0
- package/server/apiMcp.js +64 -66
- package/server/apiMcp.js.map +1 -0
- package/server/apiReview.d.ts +2 -0
- package/server/apiReview.js +45 -0
- package/server/apiReview.js.map +1 -0
- package/server/apiScan.d.ts +5 -0
- package/server/apiScan.js +90 -71
- package/server/apiScan.js.map +1 -0
- package/server/apiSearch.d.ts +33 -0
- package/server/apiSearch.js +184 -200
- package/server/apiSearch.js.map +1 -0
- package/server/apiSettings.d.ts +4 -0
- package/server/apiSettings.js +84 -85
- package/server/apiSettings.js.map +1 -0
- package/server/apiTools.d.ts +3 -0
- package/server/apiTools.js +55 -56
- package/server/apiTools.js.map +1 -0
- package/server/auth.d.ts +5 -0
- package/server/auth.js +54 -51
- package/server/auth.js.map +1 -0
- package/server/config.d.ts +42 -0
- package/server/config.js +189 -194
- package/server/config.js.map +1 -0
- package/server/daemon.d.ts +12 -0
- package/server/daemon.js +124 -114
- package/server/daemon.js.map +1 -0
- package/server/fileSourceNode.d.ts +2 -0
- package/server/fileSourceNode.js +34 -36
- package/server/fileSourceNode.js.map +1 -0
- package/server/gitClone.d.ts +9 -0
- package/server/gitClone.js +59 -61
- package/server/gitClone.js.map +1 -0
- package/server/gitDiff.d.ts +36 -0
- package/server/gitDiff.js +271 -169
- package/server/gitDiff.js.map +1 -0
- package/server/gitHistory.d.ts +12 -0
- package/server/gitHistory.js +80 -80
- package/server/gitHistory.js.map +1 -0
- package/server/gitRemote.d.ts +12 -0
- package/server/gitRemote.js +60 -0
- package/server/gitRemote.js.map +1 -0
- package/server/htmlText.d.ts +4 -0
- package/server/htmlText.js +16 -23
- package/server/htmlText.js.map +1 -0
- package/server/http.d.ts +5 -0
- package/server/http.js +27 -30
- package/server/http.js.map +1 -0
- package/server/httpGuards.d.ts +2 -0
- package/server/httpGuards.js +47 -43
- package/server/httpGuards.js.map +1 -0
- package/server/https.d.ts +34 -0
- package/server/https.js +121 -111
- package/server/https.js.map +1 -0
- package/server/index.d.ts +40 -0
- package/server/index.js +139 -147
- package/server/index.js.map +1 -0
- package/server/layout.d.ts +26 -0
- package/server/layout.js +59 -37
- package/server/layout.js.map +1 -0
- package/server/llmProxy.d.ts +3 -0
- package/server/llmProxy.js +137 -135
- package/server/llmProxy.js.map +1 -0
- package/server/logger.d.ts +38 -0
- package/server/logger.js +198 -211
- package/server/logger.js.map +1 -0
- package/server/mcp/analysis.d.ts +29 -0
- package/server/mcp/analysis.js +99 -120
- package/server/mcp/analysis.js.map +1 -0
- package/server/mcp/http.d.ts +9 -0
- package/server/mcp/http.js +128 -137
- package/server/mcp/http.js.map +1 -0
- package/server/mcp/runner.d.ts +68 -0
- package/server/mcp/runner.js +208 -218
- package/server/mcp/runner.js.map +1 -0
- package/server/mcp/server.d.ts +29 -0
- package/server/mcp/server.js +166 -179
- package/server/mcp/server.js.map +1 -0
- package/server/mcp/standalone.d.ts +1 -0
- package/server/mcp/standalone.js +8 -10
- package/server/mcp/standalone.js.map +1 -0
- package/server/mcp/tools.d.ts +2020 -0
- package/server/mcp/tools.js +523 -574
- package/server/mcp/tools.js.map +1 -0
- package/server/paths.d.ts +3 -0
- package/server/paths.js +17 -15
- package/server/paths.js.map +1 -0
- package/server/pidfile.d.ts +9 -0
- package/server/pidfile.js +43 -45
- package/server/pidfile.js.map +1 -0
- package/server/review.d.ts +5 -0
- package/server/review.js +35 -0
- package/server/review.js.map +1 -0
- package/server/router.d.ts +33 -0
- package/server/router.js +191 -197
- package/server/router.js.map +1 -0
- package/server/scanRequest.d.ts +3 -0
- package/server/scanRequest.js +36 -0
- package/server/scanRequest.js.map +1 -0
- package/server/searchIndex.d.ts +17 -0
- package/server/searchIndex.js +83 -80
- package/server/searchIndex.js.map +1 -0
- package/server/sessions.d.ts +14 -0
- package/server/sessions.js +62 -70
- package/server/sessions.js.map +1 -0
- package/server/startup.d.ts +118 -0
- package/server/startup.js +143 -148
- package/server/startup.js.map +1 -0
- package/server/static.d.ts +6 -0
- package/server/static.js +28 -31
- package/server/static.js.map +1 -0
- package/server/tools/install.d.ts +4 -0
- package/server/tools/install.js +176 -185
- package/server/tools/install.js.map +1 -0
- package/server/tools/parse.d.ts +8 -0
- package/server/tools/parse.js +112 -114
- package/server/tools/parse.js.map +1 -0
- package/server/tools/platform.d.ts +9 -0
- package/server/tools/platform.js +49 -47
- package/server/tools/platform.js.map +1 -0
- package/server/tools/registry.d.ts +137 -0
- package/server/tools/registry.js +173 -172
- package/server/tools/registry.js.map +1 -0
- package/server/tools/scan.d.ts +34 -0
- package/server/tools/scan.js +89 -98
- package/server/tools/scan.js.map +1 -0
- package/server/tools.d.ts +34 -0
- package/server/tools.js +94 -107
- package/server/tools.js.map +1 -0
- package/server/tunnel.d.ts +29 -0
- package/server/tunnel.js +61 -66
- package/server/tunnel.js.map +1 -0
- package/shared/analyzer/docs.d.ts +16 -0
- package/shared/analyzer/docs.js +99 -93
- package/shared/analyzer/docs.js.map +1 -0
- package/shared/analyzer/explainLocal.d.ts +4 -0
- package/shared/analyzer/explainLocal.js +122 -142
- package/shared/analyzer/explainLocal.js.map +1 -0
- package/shared/analyzer/github.d.ts +37 -0
- package/shared/analyzer/github.js +79 -0
- package/shared/analyzer/github.js.map +1 -0
- package/shared/analyzer/graph.d.ts +41 -0
- package/shared/analyzer/graph.js +393 -400
- package/shared/analyzer/graph.js.map +1 -0
- package/shared/analyzer/health.d.ts +33 -0
- package/shared/analyzer/health.js +197 -193
- package/shared/analyzer/health.js.map +1 -0
- package/shared/analyzer/history.d.ts +29 -0
- package/shared/analyzer/history.js +110 -111
- package/shared/analyzer/history.js.map +1 -0
- package/shared/analyzer/jsonConfig.d.ts +2 -0
- package/shared/analyzer/jsonConfig.js +61 -0
- package/shared/analyzer/jsonConfig.js.map +1 -0
- package/shared/analyzer/languages/csharp.d.ts +26 -0
- package/shared/analyzer/languages/csharp.js +83 -88
- package/shared/analyzer/languages/csharp.js.map +1 -0
- package/shared/analyzer/languages/generic.d.ts +23 -0
- package/shared/analyzer/languages/generic.js +94 -105
- package/shared/analyzer/languages/generic.js.map +1 -0
- package/shared/analyzer/languages/go.d.ts +24 -0
- package/shared/analyzer/languages/go.js +45 -54
- package/shared/analyzer/languages/go.js.map +1 -0
- package/shared/analyzer/languages/index.d.ts +6 -0
- package/shared/analyzer/languages/index.js +19 -20
- package/shared/analyzer/languages/index.js.map +1 -0
- package/shared/analyzer/languages/java.d.ts +20 -0
- package/shared/analyzer/languages/java.js +73 -78
- package/shared/analyzer/languages/java.js.map +1 -0
- package/shared/analyzer/languages/javascript.d.ts +12 -0
- package/shared/analyzer/languages/javascript.js +258 -209
- package/shared/analyzer/languages/javascript.js.map +1 -0
- package/shared/analyzer/languages/python.d.ts +23 -0
- package/shared/analyzer/languages/python.js +92 -100
- package/shared/analyzer/languages/python.js.map +1 -0
- package/shared/analyzer/languages/rust.d.ts +17 -0
- package/shared/analyzer/languages/rust.js +96 -98
- package/shared/analyzer/languages/rust.js.map +1 -0
- package/shared/analyzer/languages/typescript.d.ts +11 -0
- package/shared/analyzer/languages/typescript.js +117 -116
- package/shared/analyzer/languages/typescript.js.map +1 -0
- package/shared/analyzer/licenses.d.ts +18 -0
- package/shared/analyzer/licenses.js +130 -133
- package/shared/analyzer/licenses.js.map +1 -0
- package/shared/analyzer/metrics.d.ts +20 -0
- package/shared/analyzer/metrics.js +112 -104
- package/shared/analyzer/metrics.js.map +1 -0
- package/shared/analyzer/pathUtil.d.ts +10 -0
- package/shared/analyzer/pathUtil.js +29 -35
- package/shared/analyzer/pathUtil.js.map +1 -0
- package/shared/analyzer/patterns.d.ts +11 -0
- package/shared/analyzer/patterns.js +231 -253
- package/shared/analyzer/patterns.js.map +1 -0
- package/shared/analyzer/scan.d.ts +62 -0
- package/shared/analyzer/scan.js +451 -442
- package/shared/analyzer/scan.js.map +1 -0
- package/shared/analyzer/scanControl.d.ts +11 -0
- package/shared/analyzer/scanControl.js +62 -0
- package/shared/analyzer/scanControl.js.map +1 -0
- package/shared/analyzer/security.d.ts +18 -0
- package/shared/analyzer/security.js +159 -159
- package/shared/analyzer/security.js.map +1 -0
- package/shared/analyzer/services.d.ts +5 -0
- package/shared/analyzer/services.js +141 -138
- package/shared/analyzer/services.js.map +1 -0
- package/shared/analyzer/stack.d.ts +6 -0
- package/shared/analyzer/stack.js +134 -141
- package/shared/analyzer/stack.js.map +1 -0
- package/shared/analyzer/tour.d.ts +2 -0
- package/shared/analyzer/tour.js +45 -53
- package/shared/analyzer/tour.js.map +1 -0
- package/shared/analyzer/util.d.ts +8 -0
- package/shared/analyzer/util.js +130 -76
- package/shared/analyzer/util.js.map +1 -0
- package/shared/analyzer/workflows.d.ts +8 -0
- package/shared/analyzer/workflows.js +139 -134
- package/shared/analyzer/workflows.js.map +1 -0
- package/shared/contracts.d.ts +250 -0
- package/shared/contracts.js +2 -0
- package/shared/contracts.js.map +1 -0
- package/shared/diagram/aiFacts.d.ts +35 -0
- package/shared/diagram/aiFacts.js +102 -105
- package/shared/diagram/aiFacts.js.map +1 -0
- package/shared/diagram/aiMermaid.d.ts +5 -0
- package/shared/diagram/aiMermaid.js +46 -45
- package/shared/diagram/aiMermaid.js.map +1 -0
- package/shared/diagram/atlas.d.ts +16 -0
- package/shared/diagram/atlas.js +51 -60
- package/shared/diagram/atlas.js.map +1 -0
- package/shared/diagram/mermaid.d.ts +43 -0
- package/shared/diagram/mermaid.js +348 -370
- package/shared/diagram/mermaid.js.map +1 -0
- package/shared/review/contracts.d.ts +95 -0
- package/shared/review/contracts.js +2 -0
- package/shared/review/contracts.js.map +1 -0
- package/shared/review/review.d.ts +10 -0
- package/shared/review/review.js +184 -0
- package/shared/review/review.js.map +1 -0
- package/shared/search/query.d.ts +32 -0
- package/shared/search/query.js +395 -388
- package/shared/search/query.js.map +1 -0
package/server/mcp/http.js
CHANGED
|
@@ -22,192 +22,183 @@
|
|
|
22
22
|
// held per-connection, so a session id would gate nothing that the localhost bind
|
|
23
23
|
// does not already gate — and pretending to a security model this process does not
|
|
24
24
|
// have would be worse than not claiming one.
|
|
25
|
-
|
|
26
25
|
import http from 'node:http';
|
|
27
|
-
|
|
28
26
|
import { handle, PROTOCOL_VERSION, SERVER_INFO } from './server.js';
|
|
29
27
|
import { toolDefinitions } from './tools.js';
|
|
30
|
-
|
|
31
28
|
export const HTTP_HOST = '127.0.0.1';
|
|
32
29
|
export const DEFAULT_PORT = 8790;
|
|
33
30
|
const MAX_BODY = 4 * 1024 * 1024; // a tools/call argument list, not a file upload
|
|
34
|
-
|
|
35
31
|
// A POST without this in its Accept header is not an MCP client. The spec requires
|
|
36
32
|
// clients to send both, and enforcing it is how a stray browser `fetch` to this
|
|
37
33
|
// port is turned away at the door.
|
|
38
34
|
function acceptsBoth(req) {
|
|
39
|
-
|
|
40
|
-
|
|
35
|
+
const accept = String(req.headers.accept || '');
|
|
36
|
+
return accept.includes('application/json') && accept.includes('text/event-stream');
|
|
41
37
|
}
|
|
42
|
-
|
|
43
38
|
// The spec's DNS-rebinding defence: the Host header must name a loopback address
|
|
44
39
|
// this server actually bound to. A rebinding attack sends `Host: evil.com` with
|
|
45
40
|
// the DNS pointing at 127.0.0.1, so the name is the thing to check, not the
|
|
46
41
|
// resolved address.
|
|
47
42
|
function hostAllowed(hostHeader) {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
43
|
+
if (!hostHeader)
|
|
44
|
+
return false;
|
|
45
|
+
const host = String(hostHeader).replace(/:\d+$/, '');
|
|
46
|
+
return host === '127.0.0.1' || host === 'localhost' || host === '[::1]' || host === '::1';
|
|
51
47
|
}
|
|
52
|
-
|
|
53
48
|
// Origin, when present, must also be loopback. A request with no Origin at all is
|
|
54
49
|
// a non-browser client — a harness, curl, a test — and those are the intended
|
|
55
50
|
// callers, so their absence is not suspicious.
|
|
56
51
|
function originAllowed(req) {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
52
|
+
const origin = req.headers.origin;
|
|
53
|
+
if (!origin)
|
|
54
|
+
return true;
|
|
55
|
+
try {
|
|
56
|
+
const { hostname } = new URL(String(origin));
|
|
57
|
+
return hostname === '127.0.0.1' || hostname === 'localhost' || hostname === '[::1]';
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
65
62
|
}
|
|
66
|
-
|
|
67
63
|
function guard(req, res) {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
64
|
+
if (!hostAllowed(req.headers.host)) {
|
|
65
|
+
sendJSON(res, 421, { error: 'This endpoint is served on localhost only.' });
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
if (!originAllowed(req)) {
|
|
69
|
+
sendJSON(res, 403, { error: 'Cross-origin requests are not accepted.' });
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
return true;
|
|
77
73
|
}
|
|
78
|
-
|
|
79
74
|
function sendJSON(res, status, value, headers = {}) {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
75
|
+
const body = JSON.stringify(value);
|
|
76
|
+
res.writeHead(status, {
|
|
77
|
+
'content-type': 'application/json',
|
|
78
|
+
'content-length': Buffer.byteLength(body),
|
|
79
|
+
...headers,
|
|
80
|
+
});
|
|
81
|
+
res.end(body);
|
|
87
82
|
}
|
|
88
|
-
|
|
89
83
|
// The 2025-06-18 spec lets a server answer a request with a plain JSON body when
|
|
90
84
|
// it has nothing server-initiated to send. Sending both JSON and an event stream
|
|
91
85
|
// would make a client that honours `application/json` wait forever for a stream
|
|
92
86
|
// that never comes.
|
|
93
87
|
function sendStreamable(res, message) {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
88
|
+
const body = JSON.stringify(message);
|
|
89
|
+
res.writeHead(200, {
|
|
90
|
+
'content-type': 'application/json',
|
|
91
|
+
'content-length': Buffer.byteLength(body),
|
|
92
|
+
});
|
|
93
|
+
res.end(body);
|
|
100
94
|
}
|
|
101
|
-
|
|
102
95
|
function readBody(req) {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
96
|
+
return new Promise((resolve, reject) => {
|
|
97
|
+
const chunks = [];
|
|
98
|
+
let size = 0;
|
|
99
|
+
req.on('data', (chunk) => {
|
|
100
|
+
size += chunk.length;
|
|
101
|
+
if (size > MAX_BODY) {
|
|
102
|
+
reject(new Error('Request body too large.'));
|
|
103
|
+
req.destroy();
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
chunks.push(chunk);
|
|
107
|
+
});
|
|
108
|
+
req.on('end', () => resolve(Buffer.concat(chunks).toString('utf8')));
|
|
109
|
+
req.on('error', reject);
|
|
114
110
|
});
|
|
115
|
-
req.on('end', () => resolve(Buffer.concat(chunks).toString('utf8')));
|
|
116
|
-
req.on('error', reject);
|
|
117
|
-
});
|
|
118
111
|
}
|
|
119
|
-
|
|
120
112
|
async function onPost(req, res) {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
let msg;
|
|
128
|
-
try {
|
|
129
|
-
msg = JSON.parse(await readBody(req));
|
|
130
|
-
} catch (err) {
|
|
131
|
-
return sendJSON(res, 400, {
|
|
132
|
-
jsonrpc: '2.0', id: null,
|
|
133
|
-
error: { code: -32700, message: `Could not parse the request: ${err.message}` },
|
|
134
|
-
});
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// A batch is legal JSON-RPC, and answering it in order keeps the client simple.
|
|
138
|
-
// Notifications inside it produce no entries, which is correct: `handle` returns
|
|
139
|
-
// undefined for them and they are filtered out here.
|
|
140
|
-
if (Array.isArray(msg)) {
|
|
141
|
-
const replies = [];
|
|
142
|
-
for (const one of msg) {
|
|
143
|
-
const reply = await handle(one);
|
|
144
|
-
if (reply) replies.push(reply);
|
|
113
|
+
if (!acceptsBoth(req)) {
|
|
114
|
+
return sendJSON(res, 406, {
|
|
115
|
+
error: 'An MCP client must Accept: application/json and text/event-stream.',
|
|
116
|
+
});
|
|
145
117
|
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
118
|
+
let msg;
|
|
119
|
+
try {
|
|
120
|
+
msg = JSON.parse(String(await readBody(req)));
|
|
149
121
|
}
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
122
|
+
catch (err) {
|
|
123
|
+
return sendJSON(res, 400, {
|
|
124
|
+
jsonrpc: '2.0', id: null,
|
|
125
|
+
error: { code: -32700, message: `Could not parse the request: ${err.message}` },
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
// A batch is legal JSON-RPC, and answering it in order keeps the client simple.
|
|
129
|
+
// Notifications inside it produce no entries, which is correct: `handle` returns
|
|
130
|
+
// undefined for them and they are filtered out here.
|
|
131
|
+
if (Array.isArray(msg)) {
|
|
132
|
+
const replies = [];
|
|
133
|
+
for (const one of msg) {
|
|
134
|
+
const reply = await handle(one);
|
|
135
|
+
if (reply)
|
|
136
|
+
replies.push(reply);
|
|
137
|
+
}
|
|
138
|
+
if (!replies.length) {
|
|
139
|
+
res.writeHead(202).end();
|
|
140
|
+
return undefined;
|
|
141
|
+
}
|
|
142
|
+
return sendStreamable(res, replies);
|
|
143
|
+
}
|
|
144
|
+
const reply = await handle(msg);
|
|
145
|
+
// A lone notification: the spec says answer 202 with no body.
|
|
146
|
+
if (!reply) {
|
|
147
|
+
res.writeHead(202).end();
|
|
148
|
+
return undefined;
|
|
149
|
+
}
|
|
150
|
+
return sendStreamable(res, reply);
|
|
160
151
|
}
|
|
161
|
-
|
|
162
152
|
function onGet(res) {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
153
|
+
// Without SSE there is no stream to open. 405 is the honest answer: this server
|
|
154
|
+
// does not offer the GET half of the transport, and a client that wants
|
|
155
|
+
// server-initiated messages should have used stdio.
|
|
156
|
+
res.writeHead(405, { allow: 'POST', 'content-type': 'application/json' });
|
|
157
|
+
res.end(JSON.stringify({
|
|
158
|
+
error: 'This server does not offer server-initiated streams. Use the stdio transport, or POST to this endpoint.',
|
|
159
|
+
}));
|
|
170
160
|
}
|
|
171
|
-
|
|
172
161
|
export function handleMcpHttpRequest(req, res) {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
162
|
+
if (!guard(req, res))
|
|
163
|
+
return undefined;
|
|
164
|
+
if (req.method === 'POST')
|
|
165
|
+
return onPost(req, res);
|
|
166
|
+
if (req.method === 'GET')
|
|
167
|
+
return onGet(res);
|
|
168
|
+
if (req.method === 'DELETE') {
|
|
169
|
+
// No sessions exist, so there is nothing to delete. Saying so keeps a client
|
|
170
|
+
// that cleans up politely from logging an error on the way out.
|
|
171
|
+
res.writeHead(200, { 'content-type': 'application/json' });
|
|
172
|
+
res.end(JSON.stringify({ ok: true }));
|
|
173
|
+
return undefined;
|
|
174
|
+
}
|
|
175
|
+
res.writeHead(405, { allow: 'POST, GET, DELETE' }).end();
|
|
181
176
|
return undefined;
|
|
182
|
-
}
|
|
183
|
-
res.writeHead(405, { allow: 'POST, GET, DELETE' }).end();
|
|
184
|
-
return undefined;
|
|
185
177
|
}
|
|
186
|
-
|
|
187
178
|
/**
|
|
188
179
|
* Start the Streamable HTTP transport. Returns `{ url, port, server, close }`, and
|
|
189
180
|
* `port` is the port actually bound — which matters because the caller may have
|
|
190
181
|
* asked for 0 and gets a free one back.
|
|
191
182
|
*/
|
|
192
183
|
export function createHttpTransport({ port = DEFAULT_PORT, host = HTTP_HOST } = {}) {
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
184
|
+
const server = http.createServer(handleMcpHttpRequest);
|
|
185
|
+
// A long tool call is a scan of a large repository. The default 5s headers
|
|
186
|
+
// timeout would cut the request off before the body finished arriving; the
|
|
187
|
+
// request timeout covers the whole exchange and is generous on purpose, since
|
|
188
|
+
// the person who asked for it is waiting for it.
|
|
189
|
+
server.headersTimeout = 30_000;
|
|
190
|
+
server.requestTimeout = 600_000;
|
|
191
|
+
return new Promise((resolve, reject) => {
|
|
192
|
+
server.once('error', reject);
|
|
193
|
+
server.listen(port, host, () => {
|
|
194
|
+
const actual = server.address().port;
|
|
195
|
+
resolve({
|
|
196
|
+
url: `http://${host}:${actual}/mcp`,
|
|
197
|
+
port: actual,
|
|
198
|
+
server,
|
|
199
|
+
close: () => new Promise((done) => server.close(done)),
|
|
200
|
+
});
|
|
201
|
+
});
|
|
211
202
|
});
|
|
212
|
-
});
|
|
213
203
|
}
|
|
204
|
+
//# sourceMappingURL=http.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/server/mcp/http.ts"],"names":[],"mappings":"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","sourcesContent":["// The Streamable HTTP transport (MCP 2025-06-18), on one endpoint that answers\n// POST and GET.\n//\n// This exists because of the button. A stdio server is spawned *by* its client, so\n// a child this app started has nobody to talk to it — starting one from the UI\n// would launch a process no harness could ever reach. Over HTTP the server is a\n// server: the button starts it, a harness connects to it, and stopping it closes\n// the door for everyone. Both transports are offered because they suit different\n// clients, and the spec says clients should support stdio where possible.\n//\n// The security section of the spec is not optional here, and this server has no\n// authentication at all, so the three protections it names are all the protection\n// there is:\n// * Bind 127.0.0.1 only. Never 0.0.0.0 — this process will read any folder it\n// is asked to, and a LAN-reachable copy of that is not something to ship by\n// accident.\n// * Validate `Origin` on every request, so a page on another site cannot drive\n// it on the person's behalf.\n// * Validate `Host`, so a rebinding name cannot resolve here either.\n//\n// What is deliberately *not* implemented: OAuth and `Mcp-Session-Id`. Nothing is\n// held per-connection, so a session id would gate nothing that the localhost bind\n// does not already gate — and pretending to a security model this process does not\n// have would be worse than not claiming one.\n\nimport http from 'node:http';\n\nimport { handle, PROTOCOL_VERSION, SERVER_INFO } from './server.js';\nimport { toolDefinitions } from './tools.js';\n\nexport const HTTP_HOST = '127.0.0.1';\nexport const DEFAULT_PORT = 8790;\nconst MAX_BODY = 4 * 1024 * 1024; // a tools/call argument list, not a file upload\n\n// A POST without this in its Accept header is not an MCP client. The spec requires\n// clients to send both, and enforcing it is how a stray browser `fetch` to this\n// port is turned away at the door.\nfunction acceptsBoth(req) {\n const accept = String(req.headers.accept || '');\n return accept.includes('application/json') && accept.includes('text/event-stream');\n}\n\n// The spec's DNS-rebinding defence: the Host header must name a loopback address\n// this server actually bound to. A rebinding attack sends `Host: evil.com` with\n// the DNS pointing at 127.0.0.1, so the name is the thing to check, not the\n// resolved address.\nfunction hostAllowed(hostHeader) {\n if (!hostHeader) return false;\n const host = String(hostHeader).replace(/:\\d+$/, '');\n return host === '127.0.0.1' || host === 'localhost' || host === '[::1]' || host === '::1';\n}\n\n// Origin, when present, must also be loopback. A request with no Origin at all is\n// a non-browser client — a harness, curl, a test — and those are the intended\n// callers, so their absence is not suspicious.\nfunction originAllowed(req) {\n const origin = req.headers.origin;\n if (!origin) return true;\n try {\n const { hostname } = new URL(String(origin));\n return hostname === '127.0.0.1' || hostname === 'localhost' || hostname === '[::1]';\n } catch {\n return false;\n }\n}\n\nfunction guard(req, res) {\n if (!hostAllowed(req.headers.host)) {\n sendJSON(res, 421, { error: 'This endpoint is served on localhost only.' });\n return false;\n }\n if (!originAllowed(req)) {\n sendJSON(res, 403, { error: 'Cross-origin requests are not accepted.' });\n return false;\n }\n return true;\n}\n\nfunction sendJSON(res, status, value, headers: Record<string, any> = {}) {\n const body = JSON.stringify(value);\n res.writeHead(status, {\n 'content-type': 'application/json',\n 'content-length': Buffer.byteLength(body),\n ...headers,\n });\n res.end(body);\n}\n\n// The 2025-06-18 spec lets a server answer a request with a plain JSON body when\n// it has nothing server-initiated to send. Sending both JSON and an event stream\n// would make a client that honours `application/json` wait forever for a stream\n// that never comes.\nfunction sendStreamable(res, message) {\n const body = JSON.stringify(message);\n res.writeHead(200, {\n 'content-type': 'application/json',\n 'content-length': Buffer.byteLength(body),\n });\n res.end(body);\n}\n\nfunction readBody(req) {\n return new Promise((resolve, reject) => {\n const chunks = [];\n let size = 0;\n req.on('data', (chunk) => {\n size += chunk.length;\n if (size > MAX_BODY) {\n reject(new Error('Request body too large.'));\n req.destroy();\n return;\n }\n chunks.push(chunk);\n });\n req.on('end', () => resolve(Buffer.concat(chunks).toString('utf8')));\n req.on('error', reject);\n });\n}\n\nasync function onPost(req, res) {\n if (!acceptsBoth(req)) {\n return sendJSON(res, 406, {\n error: 'An MCP client must Accept: application/json and text/event-stream.',\n });\n }\n\n let msg;\n try {\n msg = JSON.parse(String(await readBody(req)));\n } catch (err) {\n return sendJSON(res, 400, {\n jsonrpc: '2.0', id: null,\n error: { code: -32700, message: `Could not parse the request: ${err.message}` },\n });\n }\n\n // A batch is legal JSON-RPC, and answering it in order keeps the client simple.\n // Notifications inside it produce no entries, which is correct: `handle` returns\n // undefined for them and they are filtered out here.\n if (Array.isArray(msg)) {\n const replies = [];\n for (const one of msg) {\n const reply = await handle(one);\n if (reply) replies.push(reply);\n }\n if (!replies.length) {\n res.writeHead(202).end();\n return undefined;\n }\n return sendStreamable(res, replies);\n }\n\n const reply = await handle(msg);\n // A lone notification: the spec says answer 202 with no body.\n if (!reply) {\n res.writeHead(202).end();\n return undefined;\n }\n return sendStreamable(res, reply);\n}\n\nfunction onGet(res) {\n // Without SSE there is no stream to open. 405 is the honest answer: this server\n // does not offer the GET half of the transport, and a client that wants\n // server-initiated messages should have used stdio.\n res.writeHead(405, { allow: 'POST', 'content-type': 'application/json' });\n res.end(JSON.stringify({\n error: 'This server does not offer server-initiated streams. Use the stdio transport, or POST to this endpoint.',\n }));\n}\n\nexport function handleMcpHttpRequest(req, res) {\n if (!guard(req, res)) return undefined;\n if (req.method === 'POST') return onPost(req, res);\n if (req.method === 'GET') return onGet(res);\n if (req.method === 'DELETE') {\n // No sessions exist, so there is nothing to delete. Saying so keeps a client\n // that cleans up politely from logging an error on the way out.\n res.writeHead(200, { 'content-type': 'application/json' });\n res.end(JSON.stringify({ ok: true }));\n return undefined;\n }\n res.writeHead(405, { allow: 'POST, GET, DELETE' }).end();\n return undefined;\n}\n\n/**\n * Start the Streamable HTTP transport. Returns `{ url, port, server, close }`, and\n * `port` is the port actually bound — which matters because the caller may have\n * asked for 0 and gets a free one back.\n */\nexport function createHttpTransport({ port = DEFAULT_PORT, host = HTTP_HOST }: Record<string, any> = {}) {\n const server = http.createServer(handleMcpHttpRequest);\n // A long tool call is a scan of a large repository. The default 5s headers\n // timeout would cut the request off before the body finished arriving; the\n // request timeout covers the whole exchange and is generous on purpose, since\n // the person who asked for it is waiting for it.\n server.headersTimeout = 30_000;\n server.requestTimeout = 600_000;\n\n return new Promise((resolve, reject) => {\n server.once('error', reject);\n server.listen(port, host, () => {\n const actual = (server.address() as import('node:net').AddressInfo).port;\n resolve({\n url: `http://${host}:${actual}/mcp`,\n port: actual,\n server,\n close: () => new Promise((done) => server.close(done)),\n });\n });\n });\n}\n"]}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
export declare const REPO_ROOT: string;
|
|
2
|
+
export declare const ENTRY: string;
|
|
3
|
+
export declare function mcpCommand(): string;
|
|
4
|
+
export declare function mcpEntryPoint(): string;
|
|
5
|
+
export declare function mcpConfig(override: any): {
|
|
6
|
+
command: any;
|
|
7
|
+
args: any;
|
|
8
|
+
cwd: any;
|
|
9
|
+
};
|
|
10
|
+
export declare class McpRunner {
|
|
11
|
+
commandOverride: any;
|
|
12
|
+
child: any;
|
|
13
|
+
state: string;
|
|
14
|
+
startedAt: any;
|
|
15
|
+
lastError: string;
|
|
16
|
+
log: any[];
|
|
17
|
+
onLog: any;
|
|
18
|
+
get running(): boolean;
|
|
19
|
+
note(line: any): void;
|
|
20
|
+
constructor({ onLog, command, args, cwd }?: Record<string, any>);
|
|
21
|
+
start(): Promise<{
|
|
22
|
+
transport: string;
|
|
23
|
+
toolCount: number;
|
|
24
|
+
tools: string[];
|
|
25
|
+
cachedRepositories: any[];
|
|
26
|
+
lastRoot: any;
|
|
27
|
+
analyzers: Record<string, any>;
|
|
28
|
+
state: string;
|
|
29
|
+
running: boolean;
|
|
30
|
+
pid: any;
|
|
31
|
+
startedAt: any;
|
|
32
|
+
uptimeMs: number;
|
|
33
|
+
lastError: string;
|
|
34
|
+
log: any[];
|
|
35
|
+
}>;
|
|
36
|
+
handshake(exited: any): Promise<unknown>;
|
|
37
|
+
stop(): Promise<{
|
|
38
|
+
transport: string;
|
|
39
|
+
toolCount: number;
|
|
40
|
+
tools: string[];
|
|
41
|
+
cachedRepositories: any[];
|
|
42
|
+
lastRoot: any;
|
|
43
|
+
analyzers: Record<string, any>;
|
|
44
|
+
state: string;
|
|
45
|
+
running: boolean;
|
|
46
|
+
pid: any;
|
|
47
|
+
startedAt: any;
|
|
48
|
+
uptimeMs: number;
|
|
49
|
+
lastError: string;
|
|
50
|
+
log: any[];
|
|
51
|
+
}>;
|
|
52
|
+
status(): {
|
|
53
|
+
transport: string;
|
|
54
|
+
toolCount: number;
|
|
55
|
+
tools: string[];
|
|
56
|
+
cachedRepositories: any[];
|
|
57
|
+
lastRoot: any;
|
|
58
|
+
analyzers: Record<string, any>;
|
|
59
|
+
state: string;
|
|
60
|
+
running: boolean;
|
|
61
|
+
pid: any;
|
|
62
|
+
startedAt: any;
|
|
63
|
+
uptimeMs: number;
|
|
64
|
+
lastError: string;
|
|
65
|
+
log: any[];
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
export declare function createMcpRunner(opts: any): McpRunner;
|