I Built an MCP Translation Server That Plugs Into Claude Code, Cursor, and Bob – Here’s How It Works

Translation management is one of those problems that sounds simple and turns out to be genuinely painful at scale. I built a Model Context Protocol (MCP) server that solves this by plugging directly into AI IDEs – Claude Code, Cursor, Bob, or any MCP-compatible environment – and exposing a set of tools that let the AI handle the full translation workflow autonomously. No external translation APIs. No cloud services. No manual copy-pasting between files.
This is a full breakdown of how it works, what I built, and the specific problems it solves that other approaches miss.
What makes this different
Most translation tools are either manual (you write the translations yourself) or cloud-dependent (you call DeepL or Google Translate and hope for quality). This MCP server uses your AI IDE as the translation engine — the same model you already trust for code review and reasoning — applied to your actual project files, with git-awareness and safety validation built in.
What Is MCP and Why Does It Matter Here?
Model Context Protocol (MCP) is Anthropic’s open standard for connecting AI models to external tools and data sources. When you run an MCP server, AI IDEs like Claude Code and Cursor can discover its tools and call them during a conversation — the same way a human developer would use a terminal command or a function.
For translation, this is powerful: instead of exporting strings, pasting them into a translation service, and importing results back, you ask your AI IDE to translate everything, and it uses the MCP tools to read the source files, generate translations, validate them, and write them back — all in one workflow.
The server communicates over stdio transport, which means setup is a single JSON configuration entry. No ports, no authentication, no running services.
Architecture: 7 Components, One Clean Workflow
The server is built in Node.js and structured into a main entry point plus six specialised library modules. I kept each module focused on a single responsibility – easier to test, easier to debug, easier to extend.
The 6 Tools the AI Uses
The server exposes exactly 6 tools to the AI IDE. Each one does one thing clearly. The AI discovers them via list_tools and orchestrates the rest of the workflow.
| Tool | What It Does | Key Parameters |
|---|---|---|
list_tools | Shows all tools and the recommended workflow. Entry point for first-time use. | None |
list_bundles | Discovers all translation bundles in the repo. Returns bundle IDs like repo/src/nls::resources. | rescan, filter |
check_status | Shows translation coverage per locale — how many keys are missing or stale in each language. | bundleId, verbose, changedOnly |
get_diff | Returns the keys the AI needs to translate. Smart mode returns only recently changed keys by default. | bundleId, locale, showAll, sinceCommit |
write_translations | Writes translated keys back to locale files. Validates placeholders, merges safely, preserves formatting. | bundleId, translations |
remove_deleted_keys | Removes stale keys from locale files. Defaults to dry run – always previews before deleting. | bundleId, dryRun, locale |

