@dependfix/mcp 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +67 -0
- package/dist/bin.d.mts +1 -0
- package/dist/bin.mjs +12 -0
- package/dist/bin.mjs.map +1 -0
- package/dist/index.d.mts +19 -0
- package/dist/index.mjs +3 -0
- package/dist/src.mjs +561 -0
- package/dist/src.mjs.map +1 -0
- package/package.json +66 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 CaoMeiYouRen <https://github.com/CaoMeiYouRen>
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# @dependfix/mcp
|
|
2
|
+
|
|
3
|
+
> dependfix 的 MCP Server 包。通过 [Model Context Protocol](https://modelcontextprotocol.io/) 将 dependfix 的扫描/修复能力暴露给 AI 编程助手(Claude、Copilot、Cursor 等)。
|
|
4
|
+
|
|
5
|
+
## 安装
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add @dependfix/mcp
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Tool 清单
|
|
12
|
+
|
|
13
|
+
| Tool | 功能 | 输入 |
|
|
14
|
+
|:-----|:-----|:-----|
|
|
15
|
+
| `fetch_alerts` | 拉取指定仓库的 Dependabot 安全告警(可选并行 Code Scanning,只读) | `repo`, `severity?`, `code_scanning?` |
|
|
16
|
+
| `discover_repos` | 按 owner / org 自动发现仓库(只读) | `owner[]`, `topics?`, `include?`, `exclude?`, `probe_dependabot?` |
|
|
17
|
+
| `run_scan` | 对目标仓库执行 dependfix 扫描并修复 | `repo`, `mode?`, `severity?`, `code_scanning?`, `max_alerts?`, `max_concurrency?`, `dry_run?`, `allow_major_upgrade?`, `ai_enabled?`, `ai_provider?`, `ai_model?`, `ai_trigger?` |
|
|
18
|
+
| `fix_dependency` | 修复单个依赖或 lockfile(override / direct / lockfile) | `workDir`, `fix_type?`, `packageName?`, `targetVersion?` |
|
|
19
|
+
| `cleanup_branches` | 清理已合并/已关闭的 dependfix 分支(非交互) | `repo`, `dry_run?` |
|
|
20
|
+
| `history` | 查询指定仓库的历史运行摘要(只读) | `repo` |
|
|
21
|
+
| `get_last_report` | 读取最近一次 JSON 报告(只读) | — |
|
|
22
|
+
|
|
23
|
+
参数语义与 CLI 对齐(severity 为阈值语义:`high` 保留 critical + high;`dry_run` 缺省按 mode 推断;AI 参数仅透传开关与模型,apiKey 从环境变量读取)。
|
|
24
|
+
|
|
25
|
+
## 配置
|
|
26
|
+
|
|
27
|
+
通过 MCP 配置文件添加(stdio 传输):
|
|
28
|
+
|
|
29
|
+
```json
|
|
30
|
+
{
|
|
31
|
+
"mcpServers": {
|
|
32
|
+
"dependfix": {
|
|
33
|
+
"command": "npx",
|
|
34
|
+
"args": ["@dependfix/mcp"],
|
|
35
|
+
"env": {
|
|
36
|
+
"GITHUB_TOKEN": "${GITHUB_TOKEN}"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
环境变量:
|
|
44
|
+
|
|
45
|
+
| 变量 | 说明 |
|
|
46
|
+
|:-----|:-----|
|
|
47
|
+
| `GITHUB_TOKEN` | GitHub 访问凭据(拉取告警 / 执行扫描 / 分支清理必需) |
|
|
48
|
+
| `DEPENDFIX_MCP_REPORT_DIR` | JSON 报告输出目录(默认 `./dependfix-reports`) |
|
|
49
|
+
| `DEPENDFIX_AI_API_KEY` | AI 研判 API Key(启用 `run_scan` 的 `ai_enabled` 时必需;仅经 env 读取,禁止经 tool 参数传入) |
|
|
50
|
+
|
|
51
|
+
## 安全边界
|
|
52
|
+
|
|
53
|
+
- 凭据仅从环境变量读取(`GITHUB_TOKEN` / `DEPENDFIX_AI_API_KEY`),tool 参数不透传敏感信息
|
|
54
|
+
- `cleanup_branches` 为纯 GitHub API 操作(列表/状态/删除远程分支),无需本地仓库;只删除 `dependfix/` 前缀且已合并/已关闭的分支,绝不触碰 open PR 分支
|
|
55
|
+
- `fix_dependency` 需要本地已 clone 仓库目录(`workDir`,操作 package.json / pnpm-workspace.yaml / pnpm-lock.yaml)
|
|
56
|
+
|
|
57
|
+
## 本地开发
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
pnpm --filter @dependfix/mcp build # 构建 dist
|
|
61
|
+
pnpm --filter @dependfix/mcp test # 一致性测试
|
|
62
|
+
node packages/mcp/dist/bin.mjs # stdio 启动
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## 设计
|
|
66
|
+
|
|
67
|
+
详见 [mcp-server.md](../../docs/design/governance/mcp-server.md)(Tool schema、与 CLI 的一致性、错误处理、能力差距与演进路线)。
|
package/dist/bin.d.mts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {}
|
package/dist/bin.mjs
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { t as connectStdio } from "./src.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/bin.ts
|
|
5
|
+
connectStdio().catch((error) => {
|
|
6
|
+
console.error("[dependfix-mcp] 启动失败:", error);
|
|
7
|
+
process.exit(1);
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
//#endregion
|
|
11
|
+
export { };
|
|
12
|
+
//# sourceMappingURL=bin.mjs.map
|
package/dist/bin.mjs.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bin.mjs","names":[],"sources":["../src/bin.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { connectStdio } from './index'\n\nconnectStdio().catch((error) => {\n console.error('[dependfix-mcp] 启动失败:', error)\n process.exit(1)\n})\n"],"mappings":";;;;AAGA,aAAa,CAAC,CAAC,OAAO,UAAU;CAC5B,QAAQ,MAAM,yBAAyB,KAAK;CAC5C,QAAQ,KAAK,CAAC;AAClB,CAAC"}
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
//#region src/index.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* dependfix MCP Server:向 AI 助手暴露 7 个 tool。
|
|
5
|
+
* - fetch_alerts(只读):拉取 Dependabot / Code Scanning 告警
|
|
6
|
+
* - get_last_report(只读):读取最近 JSON 报告
|
|
7
|
+
* - run_scan(写入):执行扫描/修复(默认 report-only;支持 AI 研判透传)
|
|
8
|
+
* - fix_dependency(写入):修复单个依赖(override / direct / lockfile)
|
|
9
|
+
* - discover_repos(只读):按 owner / org 自动发现仓库
|
|
10
|
+
* - cleanup_branches(写入):清理已合并/已关闭的 dependfix 分支(非交互)
|
|
11
|
+
* - history(只读):查询仓库历史运行摘要
|
|
12
|
+
* 凭据从 GITHUB_TOKEN 环境变量读取(mcp-server.md §4.3)。
|
|
13
|
+
*/
|
|
14
|
+
declare const createMcpServer: () => McpServer;
|
|
15
|
+
/** 连接 stdio 传输(bin 入口调用) */
|
|
16
|
+
declare const connectStdio: () => Promise<void>;
|
|
17
|
+
//#endregion
|
|
18
|
+
export { connectStdio, createMcpServer };
|
|
19
|
+
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.mjs
ADDED
package/dist/src.mjs
ADDED
|
@@ -0,0 +1,561 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { DEFAULT_RUNTIME_CONFIG, DependfixApp, RUNTIME_MODES, SEVERITY_THRESHOLDS, createGitHubClient, deleteRemoteBranch, discoverRepositories, fetchCodeScanningAlerts, fetchDependabotAlerts, getBranchPrStatus, listDependfixBranches, overrideTransitiveDependency, queryRepoHistory, repairLockfile, upgradeDependency } from "@dependfix/engine";
|
|
5
|
+
import { filterAlerts, isValidRepoIdentifier } from "@dependfix/core";
|
|
6
|
+
import { readFileSync, readdirSync } from "node:fs";
|
|
7
|
+
import { join } from "node:path";
|
|
8
|
+
|
|
9
|
+
//#region src/tools/schemas.ts
|
|
10
|
+
const RUN_SCAN_MODES = RUNTIME_MODES.filter((m) => m !== "cleanup-branches");
|
|
11
|
+
/** `fetch_alerts` 输入:拉取指定仓库的安全告警(Dependabot + 可选 Code Scanning) */
|
|
12
|
+
const fetchAlertsSchema = z.object({
|
|
13
|
+
repo: z.string().describe("目标仓库,格式 owner/repo"),
|
|
14
|
+
severity: z.enum(SEVERITY_THRESHOLDS).default("high").describe("严重级别阈值(high 保留 critical + high,与 CLI 一致)"),
|
|
15
|
+
code_scanning: z.boolean().optional().describe("同时拉取 Code Scanning 告警(与 Dependabot 并行;需要 token 具备 security-events: read)")
|
|
16
|
+
});
|
|
17
|
+
/** `get_last_report` 输入:读取最近一次 JSON 报告 */
|
|
18
|
+
const getLastReportSchema = z.object({});
|
|
19
|
+
/** `run_scan` 输入:对目标仓库执行 dependfix 扫描并修复 */
|
|
20
|
+
const runScanSchema = z.object({
|
|
21
|
+
repo: z.string().describe("目标仓库,格式 owner/repo"),
|
|
22
|
+
mode: z.enum(RUN_SCAN_MODES).default("report-only").describe("执行模式(默认仅报告)"),
|
|
23
|
+
severity: z.enum(SEVERITY_THRESHOLDS).default("high").describe("严重级别阈值"),
|
|
24
|
+
code_scanning: z.boolean().optional().describe("同时拉取 Code Scanning 告警(默认 false)"),
|
|
25
|
+
max_alerts: z.number().int().min(1).max(1e3).optional().describe("每仓库最多处理的告警数(默认 20)"),
|
|
26
|
+
max_concurrency: z.number().int().min(1).max(16).optional().describe("多仓库并发窗口(默认 1 保守串行)"),
|
|
27
|
+
dry_run: z.boolean().optional().describe("试运行不实际写入;缺省按 mode 推断(report-only 为 true)。与 mode=fix/fix-and-pr 互斥(会返回配置校验错误)"),
|
|
28
|
+
allow_major_upgrade: z.boolean().optional().describe("跨线 major 升级显式授权(默认 false;仅根直接依赖 + lockfile 单版本,强制完整验证)"),
|
|
29
|
+
ai_enabled: z.boolean().optional().describe("开启 AI breaking change 研判(默认 false;apiKey 从 DEPENDFIX_AI_API_KEY env 读取,禁止经 tool 参数传入)"),
|
|
30
|
+
ai_provider: z.enum(["openai-compatible", "anthropic"]).optional().describe("AI 提供商(默认 openai-compatible)"),
|
|
31
|
+
ai_model: z.string().optional().describe("AI 模型名(默认 deepseek-v4-flash)"),
|
|
32
|
+
ai_trigger: z.enum([
|
|
33
|
+
"failure",
|
|
34
|
+
"major",
|
|
35
|
+
"both"
|
|
36
|
+
]).optional().describe("AI 触发范围(默认 both)")
|
|
37
|
+
});
|
|
38
|
+
/** `fix_dependency` 输入:修复单个依赖(多修复类型) */
|
|
39
|
+
const fixDependencySchema = z.object({
|
|
40
|
+
/** 本地仓库路径(已 clone 的目录,含 package.json/pnpm-lock.yaml) */
|
|
41
|
+
workDir: z.string().describe("本地仓库工作目录(已 clone,包含 package.json 与 pnpm-lock.yaml)"),
|
|
42
|
+
/** 修复类型:override(间接依赖 overrides)/ direct(直接依赖升级)/ lockfile(frozen-lockfile 漂移修复) */
|
|
43
|
+
fix_type: z.enum([
|
|
44
|
+
"override",
|
|
45
|
+
"direct",
|
|
46
|
+
"lockfile"
|
|
47
|
+
]).default("override").describe("修复类型(默认 override)"),
|
|
48
|
+
/** override / direct 必填 */
|
|
49
|
+
packageName: z.string().optional().describe("依赖包名(fix_type=override/direct 必填)"),
|
|
50
|
+
/** override / direct 必填 */
|
|
51
|
+
targetVersion: z.string().optional().describe("目标精确版本,如 4.17.21(fix_type=override/direct 必填)")
|
|
52
|
+
});
|
|
53
|
+
/** `discover_repos` 输入:按 owner / org 自动发现仓库 */
|
|
54
|
+
const discoverReposSchema = z.object({
|
|
55
|
+
owner: z.array(z.string()).min(1).describe("owner / org 列表(分别发现后合并)"),
|
|
56
|
+
topics: z.array(z.string()).optional().describe("topic 白名单(AND 语义:必须包含全部指定 topics)"),
|
|
57
|
+
include: z.array(z.string()).optional().describe("仓库白名单 glob(如 owner/*、owner/pkg-*)"),
|
|
58
|
+
exclude: z.array(z.string()).optional().describe("仓库黑名单 glob(与 include 冲突时胜出)"),
|
|
59
|
+
probe_dependabot: z.boolean().optional().describe("探测 .github/dependabot.yml 存在性(默认 true;会额外触达 contents API)")
|
|
60
|
+
});
|
|
61
|
+
/** `cleanup_branches` 输入:清理已合并/已关闭的 dependfix 分支 */
|
|
62
|
+
const cleanupBranchesSchema = z.object({
|
|
63
|
+
repo: z.string().describe("目标仓库,格式 owner/repo"),
|
|
64
|
+
dry_run: z.boolean().optional().describe("仅列出待清理分支,不执行删除(默认 false)")
|
|
65
|
+
});
|
|
66
|
+
/** `history` 输入:查询仓库历史运行摘要 */
|
|
67
|
+
const historySchema = z.object({ repo: z.string().describe("目标仓库,格式 owner/repo") });
|
|
68
|
+
|
|
69
|
+
//#endregion
|
|
70
|
+
//#region src/tools/errors.ts
|
|
71
|
+
const requireToken = () => {
|
|
72
|
+
const token = process.env.GITHUB_TOKEN;
|
|
73
|
+
if (!token) return {
|
|
74
|
+
ok: false,
|
|
75
|
+
error: "GITHUB_TOKEN not set(请配置环境变量)"
|
|
76
|
+
};
|
|
77
|
+
return token;
|
|
78
|
+
};
|
|
79
|
+
const toToolError = (error) => ({
|
|
80
|
+
ok: false,
|
|
81
|
+
error: error instanceof Error ? error.message : String(error)
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
//#endregion
|
|
85
|
+
//#region src/tools/fetch-alerts.ts
|
|
86
|
+
/**
|
|
87
|
+
* `fetch_alerts`:拉取指定仓库的 Dependabot 安全告警(只读)。
|
|
88
|
+
* 凭据从 GITHUB_TOKEN 环境变量读取(mcp-server.md §4.3)。
|
|
89
|
+
*/
|
|
90
|
+
const fetchAlerts = async (input) => {
|
|
91
|
+
const token = requireToken();
|
|
92
|
+
if (typeof token !== "string") return token;
|
|
93
|
+
if (!isValidRepoIdentifier(input.repo)) return {
|
|
94
|
+
ok: false,
|
|
95
|
+
error: `repo 格式非法(预期 owner/repo,收到 ${input.repo})`
|
|
96
|
+
};
|
|
97
|
+
const [owner, repo] = input.repo.split("/");
|
|
98
|
+
try {
|
|
99
|
+
const client = createGitHubClient({ token });
|
|
100
|
+
const params = {
|
|
101
|
+
owner,
|
|
102
|
+
repo,
|
|
103
|
+
state: "open"
|
|
104
|
+
};
|
|
105
|
+
const codeScanningEnabled = input.code_scanning ?? false;
|
|
106
|
+
const [dependabotAlerts, codeScanningAlerts] = await Promise.all([fetchDependabotAlerts(client, params), codeScanningEnabled ? fetchCodeScanningAlerts(client, {
|
|
107
|
+
owner,
|
|
108
|
+
repo
|
|
109
|
+
}) : Promise.resolve([])]);
|
|
110
|
+
const alerts = [...dependabotAlerts, ...codeScanningAlerts];
|
|
111
|
+
const { filtered } = filterAlerts(alerts, { severityThreshold: input.severity });
|
|
112
|
+
return {
|
|
113
|
+
ok: true,
|
|
114
|
+
count: filtered.length,
|
|
115
|
+
alerts: filtered.map((a) => ({
|
|
116
|
+
id: a.id,
|
|
117
|
+
severity: a.severity,
|
|
118
|
+
packageName: a.packageName,
|
|
119
|
+
manifestPath: a.manifestPath,
|
|
120
|
+
recommendedVersion: a.recommendedVersion,
|
|
121
|
+
fixable: a.fixable,
|
|
122
|
+
htmlUrl: a.htmlUrl,
|
|
123
|
+
summary: a.summary
|
|
124
|
+
}))
|
|
125
|
+
};
|
|
126
|
+
} catch (error) {
|
|
127
|
+
return toToolError(error);
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
//#endregion
|
|
132
|
+
//#region src/tools/get-last-report.ts
|
|
133
|
+
/**
|
|
134
|
+
* `get_last_report`:读取最近一次 JSON 报告(只读)。
|
|
135
|
+
* 报告目录默认为 `./dependfix-reports`(可用 `DEPENDFIX_MCP_REPORT_DIR` 覆盖)。
|
|
136
|
+
*/
|
|
137
|
+
const getLastReport = async () => {
|
|
138
|
+
const reportDir = process.env.DEPENDFIX_MCP_REPORT_DIR ?? "./dependfix-reports";
|
|
139
|
+
try {
|
|
140
|
+
const files = readdirSync(reportDir).filter((f) => f.endsWith(".json")).sort();
|
|
141
|
+
if (files.length === 0) return {
|
|
142
|
+
ok: false,
|
|
143
|
+
error: `未找到报告(目录 ${reportDir} 为空)`
|
|
144
|
+
};
|
|
145
|
+
const latest = files[files.length - 1];
|
|
146
|
+
const content = readFileSync(join(reportDir, latest), "utf-8");
|
|
147
|
+
return {
|
|
148
|
+
ok: true,
|
|
149
|
+
file: latest,
|
|
150
|
+
report: JSON.parse(content)
|
|
151
|
+
};
|
|
152
|
+
} catch (error) {
|
|
153
|
+
return toToolError(error);
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
//#endregion
|
|
158
|
+
//#region src/tools/run-scan.ts
|
|
159
|
+
/**
|
|
160
|
+
* `run_scan`:对目标仓库执行 dependfix 扫描并修复。
|
|
161
|
+
* 凭据从 GITHUB_TOKEN 环境变量读取;repo 为 GitHub 远程仓库(report-only 无需 clone)。
|
|
162
|
+
*/
|
|
163
|
+
const runScan = async (input) => {
|
|
164
|
+
const token = requireToken();
|
|
165
|
+
if (typeof token !== "string") return token;
|
|
166
|
+
if (!isValidRepoIdentifier(input.repo)) return {
|
|
167
|
+
ok: false,
|
|
168
|
+
error: `repo 格式非法(预期 owner/repo,收到 ${input.repo})`
|
|
169
|
+
};
|
|
170
|
+
const [owner, repo] = input.repo.split("/");
|
|
171
|
+
const defaultAi = DEFAULT_RUNTIME_CONFIG.ai;
|
|
172
|
+
const config = {
|
|
173
|
+
...DEFAULT_RUNTIME_CONFIG,
|
|
174
|
+
mode: input.mode,
|
|
175
|
+
severityThreshold: input.severity,
|
|
176
|
+
repositories: [`${owner}/${repo}`],
|
|
177
|
+
dryRun: input.dry_run ?? input.mode === "report-only",
|
|
178
|
+
createPullRequest: input.mode === "fix-and-pr",
|
|
179
|
+
commit: input.mode === "fix",
|
|
180
|
+
cleanupBranches: false,
|
|
181
|
+
cleanupBranchesAuto: false,
|
|
182
|
+
githubToken: token,
|
|
183
|
+
codeScanningEnabled: input.code_scanning ?? DEFAULT_RUNTIME_CONFIG.codeScanningEnabled,
|
|
184
|
+
allowMajorUpgrade: input.allow_major_upgrade ?? DEFAULT_RUNTIME_CONFIG.allowMajorUpgrade,
|
|
185
|
+
maxAlertsPerRepository: input.max_alerts ?? DEFAULT_RUNTIME_CONFIG.maxAlertsPerRepository,
|
|
186
|
+
maxConcurrency: input.max_concurrency ?? DEFAULT_RUNTIME_CONFIG.maxConcurrency,
|
|
187
|
+
ai: input.ai_enabled && defaultAi ? {
|
|
188
|
+
...defaultAi,
|
|
189
|
+
enabled: true,
|
|
190
|
+
provider: input.ai_provider ?? defaultAi.provider,
|
|
191
|
+
model: input.ai_model ?? defaultAi.model,
|
|
192
|
+
trigger: input.ai_trigger ?? defaultAi.trigger,
|
|
193
|
+
apiKey: process.env.DEPENDFIX_AI_API_KEY
|
|
194
|
+
} : void 0
|
|
195
|
+
};
|
|
196
|
+
try {
|
|
197
|
+
const { result, exitCode } = await new DependfixApp({
|
|
198
|
+
config,
|
|
199
|
+
workDir: process.cwd(),
|
|
200
|
+
reportOutputDir: process.env.DEPENDFIX_MCP_REPORT_DIR ?? "./dependfix-reports"
|
|
201
|
+
}).run();
|
|
202
|
+
return {
|
|
203
|
+
ok: true,
|
|
204
|
+
exitCode,
|
|
205
|
+
runId: result.runId,
|
|
206
|
+
summary: result.summary,
|
|
207
|
+
repositories: result.repositories.map((r) => ({
|
|
208
|
+
repository: r.repository,
|
|
209
|
+
alertsCount: r.alertsCount,
|
|
210
|
+
fixable: r.fixable,
|
|
211
|
+
fixed: r.fixed,
|
|
212
|
+
failed: r.failed,
|
|
213
|
+
lockfileRepaired: r.lockfileRepaired,
|
|
214
|
+
verificationPassed: r.verificationPassed ?? void 0,
|
|
215
|
+
durationMs: r.durationMs
|
|
216
|
+
})),
|
|
217
|
+
errors: result.errors.map((e) => ({
|
|
218
|
+
repository: e.repository,
|
|
219
|
+
stage: e.stage,
|
|
220
|
+
category: e.category,
|
|
221
|
+
message: e.message
|
|
222
|
+
}))
|
|
223
|
+
};
|
|
224
|
+
} catch (error) {
|
|
225
|
+
return toToolError(error);
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
//#endregion
|
|
230
|
+
//#region src/tools/fix-dependency.ts
|
|
231
|
+
/**
|
|
232
|
+
* `fix_dependency`:修复单个依赖或 lockfile(按 `fix_type` 分发,复用 cli fixers):
|
|
233
|
+
* - `override`(默认):间接依赖 → `overrideTransitiveDependency`(写入 pnpm overrides)
|
|
234
|
+
* - `direct`:直接依赖 → `upgradeDependency`(改写 manifest + `pnpm install`,失败回滚)
|
|
235
|
+
* - `lockfile`:frozen-lockfile 漂移 → `repairLockfile`(策略链修复,全部失败回滚)
|
|
236
|
+
* 均需本地已 clone 的仓库目录(workDir)。
|
|
237
|
+
*/
|
|
238
|
+
const fixDependency = async (input) => {
|
|
239
|
+
const fixType = input.fix_type ?? "override";
|
|
240
|
+
try {
|
|
241
|
+
switch (fixType) {
|
|
242
|
+
case "lockfile": {
|
|
243
|
+
const result = repairLockfile({ workDir: input.workDir });
|
|
244
|
+
if (result.success) return {
|
|
245
|
+
ok: true,
|
|
246
|
+
fixType: "lockfile",
|
|
247
|
+
strategy: result.strategy,
|
|
248
|
+
diff: result.diff ?? null,
|
|
249
|
+
lockfileVersion: result.lockfileVersion,
|
|
250
|
+
lockfileVersionChanged: result.lockfileVersionChanged
|
|
251
|
+
};
|
|
252
|
+
return {
|
|
253
|
+
ok: false,
|
|
254
|
+
fixType: "lockfile",
|
|
255
|
+
error: result.failureDetail ?? "lockfile repair failed"
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
case "direct": {
|
|
259
|
+
if (!input.packageName || !input.targetVersion) return {
|
|
260
|
+
ok: false,
|
|
261
|
+
fixType: "direct",
|
|
262
|
+
error: "packageName 与 targetVersion 必填(fix_type=direct)"
|
|
263
|
+
};
|
|
264
|
+
const result = await upgradeDependency({
|
|
265
|
+
packageName: input.packageName,
|
|
266
|
+
targetVersion: input.targetVersion,
|
|
267
|
+
workDir: input.workDir
|
|
268
|
+
});
|
|
269
|
+
if (result.success) return {
|
|
270
|
+
ok: true,
|
|
271
|
+
fixType: "direct",
|
|
272
|
+
packageName: result.packageName,
|
|
273
|
+
fromVersion: result.fromVersion,
|
|
274
|
+
toVersion: result.toVersion,
|
|
275
|
+
isMajor: result.isMajor,
|
|
276
|
+
warning: result.warning
|
|
277
|
+
};
|
|
278
|
+
return {
|
|
279
|
+
ok: false,
|
|
280
|
+
fixType: "direct",
|
|
281
|
+
packageName: result.packageName,
|
|
282
|
+
fromVersion: result.fromVersion,
|
|
283
|
+
toVersion: result.toVersion,
|
|
284
|
+
isMajor: result.isMajor,
|
|
285
|
+
error: result.error ?? "upgrade failed"
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
case "override": {
|
|
289
|
+
if (!input.packageName || !input.targetVersion) return {
|
|
290
|
+
ok: false,
|
|
291
|
+
fixType: "override",
|
|
292
|
+
error: "packageName 与 targetVersion 必填(fix_type=override)"
|
|
293
|
+
};
|
|
294
|
+
const result = await overrideTransitiveDependency({
|
|
295
|
+
packageName: input.packageName,
|
|
296
|
+
targetVersion: input.targetVersion,
|
|
297
|
+
workDir: input.workDir
|
|
298
|
+
});
|
|
299
|
+
if (result.success) return {
|
|
300
|
+
ok: true,
|
|
301
|
+
fixType: "override",
|
|
302
|
+
packageName: result.packageName,
|
|
303
|
+
fromVersion: result.fromVersion,
|
|
304
|
+
toVersion: result.toVersion,
|
|
305
|
+
isMajor: result.isMajor,
|
|
306
|
+
warning: result.warning
|
|
307
|
+
};
|
|
308
|
+
return {
|
|
309
|
+
ok: false,
|
|
310
|
+
fixType: "override",
|
|
311
|
+
packageName: result.packageName,
|
|
312
|
+
fromVersion: result.fromVersion,
|
|
313
|
+
toVersion: result.toVersion,
|
|
314
|
+
isMajor: result.isMajor,
|
|
315
|
+
error: result.error ?? "override failed"
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
} catch (error) {
|
|
320
|
+
return {
|
|
321
|
+
ok: false,
|
|
322
|
+
fixType,
|
|
323
|
+
error: toToolError(error).error
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
//#endregion
|
|
329
|
+
//#region src/tools/discover-repos.ts
|
|
330
|
+
/**
|
|
331
|
+
* `discover_repos`:按 owner / org 自动发现仓库(复用 cli discoverRepositories,
|
|
332
|
+
* 与 CLI `--owner` / `--repo-topics` / `--repo-include` / `--repo-exclude` 同源过滤链)。
|
|
333
|
+
* 凭据从 GITHUB_TOKEN 环境变量读取。
|
|
334
|
+
*/
|
|
335
|
+
const discoverRepos = async (input) => {
|
|
336
|
+
const token = requireToken();
|
|
337
|
+
if (typeof token !== "string") return token;
|
|
338
|
+
if (input.owner.length === 0) return {
|
|
339
|
+
ok: false,
|
|
340
|
+
error: "owner 必填(至少一个 owner/org)"
|
|
341
|
+
};
|
|
342
|
+
try {
|
|
343
|
+
const client = createGitHubClient({ token });
|
|
344
|
+
const policy = {
|
|
345
|
+
include: input.include && input.include.length > 0 ? input.include : void 0,
|
|
346
|
+
exclude: input.exclude && input.exclude.length > 0 ? input.exclude : void 0
|
|
347
|
+
};
|
|
348
|
+
const repos = await discoverRepositories({
|
|
349
|
+
client,
|
|
350
|
+
owners: input.owner,
|
|
351
|
+
topics: input.topics,
|
|
352
|
+
policy,
|
|
353
|
+
probeDependabot: input.probe_dependabot ?? true
|
|
354
|
+
});
|
|
355
|
+
return {
|
|
356
|
+
ok: true,
|
|
357
|
+
count: repos.length,
|
|
358
|
+
repositories: repos.map((r) => ({
|
|
359
|
+
fullName: r.fullName,
|
|
360
|
+
defaultBranch: r.defaultBranch,
|
|
361
|
+
topics: r.topics,
|
|
362
|
+
hasDependabotConfig: r.hasDependabotConfig
|
|
363
|
+
}))
|
|
364
|
+
};
|
|
365
|
+
} catch (error) {
|
|
366
|
+
return toToolError(error);
|
|
367
|
+
}
|
|
368
|
+
};
|
|
369
|
+
|
|
370
|
+
//#endregion
|
|
371
|
+
//#region src/tools/cleanup-branches.ts
|
|
372
|
+
/**
|
|
373
|
+
* `cleanup_branches`:清理已合并/已关闭的 dependfix 分支(非交互)。
|
|
374
|
+
*
|
|
375
|
+
* 复用 cli pr-creator 底层函数自编排,语义对齐 `autoCleanupMergedBranches`:
|
|
376
|
+
* - 只处理 `dependfix/` 前缀分支(listDependfixBranches 已过滤)
|
|
377
|
+
* - 删除候选 = 已合并(merged)+ 已关闭未合并(orphaned);绝不触碰 open PR 分支
|
|
378
|
+
* - 单分支删除失败记录到 `failed`,不中断其余删除(best-effort)
|
|
379
|
+
* - dry_run 仅列清单(deleted/failed 为空)
|
|
380
|
+
*
|
|
381
|
+
* 刻意不走 DependfixApp 的 cleanup-branches mode:`runBranchCleanupForRepo`
|
|
382
|
+
* 含交互式确认(非 TTY 默认拒绝),MCP stdio 下不可用。
|
|
383
|
+
*/
|
|
384
|
+
const cleanupBranches = async (input) => {
|
|
385
|
+
const token = requireToken();
|
|
386
|
+
if (typeof token !== "string") return token;
|
|
387
|
+
if (!isValidRepoIdentifier(input.repo)) return {
|
|
388
|
+
ok: false,
|
|
389
|
+
error: `repo 格式非法(预期 owner/repo,收到 ${input.repo})`
|
|
390
|
+
};
|
|
391
|
+
const [owner, repo] = input.repo.split("/");
|
|
392
|
+
const dryRun = input.dry_run ?? false;
|
|
393
|
+
try {
|
|
394
|
+
const client = createGitHubClient({ token });
|
|
395
|
+
const branches = await listDependfixBranches(client, owner, repo);
|
|
396
|
+
const statuses = await Promise.all(branches.map((branch) => getBranchPrStatus(client, owner, repo, branch)));
|
|
397
|
+
const merged = statuses.filter((s) => s.merged);
|
|
398
|
+
const orphaned = statuses.filter((s) => s.closed && !s.merged);
|
|
399
|
+
const kept = statuses.filter((s) => !s.closed);
|
|
400
|
+
const candidates = [...merged, ...orphaned];
|
|
401
|
+
if (dryRun) return {
|
|
402
|
+
ok: true,
|
|
403
|
+
dryRun: true,
|
|
404
|
+
scanned: branches,
|
|
405
|
+
deleted: [],
|
|
406
|
+
kept: kept.map((s) => s.branch),
|
|
407
|
+
failed: []
|
|
408
|
+
};
|
|
409
|
+
const deleted = [];
|
|
410
|
+
const failed = [];
|
|
411
|
+
for (const s of candidates) try {
|
|
412
|
+
await deleteRemoteBranch(client, owner, repo, s.branch);
|
|
413
|
+
deleted.push(s.branch);
|
|
414
|
+
} catch {
|
|
415
|
+
failed.push(s.branch);
|
|
416
|
+
}
|
|
417
|
+
return {
|
|
418
|
+
ok: true,
|
|
419
|
+
dryRun: false,
|
|
420
|
+
scanned: branches,
|
|
421
|
+
deleted,
|
|
422
|
+
kept: kept.map((s) => s.branch),
|
|
423
|
+
failed
|
|
424
|
+
};
|
|
425
|
+
} catch (error) {
|
|
426
|
+
return toToolError(error);
|
|
427
|
+
}
|
|
428
|
+
};
|
|
429
|
+
|
|
430
|
+
//#endregion
|
|
431
|
+
//#region src/tools/history.ts
|
|
432
|
+
/**
|
|
433
|
+
* `history`:查询某仓库的历史运行摘要(倒序时间:最新在前)。
|
|
434
|
+
* 复用 cli `queryRepoHistory`(读 dependfix-reports/index.json 聚合索引,
|
|
435
|
+
* 与 `get_last_report` 的单文件语义不同);报告目录可用 `DEPENDFIX_MCP_REPORT_DIR` 覆盖。
|
|
436
|
+
*/
|
|
437
|
+
const getHistory = async (input) => {
|
|
438
|
+
if (!isValidRepoIdentifier(input.repo)) return {
|
|
439
|
+
ok: false,
|
|
440
|
+
error: `repo 格式非法(预期 owner/repo,收到 ${input.repo})`
|
|
441
|
+
};
|
|
442
|
+
try {
|
|
443
|
+
const reportDir = process.env.DEPENDFIX_MCP_REPORT_DIR ?? "./dependfix-reports";
|
|
444
|
+
const entries = queryRepoHistory(input.repo, reportDir);
|
|
445
|
+
return {
|
|
446
|
+
ok: true,
|
|
447
|
+
repo: input.repo,
|
|
448
|
+
runs: entries.map((e) => ({
|
|
449
|
+
runId: e.runId,
|
|
450
|
+
startedAt: e.startedAt,
|
|
451
|
+
durationMs: e.durationMs,
|
|
452
|
+
repositories: e.repositories,
|
|
453
|
+
summary: e.summary,
|
|
454
|
+
repoStats: e.repoStats
|
|
455
|
+
}))
|
|
456
|
+
};
|
|
457
|
+
} catch (error) {
|
|
458
|
+
return toToolError(error);
|
|
459
|
+
}
|
|
460
|
+
};
|
|
461
|
+
|
|
462
|
+
//#endregion
|
|
463
|
+
//#region src/index.ts
|
|
464
|
+
/**
|
|
465
|
+
* dependfix MCP Server:向 AI 助手暴露 7 个 tool。
|
|
466
|
+
* - fetch_alerts(只读):拉取 Dependabot / Code Scanning 告警
|
|
467
|
+
* - get_last_report(只读):读取最近 JSON 报告
|
|
468
|
+
* - run_scan(写入):执行扫描/修复(默认 report-only;支持 AI 研判透传)
|
|
469
|
+
* - fix_dependency(写入):修复单个依赖(override / direct / lockfile)
|
|
470
|
+
* - discover_repos(只读):按 owner / org 自动发现仓库
|
|
471
|
+
* - cleanup_branches(写入):清理已合并/已关闭的 dependfix 分支(非交互)
|
|
472
|
+
* - history(只读):查询仓库历史运行摘要
|
|
473
|
+
* 凭据从 GITHUB_TOKEN 环境变量读取(mcp-server.md §4.3)。
|
|
474
|
+
*/
|
|
475
|
+
const createMcpServer = () => {
|
|
476
|
+
const server = new McpServer({
|
|
477
|
+
name: "dependfix",
|
|
478
|
+
version: "0.1.0"
|
|
479
|
+
});
|
|
480
|
+
server.registerTool("fetch_alerts", {
|
|
481
|
+
description: "拉取指定仓库的 Dependabot 安全告警(可选并行 Code Scanning,只读)",
|
|
482
|
+
inputSchema: fetchAlertsSchema
|
|
483
|
+
}, async (input) => {
|
|
484
|
+
const result = await fetchAlerts(input);
|
|
485
|
+
return { content: [{
|
|
486
|
+
type: "text",
|
|
487
|
+
text: JSON.stringify(result, null, 2)
|
|
488
|
+
}] };
|
|
489
|
+
});
|
|
490
|
+
server.registerTool("get_last_report", {
|
|
491
|
+
description: "读取最近一次 dependfix JSON 报告(只读)",
|
|
492
|
+
inputSchema: getLastReportSchema
|
|
493
|
+
}, async () => {
|
|
494
|
+
const result = await getLastReport();
|
|
495
|
+
return { content: [{
|
|
496
|
+
type: "text",
|
|
497
|
+
text: JSON.stringify(result, null, 2)
|
|
498
|
+
}] };
|
|
499
|
+
});
|
|
500
|
+
server.registerTool("run_scan", {
|
|
501
|
+
description: "对目标仓库执行 dependfix 扫描并修复(默认 report-only;支持 code-scanning / AI 研判等参数)",
|
|
502
|
+
inputSchema: runScanSchema
|
|
503
|
+
}, async (input) => {
|
|
504
|
+
const result = await runScan(input);
|
|
505
|
+
return { content: [{
|
|
506
|
+
type: "text",
|
|
507
|
+
text: JSON.stringify(result, null, 2)
|
|
508
|
+
}] };
|
|
509
|
+
});
|
|
510
|
+
server.registerTool("fix_dependency", {
|
|
511
|
+
description: "修复单个依赖或 lockfile(override / direct / lockfile;需要本地已 clone 仓库目录)",
|
|
512
|
+
inputSchema: fixDependencySchema
|
|
513
|
+
}, async (input) => {
|
|
514
|
+
const result = await fixDependency(input);
|
|
515
|
+
return { content: [{
|
|
516
|
+
type: "text",
|
|
517
|
+
text: JSON.stringify(result, null, 2)
|
|
518
|
+
}] };
|
|
519
|
+
});
|
|
520
|
+
server.registerTool("discover_repos", {
|
|
521
|
+
description: "按 owner / org 自动发现仓库(支持 topics / include / exclude 名单策略,只读)",
|
|
522
|
+
inputSchema: discoverReposSchema
|
|
523
|
+
}, async (input) => {
|
|
524
|
+
const result = await discoverRepos(input);
|
|
525
|
+
return { content: [{
|
|
526
|
+
type: "text",
|
|
527
|
+
text: JSON.stringify(result, null, 2)
|
|
528
|
+
}] };
|
|
529
|
+
});
|
|
530
|
+
server.registerTool("cleanup_branches", {
|
|
531
|
+
description: "清理已合并/已关闭的 dependfix 分支(非交互;只删 dependfix/ 前缀且 merged/closed,绝不触碰 open PR 分支)",
|
|
532
|
+
inputSchema: cleanupBranchesSchema
|
|
533
|
+
}, async (input) => {
|
|
534
|
+
const result = await cleanupBranches(input);
|
|
535
|
+
return { content: [{
|
|
536
|
+
type: "text",
|
|
537
|
+
text: JSON.stringify(result, null, 2)
|
|
538
|
+
}] };
|
|
539
|
+
});
|
|
540
|
+
server.registerTool("history", {
|
|
541
|
+
description: "查询指定仓库的历史运行摘要(倒序时间,只读)",
|
|
542
|
+
inputSchema: historySchema
|
|
543
|
+
}, async (input) => {
|
|
544
|
+
const result = await getHistory(input);
|
|
545
|
+
return { content: [{
|
|
546
|
+
type: "text",
|
|
547
|
+
text: JSON.stringify(result, null, 2)
|
|
548
|
+
}] };
|
|
549
|
+
});
|
|
550
|
+
return server;
|
|
551
|
+
};
|
|
552
|
+
/** 连接 stdio 传输(bin 入口调用) */
|
|
553
|
+
const connectStdio = async () => {
|
|
554
|
+
const server = createMcpServer();
|
|
555
|
+
const transport = new StdioServerTransport();
|
|
556
|
+
await server.connect(transport);
|
|
557
|
+
};
|
|
558
|
+
|
|
559
|
+
//#endregion
|
|
560
|
+
export { createMcpServer as n, connectStdio as t };
|
|
561
|
+
//# sourceMappingURL=src.mjs.map
|
package/dist/src.mjs.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"src.mjs","names":[],"sources":["../src/tools/schemas.ts","../src/tools/errors.ts","../src/tools/fetch-alerts.ts","../src/tools/get-last-report.ts","../src/tools/run-scan.ts","../src/tools/fix-dependency.ts","../src/tools/discover-repos.ts","../src/tools/cleanup-branches.ts","../src/tools/history.ts","../src/index.ts"],"sourcesContent":["import { z } from 'zod'\nimport { RUNTIME_MODES, SEVERITY_THRESHOLDS } from '@dependfix/engine'\n\n// run_scan 的 mode 子集:排除 cleanup-branches(由独立 cleanup_branches tool 承担;\n// DependfixApp 的该 mode 走交互确认,MCP stdio 不可用——见 mcp-server.md §8.3)。\n// 从 cli RUNTIME_MODES 派生(filter 跟随 cli 演进),非独立硬编码。\n// as unknown 桥接:filter 返回数组类型,z.enum 需要 readonly 元组。\nconst RUN_SCAN_MODES = RUNTIME_MODES.filter((m) => m !== 'cleanup-branches') as unknown as readonly ['report-only', 'fix', 'fix-and-pr']\n\n/** `fetch_alerts` 输入:拉取指定仓库的安全告警(Dependabot + 可选 Code Scanning) */\nexport const fetchAlertsSchema = z.object({\n repo: z.string().describe('目标仓库,格式 owner/repo'),\n severity: z.enum(SEVERITY_THRESHOLDS).default('high').describe('严重级别阈值(high 保留 critical + high,与 CLI 一致)'),\n code_scanning: z.boolean().optional().describe('同时拉取 Code Scanning 告警(与 Dependabot 并行;需要 token 具备 security-events: read)'),\n})\n\n/** `get_last_report` 输入:读取最近一次 JSON 报告 */\nexport const getLastReportSchema = z.object({})\n\n/** `run_scan` 输入:对目标仓库执行 dependfix 扫描并修复 */\nexport const runScanSchema = z.object({\n repo: z.string().describe('目标仓库,格式 owner/repo'),\n mode: z.enum(RUN_SCAN_MODES).default('report-only').describe('执行模式(默认仅报告)'),\n severity: z.enum(SEVERITY_THRESHOLDS).default('high').describe('严重级别阈值'),\n code_scanning: z.boolean().optional().describe('同时拉取 Code Scanning 告警(默认 false)'),\n max_alerts: z.number().int().min(1).max(1000).optional().describe('每仓库最多处理的告警数(默认 20)'),\n max_concurrency: z.number().int().min(1).max(16).optional().describe('多仓库并发窗口(默认 1 保守串行)'),\n dry_run: z.boolean().optional().describe('试运行不实际写入;缺省按 mode 推断(report-only 为 true)。与 mode=fix/fix-and-pr 互斥(会返回配置校验错误)'),\n allow_major_upgrade: z.boolean().optional().describe('跨线 major 升级显式授权(默认 false;仅根直接依赖 + lockfile 单版本,强制完整验证)'),\n ai_enabled: z.boolean().optional().describe('开启 AI breaking change 研判(默认 false;apiKey 从 DEPENDFIX_AI_API_KEY env 读取,禁止经 tool 参数传入)'),\n ai_provider: z.enum(['openai-compatible', 'anthropic']).optional().describe('AI 提供商(默认 openai-compatible)'),\n ai_model: z.string().optional().describe('AI 模型名(默认 deepseek-v4-flash)'),\n ai_trigger: z.enum(['failure', 'major', 'both']).optional().describe('AI 触发范围(默认 both)'),\n})\n\n/** `fix_dependency` 输入:修复单个依赖(多修复类型) */\nexport const fixDependencySchema = z.object({\n /** 本地仓库路径(已 clone 的目录,含 package.json/pnpm-lock.yaml) */\n workDir: z.string().describe('本地仓库工作目录(已 clone,包含 package.json 与 pnpm-lock.yaml)'),\n /** 修复类型:override(间接依赖 overrides)/ direct(直接依赖升级)/ lockfile(frozen-lockfile 漂移修复) */\n fix_type: z.enum(['override', 'direct', 'lockfile']).default('override').describe('修复类型(默认 override)'),\n /** override / direct 必填 */\n packageName: z.string().optional().describe('依赖包名(fix_type=override/direct 必填)'),\n /** override / direct 必填 */\n targetVersion: z.string().optional().describe('目标精确版本,如 4.17.21(fix_type=override/direct 必填)'),\n})\n\n/** `discover_repos` 输入:按 owner / org 自动发现仓库 */\nexport const discoverReposSchema = z.object({\n owner: z.array(z.string()).min(1).describe('owner / org 列表(分别发现后合并)'),\n topics: z.array(z.string()).optional().describe('topic 白名单(AND 语义:必须包含全部指定 topics)'),\n include: z.array(z.string()).optional().describe('仓库白名单 glob(如 owner/*、owner/pkg-*)'),\n exclude: z.array(z.string()).optional().describe('仓库黑名单 glob(与 include 冲突时胜出)'),\n probe_dependabot: z.boolean().optional().describe('探测 .github/dependabot.yml 存在性(默认 true;会额外触达 contents API)'),\n})\n\n/** `cleanup_branches` 输入:清理已合并/已关闭的 dependfix 分支 */\nexport const cleanupBranchesSchema = z.object({\n repo: z.string().describe('目标仓库,格式 owner/repo'),\n dry_run: z.boolean().optional().describe('仅列出待清理分支,不执行删除(默认 false)'),\n})\n\n/** `history` 输入:查询仓库历史运行摘要 */\nexport const historySchema = z.object({\n repo: z.string().describe('目标仓库,格式 owner/repo'),\n})\n","// 统一 tool 错误模板(复用收口):\n// - requireToken:GITHUB_TOKEN 检查。返回 token 字符串或错误对象;\n// 调用方用 `typeof token !== 'string'` 守卫收窄(项目未开 strictNullChecks,\n// truthiness 判别收窄不生效,typeof 守卫是兼容形式)。\n// - toToolError:任意错误 → ok:false(统一 Error.message / String 转换)\n// 各 tool 的返回联合类型均含 `{ ok: false, error: string }` 分支,可安全返回。\n\nexport type ToolError = { ok: false, error: string }\n\nexport const requireToken = (): string | ToolError => {\n const token = process.env.GITHUB_TOKEN\n if (!token) {\n return { ok: false, error: 'GITHUB_TOKEN not set(请配置环境变量)' }\n }\n return token\n}\n\nexport const toToolError = (error: unknown): ToolError => ({\n ok: false,\n error: error instanceof Error ? error.message : String(error),\n})\n","import { createGitHubClient, fetchCodeScanningAlerts, fetchDependabotAlerts, type FetchDependabotAlertsParams } from '@dependfix/engine'\nimport { filterAlerts, isValidRepoIdentifier, type SeverityThreshold } from '@dependfix/core'\nimport { requireToken, toToolError } from './errors'\n\n/** `fetch_alerts` 返回结构 */\nexport type FetchAlertsResult =\n | {\n ok: true\n count: number\n alerts: Array<{\n id: number\n severity: string\n packageName: string\n manifestPath: string\n recommendedVersion: string\n fixable: boolean\n htmlUrl: string\n summary: string\n }>\n }\n | { ok: false, error: string }\n\n/**\n * `fetch_alerts`:拉取指定仓库的 Dependabot 安全告警(只读)。\n * 凭据从 GITHUB_TOKEN 环境变量读取(mcp-server.md §4.3)。\n */\nexport const fetchAlerts = async (input: { repo: string, severity: SeverityThreshold, code_scanning?: boolean }): Promise<FetchAlertsResult> => {\n const token = requireToken()\n if (typeof token !== 'string') {\n return token\n }\n\n // repo 格式校验复用 core(与 CLI 同源,避免自研校验漂移)\n if (!isValidRepoIdentifier(input.repo)) {\n return { ok: false, error: `repo 格式非法(预期 owner/repo,收到 ${input.repo})` }\n }\n const [owner, repo] = input.repo.split('/')\n\n try {\n const client = createGitHubClient({ token })\n const params: FetchDependabotAlertsParams = {\n owner,\n repo,\n state: 'open',\n }\n\n // Dependabot + 可选 Code Scanning 并行(复用 cli fetcher;与 CLI --code-scanning 同源)。\n // 注意:CS 拉取失败(权限/网络)会使整个 tool 失败——与 CLI 现状一致\n // (per-source 错误隔离为 backlog 登记项,暂缓),结果不静默丢弃。\n const codeScanningEnabled = input.code_scanning ?? false\n const [dependabotAlerts, codeScanningAlerts] = await Promise.all([\n fetchDependabotAlerts(client, params),\n codeScanningEnabled\n ? fetchCodeScanningAlerts(client, { owner, repo })\n : Promise.resolve([] as Awaited<ReturnType<typeof fetchDependabotAlerts>>),\n ])\n const alerts = [...dependabotAlerts, ...codeScanningAlerts]\n\n // 严重级别过滤复用 core 阈值语义(与 CLI 一致:high 保留 critical + high;\n // all 不过滤;Code Scanning 源 unknown 恒透传)。不使用相等匹配,避免 high 漏掉 critical。\n const { filtered } = filterAlerts(alerts, { severityThreshold: input.severity })\n\n return {\n ok: true,\n count: filtered.length,\n alerts: filtered.map((a) => ({\n id: a.id,\n severity: a.severity,\n packageName: a.packageName,\n manifestPath: a.manifestPath,\n recommendedVersion: a.recommendedVersion,\n fixable: a.fixable,\n htmlUrl: a.htmlUrl,\n summary: a.summary,\n })),\n }\n } catch (error) {\n return toToolError(error)\n }\n}\n","import { readFileSync, readdirSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { toToolError } from './errors'\n\n/** `get_last_report` 返回结构 */\nexport type GetLastReportResult =\n | { ok: true, file: string, report: unknown }\n | { ok: false, error: string }\n\n/**\n * `get_last_report`:读取最近一次 JSON 报告(只读)。\n * 报告目录默认为 `./dependfix-reports`(可用 `DEPENDFIX_MCP_REPORT_DIR` 覆盖)。\n */\nexport const getLastReport = async (): Promise<GetLastReportResult> => {\n const reportDir = process.env.DEPENDFIX_MCP_REPORT_DIR ?? './dependfix-reports'\n try {\n const files = readdirSync(reportDir)\n .filter((f) => f.endsWith('.json'))\n .sort()\n if (files.length === 0) {\n return { ok: false, error: `未找到报告(目录 ${reportDir} 为空)` }\n }\n const latest = files[files.length - 1]\n const content = readFileSync(join(reportDir, latest), 'utf-8')\n return {\n ok: true,\n file: latest,\n report: JSON.parse(content),\n }\n } catch (error) {\n return toToolError(error)\n }\n}\n","import { DependfixApp, DEFAULT_RUNTIME_CONFIG, type RuntimeConfig } from '@dependfix/engine'\nimport { isValidRepoIdentifier } from '@dependfix/core'\nimport { requireToken, toToolError } from './errors'\n\n/** `run_scan` 返回结构 */\nexport type RunScanResult =\n | {\n ok: true\n exitCode: number\n runId: string\n summary: import('@dependfix/core').RunSummary\n repositories: Array<Record<string, unknown>>\n errors: Array<Record<string, unknown>>\n }\n | { ok: false, error: string }\n\n/**\n * `run_scan`:对目标仓库执行 dependfix 扫描并修复。\n * 凭据从 GITHUB_TOKEN 环境变量读取;repo 为 GitHub 远程仓库(report-only 无需 clone)。\n */\nexport const runScan = async (input: {\n repo: string\n mode: 'report-only' | 'fix' | 'fix-and-pr'\n severity: string\n code_scanning?: boolean\n max_alerts?: number\n max_concurrency?: number\n dry_run?: boolean\n allow_major_upgrade?: boolean\n ai_enabled?: boolean\n ai_provider?: 'openai-compatible' | 'anthropic'\n ai_model?: string\n ai_trigger?: 'failure' | 'major' | 'both'\n}): Promise<RunScanResult> => {\n const token = requireToken()\n if (typeof token !== 'string') {\n return token\n }\n\n // repo 格式校验复用 core(与 CLI 同源)\n if (!isValidRepoIdentifier(input.repo)) {\n return { ok: false, error: `repo 格式非法(预期 owner/repo,收到 ${input.repo})` }\n }\n const [owner, repo] = input.repo.split('/')\n\n // 展开 cli 默认配置(maxAlerts/maxConcurrency/maxRetries/maxBackoff/alertSource/ai 默认等\n // 与 CLI 单一事实源对齐,避免手写默认值漂移),仅覆盖 tool 参数可控制字段。\n const defaultAi = DEFAULT_RUNTIME_CONFIG.ai\n const config: RuntimeConfig = {\n ...DEFAULT_RUNTIME_CONFIG,\n mode: input.mode,\n severityThreshold: input.severity as 'critical' | 'high' | 'medium' | 'all',\n repositories: [`${owner}/${repo}`],\n // dry-run 显式参数优先,缺省按 mode 推断(report-only 即只读)\n dryRun: input.dry_run ?? (input.mode === 'report-only'),\n createPullRequest: input.mode === 'fix-and-pr',\n commit: input.mode === 'fix',\n cleanupBranches: false,\n cleanupBranchesAuto: false,\n githubToken: token,\n codeScanningEnabled: input.code_scanning ?? DEFAULT_RUNTIME_CONFIG.codeScanningEnabled,\n allowMajorUpgrade: input.allow_major_upgrade ?? DEFAULT_RUNTIME_CONFIG.allowMajorUpgrade,\n maxAlertsPerRepository: input.max_alerts ?? DEFAULT_RUNTIME_CONFIG.maxAlertsPerRepository,\n maxConcurrency: input.max_concurrency ?? DEFAULT_RUNTIME_CONFIG.maxConcurrency,\n // AI 研判:展开 cli 默认(provider/model/baseUrl/trigger 与 CLI 对齐),\n // 仅覆盖开关与显式参数;apiKey 只从 env 读取(DEPENDFIX_AI_API_KEY),\n // 禁止经 tool 参数传入(防客户端日志泄露)。\n // defaultAi 收窄:默认配置缺失时视为未开启(与类型声明一致,运行时恒有值)\n ai: input.ai_enabled && defaultAi\n ? {\n ...defaultAi,\n enabled: true,\n provider: input.ai_provider ?? defaultAi.provider,\n model: input.ai_model ?? defaultAi.model,\n trigger: input.ai_trigger ?? defaultAi.trigger,\n apiKey: process.env.DEPENDFIX_AI_API_KEY,\n }\n : undefined,\n }\n\n try {\n const app = new DependfixApp({\n config,\n workDir: process.cwd(),\n reportOutputDir: process.env.DEPENDFIX_MCP_REPORT_DIR ?? './dependfix-reports',\n })\n const { result, exitCode } = await app.run()\n\n return {\n ok: true,\n exitCode,\n runId: result.runId,\n summary: result.summary,\n repositories: result.repositories.map((r) => ({\n repository: r.repository,\n alertsCount: r.alertsCount,\n fixable: r.fixable,\n fixed: r.fixed,\n failed: r.failed,\n lockfileRepaired: r.lockfileRepaired,\n verificationPassed: r.verificationPassed ?? undefined,\n durationMs: r.durationMs,\n })),\n errors: result.errors.map((e) => ({\n repository: e.repository,\n stage: e.stage,\n category: e.category,\n message: e.message,\n })),\n }\n } catch (error) {\n return toToolError(error)\n }\n}\n","import { overrideTransitiveDependency, repairLockfile, upgradeDependency, type LockfileDiff } from '@dependfix/engine'\nimport { toToolError } from './errors'\n\n/** `fix_dependency` 返回结构(按 fixType 判别) */\nexport type FixDependencyResult =\n | {\n ok: true\n fixType: 'override' | 'direct'\n packageName: string\n fromVersion: string\n toVersion: string\n isMajor: boolean\n warning?: string\n }\n | {\n ok: true\n fixType: 'lockfile'\n strategy?: string\n diff?: LockfileDiff | null\n lockfileVersion?: string\n lockfileVersionChanged?: boolean\n }\n | {\n ok: false\n fixType: 'override' | 'direct' | 'lockfile'\n packageName?: string\n fromVersion?: string\n toVersion?: string\n isMajor?: boolean\n error: string\n }\n\n/**\n * `fix_dependency`:修复单个依赖或 lockfile(按 `fix_type` 分发,复用 cli fixers):\n * - `override`(默认):间接依赖 → `overrideTransitiveDependency`(写入 pnpm overrides)\n * - `direct`:直接依赖 → `upgradeDependency`(改写 manifest + `pnpm install`,失败回滚)\n * - `lockfile`:frozen-lockfile 漂移 → `repairLockfile`(策略链修复,全部失败回滚)\n * 均需本地已 clone 的仓库目录(workDir)。\n */\nexport const fixDependency = async (input: {\n workDir: string\n fix_type?: 'override' | 'direct' | 'lockfile'\n packageName?: string\n targetVersion?: string\n}): Promise<FixDependencyResult> => {\n const fixType = input.fix_type ?? 'override'\n try {\n switch (fixType) {\n case 'lockfile': {\n const result = repairLockfile({ workDir: input.workDir })\n if (result.success) {\n return {\n ok: true,\n fixType: 'lockfile',\n strategy: result.strategy,\n diff: result.diff ?? null,\n lockfileVersion: result.lockfileVersion,\n lockfileVersionChanged: result.lockfileVersionChanged,\n }\n }\n return {\n ok: false,\n fixType: 'lockfile',\n error: result.failureDetail ?? 'lockfile repair failed',\n }\n }\n case 'direct': {\n if (!input.packageName || !input.targetVersion) {\n return { ok: false, fixType: 'direct', error: 'packageName 与 targetVersion 必填(fix_type=direct)' }\n }\n const result = await upgradeDependency({\n packageName: input.packageName,\n targetVersion: input.targetVersion,\n workDir: input.workDir,\n })\n if (result.success) {\n return {\n ok: true,\n fixType: 'direct',\n packageName: result.packageName,\n fromVersion: result.fromVersion,\n toVersion: result.toVersion,\n isMajor: result.isMajor,\n warning: result.warning,\n }\n }\n return {\n ok: false,\n fixType: 'direct',\n packageName: result.packageName,\n fromVersion: result.fromVersion,\n toVersion: result.toVersion,\n isMajor: result.isMajor,\n error: result.error ?? 'upgrade failed',\n }\n }\n case 'override': {\n if (!input.packageName || !input.targetVersion) {\n return { ok: false, fixType: 'override', error: 'packageName 与 targetVersion 必填(fix_type=override)' }\n }\n const result = await overrideTransitiveDependency({\n packageName: input.packageName,\n targetVersion: input.targetVersion,\n workDir: input.workDir,\n })\n if (result.success) {\n return {\n ok: true,\n fixType: 'override',\n packageName: result.packageName,\n fromVersion: result.fromVersion,\n toVersion: result.toVersion,\n isMajor: result.isMajor,\n warning: result.warning,\n }\n }\n return {\n ok: false,\n fixType: 'override',\n packageName: result.packageName,\n fromVersion: result.fromVersion,\n toVersion: result.toVersion,\n isMajor: result.isMajor,\n error: result.error ?? 'override failed',\n }\n }\n }\n } catch (error) {\n return {\n ok: false,\n fixType,\n error: toToolError(error).error,\n }\n }\n}\n","import { createGitHubClient, discoverRepositories, type RepoPolicy } from '@dependfix/engine'\nimport { requireToken, toToolError } from './errors'\n\n/** `discover_repos` 返回结构 */\nexport type DiscoverReposResult =\n | {\n ok: true\n count: number\n repositories: Array<{\n fullName: string\n defaultBranch: string\n topics: string[]\n hasDependabotConfig: boolean\n }>\n }\n | { ok: false, error: string }\n\n/**\n * `discover_repos`:按 owner / org 自动发现仓库(复用 cli discoverRepositories,\n * 与 CLI `--owner` / `--repo-topics` / `--repo-include` / `--repo-exclude` 同源过滤链)。\n * 凭据从 GITHUB_TOKEN 环境变量读取。\n */\nexport const discoverRepos = async (input: {\n owner: string[]\n topics?: string[]\n include?: string[]\n exclude?: string[]\n probe_dependabot?: boolean\n}): Promise<DiscoverReposResult> => {\n const token = requireToken()\n if (typeof token !== 'string') {\n return token\n }\n if (input.owner.length === 0) {\n return { ok: false, error: 'owner 必填(至少一个 owner/org)' }\n }\n\n try {\n const client = createGitHubClient({ token })\n const policy: RepoPolicy = {\n include: input.include && input.include.length > 0 ? input.include : undefined,\n exclude: input.exclude && input.exclude.length > 0 ? input.exclude : undefined,\n }\n const repos = await discoverRepositories({\n client,\n owners: input.owner,\n topics: input.topics,\n policy,\n probeDependabot: input.probe_dependabot ?? true,\n })\n return {\n ok: true,\n count: repos.length,\n repositories: repos.map((r) => ({\n fullName: r.fullName,\n defaultBranch: r.defaultBranch,\n topics: r.topics,\n hasDependabotConfig: r.hasDependabotConfig,\n })),\n }\n } catch (error) {\n return toToolError(error)\n }\n}\n","import { createGitHubClient, deleteRemoteBranch, getBranchPrStatus, listDependfixBranches } from '@dependfix/engine'\nimport { isValidRepoIdentifier } from '@dependfix/core'\nimport { requireToken, toToolError } from './errors'\n\n/** `cleanup_branches` 返回结构 */\nexport type CleanupBranchesResult =\n | {\n ok: true\n dryRun: boolean\n scanned: string[]\n /** 已删除分支(dry_run 时为空) */\n deleted: string[]\n /** 保留分支(open PR / 无 PR 未关闭) */\n kept: string[]\n /** 删除失败分支(best-effort,不中断) */\n failed: string[]\n }\n | { ok: false, error: string }\n\n/**\n * `cleanup_branches`:清理已合并/已关闭的 dependfix 分支(非交互)。\n *\n * 复用 cli pr-creator 底层函数自编排,语义对齐 `autoCleanupMergedBranches`:\n * - 只处理 `dependfix/` 前缀分支(listDependfixBranches 已过滤)\n * - 删除候选 = 已合并(merged)+ 已关闭未合并(orphaned);绝不触碰 open PR 分支\n * - 单分支删除失败记录到 `failed`,不中断其余删除(best-effort)\n * - dry_run 仅列清单(deleted/failed 为空)\n *\n * 刻意不走 DependfixApp 的 cleanup-branches mode:`runBranchCleanupForRepo`\n * 含交互式确认(非 TTY 默认拒绝),MCP stdio 下不可用。\n */\nexport const cleanupBranches = async (input: { repo: string, dry_run?: boolean }): Promise<CleanupBranchesResult> => {\n const token = requireToken()\n if (typeof token !== 'string') {\n return token\n }\n if (!isValidRepoIdentifier(input.repo)) {\n return { ok: false, error: `repo 格式非法(预期 owner/repo,收到 ${input.repo})` }\n }\n const [owner, repo] = input.repo.split('/')\n const dryRun = input.dry_run ?? false\n\n try {\n const client = createGitHubClient({ token })\n const branches = await listDependfixBranches(client, owner, repo)\n const statuses = await Promise.all(\n branches.map((branch) => getBranchPrStatus(client, owner, repo, branch)),\n )\n\n const merged = statuses.filter((s) => s.merged)\n const orphaned = statuses.filter((s) => s.closed && !s.merged)\n const kept = statuses.filter((s) => !s.closed)\n const candidates = [...merged, ...orphaned]\n\n if (dryRun) {\n return {\n ok: true,\n dryRun: true,\n scanned: branches,\n deleted: [],\n kept: kept.map((s) => s.branch),\n failed: [],\n }\n }\n\n const deleted: string[] = []\n const failed: string[] = []\n for (const s of candidates) {\n try {\n await deleteRemoteBranch(client, owner, repo, s.branch)\n deleted.push(s.branch)\n } catch {\n // 单分支删除失败(分支保护/不存在)不中断其余删除,best-effort\n failed.push(s.branch)\n }\n }\n\n return {\n ok: true,\n dryRun: false,\n scanned: branches,\n deleted,\n kept: kept.map((s) => s.branch),\n failed,\n }\n } catch (error) {\n return toToolError(error)\n }\n}\n","import { queryRepoHistory } from '@dependfix/engine'\nimport { isValidRepoIdentifier } from '@dependfix/core'\nimport { toToolError } from './errors'\n\n/** `history` 返回结构 */\nexport type HistoryResult =\n | {\n ok: true\n repo: string\n runs: Array<{\n runId: string\n startedAt: string\n durationMs: number\n repositories: string[]\n summary: Record<string, unknown>\n repoStats: Array<Record<string, unknown>>\n }>\n }\n | { ok: false, error: string }\n\n/**\n * `history`:查询某仓库的历史运行摘要(倒序时间:最新在前)。\n * 复用 cli `queryRepoHistory`(读 dependfix-reports/index.json 聚合索引,\n * 与 `get_last_report` 的单文件语义不同);报告目录可用 `DEPENDFIX_MCP_REPORT_DIR` 覆盖。\n */\nexport const getHistory = async (input: { repo: string }): Promise<HistoryResult> => {\n if (!isValidRepoIdentifier(input.repo)) {\n return { ok: false, error: `repo 格式非法(预期 owner/repo,收到 ${input.repo})` }\n }\n try {\n const reportDir = process.env.DEPENDFIX_MCP_REPORT_DIR ?? './dependfix-reports'\n const entries = queryRepoHistory(input.repo, reportDir)\n return {\n ok: true,\n repo: input.repo,\n runs: entries.map((e) => ({\n runId: e.runId,\n startedAt: e.startedAt,\n durationMs: e.durationMs,\n repositories: e.repositories,\n // 桥接:RunSummary/ArchiveRepoStats 无索引签名,显式转 unknown 再收窄\n summary: e.summary as unknown as Record<string, unknown>,\n repoStats: e.repoStats as unknown as Array<Record<string, unknown>>,\n })),\n }\n } catch (error) {\n return toToolError(error)\n }\n}\n","import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'\nimport { fetchAlertsSchema, getLastReportSchema, runScanSchema, fixDependencySchema, discoverReposSchema, cleanupBranchesSchema, historySchema } from './tools/schemas'\nimport { fetchAlerts } from './tools/fetch-alerts'\nimport { getLastReport } from './tools/get-last-report'\nimport { runScan } from './tools/run-scan'\nimport { fixDependency } from './tools/fix-dependency'\nimport { discoverRepos } from './tools/discover-repos'\nimport { cleanupBranches } from './tools/cleanup-branches'\nimport { getHistory } from './tools/history'\n\n/**\n * dependfix MCP Server:向 AI 助手暴露 7 个 tool。\n * - fetch_alerts(只读):拉取 Dependabot / Code Scanning 告警\n * - get_last_report(只读):读取最近 JSON 报告\n * - run_scan(写入):执行扫描/修复(默认 report-only;支持 AI 研判透传)\n * - fix_dependency(写入):修复单个依赖(override / direct / lockfile)\n * - discover_repos(只读):按 owner / org 自动发现仓库\n * - cleanup_branches(写入):清理已合并/已关闭的 dependfix 分支(非交互)\n * - history(只读):查询仓库历史运行摘要\n * 凭据从 GITHUB_TOKEN 环境变量读取(mcp-server.md §4.3)。\n */\nexport const createMcpServer = (): McpServer => {\n const server = new McpServer({\n name: 'dependfix',\n version: '0.1.0',\n })\n\n server.registerTool(\n 'fetch_alerts',\n {\n description: '拉取指定仓库的 Dependabot 安全告警(可选并行 Code Scanning,只读)',\n inputSchema: fetchAlertsSchema,\n },\n async (input) => {\n const result = await fetchAlerts(input)\n return {\n content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],\n }\n },\n )\n\n server.registerTool(\n 'get_last_report',\n {\n description: '读取最近一次 dependfix JSON 报告(只读)',\n inputSchema: getLastReportSchema,\n },\n async () => {\n const result = await getLastReport()\n return {\n content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],\n }\n },\n )\n\n server.registerTool(\n 'run_scan',\n {\n description: '对目标仓库执行 dependfix 扫描并修复(默认 report-only;支持 code-scanning / AI 研判等参数)',\n inputSchema: runScanSchema,\n },\n async (input) => {\n const result = await runScan(input)\n return {\n content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],\n }\n },\n )\n\n server.registerTool(\n 'fix_dependency',\n {\n description: '修复单个依赖或 lockfile(override / direct / lockfile;需要本地已 clone 仓库目录)',\n inputSchema: fixDependencySchema,\n },\n async (input) => {\n const result = await fixDependency(input)\n return {\n content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],\n }\n },\n )\n\n server.registerTool(\n 'discover_repos',\n {\n description: '按 owner / org 自动发现仓库(支持 topics / include / exclude 名单策略,只读)',\n inputSchema: discoverReposSchema,\n },\n async (input) => {\n const result = await discoverRepos(input)\n return {\n content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],\n }\n },\n )\n\n server.registerTool(\n 'cleanup_branches',\n {\n description: '清理已合并/已关闭的 dependfix 分支(非交互;只删 dependfix/ 前缀且 merged/closed,绝不触碰 open PR 分支)',\n inputSchema: cleanupBranchesSchema,\n },\n async (input) => {\n const result = await cleanupBranches(input)\n return {\n content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],\n }\n },\n )\n\n server.registerTool(\n 'history',\n {\n description: '查询指定仓库的历史运行摘要(倒序时间,只读)',\n inputSchema: historySchema,\n },\n async (input) => {\n const result = await getHistory(input)\n return {\n content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],\n }\n },\n )\n\n return server\n}\n\n/** 连接 stdio 传输(bin 入口调用) */\nexport const connectStdio = async (): Promise<void> => {\n const server = createMcpServer()\n const transport = new StdioServerTransport()\n await server.connect(transport)\n}\n"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@dependfix/mcp",
|
|
3
|
+
"version": "0.1.2",
|
|
4
|
+
"description": "MCP Server for dependfix: expose scan/fix capabilities to AI assistants",
|
|
5
|
+
"author": "CaoMeiYouRen",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"keywords": [
|
|
9
|
+
"mcp",
|
|
10
|
+
"model-context-protocol",
|
|
11
|
+
"dependabot",
|
|
12
|
+
"security",
|
|
13
|
+
"dependfix"
|
|
14
|
+
],
|
|
15
|
+
"homepage": "https://github.com/dependfix/dependfix#readme",
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "git+https://github.com/dependfix/dependfix.git"
|
|
19
|
+
},
|
|
20
|
+
"bugs": {
|
|
21
|
+
"url": "https://github.com/dependfix/dependfix/issues"
|
|
22
|
+
},
|
|
23
|
+
"main": "./dist/index.mjs",
|
|
24
|
+
"module": "./dist/index.mjs",
|
|
25
|
+
"types": "./dist/index.d.mts",
|
|
26
|
+
"bin": {
|
|
27
|
+
"dependfix-mcp": "./dist/bin.mjs"
|
|
28
|
+
},
|
|
29
|
+
"engines": {
|
|
30
|
+
"node": ">=20"
|
|
31
|
+
},
|
|
32
|
+
"exports": {
|
|
33
|
+
".": {
|
|
34
|
+
"types": "./dist/index.d.mts",
|
|
35
|
+
"import": "./dist/index.mjs",
|
|
36
|
+
"default": "./dist/index.mjs"
|
|
37
|
+
},
|
|
38
|
+
"./package.json": "./package.json"
|
|
39
|
+
},
|
|
40
|
+
"files": [
|
|
41
|
+
"dist"
|
|
42
|
+
],
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
45
|
+
"zod": "^4.4.3",
|
|
46
|
+
"@dependfix/engine": "0.1.3",
|
|
47
|
+
"@dependfix/core": "0.2.1"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"nock": "^14.0.17",
|
|
51
|
+
"rimraf": "^6.1.3",
|
|
52
|
+
"tsdown": "^0.22.14",
|
|
53
|
+
"typescript": "^6.0.3"
|
|
54
|
+
},
|
|
55
|
+
"publishConfig": {
|
|
56
|
+
"access": "public"
|
|
57
|
+
},
|
|
58
|
+
"scripts": {
|
|
59
|
+
"build": "tsdown",
|
|
60
|
+
"prebuild": "rimraf dist",
|
|
61
|
+
"dev": "tsdown --watch",
|
|
62
|
+
"typecheck": "tsc --noEmit",
|
|
63
|
+
"lint": "eslint . --fix",
|
|
64
|
+
"test": "vitest run"
|
|
65
|
+
}
|
|
66
|
+
}
|