AppRelay ships an MCP server, so Claude Code and Claude Desktop can operate your build pipeline directly — read the state of every project, work out what a release would actually do, run the build, and ship it when you say so.
Without it, working with an agent on a release means being the copy-and-paste layer: you run the build, you paste the failure, it suggests a fix, you run it again.
With it, the agent reads the failing run itself — the exact step, the exact exit code — checks whether the tool it blames is even installed, and proposes a fix it can verify by building again. The parts that matter stay yours: nothing reaches a store, a registry or a host without you saying so, in that turn, about that release.
This is the opposite of the Claude features inside AppRelay. Those are buttons in the app that ask Claude for help. This puts AppRelay inside Claude. Use either, both, or neither.
Exactly two of the 25 reach the outside world: release, and run_trigger for a trigger whose action is a ship. Both refuse unless called with an explicit confirmation, and release must clear a second --confirm at the CLI behind the bridge — so the deliberate step to publish can't be skipped.
No tool returns a secret value. list_secrets answers which fields are filled in, so an agent can tell you a credential is incomplete without ever seeing it. Values are substituted at run time, delivered through the environment rather than the command line, and masked out of everything printed.
A channel that requires production approval can’t be shipped through the bridge at all. That one only happens in the app, where the approver is recorded against the run.
A build an agent starts takes the same per-folder lock your own runs do, so it can never race a build you kicked off yourself, and it lands in the same run history with the same attribution. Nothing an agent does happens behind your back.
Every tool is annotated, so your client can tell you which ones can change something before it calls them.
| Tool | What it does | Effect |
|---|---|---|
list_projects |
Every project, with its toolchains, tags and suite | Read-only |
project_status |
One project in full — lanes, recipes, distributions, test suites | Read-only |
list_groups |
Suites and tags, so “the whole X suite” resolves to real projects | Read-only |
doctor |
Install health, and the two faults that break a headless build | Read-only |
license_status |
Your license and plan — what’s active on this machine | Read-only |
| Tool | What it does | Effect |
|---|---|---|
versions |
The version and build number of every lane | Read-only |
version_state |
One lane’s version, its file, and whether that format can be written | Read-only |
git_status |
Branch, upstream, ahead/behind and dirty state per repo | Read-only |
requirements |
Which required tools are installed, with versions and install hints | Read-only |
list_recipes |
The actual shell steps behind build, run and ship | Read-only |
list_environments |
Deploy environments — variables in full, secrets by name only | Read-only |
list_secrets |
Which credential fields are filled in. Never a value | Read-only |
list_targets |
The simulators, devices and emulators you can run on right now | Read-only |
| Tool | What it does | Effect |
|---|---|---|
channels |
Where a lane ships, what’s live there, and what already went out | Read-only |
deployments |
Deploy history — version, when, by whom, health, artifact | Read-only |
rollback_plan |
Whether a channel can be rolled back, and what that would take | Read-only |
runs |
Recent runs across every project, newest first | Read-only |
run_log |
One run in full — every step, its exit code, and where it stopped | Read-only |
list_triggers |
The triggers you have configured | Read-only |
| Tool | What it does | Effect |
|---|---|---|
bump_version |
Write a new version to the lane’s version file | Runs here |
build |
Build a lane | Runs here |
run |
Build a lane and launch it, optionally on a chosen device | Runs here |
run_tests |
Run a project’s test suites | Runs here |
| Tool | What it does | Effect |
|---|---|---|
run_trigger |
Fire a configured trigger now | Needs confirmation |
release |
Ship a lane to a distribution channel | Needs confirmation |
Anywhere a project is named, an agent can use its slug, its id, its exact name, or its position in the list. Lanes work the same way, by label or position. A release can also name a deployment environment, so it ships against Staging or Production with that environment’s variables and secrets.
The bridge ships prompts as well as tools. Your client surfaces them as slash commands, with your own project and lane names auto-completing as you type.
Walks a project from its current state to a shipped release — checks first, then bump, build, test, and ship on your say-so.
A read-only pre-release audit: everything that would block or spoil a release, with nothing run and nothing changed.
Reads the run log, finds the step that actually failed, and works out why.
What is currently deployed across your projects, and anything stale or unhealthy.
Install AppRelay and the bridge is already on disk. There is nothing to download, nothing to configure, and no path to keep in step with your install.
claude mcp add apprelay -- node \
"/Applications/AppRelay.app/Contents/Resources/apprelay-mcp.mjs"
claude mcp add apprelay -- node ^
"C:\Program Files\AppRelay\apprelay-mcp.mjs"
For Claude Desktop, add the same path to mcpServers in claude_desktop_config.json and restart the app — the full snippet is in the documentation. Installed AppRelay somewhere non-standard? Set APPRELAY_BIN to the binary and the bridge uses that ahead of everything else. If it can’t find AppRelay at all it says so, listing every path it tried, rather than failing mysteriously.
The bridge is a thin wrapper over a headless command line built into the app itself. It reads the same workspace, prints JSON, and is just as happy in a shell script or a CI job as behind an agent.
$ apprelay channels hydrants-ios
{
"project": "hydrants-ios",
"lane": "iOS",
"version": "2.4.1",
"channels": [
{
"channel": "appStoreConnect",
"liveVersion": "2.4.1",
"currentVersionShipped": true,
"reversible": false,
"requiresApproval": false
}
]
}
Every read command prints JSON; every action command streams its output and exits non-zero on failure. The full command list is in the docs.
release and run_trigger — refuse to run unless they are called with an explicit confirmation, and the app demands that confirmation a second time behind the bridge. A channel that requires production approval cannot be shipped this way at all; that one only happens in the app, where the approver is recorded.list_secrets reports only which credential fields have been filled in, so an agent can tell you the App Store Connect key is missing without ever seeing one. Secrets are substituted into commands at run time and masked out of everything printed.