Skip to main content
Glama
ShipLocale

shiplocale-mcp

Official
by ShipLocale
README.md
# shiplocale-mcp

MCP server for [ShipLocale](https://shiplocale.com) — lets Claude (or any MCP client) read and edit your localized App Store / Google Play metadata: app copy, release notes, IAP display names, screenshot texts, target languages, Store Health diagnostics, and — optionally, behind an elevated scope — push approved copy to the live store listing.

## How it works

ShipLocale keeps two layers, and this server mirrors that split:

1. **Local drafts** — metadata edited and AI-translated inside ShipLocale. Safe to let an agent modify freely; nothing reaches a real store.
2. **Store push** — explicit, irreversible writes to App Store Connect / Google Play. Push tools are only registered when your key (and `SHIPLOCALE_SCOPES`) includes the `push` scope, so an agent with a `read translate` key physically cannot ship anything.

## Setup

### 1. Mint an API key

API keys are an Indie/Pro plan feature. In the ShipLocale dashboard: **Settings → API Keys → Create**. Pick a label (e.g. "MCP — Claude") and scopes:

| Scope | Grants |
|---|---|
| `read` | Read apps, metadata, releases, screenshot texts, media library, target languages |
| `translate` | Edit local drafts, assign media to screenshot slots, trigger AI generation/translation |
| `health` | Read Store Health reports/overview and toggle finding suppressions |
| `push` | Write to the live App Store / Google Play listing — add only if you want the agent able to ship |

You'll get a `clientId` (`slk_...`) and a `clientSecret` (`sls_...`, shown once).

**Recommended:** mint a `read translate health` key. Add `push` only when you explicitly want agentic store pushes.

### 2. Configure your MCP client

Requires Node.js 20+. No install step needed — `npx` fetches the package from npm.

Environment variables:

| Variable | Required | Default | Purpose |
|---|---|---|---|
| `SHIPLOCALE_CLIENT_ID` | yes | — | API key client ID (`slk_...`) |
| `SHIPLOCALE_CLIENT_SECRET` | yes | — | API key secret (`sls_...`) |
| `SHIPLOCALE_SCOPES` | no | `read translate health` | Space-separated scopes to request — must be a subset of what the key holds |
| `SHIPLOCALE_API_URL` | no | `https://api.shiplocale.com` | Override for local development |

**Claude Code:**

```sh
claude mcp add shiplocale \
  -e SHIPLOCALE_CLIENT_ID=slk_xxx \
  -e SHIPLOCALE_CLIENT_SECRET=sls_xxx \
  -- npx -y @shiplocale/shiplocale-mcp
```

**Claude Desktop** (`claude_desktop_config.json`):

```json
{
  "mcpServers": {
    "shiplocale": {
      "command": "npx",
      "args": ["-y", "@shiplocale/shiplocale-mcp"],
      "env": {
        "SHIPLOCALE_CLIENT_ID": "slk_xxx",
        "SHIPLOCALE_CLIENT_SECRET": "sls_xxx"
      }
    }
  }
}
```

Auth is OAuth client-credentials against `POST /connect/token`; the server caches the 1-hour access token and re-fetches automatically on expiry or 401.

## Tools

### Read (`read` scope)

| Tool | Description |
|---|---|
| `list_apps` | Apps in the portfolio |
| `list_variants` | A/B listing variants for an app |
| `get_app_metadata` | All draft fields × locales, with status (also IAP rows via `iapProductId`) |
| `list_releases` / `get_release_notes` | Releases and their What's New in every locale |
| `get_target_languages` | Target locales at account / app / IAP level |
| `get_screenshot_texts` | Screenshot headlines/captions + translations per slot |
| `list_media_folders` | Media-library folder tree with per-folder asset counts |
| `list_media` | Uploaded images in the media library — search, sort, page |
| `get_screenshot_slots` | Which media asset each screenshot slot holds, per device/locale |
| `get_character_limits` | Per-field hard character limits |

### Local drafts (`translate` scope — never touches the store)

| Tool | Description |
|---|---|
| `update_app_copy` | Upsert base-language text for a field (incl. IAP display names) |
| `update_localization` | Edit any localization row; `approve: true` marks it Approved |
| `translate_field` | Async AI translation of a field into target locales |
| `improve_copy` | AI rewrite for review — returns text, saves nothing |
| `create_release` / `update_release_notes` | Create a release / set base What's New |
| `generate_release_notes` | AI-draft What's New from commit log / bullets |
| `translate_release_notes` | Async translation of What's New |
| `update_target_languages` | Set target locales (account / app / IAP level) |
| `update_screenshot_text` / `update_screenshot_translation` | Edit slot base text / override one translation |
| `translate_screenshot_texts` | Async translation of all screenshot texts |
| `assign_screenshot_slot` / `clear_screenshot_slot` | Put a media asset into a slot / empty it (base slot or one locale) |

### Store Health (`health` scope)

| Tool | Description |
|---|---|
| `get_health_report` | Errors/warnings for an app, with suppression state per finding |
| `refresh_health` | Force an immediate re-check, bypassing the staleness TTL |
| `get_health_overview` | Portfolio-wide error/warning counts (Pro plan only) |
| `set_health_suppression` / `clear_health_suppression` | Ignore / un-ignore a finding workspace-wide |

### Store push (`push` scope — irreversible, live listing)

| Tool | Description |
|---|---|
| `list_store_versions` / `get_store_version_localizations` | Find an editable store version and read live copy |
| `push_version_localization` | Write metadata to App Store Connect |
| `list_store_iaps` / `get_store_iap_localizations` / `push_iap_localization` | Read/write live IAP listings |
| `push_play_listing` | Write a Google Play listing (title/short/full description) |
| `push_play_release_notes` | Push What's New for one locale to a Play track |
| `push_screenshots` | Push all approved screenshot renders for a variant |

Push tools require a connected store credential (`credentialId` from the dashboard's credential vault, except Play release notes, which resolve it server-side). Localizations generally must be **Approved** before a push picks them up.

## Example prompts

- "List my apps and show me which locales are missing a translated subtitle."
- "Create release 2.4.0 from this commit log, generate the What's New, and translate it to all target languages."
- "Shorten the German promotional text to fit the 170-char limit and approve it."
- (with `push`) "Push the approved 2.4.0 release notes to the production track."

## Development

```sh
npm install
npm run build
npm run dev        # tsc --watch
npm run typecheck
```

Point at a local backend with `SHIPLOCALE_API_URL=https://localhost:7443` (or whatever the Aspire dashboard shows for the API).

TDQS

A3.6/5.0

Scored across 17 tools

Disambiguation4/5

Most tools map to distinct resource-action pairs: list/get/update/translate/improve/generate all have clear targets. The only mild ambiguity is between update_app_copy and update_localization, which both edit copy but at different levels (field-level upsert vs row-level localization edit); descriptions mostly resolve this.

Naming Consistency5/5

All tools use a consistent snake_case verb_noun pattern: list_ for enumerating entities, get_ for retrieving data, update_ for edits, translate_ for translation jobs, plus create_release, generate_release_notes, and improve_copy. There are no mixed casing or naming style deviations.

Tool Count4/5

17 tools is slightly above the typical 3-15 range, but the server covers a broad localization domain: apps, variants, releases, screenshots, target language config, metadata editing, and translation jobs. Each tool appears purposeful with no obvious duplicates, so the count is reasonable for the scope.

Completeness2/5

There are significant gaps: update_localization references get_app_metadata and get_release_notes, but neither tool is exposed, so agents cannot obtain row IDs for localization updates. The server also lacks a way to read generated release notes content beyond drafting state, creating dead ends in the core workflow.

Maintenance

ActivitySlowing
ResponsivenessNo issues