gitnexus 1.6.8-rc.25 → 1.6.8-rc.27
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 +1 -1
- package/dist/cli/ai-context.js +1 -1
- package/dist/cli/help-i18n.js +4 -0
- package/dist/cli/i18n/en.d.ts +4 -1
- package/dist/cli/i18n/en.js +4 -1
- package/dist/cli/i18n/resources.d.ts +7 -1
- package/dist/cli/i18n/zh-CN.d.ts +3 -0
- package/dist/cli/i18n/zh-CN.js +4 -1
- package/dist/cli/index.js +6 -1
- package/dist/cli/mcp.d.ts +6 -1
- package/dist/cli/mcp.js +26 -1
- package/dist/cli/skill-gen.js +1 -1
- package/dist/cli/tool.js +4 -2
- package/dist/mcp/http-transport.d.ts +134 -0
- package/dist/mcp/http-transport.js +503 -0
- package/dist/mcp/local/local-backend.js +48 -6
- package/dist/mcp/resources.js +1 -1
- package/dist/mcp/tools.js +18 -4
- package/dist/server/api.js +30 -28
- package/dist/server/mcp-http.d.ts +5 -6
- package/dist/server/mcp-http.js +9 -82
- package/dist/server/middleware.d.ts +34 -5
- package/dist/server/middleware.js +82 -17
- package/dist/server/private-ip.d.ts +1 -0
- package/dist/server/private-ip.js +15 -0
- package/package.json +1 -1
- package/skills/gitnexus-debugging.md +4 -4
- package/skills/gitnexus-exploring.md +3 -3
- package/skills/gitnexus-refactoring.md +1 -1
- package/web/assets/{agent-ay4LD70X.js → agent-CJmGaI8F.js} +1 -1
- package/web/assets/{architectureDiagram-UL44E2DR-Dc-viYhd.js → architectureDiagram-UL44E2DR-D7Nzv8Z7.js} +1 -1
- package/web/assets/{chunk-LCXTWHL2-4rpojOyj.js → chunk-LCXTWHL2-x5GBtTcn.js} +1 -1
- package/web/assets/{chunk-RG4AUYOV-BnOy944n.js → chunk-RG4AUYOV-5yz_7HGK.js} +1 -1
- package/web/assets/{classDiagram-KGZ6W3CR-Bsgpy98Q.js → classDiagram-KGZ6W3CR-Ce7th0vG.js} +1 -1
- package/web/assets/{classDiagram-v2-72OJOZXJ-D5atDGjc.js → classDiagram-v2-72OJOZXJ-Cc0N-4aA.js} +1 -1
- package/web/assets/{diagram-3NCE3AQN-Cz1OEMVi.js → diagram-3NCE3AQN-6wUsUD7U.js} +1 -1
- package/web/assets/{diagram-GF46GFSD-CWYwzfP8.js → diagram-GF46GFSD-Disbhf7W.js} +1 -1
- package/web/assets/{diagram-QXG6HAR7-DtBObr8L.js → diagram-QXG6HAR7-BeFCG-ob.js} +1 -1
- package/web/assets/{diagram-WEQXMOUZ-BUV44Ov_.js → diagram-WEQXMOUZ-Bd6Dgwiv.js} +1 -1
- package/web/assets/{erDiagram-L5TCEMPS-Ds9s-sRF.js → erDiagram-L5TCEMPS-sHox0Zi_.js} +1 -1
- package/web/assets/{flowDiagram-H6V6AXG4-CupStHQb.js → flowDiagram-H6V6AXG4-C0y_PyUc.js} +1 -1
- package/web/assets/{index-Do8AE5yF.js → index-C_FZ3Bqu.js} +6 -6
- package/web/assets/{infoDiagram-3YFTVSEB-DPTXSbgu.js → infoDiagram-3YFTVSEB-K8pFihzq.js} +1 -1
- package/web/assets/{ishikawaDiagram-BNXS4ZKH-CeK-Qhet.js → ishikawaDiagram-BNXS4ZKH-DnMJCWwI.js} +1 -1
- package/web/assets/{kanban-definition-75IXJCU3-D4tx6QQ-.js → kanban-definition-75IXJCU3-D-4EXdJe.js} +1 -1
- package/web/assets/{mindmap-definition-2TDM6QVE-Bcto_kGa.js → mindmap-definition-2TDM6QVE-CC0qeqmA.js} +1 -1
- package/web/assets/{pieDiagram-CU6KROY3-DPIeBTG6.js → pieDiagram-CU6KROY3-D-53o4Ll.js} +1 -1
- package/web/assets/{requirementDiagram-JXO7QTGE-DDGXjVKO.js → requirementDiagram-JXO7QTGE-gNmDM8qN.js} +1 -1
- package/web/assets/{sequenceDiagram-VS2MUI6T-BzDqpcVW.js → sequenceDiagram-VS2MUI6T-CxcTKXw1.js} +1 -1
- package/web/assets/{stateDiagram-7D4R322I-Bx__als3.js → stateDiagram-7D4R322I-CjnhCRbL.js} +1 -1
- package/web/assets/{stateDiagram-v2-36443NZ5-QqOh2yO-.js → stateDiagram-v2-36443NZ5-C5HPpkcW.js} +1 -1
- package/web/assets/{timeline-definition-O6YCAMPW-C1eogTOG.js → timeline-definition-O6YCAMPW-BmDoRniN.js} +1 -1
- package/web/assets/{vennDiagram-MWXL3ELB-D20F4rSW.js → vennDiagram-MWXL3ELB-S9b_NlgG.js} +1 -1
- package/web/assets/{wardleyDiagram-CUQ6CDDI-BeBHg7ST.js → wardleyDiagram-CUQ6CDDI-Bbs9z_r0.js} +1 -1
- package/web/assets/{xychartDiagram-N2JHSOCM-CdOWeoNI.js → xychartDiagram-N2JHSOCM-FyWVcm04.js} +1 -1
- package/web/index.html +1 -1
package/README.md
CHANGED
|
@@ -134,7 +134,7 @@ Your AI agent gets these tools automatically:
|
|
|
134
134
|
| `rename` | Multi-file coordinated rename with graph + text search | Optional |
|
|
135
135
|
| `cypher` | Raw Cypher graph queries | Optional |
|
|
136
136
|
|
|
137
|
-
> With one indexed repo, the `repo` param is optional. With multiple, specify which: `query({
|
|
137
|
+
> With one indexed repo, the `repo` param is optional. With multiple, specify which: `query({search_query: "auth", repo: "my-app"})`.
|
|
138
138
|
|
|
139
139
|
## MCP Resources
|
|
140
140
|
|
package/dist/cli/ai-context.js
CHANGED
|
@@ -134,7 +134,7 @@ This project is indexed by GitNexus as **${projectName}**${noStats ? '' : ` (${s
|
|
|
134
134
|
- **MUST run impact analysis before editing any symbol.** Before modifying a function, class, or method, run \`impact({target: "symbolName", direction: "upstream"})\` and report the blast radius (direct callers, affected processes, risk level) to the user.
|
|
135
135
|
- **MUST run \`detect_changes()\` before committing** to verify your changes only affect expected symbols and execution flows. For regression review, compare against the default branch: \`detect_changes({scope: "compare", base_ref: ${JSON.stringify(markdownSafeBranch(defaultBranch))}})\`.
|
|
136
136
|
- **MUST warn the user** if impact analysis returns HIGH or CRITICAL risk before proceeding with edits.
|
|
137
|
-
- When exploring unfamiliar code, use \`query({
|
|
137
|
+
- When exploring unfamiliar code, use \`query({search_query: "concept"})\` to find execution flows instead of grepping. It returns process-grouped results ranked by relevance.
|
|
138
138
|
- When you need full context on a specific symbol — callers, callees, which execution flows it participates in — use \`context({name: "symbolName"})\`.
|
|
139
139
|
- For security review, \`explain({target: "fileOrSymbol"})\` lists taint findings (source→sink flows; needs \`analyze --pdg\`).
|
|
140
140
|
|
package/dist/cli/help-i18n.js
CHANGED
|
@@ -66,6 +66,10 @@ const OPTION_DESCRIPTION_KEYS = {
|
|
|
66
66
|
'analyze|--embedding-device <device>': 'help.option.analyze.embeddingDevice',
|
|
67
67
|
'index|-f, --force': 'help.option.index.force',
|
|
68
68
|
'index|--allow-non-git': 'help.option.index.allowNonGit',
|
|
69
|
+
'mcp|--http': 'help.option.mcp.http',
|
|
70
|
+
'mcp|-p, --port <port>': 'help.option.port',
|
|
71
|
+
'mcp|--host <host>': 'help.option.mcp.host',
|
|
72
|
+
'mcp|--auth-token <token>': 'help.option.mcp.authToken',
|
|
69
73
|
'serve|-p, --port <port>': 'help.option.port',
|
|
70
74
|
'serve|--host <host>': 'help.option.serve.host',
|
|
71
75
|
'uninstall|-f, --force': 'help.option.uninstall.force',
|
package/dist/cli/i18n/en.d.ts
CHANGED
|
@@ -112,7 +112,7 @@ export declare const en: {
|
|
|
112
112
|
readonly 'help.command.analyze.description': "Index a repository (full analysis)";
|
|
113
113
|
readonly 'help.command.index.description': "Register an existing .gitnexus/ folder into the global registry (no re-analysis needed)";
|
|
114
114
|
readonly 'help.command.serve.description': "Start local HTTP server for web UI connection";
|
|
115
|
-
readonly 'help.command.mcp.description': "Start MCP server
|
|
115
|
+
readonly 'help.command.mcp.description': "Start MCP server. Default: stdio. Use --http for a remote HTTP server (Streamable HTTP at POST /mcp + legacy SSE at GET /sse, POST /messages).";
|
|
116
116
|
readonly 'help.command.list.description': "List all indexed repositories";
|
|
117
117
|
readonly 'help.command.status.description': "Show index status for current repo";
|
|
118
118
|
readonly 'help.command.doctor.description': "Show runtime platform capabilities and embedding configuration";
|
|
@@ -164,6 +164,9 @@ export declare const en: {
|
|
|
164
164
|
readonly 'help.option.index.allowNonGit': "Allow registering folders that are not Git repositories";
|
|
165
165
|
readonly 'help.option.port': "Port number";
|
|
166
166
|
readonly 'help.option.serve.host': "Bind address (default: 127.0.0.1, use 0.0.0.0 for remote access)";
|
|
167
|
+
readonly 'help.option.mcp.http': "Serve MCP over HTTP instead of stdio (for remote clients)";
|
|
168
|
+
readonly 'help.option.mcp.host': "HTTP bind address (only with --http). Default: 127.0.0.1 (loopback). Use 0.0.0.0 to expose to all interfaces.";
|
|
169
|
+
readonly 'help.option.mcp.authToken': "Require this bearer token in the Authorization header (only with --http); may also be set via the GITNEXUS_MCP_AUTH_TOKEN env var. Required for a non-loopback bind (--host 0.0.0.0/::), which otherwise refuses to start.";
|
|
167
170
|
readonly 'help.option.force.confirmation': "Skip confirmation prompt";
|
|
168
171
|
readonly 'help.option.uninstall.force': "Apply the changes (default is a dry-run preview)";
|
|
169
172
|
readonly 'help.option.clean.all': "Clean all indexed repos";
|
package/dist/cli/i18n/en.js
CHANGED
|
@@ -112,7 +112,7 @@ export const en = {
|
|
|
112
112
|
'help.command.analyze.description': 'Index a repository (full analysis)',
|
|
113
113
|
'help.command.index.description': 'Register an existing .gitnexus/ folder into the global registry (no re-analysis needed)',
|
|
114
114
|
'help.command.serve.description': 'Start local HTTP server for web UI connection',
|
|
115
|
-
'help.command.mcp.description': 'Start MCP server
|
|
115
|
+
'help.command.mcp.description': 'Start MCP server. Default: stdio. Use --http for a remote HTTP server (Streamable HTTP at POST /mcp + legacy SSE at GET /sse, POST /messages).',
|
|
116
116
|
'help.command.list.description': 'List all indexed repositories',
|
|
117
117
|
'help.command.status.description': 'Show index status for current repo',
|
|
118
118
|
'help.command.doctor.description': 'Show runtime platform capabilities and embedding configuration',
|
|
@@ -164,6 +164,9 @@ export const en = {
|
|
|
164
164
|
'help.option.index.allowNonGit': 'Allow registering folders that are not Git repositories',
|
|
165
165
|
'help.option.port': 'Port number',
|
|
166
166
|
'help.option.serve.host': 'Bind address (default: 127.0.0.1, use 0.0.0.0 for remote access)',
|
|
167
|
+
'help.option.mcp.http': 'Serve MCP over HTTP instead of stdio (for remote clients)',
|
|
168
|
+
'help.option.mcp.host': 'HTTP bind address (only with --http). Default: 127.0.0.1 (loopback). Use 0.0.0.0 to expose to all interfaces.',
|
|
169
|
+
'help.option.mcp.authToken': 'Require this bearer token in the Authorization header (only with --http); may also be set via the GITNEXUS_MCP_AUTH_TOKEN env var. Required for a non-loopback bind (--host 0.0.0.0/::), which otherwise refuses to start.',
|
|
167
170
|
'help.option.force.confirmation': 'Skip confirmation prompt',
|
|
168
171
|
'help.option.uninstall.force': 'Apply the changes (default is a dry-run preview)',
|
|
169
172
|
'help.option.clean.all': 'Clean all indexed repos',
|
|
@@ -113,7 +113,7 @@ export declare const cliResources: {
|
|
|
113
113
|
readonly 'help.command.analyze.description': "Index a repository (full analysis)";
|
|
114
114
|
readonly 'help.command.index.description': "Register an existing .gitnexus/ folder into the global registry (no re-analysis needed)";
|
|
115
115
|
readonly 'help.command.serve.description': "Start local HTTP server for web UI connection";
|
|
116
|
-
readonly 'help.command.mcp.description': "Start MCP server
|
|
116
|
+
readonly 'help.command.mcp.description': "Start MCP server. Default: stdio. Use --http for a remote HTTP server (Streamable HTTP at POST /mcp + legacy SSE at GET /sse, POST /messages).";
|
|
117
117
|
readonly 'help.command.list.description': "List all indexed repositories";
|
|
118
118
|
readonly 'help.command.status.description': "Show index status for current repo";
|
|
119
119
|
readonly 'help.command.doctor.description': "Show runtime platform capabilities and embedding configuration";
|
|
@@ -165,6 +165,9 @@ export declare const cliResources: {
|
|
|
165
165
|
readonly 'help.option.index.allowNonGit': "Allow registering folders that are not Git repositories";
|
|
166
166
|
readonly 'help.option.port': "Port number";
|
|
167
167
|
readonly 'help.option.serve.host': "Bind address (default: 127.0.0.1, use 0.0.0.0 for remote access)";
|
|
168
|
+
readonly 'help.option.mcp.http': "Serve MCP over HTTP instead of stdio (for remote clients)";
|
|
169
|
+
readonly 'help.option.mcp.host': "HTTP bind address (only with --http). Default: 127.0.0.1 (loopback). Use 0.0.0.0 to expose to all interfaces.";
|
|
170
|
+
readonly 'help.option.mcp.authToken': "Require this bearer token in the Authorization header (only with --http); may also be set via the GITNEXUS_MCP_AUTH_TOKEN env var. Required for a non-loopback bind (--host 0.0.0.0/::), which otherwise refuses to start.";
|
|
168
171
|
readonly 'help.option.force.confirmation': "Skip confirmation prompt";
|
|
169
172
|
readonly 'help.option.uninstall.force': "Apply the changes (default is a dry-run preview)";
|
|
170
173
|
readonly 'help.option.clean.all': "Clean all indexed repos";
|
|
@@ -392,6 +395,9 @@ export declare const cliResources: {
|
|
|
392
395
|
'help.option.index.allowNonGit': string;
|
|
393
396
|
'help.option.port': string;
|
|
394
397
|
'help.option.serve.host': string;
|
|
398
|
+
'help.option.mcp.http': string;
|
|
399
|
+
'help.option.mcp.host': string;
|
|
400
|
+
'help.option.mcp.authToken': string;
|
|
395
401
|
'help.option.force.confirmation': string;
|
|
396
402
|
'help.option.uninstall.force': string;
|
|
397
403
|
'help.option.clean.all': string;
|
package/dist/cli/i18n/zh-CN.d.ts
CHANGED
|
@@ -164,6 +164,9 @@ export declare const zhCN: {
|
|
|
164
164
|
'help.option.index.allowNonGit': string;
|
|
165
165
|
'help.option.port': string;
|
|
166
166
|
'help.option.serve.host': string;
|
|
167
|
+
'help.option.mcp.http': string;
|
|
168
|
+
'help.option.mcp.host': string;
|
|
169
|
+
'help.option.mcp.authToken': string;
|
|
167
170
|
'help.option.force.confirmation': string;
|
|
168
171
|
'help.option.uninstall.force': string;
|
|
169
172
|
'help.option.clean.all': string;
|
package/dist/cli/i18n/zh-CN.js
CHANGED
|
@@ -112,7 +112,7 @@ export const zhCN = {
|
|
|
112
112
|
'help.command.analyze.description': '索引仓库(完整分析)',
|
|
113
113
|
'help.command.index.description': '将现有 .gitnexus/ 文件夹注册到全局注册表(无需重新分析)',
|
|
114
114
|
'help.command.serve.description': '启动供 Web UI 连接的本地 HTTP 服务器',
|
|
115
|
-
'help.command.mcp.description': '启动 MCP
|
|
115
|
+
'help.command.mcp.description': '启动 MCP 服务器。默认为 stdio。使用 --http 启动远程 HTTP 服务器(Streamable HTTP: POST /mcp + 遗留 SSE: GET /sse, POST /messages)。',
|
|
116
116
|
'help.command.list.description': '列出所有已索引仓库',
|
|
117
117
|
'help.command.status.description': '显示当前仓库的索引状态',
|
|
118
118
|
'help.command.doctor.description': '显示运行平台能力和嵌入配置',
|
|
@@ -164,6 +164,9 @@ export const zhCN = {
|
|
|
164
164
|
'help.option.index.allowNonGit': '允许注册非 Git 仓库文件夹',
|
|
165
165
|
'help.option.port': '端口号',
|
|
166
166
|
'help.option.serve.host': '绑定地址(默认:127.0.0.1;远程访问可用 0.0.0.0)',
|
|
167
|
+
'help.option.mcp.http': '使用 HTTP 代替 stdio 提供 MCP 服务(适合远程客户端)',
|
|
168
|
+
'help.option.mcp.host': 'HTTP 绑定地址(仅与 --http 搭配使用)。默认:127.0.0.1(回环)。使用 0.0.0.0 向所有接口开放。',
|
|
169
|
+
'help.option.mcp.authToken': '要求 Authorization 头携带此 Bearer Token(仅与 --http 搭配使用);也可通过 GITNEXUS_MCP_AUTH_TOKEN 环境变量设置。非回环绑定(--host 0.0.0.0/::)时必填,否则拒绝启动。',
|
|
167
170
|
'help.option.force.confirmation': '跳过确认提示',
|
|
168
171
|
'help.option.uninstall.force': '应用更改(默认仅为预演预览)',
|
|
169
172
|
'help.option.clean.all': '清理所有已索引仓库',
|
package/dist/cli/index.js
CHANGED
|
@@ -79,7 +79,12 @@ program
|
|
|
79
79
|
.action(createLbugLazyAction(() => import('./serve.js'), 'serveCommand'));
|
|
80
80
|
program
|
|
81
81
|
.command('mcp')
|
|
82
|
-
.description('Start MCP server
|
|
82
|
+
.description('Start MCP server. Default: stdio. Use --http for a remote HTTP server ' +
|
|
83
|
+
'(Streamable HTTP at POST /mcp + legacy SSE at GET /sse, POST /messages).')
|
|
84
|
+
.option('--http', 'Serve MCP over HTTP instead of stdio (for remote clients)')
|
|
85
|
+
.option('-p, --port <port>', 'HTTP port (only with --http). Default: 3000', '3000')
|
|
86
|
+
.option('--host <host>', 'HTTP bind address (only with --http). Default: 127.0.0.1 (loopback). Use 0.0.0.0 to expose to all interfaces.', '127.0.0.1')
|
|
87
|
+
.option('--auth-token <token>', 'Require this bearer token in the Authorization header (only with --http); may also be set via the GITNEXUS_MCP_AUTH_TOKEN env var. Required for a non-loopback bind (--host 0.0.0.0/::), which otherwise refuses to start.')
|
|
83
88
|
.action(createLbugLazyAction(() => import('./mcp.js'), 'mcpCommand'));
|
|
84
89
|
program
|
|
85
90
|
.command('list')
|
package/dist/cli/mcp.d.ts
CHANGED
|
@@ -26,4 +26,9 @@
|
|
|
26
26
|
* `mcpCommand` after the sentinel install. The regression test at
|
|
27
27
|
* `gitnexus/test/integration/mcp/import-closure.test.ts` enforces this.
|
|
28
28
|
*/
|
|
29
|
-
export declare const mcpCommand: (
|
|
29
|
+
export declare const mcpCommand: (options?: {
|
|
30
|
+
http?: boolean;
|
|
31
|
+
port?: string;
|
|
32
|
+
host?: string;
|
|
33
|
+
authToken?: string;
|
|
34
|
+
}) => Promise<void>;
|
package/dist/cli/mcp.js
CHANGED
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
* `gitnexus/test/integration/mcp/import-closure.test.ts` enforces this.
|
|
28
28
|
*/
|
|
29
29
|
import { installGlobalStdoutSentinel } from '../mcp/stdio-context.js';
|
|
30
|
-
export const mcpCommand = async () => {
|
|
30
|
+
export const mcpCommand = async (options) => {
|
|
31
31
|
// Install the global stdout sentinel as the very first thing — before
|
|
32
32
|
// ANY other module loads. The static-import closure above is leaf-only
|
|
33
33
|
// (stdio-context → stdio-capture, zero non-`node:` deps), so this is
|
|
@@ -68,6 +68,31 @@ export const mcpCommand = async () => {
|
|
|
68
68
|
else {
|
|
69
69
|
logger.info({ repoCount: repos.length, repos: repos.map((r) => r.name) }, 'GitNexus: MCP server starting');
|
|
70
70
|
}
|
|
71
|
+
// Start HTTP server or fall back to stdio (default).
|
|
72
|
+
if (options?.http) {
|
|
73
|
+
// Dynamically import the HTTP transport module AFTER the sentinel installs.
|
|
74
|
+
// http-transport.ts pulls in express/cors/MCP SDK HTTP transport; these must
|
|
75
|
+
// not load before installGlobalStdoutSentinel() runs (see module doc above).
|
|
76
|
+
const port = Number(options.port ?? 3000);
|
|
77
|
+
if (!Number.isInteger(port) || port < 1 || port > 65535) {
|
|
78
|
+
logger.error({ port: options.port }, `Invalid --port value: "${options.port ?? ''}". Must be an integer between 1 and 65535.`);
|
|
79
|
+
process.exit(1);
|
|
80
|
+
}
|
|
81
|
+
// Dynamic import keeps express/cors out of mcp.ts's static graph (stdio sentinel).
|
|
82
|
+
const { startMcpHttpServer, resolveAuthToken } = await import('../mcp/http-transport.js');
|
|
83
|
+
try {
|
|
84
|
+
await startMcpHttpServer(backend, {
|
|
85
|
+
port,
|
|
86
|
+
host: options.host ?? '127.0.0.1',
|
|
87
|
+
authToken: resolveAuthToken(options.authToken, process.env),
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
catch (err) {
|
|
91
|
+
logger.error({ err: err instanceof Error ? err.message : err }, 'Failed to start the MCP HTTP server');
|
|
92
|
+
process.exit(1);
|
|
93
|
+
}
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
71
96
|
// Start MCP server (serves all repos, discovers new ones lazily)
|
|
72
97
|
await startMCPServer(backend);
|
|
73
98
|
};
|
package/dist/cli/skill-gen.js
CHANGED
|
@@ -483,7 +483,7 @@ const renderSkillMarkdown = (community, projectName, members, files, entryPoints
|
|
|
483
483
|
lines.push('## How to Explore');
|
|
484
484
|
lines.push('');
|
|
485
485
|
lines.push(`1. \`context({name: "${firstEntry}"})\` \u2014 see callers and callees`);
|
|
486
|
-
lines.push(`2. \`query({
|
|
486
|
+
lines.push(`2. \`query({search_query: "${community.label.toLowerCase()}"})\` \u2014 find related execution flows`);
|
|
487
487
|
lines.push('3. Read key files listed above for implementation details');
|
|
488
488
|
lines.push('4. `explain({target: "<file or symbol>"})` — persisted taint findings (source→sink data flows), when indexed with `--pdg`');
|
|
489
489
|
lines.push('');
|
package/dist/cli/tool.js
CHANGED
|
@@ -62,7 +62,8 @@ export async function queryCommand(queryText, options) {
|
|
|
62
62
|
}
|
|
63
63
|
const backend = await getBackend();
|
|
64
64
|
const result = await backend.callTool('query', {
|
|
65
|
-
|
|
65
|
+
// #2175: canonical param is search_query; the backend still accepts legacy "query".
|
|
66
|
+
search_query: queryText,
|
|
66
67
|
task_context: options?.context,
|
|
67
68
|
goal: options?.goal,
|
|
68
69
|
limit: options?.limit ? parseInt(options.limit) : undefined,
|
|
@@ -154,7 +155,8 @@ export async function cypherCommand(query, options) {
|
|
|
154
155
|
}
|
|
155
156
|
const backend = await getBackend();
|
|
156
157
|
const result = await backend.callTool('cypher', {
|
|
157
|
-
query
|
|
158
|
+
// #2175: canonical param is statement; the backend still accepts legacy "query".
|
|
159
|
+
statement: query,
|
|
158
160
|
repo: options?.repo,
|
|
159
161
|
branch: options?.branch,
|
|
160
162
|
});
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dedicated MCP HTTP server.
|
|
3
|
+
*
|
|
4
|
+
* Provides HTTP-based MCP transport supporting:
|
|
5
|
+
* - Modern Streamable HTTP: POST /mcp
|
|
6
|
+
* - Legacy SSE transport: GET /sse + POST /messages
|
|
7
|
+
*
|
|
8
|
+
* Started via `gitnexus mcp --http`.
|
|
9
|
+
* stdio remains the default mode for `gitnexus mcp` (no breaking change).
|
|
10
|
+
*
|
|
11
|
+
* Exports createStreamableHttpHandler and createSseHandlers so that
|
|
12
|
+
* server/mcp-http.ts (web-UI route mount) can reuse them without inverting
|
|
13
|
+
* the established server/ → mcp/ dependency direction.
|
|
14
|
+
*
|
|
15
|
+
* Security considerations:
|
|
16
|
+
* - Default binds to 127.0.0.1 (loopback only).
|
|
17
|
+
* - Use --auth-token to enable Bearer Token authentication.
|
|
18
|
+
* - Use --host 0.0.0.0 to expose to all interfaces (requires --auth-token — refuses to start otherwise).
|
|
19
|
+
* - CORS is restricted to loopback origins when no auth token is configured.
|
|
20
|
+
* - PNA (Private Network Access) header is emitted only in response to browser preflight requests.
|
|
21
|
+
*/
|
|
22
|
+
import type { Server as HttpServer } from 'http';
|
|
23
|
+
import { type Request, type Response, type NextFunction } from 'express';
|
|
24
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
25
|
+
import type { LocalBackend } from './local/local-backend.js';
|
|
26
|
+
/** HTTP server configuration options. */
|
|
27
|
+
export interface McpHttpOptions {
|
|
28
|
+
/** Listening port. */
|
|
29
|
+
port: number;
|
|
30
|
+
/** Bind address (default: 127.0.0.1). */
|
|
31
|
+
host: string;
|
|
32
|
+
/** Bearer auth token (optional; no auth when omitted). */
|
|
33
|
+
authToken?: string;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Creates a Bearer Token authentication middleware.
|
|
37
|
+
*
|
|
38
|
+
* - When authToken is not set, all requests pass through.
|
|
39
|
+
* - When authToken is set, checks the Authorization: Bearer <token> header.
|
|
40
|
+
* - Uses constant-time comparison to prevent timing oracle attacks.
|
|
41
|
+
* - Returns a JSON-RPC formatted 401 on failure.
|
|
42
|
+
*/
|
|
43
|
+
export declare function createAuthMiddleware(authToken?: string): (req: Request, res: Response, next: NextFunction) => void;
|
|
44
|
+
/**
|
|
45
|
+
* Returns true when an Origin should be allowed by the no-auth (loopback-only)
|
|
46
|
+
* CORS policy — i.e. it is absent (non-browser caller) or a loopback origin.
|
|
47
|
+
*
|
|
48
|
+
* WHATWG URL keeps the brackets on IPv6 literals
|
|
49
|
+
* (`new URL('http://[::1]/').hostname === '[::1]'`) and canonicalizes the
|
|
50
|
+
* IPv4-mapped loopback to `[::ffff:7f00:1]`; loopback IPv4 is the whole
|
|
51
|
+
* 127.0.0.0/8 block — so all of those forms are matched explicitly.
|
|
52
|
+
*/
|
|
53
|
+
export declare function isLoopbackOrigin(origin: string | undefined): boolean;
|
|
54
|
+
/** True for the exact loopback bind addresses. */
|
|
55
|
+
export declare function isLoopbackHost(host: string): boolean;
|
|
56
|
+
/** True for any-interface wildcard binds, whose externally-used Host is unknowable. */
|
|
57
|
+
export declare function isWildcardHost(host: string): boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Computes the SDK DNS-rebinding `allowedHosts` list (a Host-header allowlist) for a
|
|
60
|
+
* bind host/port, or `undefined` when protection should stay off.
|
|
61
|
+
*
|
|
62
|
+
* Wildcard binds (`0.0.0.0` / `::`) return `undefined` — the Host a client
|
|
63
|
+
* legitimately uses is unknowable, so the bearer token (required for non-loopback
|
|
64
|
+
* binds) is the control. Loopback binds allow all three loopback host forms
|
|
65
|
+
* (bare + `:port`); a specific host (e.g. `192.168.1.50`) allows that host
|
|
66
|
+
* (bare + `:port`), which is knowable and a free defence-in-depth win.
|
|
67
|
+
*/
|
|
68
|
+
export declare function computeAllowedHosts(host: string, port: number): string[] | undefined;
|
|
69
|
+
/**
|
|
70
|
+
* Resolves the MCP HTTP bearer token from the `--auth-token` flag or the
|
|
71
|
+
* `GITNEXUS_MCP_AUTH_TOKEN` env var (the flag wins). An empty or whitespace-only
|
|
72
|
+
* value is treated as "no token" so a blank env var cannot silently disable auth
|
|
73
|
+
* (and slip past the non-loopback hard-fail).
|
|
74
|
+
*/
|
|
75
|
+
export declare function resolveAuthToken(optToken: string | undefined, env: NodeJS.ProcessEnv): string | undefined;
|
|
76
|
+
/**
|
|
77
|
+
* Starts a periodic sweep that closes and evicts sessions idle longer than
|
|
78
|
+
* `ttlMs`, returning the (unref'd) timer. Shared by both transport factories to
|
|
79
|
+
* guard against network drops where the per-session onclose never fires.
|
|
80
|
+
*/
|
|
81
|
+
export declare function startIdleSweep<T extends {
|
|
82
|
+
server: Server;
|
|
83
|
+
lastActivity: number;
|
|
84
|
+
}>(sessions: Map<string, T>, ttlMs: number, intervalMs: number): NodeJS.Timeout;
|
|
85
|
+
/**
|
|
86
|
+
* Creates a reusable StreamableHTTP request handler.
|
|
87
|
+
*
|
|
88
|
+
* Encapsulates the session map and request-dispatch logic as an independent
|
|
89
|
+
* factory, reused by both startMcpHttpServer (POST /mcp) and the web-UI server
|
|
90
|
+
* route mount in server/mcp-http.ts (/api/mcp).
|
|
91
|
+
*/
|
|
92
|
+
export declare function createStreamableHttpHandler(backend: LocalBackend, opts?: {
|
|
93
|
+
createServer?: () => Server;
|
|
94
|
+
host?: string;
|
|
95
|
+
port?: number;
|
|
96
|
+
}): {
|
|
97
|
+
handler: (req: Request, res: Response) => Promise<void>;
|
|
98
|
+
cleanup: () => Promise<void>;
|
|
99
|
+
};
|
|
100
|
+
/**
|
|
101
|
+
* Creates legacy SSE transport handlers.
|
|
102
|
+
*
|
|
103
|
+
* GET /sse (or custom path) establishes the SSE stream;
|
|
104
|
+
* POST /messages (or custom path) receives client JSON-RPC messages.
|
|
105
|
+
*
|
|
106
|
+
* Includes the same idle-TTL eviction as createStreamableHttpHandler to prevent
|
|
107
|
+
* memory leaks when clients drop without closing the SSE connection cleanly.
|
|
108
|
+
*
|
|
109
|
+
* @param backend LocalBackend instance
|
|
110
|
+
* @param messagesPath Path clients POST messages to (default: '/messages')
|
|
111
|
+
*/
|
|
112
|
+
export declare function createSseHandlers(backend: LocalBackend, messagesPath?: string, opts?: {
|
|
113
|
+
maxSessions?: number;
|
|
114
|
+
host?: string;
|
|
115
|
+
port?: number;
|
|
116
|
+
}): {
|
|
117
|
+
sseHandler: (req: Request, res: Response) => Promise<void>;
|
|
118
|
+
messageHandler: (req: Request, res: Response) => Promise<void>;
|
|
119
|
+
cleanup: () => Promise<void>;
|
|
120
|
+
};
|
|
121
|
+
/**
|
|
122
|
+
* Creates and starts the dedicated MCP HTTP server.
|
|
123
|
+
*
|
|
124
|
+
* Mounts the following routes:
|
|
125
|
+
* - GET /health — health check (no auth required; for orchestrators/probes)
|
|
126
|
+
* - POST /mcp — Streamable HTTP (modern clients)
|
|
127
|
+
* - GET /sse — legacy SSE stream (old clients)
|
|
128
|
+
* - POST /messages — legacy SSE message endpoint
|
|
129
|
+
*
|
|
130
|
+
* @param backend LocalBackend instance
|
|
131
|
+
* @param options Server configuration
|
|
132
|
+
* @returns The listening http.Server
|
|
133
|
+
*/
|
|
134
|
+
export declare function startMcpHttpServer(backend: LocalBackend, options: McpHttpOptions): Promise<HttpServer>;
|