The Most Important Feature: Smart Mode
This is the feature that makes the server genuinely usable on large projects. Without it, a project with 1,000 missing translations across 8 locales would overwhelm any AI — you’d get token limits, incomplete outputs, and a frustrated developer.
Smart mode uses git history to focus on what changed recently, not everything that’s ever missing. The logic auto-detects three scenarios:
Scenario A
Uncommitted changes — Developer added keys but hasn’t committed yet. Compares the working directory vs HEAD. Only new/modified keys are returned.
Scenario B
Already committed — git status is clean. Automatically compares HEAD vs HEAD~1. Catches the most recent commit’s changes.
Scenario C
Custom range — Pass sinceCommit: "HEAD~5" to compare against any git reference. Useful for catching up after a sprint.
Fallback
Non-git repo or new file — Gracefully treats all keys as recent. Works in any environment, with or without Git.
// Default: Smart mode — only recent keys
get_diff()
// Override: Get everything missing across all locales
get_diff({ showAll: true })
// Custom: Last 5 commits
get_diff({ sinceCommit: "HEAD~5" })
Placeholder Validation — The Silent Bug Killer
This is the feature I’m most proud of. Here’s the problem it solves: translations often silently break because an AI (or human) translator removes or renames a placeholder.
// Source string
"Welcome {name}, you have {count} messages"
// ✅ Valid German translation
"Willkommen {name}, Sie haben {count} Nachrichten"
// ❌ This breaks at runtime — {count} was dropped
"Willkommen {name}, Sie haben Nachrichten"
// Error thrown: Missing placeholders: {count}
The validator automatically detects common placeholder patterns — Mustache ({{name}}), curly braces ({count}), printf (%s, %d), HTML tags, and square brackets. For custom patterns, you don’t need to know regex — you provide examples, and the system generates the pattern for you:
// In your MCP config — just provide examples
{
"args": [
"/path/to/translation-mcp/index.js",
"--placeholders=${placeholder}, @@placeholder@@"
]
}
// System auto-generates:
// ${placeholder} → regex: \$\{[a-zA-Z_][a-zA-Z0-9_]*\}
// @@placeholder@@ → regex: @@[a-zA-Z_][a-zA-Z0-9_]*@@
Validation runs automatically on every write_translations call. If a placeholder is missing or extra, the write is blocked and a clear error is returned to the AI with exactly what’s wrong.
Patch-Based File Updates — Why It Matters
Most file-writing approaches rewrite the entire file. That creates huge git diffs that obscure what actually changed and destroy any custom formatting or comments in the file.
The patch writer modifies only the specific key values that need updating:
// Before — entire file untouched except two keys
define({
"key1": "old value", // Will be updated
"key2": "unchanged", // Left completely alone
"key3": "old value" // Will be updated
});
// After — only key1 and key3 changed in the diff
define({
"key1": "new value", // ← Changed
"key2": "unchanged", // ← Not touched
"key3": "new value" // ← Changed
});
The git diff is minimal, reviewable, and honest about exactly what the AI changed. This matters enormously when you’re running this in a team codebase with code review.
Supported Translation Formats
The scanner handles the four formats I’ve encountered most in real enterprise codebases:
- NLS / Dojo / AMD —
define({ "key": "value" })format used in enterprise JavaScript applications - JSON — Standard
{ "key": "value" }, including nested structures and dot-notation - Java Properties —
key=valueformat with support for prefixed namespacing - JS/TS exports —
export default { ... }andmodule.exports = { ... }
Setting It Up — Three Configurations
The simplest setup requires a single JSON config block in your IDE’s MCP settings. Auto-detection handles the rest — workspace root, file formats, and locale structure.
Minimal (auto-detect everything)
{
"mcpServers": {
"translation": {
"command": "node",
"args": ["/path/to/translation-mcp/index.js"]
}
}
}
With custom placeholder patterns
{
"mcpServers": {
"translation": {
"command": "node",
"args": [
"/path/to/translation-mcp/index.js",
"--placeholders=${placeholder}, @@placeholder@@"
]
}
}
}
Large monorepo with scan path limits
{
"mcpServers": {
"translation": {
"command": "node",
"args": [
"/path/to/translation-mcp/index.js",
"--scan-paths=service1/src/nls,service2/resources",
"--exclude-paths=target,dist,build,node_modules"
]
}
}
}
The Full Workflow in Practice
Once the server is running in your AI IDE, the workflow looks like this:
- The developer adds new source strings to the English NLS file
- Ask the AI: “Translate the new keys I just added.”
- AI calls
get_diff— smart mode returns only the keys added since the last commit - AI generates translations for each locale
- AI calls
write_translations— placeholder validation runs automatically - If validation passes, only the changed lines are patched in each locale file
- The developer reviews a clean, minimal git diff and merges
The entire workflow — from “I added 5 new strings” to “all 8 locales are updated and validated” — takes under 60 seconds.
What makes this worth building
Zero external dependencies – No DeepL, no Google Translate, no cloud API keys to manage
AI-native – The translation quality comes from the same model doing your code review
Smart by default – Large projects never get overwhelmed; smart mode focuses on what just changed
Safe – Placeholder validation blocks broken writes; dry-run protects deletions
Minimal diffs – Patch-based updates keep git history clean and reviewable
Monorepo-ready – Handles complex structures with multiple services and mixed formats
One command setup – stdio transport, no ports, no auth, no running services
