MCP server

Your reviews, from inside your AI assistant.

Connect Claude, ChatGPT, Claude Code, Cursor, VS Code or Codex to your organization. Your assistant triages reviews by app, country and rating, reads the insights and the rating by country, and drafts replies in the reviewer's language for a person to send. With a localization project connected it reaches the localization tools too, always with exactly the permissions you give it: the scopes you approve at sign-in, or the scopes of the token.

Claude Code
claude mcp add --transport http countrymanager https://countrymanager.app/api/loc/mcp

What you get

Your assistant triages and drafts, a person sends.

  • Reviews by app, country and rating

    The assistant lists your apps, filters reviews by country, star rating, state and date, reads one review with its translation, tags, notes and reply history, and pulls the insights and the per-country ratings your dashboard shows.

  • Drafts in the reviewer's language, sent by a person

    draft_reply writes the draft the team sees in the dashboard, in the language the review was written in. A draft is never sent to the store: a person opens the review, edits if needed and sends it.

  • Publishing is off until an admin turns it on

    publish_reply is offered only when an admin has switched on publishing via the API under Settings, Integrations and the connection carries reviews:publish, which only an admin can approve. It then runs the same submit as the dashboard's own button, and the reply reaches the store under your developer name.

  • The localization tools, too (Team and up)

    Connect a localization project alongside the organization and the same assistant adds keys, sees what each language still lacks, writes or drafts every value against your glossary and pulls the files. Values it writes wait unverified for a person to check.

    Localization

In practice

One prompt, two drafts waiting.

The assistant finds the app, filters this week's low ratings from one country, and writes a draft on each review in the reviewer's language. You open the review to a draft, ready to edit or send.

  1. > Show me this week's 1 and 2 star reviews of Widget from Germany and draft a reply to each in the reviewer's language.

  2. list_apps→ Widget (App Store) a1b2c3

  3. list_reviewsapp=a1b2c3 country=DE ratings=[1,2] since=2026-09-23→ 2 reviews

  4. draft_replyr-8f31 de→ draft

  5. draft_replyr-8f4c de→ draft

  6. Two drafts are waiting in the dashboard, both in German: one on the sync that keeps failing, one on the crash after the update. Nothing has been sent; a person sends each from the review.

Tools

27 tools, 6 scopes.

Reviews

reviews:readRead apps, reviews, insights and ratings.

  • list_apps

    Use this first for review work: it lists the apps this connection can see and gives the app id the other review tools take. Returns each app's id, name, platform (App Store or Google Play), store id and icon.

  • list_reviews

    Use this to read store reviews, newest first, filtered by app, country, star rating, state and date window. Each review carries its rating, title, body, language, country, state and its reply if one exists. Returns up to 25 reviews per page (at most 100); to page further, call again with cursor set to the nextCursor of the previous page, and stop when nextCursor is null.

  • get_review

    Use this to read one review in full: the text and its translation, tags, internal notes and the whole reply history (drafts, what was published and when). Takes the review id from list_reviews.

  • list_insights

    Use this to learn what reviewers are talking about: the themes the product's analysis clustered from recent reviews, each with how many reviews it covers and the reviews that are its evidence. Filter by app and by a start date to answer questions like what one country is unhappy about this month.

  • get_ratingsAnalytics

    Use this to see an app's store rating by country: the star histogram per country and the timeline of how the rating moved. Takes the app id from list_apps. Needs the Analytics plan feature.

reviews:replyWrite reply drafts a person sends.

  • draft_replydestructive

    Use this to write or replace the reply draft on one review. The draft is saved inside countrymanager and goes nowhere else; it appears in the team's dashboard, and a person decides later whether to publish it. Write it in the reviewer's language. Calling it again replaces the draft. Returns the reply with its state (draft) and body.

