Content
# codemagic-mcp
[](https://github.com/lexandro/codemagic-mcp/actions/workflows/ci.yml)
[](https://pkg.go.dev/github.com/lexandro/codemagic-mcp)
[](https://opensource.org/licenses/MIT)
[](https://modelcontextprotocol.io)
An MCP (Model Context Protocol) server that lets an AI agent drive
[Codemagic](https://codemagic.io) CI/CD — start builds, poll status, and diagnose failures from
build logs — built around two hard constraints: **token economy** and **secret privacy**.
> **Privacy in one paragraph.** The Codemagic API token is read **only** from the
> `CODEMAGIC_API_TOKEN` environment variable — never a tool parameter, never written to disk,
> never echoed in output or errors. The **values** of your Codemagic environment variables are
> never exposed; group and variable **names** only. **Every string the server returns passes
> through a redaction pass** that strips PEM blocks, long base64 blobs, JWTs, `key=value`
> secrets, credentials in URLs, and signed download URLs. Builds **cannot be triggered** unless
> you explicitly set `CODEMAGIC_MCP_ALLOW_BUILDS=true`. No telemetry, no cache, no filesystem
> writes. See [SECURITY.md](SECURITY.md) for the threat model and the honest limits.
## Why this exists
Mobile release engineering is a slow feedback loop: trigger a build, wait, read a long log, fix,
repeat. An AI agent can drive that loop — but only if it can start builds, poll status, and read
failures without burning its context window on megabytes of log, and without piping your signing
keys into a chat transcript.
A real Codemagic iOS build log runs to megabytes. This server turns one into ~730 tokens with the
actionable error on the first line:
```
step: Build ipa (failed, 8m29s)
selected: failed step
mode: error-focused
lines: 41/625
matches: 6
firstError: Error (Xcode): No profiles for 'com.example.myapp' were found: Xcode couldn't find
any iOS App Store provisioning profiles matching 'com.example.myapp'. Automatic signing is
disabled and unable to generate a profile. To enable automatic signing, pass
-allowProvisioningUpdates to xcodebuild.
--
…
```
Measured numbers for every tool: [docs/TOKEN-BUDGET.md](docs/TOKEN-BUDGET.md).
## Install
**Letting an AI install it for you:** point your agent at
[docs/AI-INSTALL.md](docs/AI-INSTALL.md) — it is a deterministic, step-by-step recipe written for
an agent to follow, with the expected output of each step.
**By hand**, with a Go toolchain:
```bash
go install github.com/lexandro/codemagic-mcp@latest
```
If you also develop this server, install it somewhere other than `go install`'s output
directory — see [Installing alongside development](#installing-alongside-development).
Or download a binary for your platform from the
[releases page](https://github.com/lexandro/codemagic-mcp/releases). It is a single static
executable with no runtime dependencies. Verify it against `checksums.txt` from the same
release — you are about to give this binary an API token.
## Configure
1. Get an API token: Codemagic → **Account settings → API token**.
2. Export it in the environment that launches your MCP client:
```bash
export CODEMAGIC_API_TOKEN="your-token-here" # macOS / Linux
setx CODEMAGIC_API_TOKEN "your-token-here" # Windows, then reopen the terminal
```
3. Register the server:
```bash
codemagic-mcp register project # writes ./.mcp.json
codemagic-mcp register user # writes ~/.claude.json
```
To also enable build triggering, set the gate before registering:
```bash
CODEMAGIC_MCP_ALLOW_BUILDS=true codemagic-mcp register project
```
4. Restart your MCP client and call `status` to confirm.
### Manual configuration
`register` writes an entry like this. Note that the token is a **reference**, not a value — your
MCP client expands it at launch, so this file is safe to commit:
```json
{
"mcpServers": {
"codemagic": {
"command": "/usr/local/bin/codemagic-mcp",
"args": [],
"env": {
"CODEMAGIC_API_TOKEN": "${CODEMAGIC_API_TOKEN}"
}
}
}
}
```
Add `"CODEMAGIC_MCP_ALLOW_BUILDS": "true"` to the `env` block to enable `start_build` and
`cancel_build`.
### Environment variables
| Variable | Required | Effect |
|---|---|---|
| `CODEMAGIC_API_TOKEN` | yes | The API token. The server refuses to start without it. |
| `CODEMAGIC_MCP_ALLOW_BUILDS` | no | Set to `true` to enable `start_build` and `cancel_build`. Anything else leaves the server read-only. |
### Flags
| Flag | Default | Effect |
|---|---|---|
| `--timeout` | `30s` | Timeout for a single Codemagic API request. |
There is deliberately **no flag to change the API host.** One pointing at another host would send
your token there.
## Tools
| Tool | Purpose | Typical cost |
|---|---|---|
| `status` | Token validity, reachability of both API hosts, whether builds are enabled | ~40 tokens |
| `list_apps` | Applications the token can see | ~17 tokens/app |
| `get_app` | Workflows, branches, environment variable group **names** | ~55 tokens |
| `list_builds` | Recent builds, filterable by app, workflow, branch, tag, status | ~24 tokens/build |
| `get_build` | One build's status — the polling tool | ~52 tokens |
| `get_build_log` | Diagnose a failure; error-focused by default, never the whole log | ~730–3,000 tokens |
| `list_artifacts` | What a build produced. Content is never fetched, and signed download URLs are never returned | ~5 tokens/artifact |
| `start_build` | Trigger a build. Requires `CODEMAGIC_MCP_ALLOW_BUILDS=true` | ~15 tokens |
| `cancel_build` | Stop a build. Same gate | ~10 tokens |
Every list tool takes `limit` (default 10, max 100) and reports clipping as `truncated: 10/42`.
Every tool takes `verbosity` (`summary` by default, `detail` on request).
### What the output looks like
```
$ status
status: ok
account: 60a0b1c2d3e4f56789abcdef
codemagic.io: ok
api.codemagic.io: ok
CODEMAGIC_API_TOKEN is set (36 characters)
redaction: always on
builds: disabled (set CODEMAGIC_MCP_ALLOW_BUILDS=true and restart to enable start_build and cancel_build)
$ get_app appId=60a0b1c2d3e4f56789abcdef
id: 60a0b1c2d3e4f56789abcdef
name: myapp-ios
repository: https://github.com/example/myapp
provider: github
defaultBranch: main
branches: main, develop
workflows: ios-workflow=iOS Release
variableGroups: appstore, firebase
$ get_build buildId=6890abcdef1234567890abcd
id: 6890abcdef1234567890abcd
status: failed
workflow: ios-workflow=iOS Release
branch: main
build: #42
started: 2026-07-26T10:12:03Z
duration: 8m41s
failedStep: Build ipa
commit: a1b2c3d fix: bump build number
$ list_artifacts buildId=6890abcdef1234567890abcd
Runner.ipa 43MB ipa
```
Fields with nothing to say produce no line at all. That omission is the single largest token
saving in the server.
### Errors
Errors are classified so an agent knows whether to retry, wait, or stop:
```
Error [fatal]: invalid or expired API token
Action: Generate a new token in Codemagic > Account settings > API token, set CODEMAGIC_API_TOKEN to it, then restart the MCP server
Details: HTTP 401 from api.codemagic.io
```
`transient` means retrying helps and the server already retried. `degraded` means back off — rate
limiting, usually with a wait in seconds. `fatal` means a human has to change something. The
server never exits on a connection failure: once Codemagic recovers, the next call just works.
## Known Codemagic quirks
Worth knowing before your first build:
- **A `codemagic.yaml` app reports the wrong workflows, or none at all.** Codemagic does not store
the yaml configuration, so `get_app` returns whatever workflow the web UI has — often a stale
"Default Workflow" that no build has ever used — or nothing. For those apps the `workflowId` you
pass to `start_build` is the **workflow key from your `codemagic.yaml`** (for example
`ios-workflow`), not an id from `get_app`. This is the most common first-run failure. The
reliable way to find the real key is `list_builds`, which shows the workflow each build actually
ran.
- **Two APIs on two hosts.** Codemagic runs a legacy API on `api.codemagic.io` and a current one
on `codemagic.io/api/v3`, and this server needs both — only v1 can read build logs or start a
build, only v3 has typed build detail and variable groups. Egress is restricted to exactly those
two hosts.
- **Some endpoints are undocumented.** `GET /builds`, `GET /builds/:id/step/:stepId` (the only way
to read a log), and the shape of v1 responses are not in the published docs. Responses are
decoded defensively: a missing field becomes an omitted output line, never a crash.
- **Codemagic returns 404 for things your token cannot see**, not 403. The server says "not found,
or not accessible with this token" rather than guessing which it was.
- **Artifact download URLs are pre-signed in the path**, not the query string, so there is nothing
to strip and the link works for anyone who has it. `list_artifacts` therefore returns names,
sizes and types but no URL. Download from the Codemagic UI.
- **Build logs arrive as HTML.** Codemagic wraps coloured lines in `<span>` elements and escapes
the content. The markup is stripped and the entities decoded before anything else happens.
## Dependencies
One runtime dependency, on purpose:
| Dependency | Why |
|---|---|
| `github.com/modelcontextprotocol/go-sdk` | The official MCP protocol implementation. |
| Go standard library | HTTP, JSON, regexp, TLS. No HTTP client library, no logging framework. |
## Development
```bash
go build -o codemagic-mcp . # build
go vet ./... # vet
go test ./... # everything, no live token needed
go test ./test -run Test_TokenBudget -v # regenerate the token budget table
```
### Installing alongside development
**Never register the binary you are rebuilding.** A running MCP server holds an open handle on
its own executable, so on Windows the next `go install` fails with "Access is denied" as soon as
any editor has the server loaded — and the editor that has it loaded is usually the one you are
using to fix it.
Keep the two apart: the dev build stays in the repository, and MCP clients point at an installed
copy you update deliberately.
```bash
scripts/install.bat # Windows -> %LOCALAPPDATA%\Programs\codemagic-mcp\
scripts/install.sh # macOS/Linux -> ~/.local/bin (override with CODEMAGIC_MCP_PREFIX)
```
Both build first, then install by renaming the old binary aside rather than overwriting it, so
updating works **while a client is still running the previous version**. The client keeps using
the renamed file until it restarts, then picks up the new one.
Then register that path:
```bash
"$LOCALAPPDATA/Programs/codemagic-mcp/codemagic-mcp.exe" register project
```
If you only use this server and never modify it, none of this applies — `go install` or a release
binary is fine.
Tests never touch the network: they run against a fake Codemagic and a real MCP session, so the
redaction middleware and the protocol layer are exercised the same way an agent would.
See [CLAUDE.md](CLAUDE.md) for the architecture and coding principles.
## License
MIT — see [LICENSE](LICENSE).
MCP Config
Below is the configuration for this MCP Server. You can copy it directly to Cursor or other MCP clients.
mcp.json
Connection Info
You Might Also Like
No recommendations available