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/server.js
CHANGED
|
@@ -16,24 +16,20 @@
|
|
|
16
16
|
// * A tool that throws is answered with a *result* carrying `isError: true`,
|
|
17
17
|
// not a JSON-RPC error. That is what puts the message in front of the model
|
|
18
18
|
// so it can correct itself; a protocol error just fails the turn.
|
|
19
|
-
|
|
20
19
|
import { toolDefinitions, callTool, findTool } from './tools.js';
|
|
21
20
|
import { ToolError } from './analysis.js';
|
|
22
|
-
|
|
23
21
|
export const PROTOCOL_VERSION = '2025-06-18';
|
|
24
22
|
export const SERVER_INFO = {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
+ 'repository scanned. The repository is read, never written.',
|
|
23
|
+
name: 'onboarder',
|
|
24
|
+
version: '1.0.0',
|
|
25
|
+
title: 'Onboarder',
|
|
26
|
+
instructions: 'Onboarder explains a codebase. Start with onboarder_scan on a repository path; '
|
|
27
|
+
+ 'it returns a written overview, the entry points, the most depended-upon files, and '
|
|
28
|
+
+ 'any dependency cycles. Then use onboarder_tour for a reading order, onboarder_search '
|
|
29
|
+
+ 'to find things by name, onboarder_explain_file for one file, and onboarder_read_file '
|
|
30
|
+
+ 'for raw source. Every tool also takes `path`; omit it to keep working on the last '
|
|
31
|
+
+ 'repository scanned. The repository is read, never written.',
|
|
35
32
|
};
|
|
36
|
-
|
|
37
33
|
// JSON-RPC error codes. Only the first two are protocol-level; the rest are
|
|
38
34
|
// conventional in MCP and keep a misbehaving client from parsing a server bug as
|
|
39
35
|
// a server bug it caused.
|
|
@@ -41,201 +37,192 @@ const PARSE_ERROR = -32700;
|
|
|
41
37
|
const INVALID_REQUEST = -32600;
|
|
42
38
|
const METHOD_NOT_FOUND = -32601;
|
|
43
39
|
const INVALID_PARAMS = -32602;
|
|
44
|
-
|
|
45
40
|
function result(id, value) {
|
|
46
|
-
|
|
41
|
+
return { jsonrpc: '2.0', id, result: value };
|
|
47
42
|
}
|
|
48
|
-
|
|
49
43
|
function failure(id, code, message, data) {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
44
|
+
const error = { code, message };
|
|
45
|
+
if (data !== undefined)
|
|
46
|
+
error.data = data;
|
|
47
|
+
return { jsonrpc: '2.0', id, error };
|
|
53
48
|
}
|
|
54
|
-
|
|
55
49
|
// A tool error and an internal error are different things. A `ToolError` is a
|
|
56
50
|
// sentence the model can act on — "that path is outside the repo" — so it becomes
|
|
57
51
|
// an isError result with that sentence intact. Anything else is a bug, and saying
|
|
58
52
|
// so plainly beats pretending it was the caller's fault.
|
|
59
53
|
async function callOne(name, args) {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
54
|
+
const tool = findTool(name);
|
|
55
|
+
if (!tool) {
|
|
56
|
+
return {
|
|
57
|
+
isError: true,
|
|
58
|
+
content: [{ type: 'text', text: `No tool called "${name}". Call tools/list to see what is available.` }],
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
try {
|
|
62
|
+
const value = await tool.run(args || {});
|
|
63
|
+
// MCP content is a list of blocks. A tool that returns structured data sends
|
|
64
|
+
// it as JSON text plus the native `structuredContent` field, which is what
|
|
65
|
+
// typed clients read; the text block is what everything else falls back to.
|
|
66
|
+
return {
|
|
67
|
+
content: [{ type: 'text', text: JSON.stringify(value, null, 2) }],
|
|
68
|
+
structuredContent: value,
|
|
69
|
+
isError: false,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
catch (err) {
|
|
73
|
+
if (err instanceof ToolError) {
|
|
74
|
+
return { isError: true, content: [{ type: 'text', text: err.message }] };
|
|
75
|
+
}
|
|
76
|
+
// Unexpected. Report the message, not the stack: the caller is a model on the
|
|
77
|
+
// other end of a pipe, and a stack trace is noise. The full error is on the
|
|
78
|
+
// child process's stderr, which is where a human debugging this will look.
|
|
79
|
+
console.error('[onboarder-mcp] tool failed:', err);
|
|
80
|
+
return {
|
|
81
|
+
isError: true,
|
|
82
|
+
content: [{ type: 'text', text: `The tool failed unexpectedly: ${err?.message || String(err)}` }],
|
|
83
|
+
};
|
|
80
84
|
}
|
|
81
|
-
// Unexpected. Report the message, not the stack: the caller is a model on the
|
|
82
|
-
// other end of a pipe, and a stack trace is noise. The full error is on the
|
|
83
|
-
// child process's stderr, which is where a human debugging this will look.
|
|
84
|
-
console.error('[onboarder-mcp] tool failed:', err);
|
|
85
|
-
return {
|
|
86
|
-
isError: true,
|
|
87
|
-
content: [{ type: 'text', text: `The tool failed unexpectedly: ${err?.message || String(err)}` }],
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
85
|
}
|
|
91
|
-
|
|
92
86
|
// The dispatcher is exported because the Streamable HTTP transport in `./http.js`
|
|
93
87
|
// needs to answer the same messages without going through a line of stdio. The
|
|
94
88
|
// protocol logic lives in exactly one place; a second transport must not become a
|
|
95
89
|
// second implementation of `tools/list`.
|
|
96
90
|
export { handle };
|
|
97
|
-
|
|
98
91
|
async function handle(msg) {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
case 'resources/templates/list':
|
|
151
|
-
return result(id, { resourceTemplates: [] });
|
|
152
|
-
|
|
153
|
-
default:
|
|
154
|
-
if (isNotification) return null;
|
|
155
|
-
return failure(id, METHOD_NOT_FOUND, `No method called "${method}".`);
|
|
156
|
-
}
|
|
92
|
+
// A request must name a method and must declare the protocol version. Anything
|
|
93
|
+
// else is not a request at all, and replying to it would invent an id to answer
|
|
94
|
+
// under — so this returns nothing and the line is dropped.
|
|
95
|
+
//
|
|
96
|
+
// `null` rather than `undefined` is the contract with the loop below: both mean
|
|
97
|
+
// "say nothing", but only one of them survives being awaited and compared.
|
|
98
|
+
if (!msg || typeof msg !== 'object' || msg.jsonrpc !== '2.0' || typeof msg.method !== 'string') {
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
const { method, id, params } = msg;
|
|
102
|
+
// A notification has no id and expects no answer. Returning `null` is how the
|
|
103
|
+
// loop knows to stay silent, which matters: replying to a notification is
|
|
104
|
+
// itself a protocol violation.
|
|
105
|
+
const isNotification = id === undefined || id === null;
|
|
106
|
+
switch (method) {
|
|
107
|
+
case 'initialize':
|
|
108
|
+
return isNotification ? undefined : result(id, {
|
|
109
|
+
protocolVersion: PROTOCOL_VERSION,
|
|
110
|
+
capabilities: { tools: { listChanged: false } },
|
|
111
|
+
serverInfo: SERVER_INFO,
|
|
112
|
+
});
|
|
113
|
+
// The client's post-handshake ping. Answering it is what tells the client the
|
|
114
|
+
// handshake completed and the tool loop is live.
|
|
115
|
+
case 'notifications/initialized':
|
|
116
|
+
return null;
|
|
117
|
+
case 'ping':
|
|
118
|
+
return isNotification ? undefined : result(id, {});
|
|
119
|
+
case 'tools/list':
|
|
120
|
+
return isNotification ? undefined : result(id, { tools: toolDefinitions() });
|
|
121
|
+
case 'tools/call':
|
|
122
|
+
if (isNotification)
|
|
123
|
+
return null;
|
|
124
|
+
if (!params?.name || typeof params.name !== 'string') {
|
|
125
|
+
return failure(id, INVALID_PARAMS, 'tools/call needs a tool name.');
|
|
126
|
+
}
|
|
127
|
+
return result(id, await callOne(params.name, params.arguments));
|
|
128
|
+
// A client asking for resources or prompts is not an error — this server has
|
|
129
|
+
// none, and saying so is more useful than METHOD_NOT_FOUND. A harness that
|
|
130
|
+
// probes both at startup gets a clean answer instead of a warning.
|
|
131
|
+
case 'resources/list':
|
|
132
|
+
return result(id, { resources: [] });
|
|
133
|
+
case 'prompts/list':
|
|
134
|
+
return result(id, { prompts: [] });
|
|
135
|
+
case 'resources/templates/list':
|
|
136
|
+
return result(id, { resourceTemplates: [] });
|
|
137
|
+
default:
|
|
138
|
+
if (isNotification)
|
|
139
|
+
return null;
|
|
140
|
+
return failure(id, METHOD_NOT_FOUND, `No method called "${method}".`);
|
|
141
|
+
}
|
|
157
142
|
}
|
|
158
|
-
|
|
159
143
|
// One line in, one line out. A message that will not parse gets a parse error
|
|
160
144
|
// with `id: null`, which is what the spec requires — the client cannot know which
|
|
161
145
|
// request the bad line belonged to.
|
|
162
146
|
function parseLine(line) {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
147
|
+
try {
|
|
148
|
+
const msg = JSON.parse(line);
|
|
149
|
+
if (!msg || typeof msg !== 'object' || Array.isArray(msg)) {
|
|
150
|
+
return { bad: failure(null, INVALID_REQUEST, 'A message must be a JSON-RPC object.') };
|
|
151
|
+
}
|
|
152
|
+
return { msg };
|
|
153
|
+
}
|
|
154
|
+
catch (err) {
|
|
155
|
+
return { bad: failure(null, PARSE_ERROR, `Could not parse the message: ${err.message}`) };
|
|
167
156
|
}
|
|
168
|
-
return { msg };
|
|
169
|
-
} catch (err) {
|
|
170
|
-
return { bad: failure(null, PARSE_ERROR, `Could not parse the message: ${err.message}`) };
|
|
171
|
-
}
|
|
172
157
|
}
|
|
173
|
-
|
|
174
158
|
/**
|
|
175
159
|
* Run the server until stdin closes. `input` and `output` are parameters so tests
|
|
176
160
|
* can drive a whole session through in-memory streams.
|
|
177
161
|
*/
|
|
178
162
|
export function serveMcp({ input = process.stdin, output = process.stdout } = {}) {
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
163
|
+
let buffer = '';
|
|
164
|
+
// Messages are handled strictly in order, but not awaited inline: a long scan
|
|
165
|
+
// must not block the event loop from reading the next line, or a client that
|
|
166
|
+
// pipelines would sit with a full buffer. The promise chain is what preserves
|
|
167
|
+
// the ordering while letting reads continue.
|
|
168
|
+
let chain = Promise.resolve();
|
|
169
|
+
let closed = false;
|
|
170
|
+
const send = (message) => {
|
|
171
|
+
if (closed)
|
|
172
|
+
return;
|
|
173
|
+
output.write(JSON.stringify(message) + '\n');
|
|
174
|
+
};
|
|
175
|
+
const enqueue = (line) => {
|
|
176
|
+
chain = chain.then(async () => {
|
|
177
|
+
const { msg, bad } = parseLine(line);
|
|
178
|
+
if (bad) {
|
|
179
|
+
send(bad);
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
const response = await handle(msg);
|
|
183
|
+
if (response)
|
|
184
|
+
send(response);
|
|
185
|
+
}).catch((err) => {
|
|
186
|
+
// `handle` already turns tool failures into results. Reaching here means
|
|
187
|
+
// something threw outside that, so the only honest move is to log it and
|
|
188
|
+
// keep serving — a dead server helps nobody recover.
|
|
189
|
+
console.error('[onboarder-mcp] dispatch failed:', err);
|
|
190
|
+
});
|
|
191
|
+
};
|
|
192
|
+
input.setEncoding?.('utf8');
|
|
193
|
+
input.on('data', (chunk) => {
|
|
194
|
+
buffer += chunk;
|
|
195
|
+
let nl;
|
|
196
|
+
// A partial line at the end of a chunk stays in the buffer for the next one.
|
|
197
|
+
while ((nl = buffer.indexOf('\n')) !== -1) {
|
|
198
|
+
const line = buffer.slice(0, nl).trim();
|
|
199
|
+
buffer = buffer.slice(nl + 1);
|
|
200
|
+
if (line)
|
|
201
|
+
enqueue(line);
|
|
202
|
+
}
|
|
203
203
|
});
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
// would lose the final request of a session — which is often the only one.
|
|
221
|
-
const line = buffer.trim();
|
|
222
|
-
buffer = '';
|
|
223
|
-
if (line) enqueue(line);
|
|
224
|
-
// Let the queue finish before the process exits, so a reply written just
|
|
225
|
-
// after stdin closed still reaches the client.
|
|
226
|
-
chain.finally(() => {
|
|
227
|
-
if (output === process.stdout) process.exitCode = 0;
|
|
204
|
+
input.on('end', () => {
|
|
205
|
+
// A last line without a trailing newline is still a message. Dropping it
|
|
206
|
+
// would lose the final request of a session — which is often the only one.
|
|
207
|
+
const line = buffer.trim();
|
|
208
|
+
buffer = '';
|
|
209
|
+
if (line)
|
|
210
|
+
enqueue(line);
|
|
211
|
+
// Let the queue finish before the process exits, so a reply written just
|
|
212
|
+
// after stdin closed still reaches the client.
|
|
213
|
+
chain.finally(() => {
|
|
214
|
+
if (output === process.stdout)
|
|
215
|
+
process.exitCode = 0;
|
|
216
|
+
});
|
|
217
|
+
});
|
|
218
|
+
input.on('error', (err) => {
|
|
219
|
+
console.error('[onboarder-mcp] stdin error:', err);
|
|
228
220
|
});
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
return {
|
|
236
|
-
stop() { closed = true; },
|
|
237
|
-
// Awaiting the queue is how a test knows every reply has been written, and
|
|
238
|
-
// how a shutdown can drain in-flight work instead of cutting it off.
|
|
239
|
-
settled() { return chain; },
|
|
240
|
-
};
|
|
221
|
+
return {
|
|
222
|
+
stop() { closed = true; },
|
|
223
|
+
// Awaiting the queue is how a test knows every reply has been written, and
|
|
224
|
+
// how a shutdown can drain in-flight work instead of cutting it off.
|
|
225
|
+
settled() { return chain; },
|
|
226
|
+
};
|
|
241
227
|
}
|
|
228
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/server/mcp/server.ts"],"names":[],"mappings":"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","sourcesContent":["// The MCP server: JSON-RPC 2.0 over stdio, one JSON object per line.\n//\n// Why no SDK: the project has no dependencies, and `package.json` says so. MCP's\n// stdio transport is a framing convention (one line-delimited JSON-RPC message\n// per message, on the child's stdin/stdout), not a wire protocol with magic — so\n// implementing it directly is a few dozen lines and keeps the promise that this\n// repo installs with nothing. If the SDK ever becomes worth it, this file is the\n// only thing that changes; `tools.js` and `analysis.js` know nothing about JSON.\n//\n// The rules that matter for correctness:\n// * stdout belongs to the protocol. Anything else printed there corrupts the\n// stream, so the logger is redirected to stderr for the lifetime of the\n// child (see `runner.js`).\n// * Requests are answered in order. MCP clients pipeline, and answering a\n// `tools/call` out of order makes some clients discard the later result.\n// * A tool that throws is answered with a *result* carrying `isError: true`,\n// not a JSON-RPC error. That is what puts the message in front of the model\n// so it can correct itself; a protocol error just fails the turn.\n\nimport { toolDefinitions, callTool, findTool } from './tools.js';\nimport { ToolError } from './analysis.js';\n\nexport const PROTOCOL_VERSION = '2025-06-18';\nexport const SERVER_INFO = {\n name: 'onboarder',\n version: '1.0.0',\n title: 'Onboarder',\n instructions:\n 'Onboarder explains a codebase. Start with onboarder_scan on a repository path; '\n + 'it returns a written overview, the entry points, the most depended-upon files, and '\n + 'any dependency cycles. Then use onboarder_tour for a reading order, onboarder_search '\n + 'to find things by name, onboarder_explain_file for one file, and onboarder_read_file '\n + 'for raw source. Every tool also takes `path`; omit it to keep working on the last '\n + 'repository scanned. The repository is read, never written.',\n};\n\n// JSON-RPC error codes. Only the first two are protocol-level; the rest are\n// conventional in MCP and keep a misbehaving client from parsing a server bug as\n// a server bug it caused.\nconst PARSE_ERROR = -32700;\nconst INVALID_REQUEST = -32600;\nconst METHOD_NOT_FOUND = -32601;\nconst INVALID_PARAMS = -32602;\n\nfunction result(id, value) {\n return { jsonrpc: '2.0', id, result: value };\n}\n\nfunction failure(id, code, message, data?: unknown) {\n const error: { code: number; message: string; data?: unknown } = { code, message };\n if (data !== undefined) error.data = data;\n return { jsonrpc: '2.0', id, error };\n}\n\n// A tool error and an internal error are different things. A `ToolError` is a\n// sentence the model can act on — \"that path is outside the repo\" — so it becomes\n// an isError result with that sentence intact. Anything else is a bug, and saying\n// so plainly beats pretending it was the caller's fault.\nasync function callOne(name, args) {\n const tool = findTool(name);\n if (!tool) {\n return {\n isError: true,\n content: [{ type: 'text', text: `No tool called \"${name}\". Call tools/list to see what is available.` }],\n };\n }\n try {\n const value = await tool.run(args || {});\n // MCP content is a list of blocks. A tool that returns structured data sends\n // it as JSON text plus the native `structuredContent` field, which is what\n // typed clients read; the text block is what everything else falls back to.\n return {\n content: [{ type: 'text', text: JSON.stringify(value, null, 2) }],\n structuredContent: value,\n isError: false,\n };\n } catch (err) {\n if (err instanceof ToolError) {\n return { isError: true, content: [{ type: 'text', text: err.message }] };\n }\n // Unexpected. Report the message, not the stack: the caller is a model on the\n // other end of a pipe, and a stack trace is noise. The full error is on the\n // child process's stderr, which is where a human debugging this will look.\n console.error('[onboarder-mcp] tool failed:', err);\n return {\n isError: true,\n content: [{ type: 'text', text: `The tool failed unexpectedly: ${err?.message || String(err)}` }],\n };\n }\n}\n\n// The dispatcher is exported because the Streamable HTTP transport in `./http.js`\n// needs to answer the same messages without going through a line of stdio. The\n// protocol logic lives in exactly one place; a second transport must not become a\n// second implementation of `tools/list`.\nexport { handle };\n\nasync function handle(msg) {\n // A request must name a method and must declare the protocol version. Anything\n // else is not a request at all, and replying to it would invent an id to answer\n // under — so this returns nothing and the line is dropped.\n //\n // `null` rather than `undefined` is the contract with the loop below: both mean\n // \"say nothing\", but only one of them survives being awaited and compared.\n if (!msg || typeof msg !== 'object' || msg.jsonrpc !== '2.0' || typeof msg.method !== 'string') {\n return null;\n }\n const { method, id, params } = msg;\n\n // A notification has no id and expects no answer. Returning `null` is how the\n // loop knows to stay silent, which matters: replying to a notification is\n // itself a protocol violation.\n const isNotification = id === undefined || id === null;\n\n switch (method) {\n case 'initialize':\n return isNotification ? undefined : result(id, {\n protocolVersion: PROTOCOL_VERSION,\n capabilities: { tools: { listChanged: false } },\n serverInfo: SERVER_INFO,\n });\n\n // The client's post-handshake ping. Answering it is what tells the client the\n // handshake completed and the tool loop is live.\n case 'notifications/initialized':\n return null;\n\n case 'ping':\n return isNotification ? undefined : result(id, {});\n\n case 'tools/list':\n return isNotification ? undefined : result(id, { tools: toolDefinitions() });\n\n case 'tools/call':\n if (isNotification) return null;\n if (!params?.name || typeof params.name !== 'string') {\n return failure(id, INVALID_PARAMS, 'tools/call needs a tool name.');\n }\n return result(id, await callOne(params.name, params.arguments));\n\n // A client asking for resources or prompts is not an error — this server has\n // none, and saying so is more useful than METHOD_NOT_FOUND. A harness that\n // probes both at startup gets a clean answer instead of a warning.\n case 'resources/list':\n return result(id, { resources: [] });\n\n case 'prompts/list':\n return result(id, { prompts: [] });\n\n case 'resources/templates/list':\n return result(id, { resourceTemplates: [] });\n\n default:\n if (isNotification) return null;\n return failure(id, METHOD_NOT_FOUND, `No method called \"${method}\".`);\n }\n}\n\n// One line in, one line out. A message that will not parse gets a parse error\n// with `id: null`, which is what the spec requires — the client cannot know which\n// request the bad line belonged to.\nfunction parseLine(line) {\n try {\n const msg = JSON.parse(line);\n if (!msg || typeof msg !== 'object' || Array.isArray(msg)) {\n return { bad: failure(null, INVALID_REQUEST, 'A message must be a JSON-RPC object.') };\n }\n return { msg };\n } catch (err) {\n return { bad: failure(null, PARSE_ERROR, `Could not parse the message: ${err.message}`) };\n }\n}\n\n/**\n * Run the server until stdin closes. `input` and `output` are parameters so tests\n * can drive a whole session through in-memory streams.\n */\nexport function serveMcp({ input = process.stdin, output = process.stdout }: Record<string, any> = {}) {\n let buffer = '';\n // Messages are handled strictly in order, but not awaited inline: a long scan\n // must not block the event loop from reading the next line, or a client that\n // pipelines would sit with a full buffer. The promise chain is what preserves\n // the ordering while letting reads continue.\n let chain = Promise.resolve();\n let closed = false;\n\n const send = (message) => {\n if (closed) return;\n output.write(JSON.stringify(message) + '\\n');\n };\n\n const enqueue = (line) => {\n chain = chain.then(async () => {\n const { msg, bad } = parseLine(line);\n if (bad) { send(bad); return; }\n const response = await handle(msg);\n if (response) send(response);\n }).catch((err) => {\n // `handle` already turns tool failures into results. Reaching here means\n // something threw outside that, so the only honest move is to log it and\n // keep serving — a dead server helps nobody recover.\n console.error('[onboarder-mcp] dispatch failed:', err);\n });\n };\n\n input.setEncoding?.('utf8');\n input.on('data', (chunk) => {\n buffer += chunk;\n let nl;\n // A partial line at the end of a chunk stays in the buffer for the next one.\n while ((nl = buffer.indexOf('\\n')) !== -1) {\n const line = buffer.slice(0, nl).trim();\n buffer = buffer.slice(nl + 1);\n if (line) enqueue(line);\n }\n });\n\n input.on('end', () => {\n // A last line without a trailing newline is still a message. Dropping it\n // would lose the final request of a session — which is often the only one.\n const line = buffer.trim();\n buffer = '';\n if (line) enqueue(line);\n // Let the queue finish before the process exits, so a reply written just\n // after stdin closed still reaches the client.\n chain.finally(() => {\n if (output === process.stdout) process.exitCode = 0;\n });\n });\n\n input.on('error', (err) => {\n console.error('[onboarder-mcp] stdin error:', err);\n });\n\n return {\n stop() { closed = true; },\n // Awaiting the queue is how a test knows every reply has been written, and\n // how a shutdown can drain in-flight work instead of cutting it off.\n settled() { return chain; },\n };\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/server/mcp/standalone.js
CHANGED
|
@@ -11,9 +11,7 @@
|
|
|
11
11
|
// would look like a server bug rather than a logging bug. Redirecting is better
|
|
12
12
|
// than trusting: the guard costs one comparison per write and cannot be forgotten
|
|
13
13
|
// by a future contributor three files deep.
|
|
14
|
-
|
|
15
14
|
import { serveMcp, SERVER_INFO } from './server.js';
|
|
16
|
-
|
|
17
15
|
// stdout is a shared pipe with two kinds of writer: the protocol, which must be
|
|
18
16
|
// the only thing a client ever sees, and everything else — a stray `console.log`
|
|
19
17
|
// in a shared analyzer, a logger — which would be read as a malformed frame and
|
|
@@ -25,18 +23,18 @@ import { serveMcp, SERVER_INFO } from './server.js';
|
|
|
25
23
|
// on being the first thing to run.
|
|
26
24
|
const realStdoutWrite = process.stdout.write.bind(process.stdout);
|
|
27
25
|
const protocolStream = { write: (chunk) => realStdoutWrite(chunk) };
|
|
28
|
-
|
|
29
26
|
process.stdout.write = function toStderr(chunk, encoding, callback) {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
27
|
+
process.stderr.write(chunk);
|
|
28
|
+
if (typeof encoding === 'function')
|
|
29
|
+
encoding();
|
|
30
|
+
else if (typeof callback === 'function')
|
|
31
|
+
callback();
|
|
32
|
+
return true;
|
|
34
33
|
};
|
|
35
|
-
|
|
36
34
|
// Diagnostics are opt-in: a client reading stdout is reading a protocol stream
|
|
37
35
|
// and nothing else, so anything else has to be asked for.
|
|
38
36
|
if (process.env.ONBOARDER_MCP_LOG === '1') {
|
|
39
|
-
|
|
37
|
+
console.error(`[onboarder-mcp] ${SERVER_INFO.name} ${SERVER_INFO.version} starting on stdio`);
|
|
40
38
|
}
|
|
41
|
-
|
|
42
39
|
serveMcp({ output: protocolStream });
|
|
40
|
+
//# sourceMappingURL=standalone.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"standalone.js","sourceRoot":"","sources":["../../src/server/mcp/standalone.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,EAAE;AACF,kFAAkF;AAClF,+EAA+E;AAC/E,6EAA6E;AAC7E,+CAA+C;AAC/C,EAAE;AACF,8EAA8E;AAC9E,iFAAiF;AACjF,6EAA6E;AAC7E,gFAAgF;AAChF,kFAAkF;AAClF,4CAA4C;AAE5C,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAEpD,gFAAgF;AAChF,iFAAiF;AACjF,gFAAgF;AAChF,8CAA8C;AAC9C,EAAE;AACF,kFAAkF;AAClF,8EAA8E;AAC9E,kFAAkF;AAClF,mCAAmC;AACnC,MAAM,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;AAClE,MAAM,cAAc,GAAG,EAAE,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,eAAe,CAAC,KAAK,CAAC,EAAE,CAAC;AAEpE,OAAO,CAAC,MAAM,CAAC,KAAK,GAAG,SAAS,QAAQ,CAAC,KAA0B,EAAE,QAAmD,EAAE,QAAgC;IACxJ,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC5B,IAAI,OAAO,QAAQ,KAAK,UAAU;QAAE,QAAQ,EAAE,CAAC;SAC1C,IAAI,OAAO,QAAQ,KAAK,UAAU;QAAE,QAAQ,EAAE,CAAC;IACpD,OAAO,IAAI,CAAC;AACd,CAAC,CAAC;AAEF,+EAA+E;AAC/E,0DAA0D;AAC1D,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB,KAAK,GAAG,EAAE,CAAC;IAC1C,OAAO,CAAC,KAAK,CAAC,mBAAmB,WAAW,CAAC,IAAI,IAAI,WAAW,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAChG,CAAC;AAED,QAAQ,CAAC,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC,CAAC","sourcesContent":["// The MCP server as its own process: `node server/mcp/standalone.js`.\n//\n// This is the command an agent harness is configured with. It is a separate entry\n// point rather than a flag on the web server because the two have incompatible\n// requirements for stdout — the web server logs to it, the MCP server speaks\n// JSON-RPC over it and must own it completely.\n//\n// It also guards stdout for the lifetime of the process. Anything that writes\n// there — a `console.log` from a shared analyzer, a logger the tools reach for —\n// would be read by the client as a malformed protocol frame, and the failure\n// would look like a server bug rather than a logging bug. Redirecting is better\n// than trusting: the guard costs one comparison per write and cannot be forgotten\n// by a future contributor three files deep.\n\nimport { serveMcp, SERVER_INFO } from './server.js';\n\n// stdout is a shared pipe with two kinds of writer: the protocol, which must be\n// the only thing a client ever sees, and everything else — a stray `console.log`\n// in a shared analyzer, a logger — which would be read as a malformed frame and\n// make the server look broken when it is not.\n//\n// Rather than hoping nothing else writes, this builds the protocol's writer first\n// and hands it to `serveMcp`, then points `process.stdout.write` at stderr. A\n// later `console.log` cannot corrupt the stream, and the protocol does not depend\n// on being the first thing to run.\nconst realStdoutWrite = process.stdout.write.bind(process.stdout);\nconst protocolStream = { write: (chunk) => realStdoutWrite(chunk) };\n\nprocess.stdout.write = function toStderr(chunk: string | Uint8Array, encoding?: BufferEncoding | ((err?: Error) => void), callback?: (err?: Error) => void) {\n process.stderr.write(chunk);\n if (typeof encoding === 'function') encoding();\n else if (typeof callback === 'function') callback();\n return true;\n};\n\n// Diagnostics are opt-in: a client reading stdout is reading a protocol stream\n// and nothing else, so anything else has to be asked for.\nif (process.env.ONBOARDER_MCP_LOG === '1') {\n console.error(`[onboarder-mcp] ${SERVER_INFO.name} ${SERVER_INFO.version} starting on stdio`);\n}\n\nserveMcp({ output: protocolStream });\n"]}
|