reviews:publishPost replies to the store, once an admin has turned it on.

  • publish_replydestructivereaches users

    Use this only when the user has explicitly asked to send this exact reply to this review: it posts the reply to the App Store or Google Play as the developer's public response, where the reviewer and every other customer read it, and a store response cannot be quietly taken back. Without a body it publishes the review's current draft. Publishing is refused unless an admin has enabled it for the organization. Returns the reply with its state (pending until the store confirms, then published).

Localization

readRead the catalog and export files.

  • list_projects

    Use this first: it lists the localization projects this connection can access and gives the project slug every other tool takes. Returns each project's slug, name, source locale, target locales and editor URL.

  • list_locales

    Use this to learn a project's locale codes before reading or writing translations. Returns every locale with the source locale marked, plus the project's iOS string tables.

  • list_keys

    Use this to see a project's whole key set and its naming conventions. Returns every key with its string table, plural flag, tags, description and length limit, but no translations.

  • get_translations

    Use this to read one key's stored values in every locale, source locale first. Each value carries its state (untranslated, translated or verified) and, for plural keys, its CLDR category.

  • pull_file

    Use this to export one locale as a complete string file (xcstrings, android-xml, json, csv, strings, stringsdict, next-intl), exactly as the CLI writes it to disk. A locale other than the source leaves out the keys it has not translated in android-xml, strings and stringsdict, where Android reads an absent key from the default values folder and iOS looks it up in the app's other localizations and the development language; json, next-intl and csv list them with an empty value. Use list_missing to see what is untranslated. Returns the file's text, which can be large for a big catalog.

  • search

    Use this to find string keys by free text when the exact key name is unknown. Matches key names, descriptions and source-language text, case-insensitively, across every project this connection can see. Returns up to 20 results, each with an id, title (the key name), text (its source text) and url (the key in the web editor); pass an id to fetch for the full record.

  • fetch

    Use this to read one search result in full. Takes the id a search result returned and returns the key's description, string table, length limit, plural flag, tags, source locale and every translation with its state, as text and as metadata.

  • get_coverage

    Use this to answer how much of a project is translated. Returns the total number of translatable keys and, per target locale, how many keys are untranslated, translated (drafted but unreviewed) and verified, with the verified share as a percentage. A plural key counts once and is untranslated until every form the locale needs has text. Call list_missing for the keys behind a number.

  • list_missing

    Use this to see what is left to do in one locale: every key that is not yet verified there, with its description, length limit, plural flag, source text, current value and state. Untranslated keys have no usable text yet; translated ones have a draft awaiting review. Pass state to narrow to one of those. Pages of 50 keys by default (at most 200); pass nextCursor back as cursor until it is null. Write the missing values with set_translations.

  • list_glossary

    Consult this before translating or writing any value: it returns the project's glossary, the binding term base every translation must follow. A term marked doNotTranslate is kept exactly as written in every locale (brand and product names); a term with a translation must be rendered with that wording, and its note explains when. Pass a locale to get only the terms that bind it (project-wide terms plus that locale's own). Prefer glossary wording over your own whenever a term occurs in the source text.

  • check_translations

    Use this before set_translations to validate hand-written values without writing anything. Runs the editor's five checks against the proposed values: placeholders match the source text, the value fits the key's length limit, glossary terms are honoured, the value is consistent with sibling keys sharing the same source text, and the value is not empty. Takes the same values shape as set_translations and returns the issues per locale (check type and message); an empty list means the value would pass.

  • list_activity

    Use this to see who changed which translations recently: the 20 latest events by default, newest first, each with the key, locale, whether the value was translated or verified, when, and the actor (a person's name or an API token's name; values written by a token or an assistant are unverified drafts). To page further back, call again with cursor set to the nextCursor of the previous page, and stop when nextCursor is null.

