All articles
8 min read

Letting AI Coding Agents Manage Your Translations with MCP

Giving a coding agent real, branch-scoped tools for translation work through MCP, instead of letting it hand-edit locale files and drift out of sync.

MCPAI translationWorkflow

A coding agent builds a checkout feature, which means it's also adding half a dozen new strings: a button label, two error messages, a confirmation line. If it has no access to the translation system, it does the only thing it can – it opens en.json and writes the keys in directly. The other locale files it either leaves untouched, so three languages are now missing six keys each, or it tries to translate them itself inline, with no review step and no record that it ever happened. Either way, the next person to look at the French build finds out by accident.

This is not really a translation problem. It's a tooling problem: the agent that's perfectly capable of writing the feature has no equivalent capability for the string side of it, so it falls back to editing files directly, which is exactly the behaviour that causes locale files to drift.

MCP – the Model Context Protocol – is the fix, in the specific sense that it gives an agent actual tools instead of a text file to edit by hand. Translatize ships an MCP server, @translatize/mcp, with 28 tools and two ready-made workflow prompts, across groups for project and labels, branches, translation, quality checks, review and over-the-air delivery – so an MCP-capable assistant can create a branch, add keys with context, trigger translation, run the QA checks, and check status, using the same token-scoped access a human integration would use.

Setting it up

The server runs over stdio and ships as @translatize/mcp, with no install required beyond npx. Most MCP-capable assistants read a small JSON block naming a command, its arguments, and an environment map – point it at the server and pass a token:

{
  "mcpServers": {
    "translatize": {
      "command": "npx",
      "args": ["-y", "@translatize/mcp"],
      "env": {
        "TRANSLATIZE_API_TOKEN": "mcni_xxx"
      }
    }
  }
}

The token is the only required environment variable – the server exits immediately without one. Create it under Project Settings → Integrations in the app, and give it the developer role and the create-own branch scope if you want the agent to be able to open and merge its own branches; a fixed-scope token skips the branching workflow entirely and works only on its one bound branch, which is the right choice if all you want is read access or simple key additions on a single branch.

What to hand to the agent, and what to keep for yourself

The honest framing here is roles, not trust. Reading and writing labels needs only the translator role, and triggering a translation job or checking its status works with any valid token – it's creating, merging and deleting a branch specifically that needs the developer role or higher. That's the practical reason a token built for this workflow is usually issued at the developer role: not because every action demands it, but because the branch lifecycle does.

Two things are worth keeping deliberately human regardless of what the token is technically able to do. The first is approval – whether a batch of new or changed strings is actually correct is a judgement call, and the tool built for it, review_changes, is designed around that: it returns a capped, readable diff and a link into the app, and the expected pattern is that the agent stops and asks before going further, rather than deciding on your behalf. Submitting something for review doesn't need any special role – any project member, and by extension any token, can do that – but moving a key to approved or rejected is reserved for developer, admin or owner, which is one more reason not to expect the agent to be the one closing that loop.

The second is the merge. A create-own token can merge the branches it created back into its base – for main the token needs the admin role, and the project's QA merge gate can still refuse the merge – which is what makes fully automated flows possible later on. For a first rollout, keep that step human anyway: let the agent prepare everything – the branch, the keys, the translations, the review packet – and then merge yourself in the app from the link review_changes hands you, or leave it to an admin or owner, exactly as you would for a branch a colleague prepared. Automating the preparation and keeping the commit point human is a sensible default until you've watched a few sessions go by.

The token is the real safety boundary

Role controls what a token is allowed to attempt; branch scope controls what it can physically reach, and that distinction matters more than it sounds like it should.

A fixed-scope token can only read and write the one branch it was issued against. A create-own token can additionally create new branches – always forked from its base branch – and read, write, compare, merge and delete the branches it created itself. It can never touch a branch it didn't create, so a colleague's in-progress branch is out of its reach even inside the same project. A leaked or misused token is bounded by construction: it reaches its base branch and the branches it made, and nothing else. That makes the choice of base branch the one decision worth thinking about when you mint it.

One agent session, start to finish

  1. Check what the token can doAgent
    get_project_info

    Languages, role, branch scope and the branches it may write to.

  2. Open a branch for the featureAgent
    create_branch → feature-checkout-v2

    Forked from the base branch, which never sees the half-finished work.

  3. Add the new keys in one batchAgent
    upsert_labels
  4. Fill the missing languagesAgent
    auto_translate → translation_job_status

    On Professional and Agency; everything lands unreviewed.

  5. Hand over a review packet, then stopAgent
    review_changes

    A readable diff plus a link straight into the app.

  6. Approve, then mergeYou

    In the app, or tell the agent to go ahead with merge_branch.

