Skip to main content
Glama
sun-jingtao

dramabox-jenkins-mcp

by sun-jingtao
README.md
# dramabox-jenkins-mcp

DramaBox Jenkins HOT/QAT/QAT2 部署助手(MCP Server),支持 Claude Code、Claude Desktop、Cursor 等任意 MCP 客户端。

让 Agent 在对话里完成完整部署闭环:定位 Job → 查询 Jenkins 真实构建状态 → 防覆盖检查 → 修改分支并触发构建。全程不把 Token 贴进对话。

关联需求:[【PRD】Jenkins HOT/QAT 部署助手 MCP](https://www.tapd.cn/tapd_fe/59787500/story/detail/1159787500001022834)

## 快速开始

### 1. 安装依赖并构建

```bash
cd /Users/luoluo/Desktop/my-github/dramabox-jenkins-mcp
npm install
npm run build
```

自检(不连外网、不需要 Token):

```bash
npm run self-check
```

### 2. 在 MCP 客户端配置里填写凭证

各客户端配置文件位置:

| 客户端 | 配置位置 |
| --- | --- |
| Claude Code | 项目 `.mcp.json`,或 `claude mcp add` 命令 |
| Claude Desktop | 设置 → 开发者 → `claude_desktop_config.json` |
| Cursor | `~/.cursor/mcp.json`(或项目内 `.cursor/mcp.json`) |

配置内容通用(标准 `mcpServers` 格式):

```json
{
  "mcpServers": {
    "dramabox-jenkins": {
      "command": "node",
      "args": [
        "/Users/luoluo/Desktop/my-github/dramabox-jenkins-mcp/dist/index.js"
      ],
      "env": {
        "GITLAB_URL": "https://你的-gitlab-域名",
        "GITLAB_TOKEN": "你的 GitLab Personal Access Token",
        "JENKINS_URL": "http://你的-jenkins:8080",
        "JENKINS_USER": "你的 Jenkins 用户名",
        "JENKINS_TOKEN": "你的 Jenkins API Token"
      }
    }
  }
}
```

| 变量 | 说明 |
| --- | --- |
| `GITLAB_URL` | GitLab 根地址;Token 需要至少 `read_api` |
| `GITLAB_TOKEN` | GitLab Personal Access Token(`PRIVATE-TOKEN`) |
| `JENKINS_URL` | Jenkins 根地址,如 `http://192.168.x.x:8080` |
| `JENKINS_USER` | Jenkins 用户名 |
| `JENKINS_TOKEN` | Jenkins API Token(用户设置里生成,不是登录密码) |

> 凭证**只**通过 MCP 配置的 `env` 注入进程,进程内不读取 `.env` 文件;缺失任一变量时 server 启动即报错(fail-fast),不会等到调用时才发现。请勿把 Token 提交到仓库或贴进对话。

团队推广时:每人复制同一段 `mcpServers` 配置,各自换成自己的 Token;后续若发 npm 包,把 `command`/`args` 换成 `npx` 即可,`env` 字段不用改。

### 3. 启用 MCP

1. 保存配置后重启客户端(或刷新 MCP server),确认 `dramabox-jenkins` 已连接:Claude Code 里执行 `/mcp` 查看,Cursor 在 Settings → MCP 看绿点。
2. 若刚改过代码,先 `npm run build`,再重启该 server。
3. 新开对话,让 Agent 调用工具(见下方示例)。

## 使用示例

对话里直接说:

> 帮我把 dramabox_other 的 HOT 环境部署到 sunjt-0716-fix 分支

Agent 会自动串联:`find_job` 定位 → `deploy` 防覆盖检查后改分支并触发构建。切换代码线且最近成功部署版本未进入主干时会先告警,需要你明确同意后才允许 `force`。其他常用说法:

> dramabox_other 的 QAT 当前配置、最近构建和最近成功部署分别是什么?(→ find_job + get_status)
>
> dramabox_other 的 QAT2 最近成功部署的是哪个分支和 commit?(→ find_job(env=qat2) + get_status)

## 已实现工具

| 工具 | 作用 | 写操作 |
| --- | --- | --- |
| `find_job` | 按 GitLab 仓库定位候选 Job,返回 Job 名、Jenkins 当前配置分支、仓库地址和链接 | 否 |
| `get_status` | 当前配置、最近构建尝试、最近严格成功部署、触发来源、主干合并状态及 Job 描述中的部署页线索 | 否 |
| `deploy` | 并发与防覆盖检查 → 改 BranchSpec → 触发 Jenkins 构建 | **是** |

## 状态口径

- `Jenkins 当前配置分支` 来自 `config.xml` BranchSpec,只表示下一次准备构建什么,不代表服务器正在运行什么。
- `最近构建尝试` 来自 `lastBuild`,可能是 BUILDING、FAILURE、ABORTED 或 SUCCESS。
- `最近一次成功部署` 来自 `lastStableBuild`,客户端还会再次要求 `result === "SUCCESS" && building === false`。
- 实际 commit SHA 和 branch label 来自 Git Plugin `BuildData.lastBuiltRevision`;多 SCM 时必须由 `remoteUrls` 与 Job 仓库精确匹配。
- Jenkins 构建开始时间为 `timestamp`,展示的完成时间使用 `timestamp + duration`,不声称是部署步骤的精确完成时刻。

## deploy 防覆盖规则

1. Job 已在 queue 或 `lastBuild.building === true`:硬拦截,`force` 不能绕过。写配置前会再次检查,以缩小竞态窗口。
2. 最近成功部署的实际分支与目标分支标准化后同名:直接允许重部署,包括个人分支 force-push 后再次部署。
3. 分支名不同或 BuildData branch label 无法唯一确定:通过 GitLab `merge_base(deployedSha, defaultBranch)` 判断实际部署 SHA 是否已进入主干。
4. SHA 已进入主干:允许切换分支;明确未进入或查询结果 unknown:要求用户确认后用 `force=true`。
5. 无 `lastStableBuild`、构建历史轮转、BuildData 无法匹配、跨 GitLab 实例或 token 无权限:均按 unknown 处理,非 force 不修改 Jenkins。
6. 目标分支明确不存在:始终拒绝。存在性请求失败时,非 force 拦截;用户明确确认 `force=true` 后警告并继续,由 Jenkins 最终校验分支。

同分支判断有一项明确接受的边界:分支删除后以同名重建,也会被当作同分支重部署。个人开发分支允许频繁 force-push 后,单靠 Git 历史无法同时区分“正常改写”和“同名重建”。如果 BuildData 返回多个不同的标准化 branch label,工具不会猜测唯一来源,而会进入跨分支检查。

Squash merge 不保留原 deployed SHA,因此 `merge_base` 会判定该 SHA 未进入主干。工具可以根据 branch label 查询已合并 MR 并给出提示,但 MR 只用于辅助人工判断,不能自动放行。

## 仓库与环境匹配

Job 与仓库的对应关系取自 Jenkins Remote API 导出的 SCM 配置,归一化 IP/域名、`.git` 后缀、斜杠和大小写后,与 GitLab 项目路径全等比较,不按 Job 名模糊猜测。环境过滤支持 `hot`、`qat`、`qat2`,按 Job 名分隔词精确匹配,QAT 不会混入 QAT2。

`find_job` 不缓存 Jenkins Job 配置,每次调用都通过一次带 `tree` 过滤的 bulk API 请求读取当前 Job 列表、Git remote 和 BranchSpec,不逐个请求 `config.xml`。

内网 IP 与域名映射位于 `src/match.ts` 的 `HOST_ALIAS`。`GITLAB_URL` 和 Job remote 必须归一到同一实例,否则跨实例守卫会 fail-closed;换 IP、域名或实例时需要同步维护映射。

## 已删除的旧能力

`list_history`、`rollback` 和本地部署日志已从工具与 CLI 中删除。本地 JSONL 只能记录当前机器经本 MCP 发起的操作,无法覆盖其他用户直接通过 Jenkins 的部署,不能作为多人环境的权威历史。

升级不会自动删除已有的 `~/.dramabox-jenkins-mcp/deploy-log.jsonl`,但程序不再读取它;确认不需要后可由用户自行清理。

## 系统前提与待验证项

- 已确认不存在绕过 Jenkins 的常规手工服务器部署路径。
- 待真实 QAT/HOT 验证:Jenkins `SUCCESS` 必须等价于目标服务器实际部署成功。
- 待真实 QAT/HOT 验证:FAILURE/ABORTED 不得留下服务器部分更新状态。
- 如果上述前提不成立,应由服务器暴露 `/version`、release manifest、commit SHA 或制品 digest,并以运行时信息作为最终权威源。

## 验证

```bash
npm run build
npm run self-check
```

`self-check` 不访问外网,通过注入式 HTTP mock 覆盖 Jenkins BuildData、严格 SUCCESS、GitLab merge_base、同分支重部署、跨分支拦截和并发硬拦截。

TDQS

A4.2/5.0

Scored across 3 tools

Disambiguation5/5

Each tool has a distinct, non-overlapping purpose: locating candidate jobs, checking deployment status, and triggering deployments. The clear separation makes it easy for an agent to select the right tool for each step.

Naming Consistency4/5

Names follow a verb-based pattern with 'find_job' and 'get_status' using verb_noun, while 'deploy' is a bare verb. Minor inconsistency but still predictable and readable.

Tool Count5/5

Three tools is an ideal, focused set for the server's purpose of Jenkins deployment management. Each tool is essential and there is no bloat.

Completeness4/5

The set covers the core workflow: find a job, inspect its status, and deploy. It lacks an explicit cancel or rollback operation, but for the stated purpose of locating, checking, and deploying, coverage is solid.

Maintenance

ActivitySlowing
ResponsivenessNo issues