pushWrite values and upload source files.

  • set_translationsdestructive

    Use this to write one key's value in one or more locales; the key must already exist. A plural key takes an object of the locale's CLDR categories instead of a string. Written values are stored as unverified drafts until a person verifies them in the editor, and writing the source locale demotes verified targets. Returns the cells written.

  • push_filedestructive

    Use this to upload a whole string file and upsert every key in it, creating keys that do not exist yet. Additive: keys missing from the file are left in place. A blank value never replaces stored text and is counted in blankSkipped; clear a value with set_translations. Without a locale the file is taken as the source locale. Only the source locale's file decides whether a key is plural and which variables it has. An entry holding an existing key in another shape is not written: shapeRefused lists up to 200 such keys with a reason, shapeRefusedCounts gives the totals per reason, and fallbacksLeftAlone counts plain entries for plural or variable-bearing keys from a format that cannot carry that shape. Returns counts of keys created and updated.

  • draft_translationsdestructive

    Use this to have the product's own AI draft one key's translations, using the project's glossary, translation memory and the key's length limit. Without locales it drafts every target locale still missing a value; named locales are redrafted unless verified (verified values are never replaced). Drafts are written as unverified, AI-marked values a person must verify in the editor. Returns what was drafted per locale and which locales were skipped and why. Spends model calls, so pass at most 20 locales and do not call it in a loop.

manageCreate, edit and delete keys.

  • create_key

    Use this to add one new key with its metadata: a description for translators, a length limit, the plural flag, its iOS string table and tags. Fails if the name already exists. Returns the new key's id and name; it has no values until translations are set.

  • update_keydestructive

    Use this to change an existing key's metadata. Omitted fields keep their value. tags replaces the whole set and cannot be combined with addTags or removeTags. Returns the key's id and name.

  • delete_keydestructive

    Use this only when the user has explicitly asked to delete this key: it removes the key and every translation of it, permanently. Returns the deleted key's name.

  • add_glossary_term

    Use this to record a term every later translation must respect: either a do-not-translate rule (doNotTranslate true, no translation needed) or a required wording (translation set). Without a locale the term binds every locale of the project; with one it is that locale's preferred wording. Fails with a conflict if the term already exists in that scope. Returns the new term's id. Adding a term changes future translations and the terminology check, never stored values.

  • delete_glossary_termdestructive

    Use this only when the user has explicitly asked to remove a glossary term: later translations stop being bound by it, permanently. Takes the term's id or its source term; a source term that exists in several scopes needs a locale (or the id) to pick one. Returns the deleted term.

Set it up

Connected in a minute.

  1. Step 1: Sign in, or issue a token

    Claude, ChatGPT, Claude Code and Codex sign in: they send you to countrymanager, where you pick one organization, optionally one localization project, and approve the scopes; there is no token to copy. Any member above viewer can connect, and reviews:publish needs an admin. Cursor and VS Code take a token, and so does any client in CI or a headless run: an admin issues an organization-wide one under Settings, Integrations with reviews:read, reviews:reply and, behind the publishing switch, reviews:publish. Export it as CM_LOC_TOKEN; VS Code asks for it instead.

  2. Step 2: Connect your client

    The server speaks MCP over Streamable HTTP at https://countrymanager.app/api/loc/mcp. Claude, ChatGPT, Claude Code and Codex sign in with OAuth; Cursor and VS Code send a token as a bearer header.

    In claude.ai or Claude Desktop, open Customize, Connectors, choose Add custom connector and paste the URL. Claude opens countrymanager to sign in, pick your organization and approve the scopes. In a Team or Enterprise organization an Owner adds the connector under Organization settings, Connectors, and members connect to it from there.

    Remote MCP server URL
    https://countrymanager.app/api/loc/mcp
  3. Step 3: Try a prompt

    With reviews:read and reviews:reply approved, ask: "Show me this week's 1 and 2 star reviews of Widget from Germany and draft a reply to each in the reviewer's language." The assistant finds the app, filters the reviews and writes one draft per review in the reviewer's language; each waits in the dashboard for a person to send. It can also tell you what reviewers are talking about, how a country's rating moved and, with a localization project connected, what a language still lacks.

