release-mcp
Provides tools for managing multi-repo releases on GitLab, including starting releases, reconciling pipeline-driven builds, approving gates, bumping versions, and explaining failures, all via a declarative manifest and run state stored in a GitLab project.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@release-mcp start release 1.2.0 on sit with jar-bundle-2 2.3.0"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
release-agent
Deterministic, non-blocking release preparation across a fleet of GitLab repositories —
a reconciler engine over a declarative manifest, exposed as a CLI (release) and an
MCP server (release-mcp) so you can drive releases from GitHub Copilot Chat, Claude,
or any other MCP client in plain language.
Built for the reality of multi-repo products: libraries that must publish before services
can pin them, release branches with iterated tags (v1.0.0-1, -2, ...), a QA gate, a
deploy repo that pins the final versions — and CI pipelines that take 40–50 minutes.
The engine never waits: every command returns in seconds, pipelines run on their own time,
and an idempotent reconcile advances whatever is ready whenever you come back.
How it works
Manifest (
release-manifest.yaml) — declares your repos, their dependency DAG, which files to edit (maven properties, python dependencies, yaml keys), and what variables each pipeline needs. See examples/release-manifest.yaml. The engine hard-codes zero product knowledge — adoption is pure configuration.Run state — one JSON per release, stored in a small dedicated GitLab project. Shared visibility, full history, optimistic locking; any teammate can resume any release.
Reconciler — walks the DAG; per node: create branch → commit version pins → cut tag → trigger pipeline (via the API, so per-release variables travel with the build) → poll → record produced versions → unblock dependents. Nothing is ever created twice.
Gates — a manual checkpoint (e.g.
qa-signoff) the engine will not pass without an explicitrelease approve.Captures & report — manifest-declared regexes grep job logs for values of interest (Sonar URLs, image digests);
release reportassembles the whole release — tags, pipelines, versions, captured values — into markdown, optionally published to the state repo (reports/<coordinate>.md).No LLM in the engine — ever.
release explaindeterministically fetches a failed job's log tail; the model on the client side (Copilot, Claude, ...) interprets it in the same chat.ports.LogExplainerstays as an extension point if you want a hosted model, but nothing requires one.
Related MCP server: GitLab MCP Server
Install
Requires Python 3.13+ and uv.
git clone <this repo> && cd release_agent
uv sync
uv run release --helpConfigure
Everything is environment variables (per-developer PAT model):
Variable | Required | Meaning |
| yes | GitLab base URL, e.g. |
| yes | PAT with |
| no | Second identity used to approve MRs on repos with |
| yes* | Project holding run states + manifest, e.g. |
| no | Branch in the state project (default |
| no | Manifest path in the state project (default |
| no | Local manifest file (overrides the state project copy) |
| yes* | Local state directory instead of a state project (single-user/dev) |
* one of STATE_PROJECT / STATE_DIR is required.
Use — CLI
release start 1.0.0 --env sit \
-i jar_bundle_1_version=1.0.1 -i pydantic_version=10.0.0 -i jar_bundle_2_version=2.3.0
release status 1.0.0 # render the DAG, tags, pipeline URLs
release reconcile 1.0.0 # idempotent tick — run it whenever, it never double-fires
release bump 1.0.0 service-a # next vX.Y.Z-(N+1) after a QA fix
release approve 1.0.0 qa-signoff # clear the manual gate
release explain 1.0.0 service-a # advisory: why did the pipeline fail?Use — MCP (Copilot Chat, Claude, ...)
Register the stdio server with your client, e.g. VS Code .vscode/mcp.json:
{
"servers": {
"release-agent": {
"type": "stdio",
"command": "uv",
"args": ["run", "--directory", "/path/to/release_agent", "release-mcp"],
"env": {
"RELEASE_AGENT_GITLAB_URL": "https://gitlab.example.com",
"RELEASE_AGENT_GITLAB_TOKEN": "${input:gitlab-token}",
"RELEASE_AGENT_STATE_PROJECT": "group/release-state"
}
}
}
}Then just talk: "start release 1.0.0 on sit with jar-bundle-2 2.3.0, jar-bundle-1 jar 1.0.1,
pydantic 10.0.0" → the model calls release_start; later, "advance the release" →
release_reconcile. Tools exposed: release_start, release_status, release_reconcile,
release_approve, release_bump, release_explain, get_manifest.
Prompt cookbook
You say | Tool the model calls |
"Start release 1.2.0 on sit — jar-bundle-1 jar 1.0.2, pydantic 10.1.0, jar-bundle-2 2.4.0" |
|
"What exactly would starting 1.2.0 do?" |
|
"Where's release 1.2.0?" / "Did the jar-bundle-2 build finish?" |
|
"Advance the release" / "Pipelines look done, continue" |
|
"Why is service-a stuck?" |
|
"QA signed off, approve the release" |
|
"Why did service-b fail?" |
|
"Fix is merged on service-b's release branch, rebuild it" |
|
"Which files get edited during a release? What depends on what?" |
|
"What was the last released version of service-a?" |
|
"What releases are in flight?" / "What did we ship last?" |
|
"Here's my updated manifest — is it valid?" |
|
"Take 1.2.0 as far as it can go and tell me what's blocking" | chains reconcile → status → summary |
"Give me the release report" / "…and publish it" |
|
Habits that keep it reliable: always name the coordinate ("release 1.2.0") so the model never guesses which release you mean, and ask to "advance" freely — reconcile never double-fires, so an over-eager prompt costs nothing.
Adapt to your product
Copy examples/release-manifest.yaml and describe your repos, tiers, edits, and pipeline variables.
Create a
release-stateproject in GitLab, commit the manifest there.Gate your CI release/publish jobs to run only from API-triggered tag pipelines (
$CI_COMMIT_TAG && $CI_PIPELINE_SOURCE == "api"— purely additive, design §9). On GitLab 17.7+ also set each project's "Minimum role to use pipeline variables" todeveloper, or API-triggered pipelines with variables are rejected with HTTP 400.Need a new file mutation? Add one function to
EDIT_KINDSin src/release_agent/core/edits.py.Have an LLM endpoint? Implement
ports.LogExplainerand wire it in src/release_agent/bootstrap.py.
Development
uv run pytest # unit + engine tests against an in-memory fake GitLab
uv run ruff check .License
MIT
Available Tools
12 toolsget_manifestC
The release manifest YAML — the declarative source of truth for the repo topology.
Inputs: no named parameters. Returns: result
list_releasesA
Every release known to the state store, newest first, with a progress summary.
Use this to discover coordinates when the user doesn't name one ("what's in flight?", "what was our last release?").
Inputs: no named parameters. Returns: result
release_approveB
Clear a manual gate (e.g. 'qa-signoff') and advance the nodes it was blocking.
Inputs: gate (required), coordinate (required). Returns: object
release_bumpB
After a fix landed on a node's release branch: cut the next iterated tag and build it.
Inputs: node (required), coordinate (required). Returns: object
release_explainA
Explain why a node's pipeline failed (advisory; reads the failed job's log).
Inputs: node (required), coordinate (required). Returns: result
release_planA
Dry-run of release_start: exactly what would be created — branches, MRs, predicted tags (computed from the tags that exist right now), file edits with resolved values, and pipeline variables. Strictly read-only; nothing is touched.
ALWAYS call this before release_start with the same arguments and show the user the plan; only call release_start after they confirm.
Inputs: env (required), inputs (required), coordinate (required), rfc. Returns: object
release_reconcileA
One idempotent tick: read actual GitLab state and advance whatever is ready.
Safe to call any time; does nothing if pipelines are still running.
Inputs: coordinate (required). Returns: object
release_reportA
The release report (markdown): inputs, per-node tags, pipelines, produced versions, and values captured from job logs (e.g. Sonar report URLs).
With publish=true the report is also committed to the state repo (reports/.md).
Inputs: coordinate (required), publish. Returns: result
release_startA
Start a release: build run state from the manifest and fire every ready node.
inputs are the manifest-declared release inputs (e.g. library versions).
Returns immediately; pipelines run in GitLab on their own time.
Call release_plan first and show the user what will happen.
Inputs: env (required), inputs (required), coordinate (required), rfc. Returns: object
release_statusB
Read-only view of the release DAG: node states, tags, pipeline URLs, gates.
Inputs: coordinate (required). Returns: object
release_tagsA
A node's repository tags, newest first, read LIVE from GitLab — no run state needed.
Use this to answer "what was the last released version of ?" from the repo itself rather than from a release's state or the manifest.
Inputs: node (required), limit. Returns: object
validate_manifestA
Validate a release manifest YAML without touching anything.
Returns 'valid' with a topology summary, or the exact validation error. Use before committing manifest changes to the state repo.
Inputs: manifest_yaml (required). Returns: result
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 12 tools
Each tool has a clearly distinct purpose: manifest retrieval, release listing, approval, bumping, explanation, planning, reconciliation, reporting, starting, status, tags, and validation. No two tools overlap in intent.
Most tools follow the 'release_verb' pattern, but three (get_manifest, list_releases, validate_manifest) lack the prefix, creating inconsistency. The naming is still descriptive but not uniform.
12 tools is well-scoped for a release management server. Each tool serves a necessary step in the release lifecycle without unnecessary duplication.
The tool set covers the full release workflow: planning, starting, approving, bumping, reconciling, reporting, status checking, and tag fetching. Validation and explanation tools add robustness. No obvious gaps for common release operations.
Related MCP Connectors
Release intelligence for AI coding tools: releases, typed changes, breaking changes, cadence.
Generate changelogs, release emails, help-center articles, banners, and social posts from commits.
Plan Salesforce deploys, open pull requests and trigger pipelines from your AI client.
Autonomous dev team steered from chat: plain-English requests in, tested merged PRs out.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables AI agents to interact with GitLab repositories, manage merge requests, review code diffs, post comments, and handle issues directly through natural language.125 npmMIT
- FlicenseNot gradedqualityNot gradedmaintenanceConnects AI assistants to GitLab projects, enabling natural language queries to view merge requests, code reviews, discussions, pipeline test results, and respond to comments directly from chat.-
- FlicenseNot gradedqualityNot gradedmaintenanceConnects AI assistants to GitLab, enabling natural language queries for merge requests, reviews, discussions, pipeline tests, and job logs with the ability to respond to comments and resolve discussions.-
- FlicenseNot gradedqualityCmaintenanceEnables triggering Jenkins release and patch pipelines through natural language, with support for MCP and web interfaces.-