关于 Drone CI/CD MCP Server
Drone CI/CD MCP Server 为 Drone CI/CD 实例提供 MCP 接口,供客户端查询仓库、构建和其他 CI/CD 信息。默认仅启用只读工具,写入及破坏性操作需显式开启,并支持带认证的 Streamable HTTP。
主要功能
- 01提供仓库、构建、计划任务等工具
- 02默认只注册只读工具
- 03显式开启写入和破坏性操作
- 04支持带 Bearer 认证的 Streamable HTTP
- 05校验输入并提供构建详情资源
适用场景
- 01查询仓库构建状态与日志
- 02检查 Drone 仓库和计划任务
- 03在明确启用写入后管理构建或密钥
MCP 相关
该服务向 MCP 客户端提供 Drone 仓库、构建、计划任务、密钥、用户和模板相关工具,并提供构建详情资源。支持 stdio 和需 Bearer 认证的 Streamable HTTP 传输。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
docker run -i --rm ghcr.io/yusiwen/drone-mcp-server:2.0.0本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
ghcr.io/yusiwen/drone-mcp-server:2.0.0stdio工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
Drone MCP 服务
用于与 Drone CI/CD 交互的模型上下文协议(MCP)服务。此服务提供工具和资源,可从你的 Drone 实例查询构建信息、代码仓库等内容。
功能
- 45 个工具,涵盖代码仓库、构建、定时任务、密钥、用户和模板
- 默认只读:仅在使用
--enable-write-tools时才会注册 27 个写入和破坏性工具 - 可流式传输的 HTTP 传输,强制使用 bearer 身份验证,并提供 DNS 重绑定防护和跨域防护
- 已验证的输入:在将代码仓库标识符、名称、分支和构建编号传递给 Drone API 之前进行检查
- 资源访问:通过
drone://builds/{owner}/{repo}/{build}获取构建详情
安装
go mod tidy
go build -o drone-mcp-server .
配置
环境变量
| 变量 | 必需 | 说明 |
|---|---|---|
DRONE_SERVER | 是 | Drone 实例的基础 URL,例如 https://drone.example.com |
DRONE_TOKEN | 是 | Drone 个人访问令牌,每次 Drone API 调用时都会通过 Authorization: Bearer <token> 发送 |
MCP_AUTH_TOKEN | HTTP 模式 | 客户端必须提供的 bearer 令牌。未设置此令牌时,HTTP 模式将拒绝启动 |
MCP_AUTH_TOKEN_FILE | 否 | 包含 bearer 令牌的文件(Docker/Kubernetes 密钥)。其优先级高于 MCP_AUTH_TOKEN |
MCP_ENABLE_WRITE_TOOLS | 否 | 设为 true 可注册写入和破坏性工具,等同于 --enable-write-tools |
export DRONE_SERVER=https://drone.example.com
export DRONE_TOKEN=your_drone_token
export MCP_AUTH_TOKEN="$(openssl rand -base64 32)" # HTTP mode only
授予最小范围的 Drone 权限,以满足所公开工具的需求。只读工具集只需要对代码仓库和构建拥有读取权限,而 delete_user、create_org_secret 或 chown_repo 等写入工具则需要管理员权限。
安全
此服务是一个特权代理:它能够访问的任何内容,与它通信的任何人也都能访问。默认设置正是基于这一点。
- HTTP 模式默认拒绝启动。 如果未设置
MCP_AUTH_TOKEN(或MCP_AUTH_TOKEN_FILE),服务将在 HTTP 模式下拒绝启动。--insecure-allow-anonymous可绕过此限制,并会记录警告。 - 默认只读。 除非明确请求写入权限,否则只会注册 18 个只读工具。每个工具都带有 MCP 提示
readOnlyHint、destructiveHint和idempotentHint注释,以便客户端自行控制写入操作。 - 可流式传输的 HTTP 传输。 MCP 规范已移除传统的 SSE 传输,且该传输在发布时没有 DNS 重绑定或跨域防护。此服务使用 Go SDK 的
StreamableHTTPHandler,会拒绝来自环回地址、但带有非环回Host请求头的请求,并拒绝跨站浏览器请求。 - 可选允许列表。
--allowed-hosts和--allowed-origins可在传输默认设置的基础上,添加明确的Host和Origin允许列表。 - Bearer 令牌处理。 令牌通过 SHA-256 摘要以恒定时间进行比较,并会对来自同一地址的重复失败请求进行限流(每分钟 10 次,之后返回
429)。 - 输入验证。 在将代码仓库标识符、密钥和模板名称、分支及构建编号传递给 Drone API 客户端之前进行验证,因为 drone-go 会通过字符串格式化来组装请求路径。
- 日志卫生。 除非设置了
--trust-proxy,否则会忽略X-Forwarded-For/X-Real-IP;同时会从记录的值中剔除控制字符,防止请求数据伪造日志行。 - 有界请求。 请求正文设有大小上限(默认为 1 MiB),空闲会话会过期,并通过请求头读取超时和静默连接超时限制慢速客户端滥用。
部署检查清单
- 在服务器前端终止 TLS(该二进制使用纯 HTTP),切勿通过不可信网络发送 bearer token。
- 保持默认的 loopback 绑定并在前端设置反向代理,或绑定到只有 MCP 客户端能够访问的接口。
- 生成高熵的
MCP_AUTH_TOKEN(32+ 个随机字节),并将其作为平台密钥注入,而不是放在命令行中。 - 除非工作流需要,否则禁用写入工具。
- 仅当由你控制的代理会重写
X-Forwarded-For/X-Real-IP时才设置--trust-proxy;否则,日志中的客户端地址可能由攻击者控制。 - 在将服务暴露到 localhost 之外之前,请阅读 SECURITY.md。
用法
作为 MCP 服务
将该服务添加到 MCP 客户端配置中(例如 Claude Desktop):
{
"mcpServers": {
"drone": {
"command": "/path/to/drone-mcp-server",
"env": {
"DRONE_SERVER": "https://drone.example.com",
"DRONE_TOKEN": "your_token"
}
}
}
}
直接运行
你可以直接运行该服务进行测试:
# Stdio mode (default) - for local MCP clients
./drone-mcp-server
# Streamable HTTP mode - requires MCP_AUTH_TOKEN
export MCP_AUTH_TOKEN="$(openssl rand -base64 32)"
./drone-mcp-server --http --host localhost --port 8080
传输模式
-
Stdio 模式(默认):使用 MCP 协议通过 stdin/stdout 通信。适用于与 MCP 客户端进行本地集成;不会暴露到网络,也不需要身份验证。
-
Streamable HTTP 模式(
--http):单个端点,接受POST(客户端到服务端)、GET(服务端到客户端流)和DELETE(拆除会话)。**从早期版本升级:**旧的
--sse标志和 SSE 传输已移除。请使用--http,并使用支持 Streamable HTTP 的客户端。# Local only, read-only tools MCP_AUTH_TOKEN=... ./drone-mcp-server --http # Behind a TLS terminating proxy, write tools enabled MCP_AUTH_TOKEN=... ./drone-mcp-server --http --host 127.0.0.1 --port 8080 \ --enable-write-tools --allowed-hosts mcp.example.com客户端默认连接到
http://localhost:8080/,并且必须发送以下标头:Authorization: Bearer <MCP_AUTH_TOKEN>**在反向代理后运行:**作为 DNS 重绑定保护的一部分,传输层会对 loopback 连接上的公共
Host标头返回403。你可以保留 loopbackHost标头(proxy_set_header Host 127.0.0.1:8080;),也可以通过单个标志将 Host 验证交由允许列表处理:./drone-mcp-server --http --allowed-hosts mcp.example.com设置
--allowed-hosts会取代 loopback 启发式检查,因此无需设置--localhost-protection=false。如果显式传入--localhost-protection=true,则会同时应用两项检查,并再次拒绝公共Host。
命令行标志
| 标志 | 默认值 | 说明 |
|---|---|---|
--http | false | 使用 Streamable HTTP 传输 |
--host / --port | localhost / 8080 | 监听地址(仅限 HTTP 模式) |
--path | / | MCP 端点路径(仅限 HTTP 模式) |
--enable-write-tools | false | 注册 27 个写入和破坏性工具 |
--insecure-allow-anonymous | false | 允许 HTTP 模式不设置 MCP_AUTH_TOKEN |
--trust-proxy | false | 信任来自反向代理的 X-Forwarded-For / X-Real-IP |
--allowed-hosts | (空) | 以逗号分隔的 Host 允许列表;取代 loopback 启发式检查 |
--allowed-origins | (空) | 以逗号分隔的浏览器 Origin 允许列表 |
--localhost-protection | true | 拒绝携带非 loopback Host 标头的 loopback 连接;与 --allowed-hosts 一起显式设置可同时启用两项检查 |
--session-timeout | 30m | MCP 会话空闲超时时间(仅限 HTTP 模式) |
--max-request-bytes | 1048576 | MCP 请求正文的最大大小 |
--version | 打印版本信息并退出 |
可用工具
此服务实现了 45 个工具。在默认的只读模式下,仅注册 18 个只读工具;其余 27 个写入或破坏性工具需要启用 --enable-write-tools(或设置 MCP_ENABLE_WRITE_TOOLS=true)。
写入和破坏性工具: enable_repo、disable_repo、repair_repo、chown_repo、sync_repos、create_cron、delete_cron、execute_cron、create_secret、update_secret、delete_secret、create_org_secret、update_org_secret、delete_org_secret、create_user、update_user、delete_user、create_template、update_template、delete_template、restart_build、cancel_build、promote_build、rollback_build、approve_build、decline_build、create_build。
破坏性工具(删除、禁用、取消、提升、回滚和所有权变更)标记为 destructiveHint: true;其余写入工具标记为 destructiveHint: false。全部 18 个只读工具均标记为 readOnlyHint: true。
仓库管理
list_repos
列出 Drone 实例中的所有仓库。
get_repo
获取仓库详情。
参数:
owner(string):仓库所有者repo(string):仓库名称
enable_repo
启用仓库。
参数:
owner(string):仓库所有者repo(string):仓库名称
disable_repo
禁用仓库。
参数:
owner(string):仓库所有者repo(string):仓库名称
repair_repo
修复仓库。
参数:
owner(string):仓库所有者repo(string):仓库名称
chown_repo
更改仓库所有权。
参数:
owner(string):仓库所有者repo(string):仓库名称
sync_repos
同步仓库列表。
list_incomplete
列出构建未完成的仓库。
构建管理
list_builds
列出特定仓库的构建。
参数:
owner(string):仓库所有者repo(string):仓库名称
get_build
获取特定构建的详细信息。
参数:
owner(string):仓库所有者repo(string):仓库名称build(number):构建编号
get_build_last
获取仓库的最新构建(可按分支筛选)。
参数:
owner(string):仓库所有者repo(string):仓库名称branch(string,可选):分支名称
get_build_logs
获取特定构建阶段和步骤的日志。
参数:
owner(string):仓库所有者repo(string):仓库名称build(number):构建编号stage(number):阶段编号step(number):步骤编号
restart_build
重新启动构建(可选携带参数)。
参数:
owner(string):仓库所有者repo(string):仓库名称build(number):构建编号params(object,可选):构建参数
cancel_build
取消正在运行的构建。
参数:
owner(string):仓库所有者repo(string):仓库名称build(number):构建编号
promote_build
将构建提升到目标环境。
参数:
owner(string):仓库所有者repo(string):仓库名称build(number):构建编号target(string):目标环境params(object,可选):提升参数
rollback_build
将部署回滚到之前的构建。
参数:
owner(string):仓库所有者repo(string):仓库名称build(number):构建编号target(string):目标环境params(object,可选):回滚参数
approve_build
批准构建阶段(用于受控部署)。
参数:
owner(string):仓库所有者repo(string):仓库名称build(number):构建编号stage(number):阶段编号
decline_build
拒绝一个构建阶段(用于受门控的部署)。
参数:
owner(string):仓库所有者repo(string):仓库名称build(number):构建编号stage(number):阶段编号
create_build
从提交或分支创建新构建。
参数:
owner(string):仓库所有者repo(string):仓库名称commit(string, optional):提交 SHAbranch(string, optional):分支名称params(object, optional):构建参数
Cron 作业管理
list_crons
列出仓库的 Cron 作业。
参数:
owner(string):仓库所有者repo(string):仓库名称
get_cron
获取 Cron 作业详情。
参数:
owner(string):仓库所有者repo(string):仓库名称cron(string):Cron 作业名称
create_cron
创建新的 Cron 作业。
参数:
owner(string):仓库所有者repo(string):仓库名称name(string):Cron 作业名称expr(string):Cron 表达式branch(string):分支名称disable(boolean, optional):禁用 Cron 作业
delete_cron
删除 Cron 作业。
参数:
owner(string):仓库所有者repo(string):仓库名称cron(string):Cron 作业名称
execute_cron
立即执行 Cron 作业。
参数:
owner(string):仓库所有者repo(string):仓库名称cron(string):Cron 作业名称
密钥管理
list_secrets
列出仓库密钥。
参数:
owner(string):仓库所有者repo(string):仓库名称
get_secret
获取仓库密钥详情。
参数:
owner(string):仓库所有者repo(string):仓库名称name(string):密钥名称
create_secret
创建仓库密钥。
参数:
owner(string):仓库所有者repo(string):仓库名称name(string):密钥名称value(string):密钥值pull_request(boolean, optional):允许在拉取请求中使用pull_request_push(boolean, optional):允许在拉取请求推送事件中使用
update_secret
更新仓库密钥。
参数:
owner(string):仓库所有者repo(string):仓库名称name(string):密钥名称value(string):密钥值pull_request(boolean, optional):允许在拉取请求中使用pull_request_push(boolean, optional):允许在拉取请求推送事件中使用
delete_secret
删除仓库密钥。
参数:
owner(string):仓库所有者repo(string):仓库名称name(string):密钥名称
组织密钥
list_org_secrets
列出组织密钥。
参数:
namespace(string):组织命名空间
get_org_secret
获取组织密钥详情。
参数:
namespace(string):组织命名空间name(string):密钥名称
create_org_secret
创建组织密钥。
参数:
namespace(string):组织命名空间name(string):密钥名称value(string):密钥值pull_request(boolean, optional):允许在拉取请求中使用pull_request_push(boolean, optional):允许在拉取请求推送事件中使用
update_org_secret
更新组织密钥。
参数:
namespace(string):组织命名空间name(string):密钥名称value(string):密钥值pull_request(boolean, optional):允许在拉取请求中使用pull_request_push(boolean, optional):允许在拉取请求推送事件中使用
delete_org_secret
删除组织密钥。
参数:
namespace(string):组织命名空间name(string):密钥名称
用户管理
get_self
获取当前已验证身份的用户。
list_users
列出所有用户。
get_user
获取用户详情。
参数:
login(string):用户登录名
create_user
创建新用户。
参数:
login(string):用户登录名email(string,可选):用户邮箱admin(boolean,可选):管理员权限active(boolean,可选):是否启用token(string,可选):用户令牌
update_user
更新用户。
参数:
login(string):用户登录名admin(boolean,可选):管理员权限active(boolean,可选):是否启用
delete_user
删除用户。
参数:
login(string):用户登录名
模板管理
list_templates
列出模板(可按命名空间筛选)。
参数:
namespace(string,可选):模板命名空间
get_template
获取模板详情和数据。
参数:
namespace(string):模板命名空间name(string):模板名称
create_template
创建新模板。
参数:
namespace(string):模板命名空间name(string):模板名称data(string):模板数据(YAML)
update_template
更新模板。
参数:
namespace(string):模板命名空间name(string):模板名称data(string):模板数据(YAML)
delete_template
删除模板。
参数:
namespace(string):模板命名空间name(string):模板名称
资源
构建详情资源
通过资源 URI 访问构建详情:drone://builds/{owner}/{repo}/{build}
示例:
Read resource: drone://builds/owner1/repo1/123
Docker
GitHub Container Registry 上提供多架构 Docker 镜像:
# Pull the latest image
docker pull ghcr.io/yusiwen/drone-mcp-server:latest
# Run in stdio mode (for local MCP clients)
docker run --rm -i \
-e DRONE_SERVER=https://drone.example.com \
-e DRONE_TOKEN=your_token \
ghcr.io/yusiwen/drone-mcp-server
# Run in Streamable HTTP mode: read-only, authenticated, published on loopback
docker run --rm \
-e DRONE_SERVER=https://drone.example.com \
-e DRONE_TOKEN=your_token \
-e MCP_AUTH_TOKEN=your_mcp_token \
-p 127.0.0.1:8080:8080 \
ghcr.io/yusiwen/drone-mcp-server --http --host 0.0.0.0
# Add --enable-write-tools when the workflow must mutate Drone
docker run --rm \
-e DRONE_SERVER=https://drone.example.com \
-e DRONE_TOKEN=your_token \
-e MCP_AUTH_TOKEN=your_mcp_token \
-p 127.0.0.1:8080:8080 \
ghcr.io/yusiwen/drone-mcp-server --http --host 0.0.0.0 --enable-write-tools
在容器中必须使用 --host 0.0.0.0,发布的端口才能正常工作;这也正是必须提供 bearer token 的原因。除非前置了 TLS 终止代理,否则请将端口发布到 127.0.0.1。
优先使用挂载的密钥,而非环境变量:
docker run --rm \
-v /run/secrets/mcp_token:/run/secrets/mcp_token:ro \
-e MCP_AUTH_TOKEN_FILE=/run/secrets/mcp_token \
-e DRONE_SERVER=https://drone.example.com \
-e DRONE_TOKEN=your_token \
-p 127.0.0.1:8080:8080 \
ghcr.io/yusiwen/drone-mcp-server --http --host 0.0.0.0
Docker Compose 示例
services:
drone-mcp-server:
image: ghcr.io/yusiwen/drone-mcp-server:latest
environment:
DRONE_SERVER: https://drone.example.com
DRONE_TOKEN: ${DRONE_TOKEN:?DRONE_TOKEN is required}
MCP_AUTH_TOKEN: ${MCP_AUTH_TOKEN:?MCP_AUTH_TOKEN is required}
# MCP_ENABLE_WRITE_TOOLS: "true" # only when the workflow needs writes
ports:
- "127.0.0.1:8080:8080"
command: ["--http", "--host", "0.0.0.0"]
restart: unless-stopped
read_only: true
security_opt:
- no-new-privileges:true
发布版本
GitHub Releases 提供适用于 Linux(x64、arm64)、macOS(x64、arm64)和 Windows(x64)的预构建二进制文件。
版本信息
二进制文件包含版本信息:
./drone-mcp-server --version
输出示例:
drone-mcp-server
Version: v1.0.0
Commit: abc123
Build date: 2024-01-01T00:00:00Z
Go version: go1.25.1
项目结构
.
├── main.go # Entry point: CLI flags, transports, auth, HTTP hardening, tool registration
├── main_test.go # Auth middleware, allowlists, log hygiene and tool registration tests
├── tool/ # Tool handlers module
│ ├── build.go # Build-related tools (list_builds, get_build, restart_build, etc.)
│ ├── repo.go # Repository-related tools (list_repos, enable_repo, disable_repo, etc.)
│ ├── resource.go # Resource handling (drone://builds/...)
│ ├── cron.go # Cron job management tools
│ ├── secret.go # Secret management tools
│ ├── user.go # User management tools
│ ├── template.go # Template management tools
│ ├── validate.go # Input validation helpers used by every tool
│ ├── validate_args.go # Validate implementation for each tool argument struct
│ └── validate_test.go # Validation tests, including injection attempts
├── SECURITY.md # Threat model, deployment guidance and reporting process
├── server.json # MCP registry metadata
├── test_env.sh # Manual smoke test script (uses environment variables)
├── test_mcp.go # In-memory MCP integration test (build tag: test)
└── README.md
开发
依赖项
- Go 1.25.14+(工具链版本由
go.mod固定;较早的 Go 1.25 补丁版本存在标准库漏洞,会导致govulncheck检查失败) - github.com/modelcontextprotocol/go-sdk - MCP SDK(Streamable HTTP 传输)
- github.com/drone/drone-go - Drone API 客户端
构建
make build # build with version info injected through ldflags
go build -o drone-mcp-server .
测试
make test # unit tests
make test-race # with the race detector
make smoke # end-to-end security smoke test
make vuln # govulncheck (module + standard library)
go vet ./...
单元测试涵盖身份验证中间件(包括恒定时间比较和失败请求限流)、Host 策略、日志清理、客户端地址处理、输入验证以及只读工具注册。测试不需要 Drone 实例。
验证安全加固
scripts/security-smoke-test.sh 会在环回端口启动真实二进制文件,并验证关键行为,且不会联系任何 Drone 实例:
./scripts/security-smoke-test.sh # builds the binary first
BIN=./drone-mcp-server ./scripts/security-smoke-test.sh
该脚本会检查 HTTP 模式是否会在缺少令牌时拒绝启动;缺失或错误的凭据、错误的 Content-Type、超大请求体、伪造的 Host 标头以及跨站点 Origin 是否分别被 401/401/415/413/403/403 拒绝;默认工具列表是否恰好包含 18 个只读工具,以及隐藏的写入工具是否无法调用;工具参数中的路径遍历是否会被拒绝;日志注入和 X-Forwarded-For 欺骗是否会被中和;--allowed-hosts 是否会取代环回地址判断机制;写入工具是否仅在启用 --enable-write-tools 时出现;--sse 是否已移除;以及服务器是否会在收到 SIGTERM 时关闭。首次遇到失败时,脚本会以非零状态退出。它也会在 CI 中运行,因此还可充当回归检查门禁。
在真实的 Drone 上手动验证
先使用只读令牌,并确认工具能正常响应:
export DRONE_SERVER=https://ci.example.com
export DRONE_TOKEN=<read-only token>
export MCP_AUTH_TOKEN="$(openssl rand -base64 32)"
./drone-mcp-server --http --host 127.0.0.1 --port 8080
然后将 MCP 客户端连接到该服务。Stdio 模式:
{
"mcpServers": {
"drone": {
"command": "/path/to/drone-mcp-server",
"env": { "DRONE_SERVER": "https://ci.example.com", "DRONE_TOKEN": "..." }
}
}
}
Streamable HTTP 模式(大多数客户端都支持 headers 块;也可以使用 npx @modelcontextprotocol/inspector,选择“Streamable HTTP”并添加相同的标头):
{
"mcpServers": {
"drone": {
"url": "http://127.0.0.1:8080/",
"headers": { "Authorization": "Bearer <MCP_AUTH_TOKEN>" }
}
}
}
建议在真实实例上进行以下检查:get_self(确认令牌有效)、list_repos、get_build_last、get_build_logs(在模型上下文中测试不可信内容),然后使用 owner: "../users" 调用 get_repo,确认验证会拒绝该请求。写入工具只能对临时仓库运行。
本地运行
export DRONE_SERVER=https://drone.example.com
export DRONE_TOKEN=...
# Read-only stdio server
./drone-mcp-server
# HTTP mode with authentication and write tools
MCP_AUTH_TOKEN=dev-token ./drone-mcp-server --http --enable-write-tools
许可证
MIT
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。