A session, start to finish

Here's roughly what an agent-driven translation change looks like once the server is wired up.

It starts by calling get_project_info, which returns the project's languages, the token's role and branch scope, and which branches it may write to – worth calling first in any session, since everything after depends on it.

It forks a branch with create_branch, naming it after the feature (branch names are restricted to letters, numbers, hyphens and underscores, and can't be main). This needs the developer role and a create-own token; a fixed-scope token fails here with branch_scope_fixed, which is the intended outcome if that's the scope you issued.

It writes the new source strings with upsert_labels, batching the whole feature's keys in one call. New keys are created, anything matching an existing key is updated, and main never sees a half-finished feature because none of this touched it.

It translates the missing values. On any plan it can do this itself: get_missing_translations returns each key with an empty target, and it writes the result back with the same upsert_labels call. On a Professional or Agency plan, it can instead trigger the platform's own AI translation with auto_translate and poll translation_job_status, which also reports the remaining AI character quota – useful for an agent deciding whether a large batch is worth starting on its own or worth flagging to a human first. Either way, nothing gets translated until something – the agent, a person in the app, or a direct API call – actually asks for it.

It marks the touched keys with set_labels_status, then calls review_changes for a capped diff and a link into the app, and stops to ask: review here in the chat, or on Translatize. That's the point in the session where a person is supposed to actually look.

A well-behaved agent does a bit more checking before any of this. search_labels and list_labels are worth calling before create_branch even runs – a quick substring search for an existing checkout.payment.* key catches the case where a near-identical error message already exists under a slightly different name, which is a far cheaper fix than discovering two keys saying almost the same thing six months later. get_labels is useful mid-session too, to pull the full record – values, status, tags – for a handful of keys the agent is about to touch, rather than assuming nothing has changed since it last looked.

Once you say go, it folds the branch in with merge_branch – checking get_merge_conflicts first if the branch has been open a while and main might have moved – and tidies up with delete_branch. Nothing it did was reachable from outside the branch it made until this step, and this step only ran because you approved it.

Writing key names and tags an agent – and a reviewer – can use

The tools that create and update labels take a key, values, a status and tags, so the two things worth being specific about when you prompt the agent are the key name and the tags.

A dotted, feature-scoped key – checkout.payment.card_declined rather than error3 or msg_12 – tells a reviewer, and the next agent that touches the project, what the string is for without any extra lookup. Tags are the other lever: asking the agent to tag new keys by feature area or surface (checkout, email, onboarding) makes list_labels and search_labels far more useful later, for the agent itself when it comes back to the same feature in a later session as much as for people. Where a key needs a fuller note – a character limit, a line explaining where it renders – have the agent send it as context with the key (or later with set_label_context), where translators and the AI translation will see it next to the string. Screenshots stay in the app and the CI upload.

What to check afterward

Automating the drafting doesn't remove the need to look at the result; it changes what's worth looking at. review_changes is built for exactly this – a before/after view of what the branch actually changed, not a trust exercise. Spend the time there on meaning and tone rather than on mechanics: placeholder integrity and plural validity are worth checking mechanically before anything reaches a human reviewer at all, which is what run_qa is for – the agent runs it, fixes the errors it reports, and runs it again until it is clean.

It's also worth prompting the agent, once, to always stop at that point rather than merging on its own initiative – the tools let a create-own, developer-role token complete the whole cycle unattended once you trust it to, but nothing about this workflow requires that, and the pause is where most of the value of having a human in the loop actually sits.

Where this fits with everything else

None of this replaces the branching model underneath it – an agent's branch is a normal project branch, visible to every other integration and to anyone on the team, merged with the same four strategies as a branch a person created by hand. It also sits comfortably next to a CI pipeline: an agent might prepare and translate a branch during a session, while a CI job running the CLI's status gate still gates the eventual release on completeness regardless of who or what did the translating. And the discipline this all depends on – AI drafts landing as unapproved, a human owning the approval – is the same one covered in more general terms in the AI localization workflow; MCP is just what lets an agent participate in that workflow instead of working around it. If your agent is already hand-editing JSON locale files today, this guide covers the mechanics it's presumably getting wrong without the tools above.

Give the agent a session, a branch, and a reason to stop before it merges, and the string drift that started this article stops happening – not because the agent got more careful, but because it finally has somewhere proper to put the work.

Keep reading