Skip to main content
Glama
Release Health MCP Server

Release Health MCP Server

by drezzzik

Release Health MCP Server

CI License: MIT

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

list_releases(app?, track="production")

Releases on a track: version codes, status (inProgress, halted, completed), user_fraction

get_release_health(app?, version_code?)

User-perceived crash and ANR rates, compared with the previous version that has data

top_crashes(app?, version_code?, limit=5)

Largest crash/ANR issues by affected users, each with a sample stack trace

new_issues(app?, version_code?)

Issues first seen in this version (likely regressions)

recommend_rollout(app?, version_code?)

expand / hold / halt, the reasons, and a suggested next rollout fraction

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 pytest

Connect 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-mcp

Then 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

  1. 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.

  2. 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.

  3. 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.json
  4. Sanity check: compare get_release_health with 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 the versionCode dimension over the last health_window_days days of available data. Each rate is a user-weighted average. user_days is the summed daily distinct users and serves as the sample size.

  • Previous version is the highest lower versionCode that has data in the same window.

  • New issues are issues whose firstAppVersion (within issues_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 > max_user_perceived_crash_rate (default 1.09%) or ANR rate > max_user_perceived_anr_rate (default 0.47%), which are Google Play's bad-behavior thresholds

hold

Sample < min_user_days, no previous version to compare with, rate up more than max_relative_increase vs the previous version, or a new issue affecting more than max_new_issue_users users

expand

Otherwise. Suggests the next value in rollout_steps, capped at +max_step_pp (20 pp)

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        # strict
  • tests/recorded/ holds Play API responses that PlayBackend is tested against with HttpMockSequence, so no network access is needed.

  • scripts/record_responses.py --package <pkg> --key <json> --out tests/recorded/<name> --scrub captures 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.py

Roadmap

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 tools
get_release_healthB
Read-only

Crash and ANR rates for a version, compared with the previous version that has data.

NameRequiredDescriptionDefault
appNoApp alias from config or Play package name. Optional if only one app.
version_codeNoversionCode. Defaults to the release currently rolling out on production.

Output Schema

NameRequiredDescription
appYes
currentYes
previousNo
anr_rate_changeNoRelative change of user-perceived ANR rate vs previous.
crash_rate_changeNoRelative change of user-perceived crash rate vs previous.

TDQS

B3.4/5.0
Behavior3/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose4/5

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.

Usage Guidelines2/5

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_releasesB
Read-only

Current releases on a Play track with status and staged-rollout fraction.

NameRequiredDescriptionDefault
appNoApp alias from config or Play package name. Optional if only one app.
trackNoTrack name (production, beta, internal, …) or 'all'.production

Output Schema

NameRequiredDescription
resultYes

TDQS

B3.2/5.0
Behavior3/5

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.

Conciseness4/5

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.

Completeness3/5

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.

Parameters3/5

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.

Purpose4/5

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.

Usage Guidelines2/5

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_issuesA
Read-only

Crash/ANR issues first seen in this version (likely regressions).

NameRequiredDescriptionDefault
appNoApp alias from config or Play package name. Optional if only one app.
version_codeNoversionCode. Defaults to the release currently rolling out on production.

Output Schema

NameRequiredDescription
resultYes

TDQS

A3.5/5.0
Behavior3/5

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.

Conciseness4/5

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.

Completeness3/5

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.

Parameters4/5

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.

Purpose4/5

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.

Usage Guidelines3/5

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_rolloutA
Read-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.

NameRequiredDescriptionDefault
appNoApp alias from config or Play package name. Optional if only one app.
version_codeNoversionCode. Defaults to the release currently rolling out on production.

Output Schema

NameRequiredDescription
appYes
healthYes
reasonsYes
decisionYes
new_issuesNo
version_codeYes
current_fractionNo
suggested_fractionNo

TDQS

A3.8/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose4/5

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.

Usage Guidelines3/5

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_crashesB
Read-only

Largest crash/ANR issues in a version by affected users, with a sample stack trace.

NameRequiredDescriptionDefault
appNoApp alias from config or Play package name. Optional if only one app.
limitNo
version_codeNoversionCode. Defaults to the release currently rolling out on production.
include_stack_tracesNo

Output Schema

NameRequiredDescription
resultYes

TDQS

B3.2/5.0
Behavior3/5

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.

Conciseness4/5

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.

Completeness3/5

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.

Parameters3/5

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.

Purpose4/5

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.

Usage Guidelines2/5

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.

  1. 5 tool updatesv0.1.0
    • First observedget_release_health
    • First observedlist_releases
    • First observednew_issues
    • First observedrecommend_rollout
    • First observedtop_crashes

TDQS

A3.5/5.0

Scored across 5 tools

Disambiguation4/5

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.

Naming Consistency3/5

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.

Tool Count5/5

Five tools is well-scoped for a release-health advisory server. Each tool covers a meaningful part of the workflow without excessive surface area.

Completeness4/5

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

ActivityMaintained
ResponsivenessOutdated data

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    B
    maintenance
    Enables 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.
    44
    46 npm
    2
    MIT
  • A
    license
    B
    quality
    B
    maintenance
    Enables 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.
    170
    70 PyPI
    2
    Apache 2.0
  • F
    license
    B
    quality
    C
    maintenance
    Enables AI agents to manage Google Play apps with scope-based permissions, including publishing internal releases, updating listings, replying to reviews, and promoting to production.
    11
    8 npm
    -