Example prompts

  • Show me this week's 1 and 2 star reviews of Widget from Germany and draft a reply to each in the reviewer's language.

  • What are Widget's reviewers complaining about this month, and which reviews are the evidence?

  • How has Widget's rating in Brazil moved over the last 30 days, and how does it compare with Japan?

  • Draft a reply to every new one-star review, in the reviewer's language, and list the drafts for me to send.

  • Which keys in my-app still have no French translation?

  • Add keys for the new onboarding screen, 30 characters max, and write German and French.

Good to know

  • An OAuth connection covers one organization, and optionally one localization project. A token issued under Settings, Integrations is organization-wide and carries review scopes only; a localization project's own token carries the localization scopes.
  • An OAuth access token lasts 1 hour; the refresh token behind it is rotated on every use and lasts 30 days. An API token has no expiry until it is revoked.
  • publish_reply disappears from the tool list as soon as an admin switches publishing off, and the route refuses a call regardless.
  • Drafting and publishing are rate limited per token, and publishing per organization as well.
  • list_reviews returns 25 reviews per page and at most 100; the assistant pages with the cursor it is handed.
  • Custom connectors in a Claude Team or Enterprise organization are added by an Owner. Developer mode in a ChatGPT workspace is under the admin's control.

Questions

Can an assistant publish a reply to the store?
Only once an admin allows it. Publishing via the API and MCP is off for every organization until an admin switches it on under Settings, Integrations, and the connection also needs the reviews:publish scope, which only an admin can approve at sign-in or put on a token. Until both hold, publish_reply is not even offered, and a call is refused anyway. When it runs, it goes through the same submit as the dashboard, and the reply is posted to the App Store or Google Play as your public developer response.
What can a connection reach?
One organization: every app it has connected, with the review scopes you approved at sign-in, and optionally one localization project for the localization tools. The access token lasts 1 hour and is renewed with a refresh token that is replaced on every use and expires after 30 days without one. Every refresh re-checks that you are still a member with the role the scopes need.
Can it read another organization's reviews?
No. A connection or a token belongs to one organization; a review of any other is not found, and a draft on it writes nothing. The check is the API's own, not the MCP layer's.
How do I disconnect an assistant?
Remove the connector in the client, or revoke the connection on the organization's Settings, Integrations page, where connected apps are listed next to the API tokens; a connection made for a localization project is listed on that project's page. Revoking deletes the connection's access tokens with it, so access stops at once. The person who connected the app or an admin can revoke it, and leaving the organization or having your role lowered revokes it too. A token is revoked on the same page.
Which plans include it?
Every plan, as long as the organization has an active subscription. The review tools are on every plan; get_ratings needs Analytics, which starts at the Team plan, and the localization tools need the localization workspace, also from Team. An organization without an active subscription is refused, the same as on the CLI.Pricing
Who wrote a draft or a reply?
A draft or a published reply written through a connection records the writer on the reply: the token's name, or the connected app's name marked OAuth. Give each assistant its own token or connection so the record says which one. Translations it writes carry the same name in the localization activity feed.
Does it work with claude.ai or ChatGPT?
Yes. Both connect with OAuth: add the server URL, sign in to countrymanager, pick your organization and approve the scopes. Claude Code and Codex sign in the same way; Cursor and VS Code send an API token as a bearer header. Neither directory lists the server yet, so it is added by URL as a custom connector.
Should I use the MCP server or the CLI?
The CLI suits scripts and CI, where a command prints reviews or writes files to disk. The MCP server suits an assistant working with you: it reads reviews and writes drafts as tool calls instead of parsing command output. Both go through the same API, the same scopes and the same publishing switch.

Have a look inside.

The whole product, running on a sample app.

The MCP server is included in every plan. Connecting a client takes a sign-in or one token.