
Drone CI/CD MCP Server
io.github.yusiwenPublished by GitHub account yusiwenv2.0.0Updated Oct 24, 2026
MCP server for Drone CI/CD: 45 tools for builds, repos, secrets, users and templates
Overview
MCP server for Drone CI/CD that lets an assistant query repositories, builds, cron jobs, secrets, users and templates, with optional write tools.
- What you can do
- List and inspect repositories, including ones with incomplete builds
- List builds, read build details, last build by branch, and stage/step logs
- Read cron jobs, secrets, users and templates
- With write tools enabled: enable, disable, repair, chown and sync repositories
- With write tools enabled: create, delete and run crons; create, update and delete repo and org secrets
- With write tools enabled: restart, cancel, promote, rollback, approve, decline and create builds; manage users and templates
- When to use it
- Useful when you want an assistant to answer questions about a Drone CI instance — which builds failed, what a build log says, which repositories are enabled — or, with write tools on, to trigger and manage builds and configuration from chat.
- Requirements
- Runs as a local process (Go binary, prebuilt releases, or the ghcr.io container image) over stdio by default. Requires DRONE_SERVER (base URL of the Drone instance) and DRONE_TOKEN (Drone personal access token). HTTP mode additionally requires MCP_AUTH_TOKEN or MCP_AUTH_TOKEN_FILE. Network access to the Drone instance is needed.
Installation
In SourceWeft
- Open Drone CI/CD MCP Server in the dashboard and add it to a workspace.
- Enable the server for the chats that should use its tools.
Desktop only via STDIO. STDIO servers start a local process, so they need the SourceWeft desktop host.
Other MCP clients
Follow the launch instructions in the repository.
README
Drone MCP Server
A Model Context Protocol (MCP) server for interacting with Drone CI/CD. This server provides tools and resources to query build information, repositories, and more from your Drone instance.
Features
- 45 tools covering repositories, builds, cron jobs, secrets, users and templates
- Read-only by default: the 27 write and destructive tools are only registered with
--enable-write-tools - Streamable HTTP transport with mandatory bearer authentication, DNS rebinding protection and cross-origin protection
- Validated inputs: repository identifiers, names, branches and build numbers are checked before they reach the Drone API
- Resource access: build details via
drone://builds/{owner}/{repo}/{build}
Installation
Configuration
Environment variables
Grant the smallest Drone permission set that covers the tools you expose. The read-only tool set only needs read access to repositories and builds, while write tools such as delete_user, create_org_secret or chown_repo require administrator permissions.
Security
This server is a privileged proxy: whatever it can reach, anyone who can talk to it can reach too. The defaults reflect that.
- HTTP mode fails closed. Without
MCP_AUTH_TOKEN(orMCP_AUTH_TOKEN_FILE) the server refuses to start in HTTP mode.--insecure-allow-anonymousoverrides this and logs a warning. - Read-only by default. Only the 18 read-only tools are registered unless write access is requested explicitly. Every tool is annotated with the MCP hints
readOnlyHint,destructiveHintandidempotentHintso clients can gate writes themselves. - Streamable HTTP transport. The legacy SSE transport was removed from the MCP specification and shipped without DNS rebinding or cross-origin protection. This server uses the Go SDK's
StreamableHTTPHandler, which rejects requests that arrive on a loopback address with a non-loopbackHostheader and rejects cross-site browser requests. - Optional allowlists.
--allowed-hostsand--allowed-originsadd explicitHostandOriginallowlists on top of the transport defaults. - Bearer token handling. Tokens are compared in constant time over SHA-256 digests, and repeated failures from one address are throttled (10 per minute, then
429). - Input validation. Repository identifiers, secret and template names, branches and build numbers are validated before reaching the Drone API client, because drone-go assembles request paths by string formatting.
- Log hygiene.
X-Forwarded-For/X-Real-IPare ignored unless--trust-proxyis set, and control characters are stripped from logged values so request data cannot forge log lines. - Bounded requests. Request bodies are capped (1 MiB by default), idle sessions expire, and header read timeouts plus silent-connection timeouts limit slow-client abuse.
Deployment checklist
- Terminate TLS in front of the server (the binary speaks plain HTTP) and never send the bearer token over an untrusted network.
- Keep the loopback default binding and put a reverse proxy in front, or bind to an interface only your MCP clients can reach.
- Generate a high-entropy
MCP_AUTH_TOKEN(32+ random bytes) and inject it as a platform secret rather than on the command line. - Leave write tools disabled unless the workflow needs them.
- Set
--trust-proxyonly when a proxy you control rewritesX-Forwarded-For/X-Real-IP; otherwise the logged client address is attacker controlled. - Read SECURITY.md before exposing the server beyond localhost.
Usage
As an MCP server
Add the server to your MCP client configuration (e.g., Claude Desktop):
Direct execution
You can run the server directly for testing:
Transport Modes
-
Stdio mode (default): Communicates via stdin/stdout using the MCP protocol. Suitable for local integration with MCP clients; no network exposure and no authentication required.
-
Streamable HTTP mode (
--http): A single endpoint that acceptsPOST(client to server),GET(server to client stream) andDELETE(session teardown).Upgrading from earlier releases: the old
--sseflag and the SSE transport are gone. Use--httpand a client that speaks Streamable HTTP.Clients connect to
http://localhost:8080/by default and must send the header:Behind a reverse proxy: the transport rejects a public
Hostheader on a loopback connection with403as part of its DNS rebinding protection. Either keep the loopbackHostheader (proxy_set_header Host 127.0.0.1:8080;), or hand Host validation to the allowlist with a single flag:Setting
--allowed-hostsreplaces the loopback heuristic, so you do not need--localhost-protection=false. If you pass--localhost-protection=trueexplicitly, both checks are applied and the publicHostis rejected again.
Command line flags
Available Tools
The server implements 45 tools. In the default read-only mode only the 18 read-only tools are registered; the remaining 27 are write or destructive tools and require --enable-write-tools (or MCP_ENABLE_WRITE_TOOLS=true).
Write and destructive tools: 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.
The destructive ones (deletions, disables, cancellations, promotions, rollbacks, ownership changes) are advertised with destructiveHint: true; the rest of the write tools with destructiveHint: false. All 18 read-only tools are advertised with readOnlyHint: true.
Repository Management
list_repos
Lists all repositories in your Drone instance.
get_repo
Get repository details.
Arguments:
owner(string): Repository ownerrepo(string): Repository name
enable_repo
Enable a repository.
Arguments:
owner(string): Repository ownerrepo(string): Repository name
disable_repo
Disable a repository.
Arguments:
owner(string): Repository ownerrepo(string): Repository name
repair_repo
Repair a repository.
Arguments:
owner(string): Repository ownerrepo(string): Repository name
chown_repo
Change repository ownership.
Arguments:
owner(string): Repository ownerrepo(string): Repository name
sync_repos
Synchronize repository list.
list_incomplete
List repositories with incomplete builds.
Build Management
list_builds
Lists builds for a specific repository.
Arguments:
owner(string): Repository ownerrepo(string): Repository name
get_build
Get detailed information about a specific build.
Arguments:
owner(string): Repository ownerrepo(string): Repository namebuild(number): Build number
get_build_last
Get the last build for a repository (optionally by branch).
Arguments:
owner(string): Repository ownerrepo(string): Repository namebranch(string, optional): Branch name
get_build_logs
Get logs for a specific build stage and step.
Arguments:
owner(string): Repository ownerrepo(string): Repository namebuild(number): Build numberstage(number): Stage numberstep(number): Step number
restart_build
Restart a build (optionally with parameters).
Arguments:
owner(string): Repository ownerrepo(string): Repository namebuild(number): Build numberparams(object, optional): Build parameters
cancel_build
Cancel a running build.
Arguments:
owner(string): Repository ownerrepo(string): Repository namebuild(number): Build number
promote_build
Promote a build to a target environment.
Arguments:
owner(string): Repository ownerrepo(string): Repository namebuild(number): Build numbertarget(string): Target environmentparams(object, optional): Promotion parameters
rollback_build
Rollback a deployment to a previous build.
Arguments:
owner(string): Repository ownerrepo(string): Repository namebuild(number): Build numbertarget(string): Target environmentparams(object, optional): Rollback parameters
approve_build
Approve a build stage (for gated deployments).
Arguments:
owner(string): Repository ownerrepo(string): Repository namebuild(number): Build numberstage(number): Stage number
decline_build
Decline a build stage (for gated deployments).
Arguments:
owner(string): Repository ownerrepo(string): Repository namebuild(number): Build numberstage(number): Stage number
create_build
Create a new build from a commit or branch.
Arguments:
owner(string): Repository ownerrepo(string): Repository namecommit(string, optional): Commit SHAbranch(string, optional): Branch nameparams(object, optional): Build parameters
Cron Job Management
list_crons
List cron jobs for a repository.
Arguments:
owner(string): Repository ownerrepo(string): Repository name
get_cron
Get cron job details.
Arguments:
owner(string): Repository ownerrepo(string): Repository namecron(string): Cron job name
create_cron
Create a new cron job.
Arguments:
owner(string): Repository ownerrepo(string): Repository namename(string): Cron job nameexpr(string): Cron expressionbranch(string): Branch namedisable(boolean, optional): Disable the cron job
delete_cron
Delete a cron job.
Arguments:
owner(string): Repository ownerrepo(string): Repository namecron(string): Cron job name
execute_cron
Execute a cron job immediately.
Arguments:
owner(string): Repository ownerrepo(string): Repository namecron(string): Cron job name
Secret Management
list_secrets
List repository secrets.
Arguments:
owner(string): Repository ownerrepo(string): Repository name
get_secret
Get repository secret details.
Arguments:
owner(string): Repository ownerrepo(string): Repository namename(string): Secret name
create_secret
Create a repository secret.
Arguments:
owner(string): Repository ownerrepo(string): Repository namename(string): Secret namevalue(string): Secret valuepull_request(boolean, optional): Allow in pull requestspull_request_push(boolean, optional): Allow in pull request push events
update_secret
Update a repository secret.
Arguments:
owner(string): Repository ownerrepo(string): Repository namename(string): Secret namevalue(string): Secret valuepull_request(boolean, optional): Allow in pull requestspull_request_push(boolean, optional): Allow in pull request push events
delete_secret
Delete a repository secret.
Arguments:
owner(string): Repository ownerrepo(string): Repository namename(string): Secret name
Organization Secrets
list_org_secrets
List organization secrets.
Arguments:
namespace(string): Organization namespace
get_org_secret
Get organization secret details.
Arguments:
namespace(string): Organization namespacename(string): Secret name
create_org_secret
Create an organization secret.
Arguments:
namespace(string): Organization namespacename(string): Secret namevalue(string): Secret valuepull_request(boolean, optional): Allow in pull requestspull_request_push(boolean, optional): Allow in pull request push events
update_org_secret
Update an organization secret.
Arguments:
namespace(string): Organization namespacename(string): Secret namevalue(string): Secret valuepull_request(boolean, optional): Allow in pull requestspull_request_push(boolean, optional): Allow in pull request push events
delete_org_secret
Delete an organization secret.
Arguments:
namespace(string): Organization namespacename(string): Secret name
User Management
get_self
Get current authenticated user.
list_users
List all users.
get_user
Get user details.
Arguments:
login(string): User login name
create_user
Create a new user.
Arguments:
login(string): User login nameemail(string, optional): User emailadmin(boolean, optional): Admin privilegesactive(boolean, optional): Active statustoken(string, optional): User token
update_user
Update a user.
Arguments:
login(string): User login nameadmin(boolean, optional): Admin privilegesactive(boolean, optional): Active status
delete_user
Delete a user.
Arguments:
login(string): User login name
Template Management
list_templates
List templates (optionally by namespace).
Arguments:
namespace(string, optional): Template namespace
get_template
Get template details and data.
Arguments:
namespace(string): Template namespacename(string): Template name
create_template
Create a new template.
Arguments:
namespace(string): Template namespacename(string): Template namedata(string): Template data (YAML)
update_template
Update a template.
Arguments:
namespace(string): Template namespacename(string): Template namedata(string): Template data (YAML)
delete_template
Delete a template.
Arguments:
namespace(string): Template namespacename(string): Template name
Resources
Build details resource
Access build details via resource URI: drone://builds/{owner}/{repo}/{build}
Example:
Docker
A multi-architecture Docker image is available on GitHub Container Registry:
--host 0.0.0.0 is required inside a container so that published ports work, which is exactly why the bearer token is mandatory. Publish the port on 127.0.0.1 unless a TLS terminating proxy sits in front.
Prefer a mounted secret over an environment variable:
Docker Compose Example
Releases
Pre-built binaries are available for Linux (x64, arm64), macOS (x64, arm64), and Windows (x64) in the GitHub Releases.
Version Information
The binary includes version information:
Output example:
Project Structure
Development
Dependencies
- Go 1.25.14+ (the toolchain is pinned by
go.mod; earlier Go 1.25 patch releases carry standard library vulnerabilities that fail thegovulncheckgate) - github.com/modelcontextprotocol/go-sdk - MCP SDK (Streamable HTTP transport)
- github.com/drone/drone-go - Drone API client
Building
Testing
The unit tests cover the authentication middleware (including constant time comparison and failure throttling), the Host policy, log sanitization, client address handling, input validation and the read-only tool registration. They need no Drone instance.
Verifying the security hardening
scripts/security-smoke-test.sh starts the real binary on a loopback port and asserts the behaviour that matters, without contacting any Drone instance:
It checks that HTTP mode refuses to start without a token, that missing/wrong credentials, wrong Content-Type, oversized bodies, forged Host headers and cross-site Origin are rejected with 401/401/415/413/403/403, that the default tool list is exactly 18 read-only tools and that hidden write tools are not callable, that path traversal in tool arguments is refused, that log injection and X-Forwarded-For spoofing are neutralised, that --allowed-hosts replaces the loopback heuristic, that write tools appear only with --enable-write-tools, that --sse is gone, and that SIGTERM shuts the server down. It exits non-zero on the first failure set and runs in CI, so it doubles as a regression gate.
Manual verification against a real Drone
Use a read-only token first and confirm the tools answer:
Then point an MCP client at it. Stdio mode:
Streamable HTTP mode (most clients accept a headers block; npx @modelcontextprotocol/inspector works too, pick "Streamable HTTP" and add the same header):
Suggested checks against a real instance: get_self (confirms the token works), list_repos, get_build_last, get_build_logs (exercises untrusted content in the model context), then get_repo with owner: "../users" to confirm validation refuses it. Run write tools against a disposable repository only.
Running locally
License
MIT
Source: README.md at commit e67cec7
Tools
0Version history
2- v2.0.0LatestSep 18, 2026
- v1.0.0Sep 16, 2026
Score
40% of the applicable checks met
How complete this listing is, computed from the registry entry, the endpoint and public sources. Not a rating of the server and not a statement that it is safe or working today: reachability is a dated check, and no installs or reviews go into the score.
- Reached in the last 30 days25 pts
Keep the endpoint answering the MCP handshake; SourceWeft probes it every 30 days.
- Auth declared10 pts
Declare the credential headers in the registry entry, or keep the endpoint answering the probe so its auth can be classified.
- Tools listed15 pts
Answer tools/list without a credential, or ship a package that starts in a sandbox without one.
- DescriptionRequired15 pts
- Logo10 pts
- Documentation15 pts
- License10 pts
Declare a license in the repository or the registry entry.