jenkins-mcp
README.md
# jenkins-mcp
**Read-only** MCP server for Jenkins. It reports build status across the
environments of your projects and pulls the logs when something breaks.
The server cannot write: its HTTP client only ever issues `GET`, so no builds
are triggered, stopped or reconfigured through it.
## Install
Runs straight from the repository with `npx`, no local clone needed:
```bash
# public repository
npx -y github:ruslan-casafari/jenkins-mcp --help
# private repository (over your ssh key)
npx -y git+ssh://git@github.com/ruslan-casafari/jenkins-mcp.git --help
# pin a tag or commit
npx -y github:ruslan-casafari/jenkins-mcp#v0.1.0
```
Installing from git makes npm fetch the devDependencies and compile TypeScript
(`prepare` → `tsc`), so the first run takes a few seconds; later runs come from
the npx cache.
The compiled `dist/` is committed as well, so the package also works when it is
installed with scripts disabled — which is what most MCP clients do, and then
`prepare` never runs.
> After pushing new commits npx may still serve a cached version.
> Refresh with `npx --ignore-existing github:ruslan-casafari/jenkins-mcp`.
From a local clone:
```bash
git clone git@github.com:ruslan-casafari/jenkins-mcp.git
cd jenkins-mcp && npm install # npm install already builds dist/
node dist/index.js --help
```
## Configuring projects
The point of the config is that you describe your projects and their
environments once, then work with short names — `web` / `prod` instead of
`platform/web/deploy-prod`.
Create a config file (`jenkins-mcp.example.json` is a starting point):
```json
{
"url": "https://jenkins.example.com",
"user": "your-login",
"projects": {
"web": {
"description": "Main website",
"environments": {
"dev": "platform/web/deploy-dev",
"staging": "platform/web/deploy-staging",
"prod": "platform/web/deploy-prod"
}
},
"api": { "dev": "platform/api/dev", "prod": "platform/api/prod" },
"mobile": "platform/mobile/build"
}
}
```
A project can be written in three shapes, whichever is shortest for the case:
| Shape | Use it when |
| --- | --- |
| `"mobile": "path/to/job"` | one job; the environment is named `default` |
| `"api": { "dev": "...", "prod": "..." }` | several environments, no description |
| `"web": { "description": "...", "environments": { ... } }` | full form |
A job path is the job's full path in Jenkins (`folder/subfolder/job`). A URL
copied from the browser works too and is parsed — including `/view/some-view/`
tab segments, a context path and a trailing build number. If you do not know
the exact path, ask the assistant: it will find it with `jenkins_search_jobs`.
### Pull request environments
Per-PR environments come and go on their own, so they cannot be listed in the
config. Point the project at its multibranch folder instead, and name the
pull request per request:
```json
{
"pycore": {
"description": "Backend core",
"multibranch": "pycore",
"environments": { "main": "pycore/main" }
}
}
```
Given `job/pycore/view/change-requests/job/PR-2829/` in the browser, the project
is `pycore` with `multibranch: "pycore"`; `view/change-requests` is a UI tab and
does not belong in the config.
The pull request itself goes into the `branch` argument of any build tool, in
any of these forms: `2829`, `#2829`, `pr-2829`, `PR-2829`. A branch name such as
`feature/login` works as well. Static environments (`main` above) keep working
as before.
- "which PR environments are alive" → `jenkins_list_branches`
- "why did PR-2829 fail" → `jenkins_diagnose_build` with `branch: "2829"`
If PR jobs are not named `PR-*` (for example `MR-*` on GitLab), add
`"prPrefix": "MR-"` to the project, and `2829` will expand to `MR-2829`.
The other common layout is a single shared deploy job where the PR number
arrives as a build parameter. No multibranch folder is needed then; find the
build with a filter instead: `jenkins_list_builds` with
`parameters: { "PR": "2829" }`.
Where the server looks for a config when `--config` is not given (first hit wins):
1. `./jenkins-mcp.json`
2. `./.jenkins-mcp.json`
3. `~/.config/jenkins-mcp/config.json`
4. `~/.jenkins-mcp.json`
The MCP client decides the server's working directory, so an absolute
`--config` path is the reliable choice.
## Token
The token is a Jenkins API token: profile → **Security** → *Add new token*
(`https://jenkins.example.com/me/security`). A UI password will not work when
SSO is in place.
Keep the token in the `JENKINS_TOKEN` environment variable rather than in the
config file.
## Connecting Claude Code
```bash
claude mcp add jenkins \
--env JENKINS_TOKEN=xxxxxxxxxxxx \
-- npx -y github:ruslan-casafari/jenkins-mcp --config ~/.jenkins-mcp.json
```
Or in the project's `.mcp.json` / in `~/.claude.json`:
```json
{
"mcpServers": {
"jenkins": {
"type": "stdio",
"command": "npx",
"args": [
"-y",
"github:ruslan-casafari/jenkins-mcp",
"--config",
"/Users/me/.jenkins-mcp.json"
],
"env": { "JENKINS_TOKEN": "${JENKINS_TOKEN}" }
}
}
}
```
To keep everything in that one file instead, drop the config file and pass the
projects as JSON in `JENKINS_PROJECTS`:
```json
{
"mcpServers": {
"jenkins": {
"type": "stdio",
"command": "npx",
"args": ["-y", "github:ruslan-casafari/jenkins-mcp"],
"env": {
"JENKINS_URL": "https://jenkins.example.com",
"JENKINS_USER": "your-login",
"JENKINS_TOKEN": "${JENKINS_TOKEN}",
"JENKINS_PROJECTS": "{\"pycore\":{\"multibranch\":\"pycore\",\"environments\":{\"main\":\"pycore/main\"}},\"web\":{\"dev\":\"platform/web/deploy-dev\",\"prod\":\"platform/web/deploy-prod\"}}"
}
}
}
}
```
Either block suits any MCP client with a stdio transport.
To check the connection, ask the assistant to call `jenkins_whoami`: it returns
the authenticated user, the Jenkins version and how many projects are configured.
## Tools
| Tool | What it does |
| --- | --- |
| `jenkins_list_projects` | Configured projects, their environments and the jobs behind them. No Jenkins request. |
| `jenkins_project_status` | State of a project's environments: last build, who triggered it, parameters, commits, last successful and last failed build. No arguments — every project. |
| `jenkins_list_builds` | Build history of an environment, with an `onlyFailed` filter. |
| `jenkins_get_build` | Details of one build: result, parameters, changes. |
| `jenkins_get_build_log` | Console log: tail, `search` by regex with context, `start` to keep reading a running build. |
| `jenkins_diagnose_build` | Triage of a failed build in one call: the failed pipeline stage with its error and log, failed tests, console tail. |
| `jenkins_get_test_report` | Test summary and failing cases with their messages. |
| `jenkins_list_branches` | Live branch and PR environments of a project from its multibranch folder, with the last build of each. |
| `jenkins_search_jobs` | Find jobs on the controller — to get a path and add the project to the config. |
| `jenkins_whoami` | Check the URL, the credentials and the permissions. |
Every build tool takes its target the same way: `project` + `environment` (or
`project: "web/prod"`), `project` + `branch` for pull requests and branches, or
`job` with a raw path for jobs that are not in the config. The `build` argument
is a build number or a Jenkins alias (`lastBuild`, `lastFailedBuild`,
`lastSuccessfulBuild`, …), defaulting to `lastBuild`.
Questions this covers:
- "what is on prod for web" → `jenkins_project_status`
- "why did the last api build on staging fail" → `jenkins_diagnose_build`
- "show everything about timeout in the log" → `jenkins_get_build_log` with `search: "timeout"`
- "when did prod last deploy successfully" → `jenkins_list_builds`
- "what happened to the PR-2829 build" → `jenkins_diagnose_build` with `branch: "2829"`
## Runtime options
| Flag | Environment variable | Default |
| --- | --- | --- |
| `--url` | `JENKINS_URL` | — (required) |
| `--user` | `JENKINS_USER` | — |
| `--token` | `JENKINS_TOKEN`, `JENKINS_API_TOKEN` | — |
| `--config` | `JENKINS_MCP_CONFIG` | auto-discovery (see above) |
| `--insecure` | `JENKINS_INSECURE_TLS=1` | off |
| `--timeout` | `JENKINS_TIMEOUT_MS` | `30000` |
| `--max-output` | `JENKINS_MAX_OUTPUT_CHARS` | `80000` |
Flags take precedence over environment variables, which take precedence over
the config file.
`JENKINS_PROJECTS` holds the same structure as `projects` in the config file,
as a JSON string.
`--insecure` disables TLS certificate verification for the whole process — turn
it on only for an internal controller with a self-signed certificate.
## Development
```bash
npm install # installs dependencies and builds dist/
npm run typecheck
npm run build
```
Node.js 20+.
`dist/` is checked in, because MCP clients install this package with scripts
disabled and would otherwise get no compiled output. Run `npm run build` and
commit the result together with any change under `src/`.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues