Release Health MCP Server
Reads app release health and rollout data from the Google Play Developer Reporting API and Google Play Developer API, including user-perceived crash/ANR rates, top crash/ANR issues, new issues, track releases, and staged rollout state. Supports assessing whether a release is healthy enough to expand, hold, or halt.
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 Health MCP ServerIs the current production rollout healthy enough to expand?"
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 Health MCP Server
An MCP server that lets any AI agent (Claude Code, Claude Desktop, Gemini CLI, …) answer one question:
Is this release healthy enough to expand the rollout?
It reads crash rate, ANR rate and top crashes per version from the Google Play Developer Reporting API and the staged-rollout state from the Play Developer API. It then recommends expand, hold or halt against your own thresholds.
The current version is read-only: it never changes a rollout. Approval-gated rollout changes are planned for milestone 3 (see docs/ROADMAP.md).
flowchart LR
A[AI agent<br/>Claude Code / Gemini CLI] -- MCP stdio --> S[release-health-mcp]
S -- read-only service account --> R[Play Developer Reporting API<br/>crash & ANR rates, error issues]
S -- read-only service account --> P[Play Developer API<br/>tracks & staged rollouts]
S --> T[(thresholds.yaml)]Tools
Tool | Returns |
| Releases on a track: version codes, status ( |
| User-perceived crash and ANR rates, compared with the previous version that has data |
| Largest crash/ANR issues by affected users, each with a sample stack trace |
| Issues first seen in this version (likely regressions) |
|
|
app is an alias from config.yaml or a package name. If you omit version_code, the server uses the release currently rolling out on production. All tools return structured JSON and are annotated readOnlyHint.
Related MCP server: play-console-mcp
Quick start (demo data, no Google account needed)
# Python 3.12+ and uv required
uv sync
cp config.example.yaml config.yaml
cp thresholds.example.yaml thresholds.yaml
uv run pytestConnect to Claude Code
This repo ships a project-scoped .mcp.json, so starting claude in the repo picks up the server (approve it on first use). To register it globally instead:
claude mcp add release-health -e RELEASE_HEALTH_CONFIG=$PWD/config.yaml -- uv --directory $PWD run release-health-mcpThen ask: "Is the current rollout of regressed healthy enough to expand?"
Connect to Gemini CLI
Add this to ~/.gemini/settings.json:
{
"mcpServers": {
"release-health": {
"command": "uv",
"args": ["--directory", "/path/to/release-health-mcp", "run", "release-health-mcp"],
"env": { "RELEASE_HEALTH_CONFIG": "/path/to/release-health-mcp/config.yaml" }
}
}
}Inspect by hand
uv run mcp dev src/release_health_mcp/server.py opens the MCP Inspector (requires Node.js).
Using real Google Play data
In Google Cloud, enable the Google Play Developer Reporting API and the Google Play Android Developer API, then create a service account and a JSON key.
In Play Console → Users and permissions, invite the service account for the apps you want with exactly two permissions: View app information (read-only) (tracks and rollouts) and View app quality information (read-only) (Android vitals: crash/ANR rates and issues). Nothing under Releases. Don't reuse a CI/fastlane key that has release rights: least privilege matters, because milestone 3 adds a separate account for rollout changes.
In
config.yaml:backend: play apps: ada: com.alturos.ada leo: app.alturos.leo default_app: ada read_key_file: ~/.config/release-health/play-read-only.jsonSanity check: compare
get_release_healthwith Android vitals → Overview in Play Console for the same version and window.
Environment overrides: RELEASE_HEALTH_CONFIG, RELEASE_HEALTH_BACKEND, RELEASE_HEALTH_READ_KEY, RELEASE_HEALTH_THRESHOLDS.
How the numbers are computed
Rates come from
crashRateMetricSet/anrRateMetricSet, using daily rows for theversionCodedimension over the lasthealth_window_daysdays of available data. Each rate is a user-weighted average.user_daysis the summed daily distinct users and serves as the sample size.Previous version is the highest lower
versionCodethat has data in the same window.New issues are issues whose
firstAppVersion(withinissues_window_days) equals the version.
Recommendation rules
The thresholds are in thresholds.yaml (defaults plus per-package overrides):
Outcome | When |
halt | User-perceived crash rate > |
hold | Sample < |
expand | Otherwise. Suggests the next value in |
The decision logic lives in src/release_health_mcp/recommend.py. It's a pure function with table-driven tests.
Development
uv run pytest # unit, recorded-API and in-process MCP tests
uv run ruff check . && uv run ruff format --check .
uv run mypy src tests scripts # stricttests/recorded/holds Play API responses thatPlayBackendis tested against withHttpMockSequence, so no network access is needed.scripts/record_responses.py --package <pkg> --key <json> --out tests/recorded/<name> --scrubcaptures real responses for new tests (read-only calls only).
src/release_health_mcp/
server.py MCP tools (MCPServer, mcp SDK v2)
service.py composes backend + recommendation
recommend.py pure decision logic
backends/ fixture (demo JSON) | play (Google APIs)
config.py, thresholds.py, models.pyRoadmap
See docs/ROADMAP.md: approval-gated propose_rollout_change (human approval, hard limits, audit log, dry-run by default), then the showcase, iOS, remote HTTP and tracing.
License
MIT, see LICENSE.
Available Tools
5 toolsget_release_healthBRead-only
Crash and ANR rates for a version, compared with the previous version that has data.
| Name | Required | Description | Default |
|---|---|---|---|
| app | No | App alias from config or Play package name. Optional if only one app. | |
| version_code | No | versionCode. Defaults to the release currently rolling out on production. |
Output Schema
| Name | Required | Description |
|---|---|---|
| app | Yes | |
| current | Yes | |
| previous | No | |
| anr_rate_change | No | Relative change of user-perceived ANR rate vs previous. |
| crash_rate_change | No | Relative change of user-perceived crash rate vs previous. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare read-only, open-world, and non-destructive behavior. The description adds a meaningful comparison rule—previous version that has data—but does not cover data freshness, empty states, or auth/rate-limit context.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single front-loaded sentence with no wasted wording. Every phrase contributes to the purpose and comparison behavior.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema and safety annotations present, the description covers the core metrics and comparison baseline. It could add time-window or freshness context, but that is not required for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, with both optional parameters and their defaults documented in the schema. The description adds no parameter meaning beyond that, so baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States it returns crash and ANR rates for a version, explicitly comparing to the previous version with data. This distinguishes it from list-oriented siblings such as top_crashes, though no sibling is named.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides no explicit when-to-use, when-not-to-use, or alternative-tool guidance. An agent must infer that this is for release health assessment rather than crash listing or rollout recommendation.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_releasesBRead-only
Current releases on a Play track with status and staged-rollout fraction.
| Name | Required | Description | Default |
|---|---|---|---|
| app | No | App alias from config or Play package name. Optional if only one app. | |
| track | No | Track name (production, beta, internal, …) or 'all'. | production |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, destructiveHint=false, and openWorldHint=true, so the safety profile is covered externally. The description adds that results carry status and a staged-rollout fraction, which is useful signal about content, but says nothing about pagination, ordering, empty-track behavior, or what 'current' means at the boundary of a rollout.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single short clause with zero filler, and the key qualifier ('Current', 'staged-rollout fraction') is front-loaded. It is terse to the point of being a sentence fragment, but nothing is wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, the description need not explain return shape, and the parameters are fully documented in the schema. However, for a read tool whose whole value depends on scope ('current' on a track, 'all' tracks), the definition leaves the agent to infer how the scope behaves and how it differs from get_release_health.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so both parameters (app, track) are already documented in the schema, including the 'all' option and the default of 'production'. The description contributes no additional parameter meaning beyond restating the track dimension, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The fragment names a specific resource (releases) and a specific scope (current releases on a Play track), plus the fields returned (status and staged-rollout fraction). It is clearly distinct from the siblings (recommend_rollout, get_release_health, top_crashes, new_issues), though it is a noun phrase rather than a verb-led statement and never explicitly says it 'lists'.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no guidance on when to use this versus get_release_health or recommend_rollout, nor any mention of prerequisites such as needing a configured app alias. The word 'Current' weakly implies a present-state snapshot rather than history, but that is inference, not instruction.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
new_issuesARead-only
Crash/ANR issues first seen in this version (likely regressions).
| Name | Required | Description | Default |
|---|---|---|---|
| app | No | App alias from config or Play package name. Optional if only one app. | |
| version_code | No | versionCode. Defaults to the release currently rolling out on production. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, destructiveHint=false, and openWorldHint=true, so the safety profile is covered. The description adds the useful filtering semantics (only issues first appearing in the given version) and the interpretive caveat that these are 'likely' regressions, but says nothing about ordering, volume, or limits of the returned set.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single short sentence, front-loaded with the resource and the scoping condition, with no filler. It is efficient but border-line under-specified rather than genuinely polished.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists and the input schema is fully described, so the core contract is covered elsewhere. However, for a regression-triage tool the description omits how results are ordered or bounded and how to interpret empty results, leaving gaps an agent would want filled.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so both parameters (app, version_code) are fully documented with defaults in the schema. The description corroborates the version_code semantics with 'this version', but adds no new meaning beyond the schema; baseline applies, with slight credit for reinforcing the version scoping.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific resource (crash/ANR issues) and a precise scope ('first seen in this version'), which lets an agent infer this is a regression-detection listing. It falls short of a clear verb+resource statement and never explicitly distinguishes itself from the sibling 'top_crashes'.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The parenthetical '(likely regressions)' implies the use case — checking whether a rollout introduced new crashes — but there is no explicit when-to-use guidance, no mention of when to prefer 'top_crashes' or 'get_release_health' instead, and no stated prerequisites.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
recommend_rolloutARead-only
Recommend expand, hold or halt for a staged rollout, with reasons, using thresholds.yaml.
This is advice only; it does not change the rollout.
| Name | Required | Description | Default |
|---|---|---|---|
| app | No | App alias from config or Play package name. Optional if only one app. | |
| version_code | No | versionCode. Defaults to the release currently rolling out on production. |
Output Schema
| Name | Required | Description |
|---|---|---|
| app | Yes | |
| health | Yes | |
| reasons | Yes | |
| decision | Yes | |
| new_issues | No | |
| version_code | Yes | |
| current_fraction | No | |
| suggested_fraction | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false, so the safety profile is known; the description usefully reinforces this with 'This is advice only; it does not change the rollout' and adds that the response carries reasons and that thresholds come from thresholds.yaml. What's missing is anything about data windows, freshness, or what happens when thresholds.yaml is absent or a rollout isn't found.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences: the outcome and data source are front-loaded, and the second sentence delivers the one caveat that matters. Nothing is redundant or padded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a two-optional-parameter, read-only advisory tool with an output schema and full schema coverage, the description covers purpose, advisory nature, and decision source adequately. It could be slightly stronger by noting the evaluation window or the failure mode when no rollout is active.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and both optional parameters (app alias/package name, version_code defaulting to the production-rolling release) are fully documented in the schema. The description adds no additional parameter meaning, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific verb and outcome set ('Recommend expand, hold or halt') plus the resource scope ('staged rollout') and the decision source ('thresholds.yaml'), so an agent can tell this apart from get_release_health or list_releases. It stops short of explicitly contrasting itself with those siblings, which keeps it from a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The usage context is only implied: an agent can infer this is called when deciding whether to advance a rollout. There is no explicit when-to-use, no stated prerequisite (e.g. thresholds.yaml must exist), and no mention of when get_release_health or list_releases would be the better call instead.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
top_crashesBRead-only
Largest crash/ANR issues in a version by affected users, with a sample stack trace.
| Name | Required | Description | Default |
|---|---|---|---|
| app | No | App alias from config or Play package name. Optional if only one app. | |
| limit | No | ||
| version_code | No | versionCode. Defaults to the release currently rolling out on production. | |
| include_stack_traces | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, destructiveHint=false, and openWorldHint=true, so the safety profile is covered and the description's burden is lower. The description adds that results are ranked by affected users and include a sample stack trace, which is useful context. However, it does not state the default time/version scope behavior or that stack traces are controlled by a parameter that can be turned off, so the extra value is modest.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single compact sentence with zero filler, and the ranking criterion and scope are front-loaded. It is efficient, though its terseness pushes explanatory burden onto the schema rather than the prose.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be described. Still, for a tool with four parameters (two undocumented) and overlapping siblings, the definition leaves the agent guessing about default version resolution, how many issues are returned, and how it differs from new_issues.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 50%: app and version_code are documented in the schema with their defaults, while limit and include_stack_traces carry no descriptions. The phrase 'with a sample stack trace' loosely gestures at include_stack_traces but does not explain it as a toggle, and nothing clarifies the limit's ranking semantics or its 1-50 range. Baseline 3 is appropriate given partial schema coverage and marginal compensation.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Names a concrete resource (crash/ANR issues) with an explicit ranking criterion (affected users) and scope (in a version), plus what is returned (a sample stack trace). It is distinguishable from siblings like get_release_health and new_issues, but it never explicitly contrasts itself with them.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no when-to-use guidance, no exclusions, and no mention of the closest alternative (new_issues), which plausibly overlaps with this tool. The only implicit signal is 'in a version', leaving the agent to infer selection from the sibling list.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
5 tool updates
v0.1.0- First observed
get_release_health - First observed
list_releases - First observed
new_issues - First observed
recommend_rollout - First observed
top_crashes
TDQS
Scored across 5 tools
The tools mostly target distinct questions: listing releases, health metrics, top crashes, new regressions, and rollout advice. The only mild overlap is between top_crashes and new_issues, since both surface crash/ANR issues, but their ranking and regression framing help distinguish them.
Three tools follow a clear verb_noun pattern: recommend_rollout, list_releases, and get_release_health. top_crashes and new_issues do not use the same imperative-verb convention, making the set readable but not fully consistent.
Five tools is well-scoped for a release-health advisory server. Each tool covers a meaningful part of the workflow without excessive surface area.
The set covers release listing, health metrics, top issues, new regressions, and rollout recommendation, which is strong coverage for an advisory release-health domain. Minor gaps may exist around deeper release/track detail or historical trends, but core workflows are supported.
Maintenance
Related MCP Connectors
Production runtime data for Android and KMP apps (startup, ANRs, slow screens) for coding agents
Synthetic checks, nightly regression replay and model-drift alerts for AI agents
Analytics, A/B tests, remote configs and player sentiment for games and apps, run by your AI agent.
Production errors and incidents for your agent: stack traces, breadcrumbs, likely causes, triage.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceEnables AI agents to automate Android release workflows via the Google Play Android Publisher API, including deploying builds, managing listings, and replying to reviews.40MIT
- AlicenseAqualityBmaintenanceEnables AI agents to manage Google Play Console reviews and Android app releases, including replying to reviews, promoting releases, managing staged rollouts, and checking crash/ANR vitals.4446 npm2MIT
- AlicenseBqualityBmaintenanceEnables managing releases, monitoring Android vitals, analyzing earnings and search terms, optimizing ASO, and preflighting store assets through natural language, with a confirmation gate before destructive writes.17070 PyPI2Apache 2.0
- FlicenseBqualityCmaintenanceEnables AI agents to manage Google Play apps with scope-based permissions, including publishing internal releases, updating listings, replying to reviews, and promoting to production.118 npm-