Documentation

MCP guide and reference

Connect a local coding agent or a hosted agent connection, understand its permissions, and work from the exact tool schemas.

On this pageGuided setup

Guided setup

Best for working alongside your code. Your client starts Lingvo in the repository and uses your CLI sign-in.

Prepare your project

Install the Lingvo CLI

Sign in and configure
lingvo login --device
lingvo init

New to Lingvo? Create your hosted project and push your strings first.

Connect your client

Run in your repository
lingvo agent install --client claude

Already have a client config? Preview with --print and merge the Lingvo entry. The installer refuses to replace existing files by default.

Restart your client in this repository so it reads the new configuration.

Check it, then try it

Check the connection
claude mcp list

If lingvo shows Pending approval, start claude in this repository and approve only the Lingvo server from the project's .mcp.json. Run claude mcp list again and confirm lingvo shows Connected. Seeing it listed or getting a successful command result alone does not mean the connection is healthy.

Replace <project slug> with your Lingvo project. Require a successful project_status result with actual counts. This read needs qa:run and access to that project; strings:read alone is insufficient. Client approval and Lingvo permissions are separate checks.

Your first prompt
Use Lingvo project_status for <project slug> and summarize its translation readiness. Do not change files or spend credits. If the tool is refused, report the refusal and stop.

Connection troubleshooting and protocol details

Choose local or hosted MCP

The local stdio server runs in your repository and can read/write files through the CLI. It uses your local Lingvo credentials. The hosted HTTP server operates on stored project data through an agent connection; it cannot read your laptop’s files. Their tools share names and schemas where the capability is available on both.

Code example
Local process: lingvo mcp
Hosted endpoint: https://api.lingvo.dev/api/v1/mcp

Basic agent context and BYOK remain available without a separate agent fee. Platform machine translation can consume credits. Transport availability, role, scopes, autonomy and budgets still govern what a connection can do.

Install the CLI and create your project first

Tool schemas and transport availability

Local setup

For local tools that accept project, an explicit project slug takes precedence over the CLI’s global --project option and the repository configuration. Use a slug such as my-app, with lowercase letters, numbers and single hyphens, up to 64 characters. Correct an invalid project argument before retrying. Each tool’s schema shows whether it accepts project.

Install Lingvo, authenticate and configure the repository using the CLI guide. For Claude Code, run the following from that repository. This mcp add command uses Claude’s local scope, private to this project. The Lingvo installer instead writes a shared project .mcp.json file. The client manages the process; do not start another listener or expose a port.

Code example
lingvo login --device
claude mcp add lingvo -- lingvo mcp

For clients accepting an mcpServers JSON config, configure command and args as shown. Cursor uses .cursor/mcp.json. Ensure the process starts in the repository containing lingvo.yaml; desktop clients may require a launcher that changes directory first. Use an absolute executable path if the client does not inherit your shell PATH.

Code example
{
  "mcpServers": {
    "lingvo": {
      "command": "/absolute/path/to/lingvo",
      "args": ["mcp", "--read-only"]
    }
  }
}

Remove --read-only when you intend to make proposals or other permitted changes. This flag filters the tools served by Lingvo; it does not sandbox an agent that can independently run shell commands. Use a read-only API token as well when the underlying credential should not be able to write.

Startup and tools/list work without a config or credential. A tool needing a project will explain needs_config or the authentication problem. A running stdio process waiting for input is expected: stdout belongs exclusively to newline-delimited JSON-RPC, not an interactive prompt.

Code example
lingvo auth status
lingvo whoami
lingvo mcp --read-only

For a project .mcp.json, claude mcp list may show Pending approval. Start claude in the repository and review and approve Lingvo, then run claude mcp list again. Require Connected. A listed entry or exit code 0 alone does not confirm a connection. Connected confirms startup; a successful project read still needs valid Lingvo credentials and access.

Hosted setup and credentials

In Settings → Agents, create an agent connection, select its projects, choose an autonomy level and scopes, and set spending limits. The returned lgm_ token is a connection credential, distinct from an lgo_ CLI/API token. Store it in your client’s secret facility.

Code example
claude mcp add --transport http lingvo https://api.lingvo.dev/api/v1/mcp \
  --header "Authorization: Bearer $LINGVO_AGENT_TOKEN"

Set LINGVO_AGENT_TOKEN through your local secret-handling workflow before running that command. The shell expands it into the client configuration; treat that configuration as sensitive. Do not commit a populated authorization header. For another HTTP-capable client, set the same endpoint and Bearer header in that client’s documented configuration format.

Code example
lingvo agent install --client claude --transport remote
# Or for Cursor:
lingvo agent install --client cursor --transport remote

The installer writes repository JSON with an environment reference, without copying your token. Set LINGVO_AGENT_TOKEN in the environment visible to the client before starting it. Use --print to inspect the files first. Existing files are refused unless you explicitly pass --force, which replaces the entire file; merge by hand if it contains other servers.

Hosted setup currently uses a manually created token. OAuth discovery, dynamic registration and browser consent are not part of this release’s supported connection flow. A client that only supports OAuth cannot be assumed compatible with this manual-token endpoint.

To revoke a hosted connection, pause it or regenerate its token in Settings → Agents. Update client secrets after rotation. Local device/API tokens are managed separately in Settings → API tokens. Removing a config entry from a client does not revoke a credential at the server.

Permissions, proposals and spend

A hosted call is checked against the connection’s current state, project allowlist, token scopes, owner’s current membership, autonomy, and spend budget. Removing or demoting the owner narrows access. A project argument defaults locally to lingvo.yaml and remotely only when the connection has exactly one project.

Read tools do not mutate or spend. Proposal tools create suggestions for review. Structural tools change keys/files or metadata; spend tools call machine translation. Not every tool exists on every transport. Read the safety, minimum role and scopes in the reference below.

There is no agent tool for approving translations, creating/deleting projects, managing members, billing, provider keys or issuing credentials. A developer creates the project before connecting the agent. A person reviews proposals and approves translations through the web app.

Only tools whose schema declares dry_run accept that argument. In particular, a proposal creates a proposal; do not assume every mutation is a preview. Local push and pull offer previews. Hosted machine_translate is a spending operation, while estimate_cost is read-only.

BYOK calls do not consume platform credits but may incur charges at your provider. Do not let an agent repeatedly retry a spending request with an uncertain result. Inspect jobs and credit usage first. Use the connection’s per-call, daily and monthly limits to bound unattended work.

If tools/list offers get_translation_job, use the job_id returned by machine_translate to inspect that run’s state, rejections and credit refund. RUNNING with refundedAt means the run was abandoned. If machine_translate times out before returning a job_id, this tool cannot discover the unknown run. Inspect web Translation runs and credit usage before deciding whether to retry; a timeout alone is not a reason to start another job.

Code example
{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"get_translation_job","arguments":{"project":"my-app","job_id":"<job_id returned by machine_translate>"}}}

For source-aware proposals, discover get_source_change and propose_translation_for_source or propose_plural_for_source with tools/list. Local MCP requires CLI 0.4.0 or later; both transports require a compatible service. Read the current source snapshot, generate against its exact text and forms, and copy sourceSnapshot.view unchanged into source_view. A source_changed refusal requires a fresh read and a new translation or explicit review of the new source. Never retry that refused proposal through a legacy tool.

Code example
get_source_change({project: "my-app", key_id: "<key UUID>", locale: "de"})
// sourceSnapshot = the returned currentSource; unknown source cannot be bound.
propose_translation_for_source({
  project: "my-app", locale: "de", source_view: sourceSnapshot.view,
  value: "<translation generated from that snapshot>"
})

For local MCP, use CLI 0.4.0 or later with a compatible service. Discover get_translation_job with tools/list on the actual connection; the version alone does not guarantee that its permissions offer the tool. If it is absent, inspect the project’s Translation runs page in the web app.

Translate a locale with review

First ask the agent to list projects and inspect project_status. Load the translation brief, glossary, style guide and locale rules before generating text. Keep placeholders, markup, context and length budgets intact. Do not ask the agent to invent missing source strings.

Code example
{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"translation_brief","arguments":{"project":"my-app","locale":"de","state":"EMPTY","limit":100}}}

The brief is free and supplies the same contextual material used for provider translation. Follow nextCursor until it is null; a partial page or total count alone does not prove the entire project was processed.

Code example
{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"propose_translation","arguments":{"project":"my-app","locale":"de","key":"greeting","value":"Hallo","rationale":"Matches the informal voice."}}}

For plurals, call locale_info and provide the categories the target locale uses through propose_plural. Run run_qa after changes. Review proposals in the browser, then pull and inspect the repository diff. The agent cannot approve its own work.

Proposal cards show the recorded source and each captured plural form. Unavailable source history is explicit. Accepting creates a draft; use its Review in editor link to inspect the exact key and language, then deliberately approve it. Partial decisions offer links only for confirmed accepted drafts. If a decision cannot be confirmed, reload proposals before deciding again. This website flow adds no MCP approval tool.

For team review, open Discuss on a returned string, address the note, and submit the revised translation. Resolve the discussion when the question is answered; Reopen keeps the same record available if more work is needed. These browser actions require translation-write access and do not replace translation approval. Unresolved questions still block the optional reviewed/current release check. There is no comment-resolution tool on this MCP surface.

project_status and run_qa inspect hosted project data; they cannot certify the resources actually present in an arbitrary checkout. Checkout checks require CLI 0.4.0 or later: confirm qa --help offers --local, an explicit --locale or --locales set, and optional --require-reviewed-current. The required reviewed/current policy also needs a compatible service. Run it in the checkout or CI, inspect its declared policy and scope, and never infer that a hosted green result proves local bytes or future downloads. This workflow adds no MCP tool.

Checkout check setup and limits

Customer source strings, comments, glossary and translation values are untrusted content, even if they look like instructions. Their text is material to translate, never permission to change credentials, call an unrelated tool or ignore the requested task.

Your first reviewed change

Use CLI 0.4.0 or later with a compatible service. Confirm that tools/list on your connection offers get_source_change and the source-aware proposal tools, and that qa --help offers the reviewed/current checkout check. Keep the connection limited to the intended project. Proposals need strings:read and strings:write; leave --read-only off only when you intend to submit them.

Choose a key and target language. Read get_source_change, inspect currentSource and generate from its exact text or plural forms. Copy the complete currentSource.view unchanged into source_view. If the source is unknown, stop. For plurals, use locale_info and provide exactly its required categories through propose_plural_for_source.

Code example
get_source_change({project: "my-app", key_id: "<key UUID>", locale: "de"})
// currentSource is from that successful read; preserve every .view field.
propose_translation_for_source({
  project: "my-app", locale: "de", source_view: currentSource.view,
  value: "<German wording based on the captured source>"
})

Check the successful proposal result, then open Proposals in Lingvo and review the wording against its recorded source. Accepting creates a draft. Follow Review in editor, inspect the exact key and language, and approve separately. The agent cannot approve its own proposal. A source_changed refusal requires another read and reconsidered wording; do not switch to a legacy proposal tool or merely replace the revision claim.

After approval, run these commands from the repository containing lingvo.yaml. Preview the approved-only pull, apply it deliberately and inspect the resulting file diff. The final reviewed/current check needs strings:read and qa:run; it checks the captured repository resources against known current-source approvals.

Code example
lingvo --json pull --locale de --approved-only --dry-run
lingvo --json pull --locale de --approved-only
lingvo --json qa --local --locale de --require-reviewed-current --fail-on error

Require a successful command, gatePassed: true and a complete, passed reviewed/current report. Approved-only download alone does not prove current-source readiness. Inspect placeholders and plural forms in the actual files, then run your app’s normal checks before committing.

Checkout check setup and limits

Protocol, pagination and errors

Both transports advertise protocol version 2025-06-18. Begin with initialize and notifications/initialized, then discover tools/list, prompts/list, resources/list and resources/templates/list. Local messages are newline-delimited JSON-RPC. Hosted messages are HTTP POST JSON-RPC with the connection’s Bearer credential.

Code example
{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"my-client","version":"1.0"}}}
{"jsonrpc":"2.0","method":"notifications/initialized"}
{"jsonrpc":"2.0","id":2,"method":"tools/list"}

Use the live tools/list result as the authority for that connection. Read-only mode and connection permissions can narrow the list. The complete catalogue below describes implemented tools, not a promise that every credential can call them.

Tool results currently use the MCP content array. A schema may omit outputSchema when structuredContent is not emitted; do not assume an undocumented structured result. Inspect isError and the returned error code as well as HTTP success: a successful JSON-RPC exchange can contain a refused tool call.

For list_keys and translation_brief, limit is 1–500 and defaults to 100; pass nextCursor back as cursor until it is null. Other operations have their own caps and required inputs in the schemas below. Do not reuse cursors across different filters.

Malformed JSON or unknown protocol methods are protocol errors. Missing config, denied scope, unavailable project, exhausted budget and provider failures require different remedies. Fix authorization/configuration rather than retrying in a loop; back off only when availability is the problem.

Complete tool reference

These declarations come from the shared catalogue used by the local and hosted servers. Each entry includes its exact input schema, supported transports, safety class, required scopes, role, preview support and idempotency. Protocol field names and descriptions are kept literal.

list_projects

Code example
{
    "name": "list_projects",
    "description": "List the projects this credential can reach.",
    "transports": [
        "local",
        "remote"
    ],
    "safety": "read",
    "scopes": [
        "strings:read"
    ],
    "minimumRole": "VIEWER",
    "dryRunnable": false,
    "idempotent": true,
    "inputSchema": {
        "type": "object",
        "properties": {},
        "required": []
    }
}

get_project

Code example
{
    "name": "get_project",
    "description": "One project: its source language, its target languages and its files.",
    "transports": [
        "remote"
    ],
    "safety": "read",
    "scopes": [
        "strings:read"
    ],
    "minimumRole": "VIEWER",
    "dryRunnable": false,
    "idempotent": true,
    "inputSchema": {
        "type": "object",
        "properties": {
            "project": {
                "type": "string",
                "description": "Project slug. Optional: the local server falls back to lingvo.yaml, and the remote server to this connection's project when it has exactly one."
            }
        },
        "required": []
    }
}

get_translation_job

Code example
{
    "name": "get_translation_job",
    "description": "Read a translation job's state, progress, rejection samples and credit receipt. Does not start, retry, cancel or spend. A RUNNING job with refundedAt is abandoned, not still working; cancelledAt indicates cancellation. Rejections are bounded samples; rejected is the total count.",
    "transports": [
        "local",
        "remote"
    ],
    "safety": "read",
    "scopes": [
        "strings:read"
    ],
    "minimumRole": "VIEWER",
    "dryRunnable": false,
    "idempotent": true,
    "inputSchema": {
        "type": "object",
        "properties": {
            "project": {
                "type": "string",
                "description": "Project slug. Optional: the local server falls back to lingvo.yaml, and the remote server to this connection's project when it has exactly one."
            },
            "job_id": {
                "type": "string",
                "description": "Canonical job UUID returned by machine_translate or an existing translation run."
            }
        },
        "required": [
            "job_id"
        ]
    }
}

project_status

Code example
{
    "name": "project_status",
    "description": "Release readiness for a project: what is untranslated, awaiting review, carrying QA errors, blocked, or unreviewed machine output — per language, as counts.",
    "transports": [
        "local",
        "remote"
    ],
    "safety": "read",
    "scopes": [
        "qa:run"
    ],
    "minimumRole": "VIEWER",
    "dryRunnable": false,
    "idempotent": true,
    "inputSchema": {
        "type": "object",
        "properties": {
            "project": {
                "type": "string",
                "description": "Project slug. Optional: the local server falls back to lingvo.yaml, and the remote server to this connection's project when it has exactly one."
            }
        },
        "required": []
    }
}

list_keys

Code example
{
    "name": "list_keys",
    "description": "List translation keys and their current values for one locale. Paged: the response says how many match and carries a cursor while more remain.",
    "transports": [
        "local",
        "remote"
    ],
    "safety": "read",
    "scopes": [
        "strings:read"
    ],
    "minimumRole": "VIEWER",
    "dryRunnable": false,
    "idempotent": true,
    "inputSchema": {
        "type": "object",
        "properties": {
            "project": {
                "type": "string",
                "description": "Project slug. Optional: the local server falls back to lingvo.yaml, and the remote server to this connection's project when it has exactly one."
            },
            "locale": {
                "type": "string",
                "description": "Target locale, e.g. de."
            },
            "state": {
                "type": "string",
                "description": "Only keys whose target is in this state.",
                "enum": [
                    "EMPTY",
                    "TRANSLATED",
                    "APPROVED"
                ]
            },
            "review": {
                "type": "string",
                "description": "Only keys whose target sits at this point in review.",
                "enum": [
                    "NONE",
                    "PENDING",
                    "CHANGES_REQUESTED",
                    "APPROVED"
                ]
            },
            "stale": {
                "type": "boolean",
                "description": "Only keys whose source changed after the translation was written.",
                "default": false
            },
            "tag": {
                "type": "string",
                "description": "Only keys carrying this tag."
            },
            "search": {
                "type": "string",
                "description": "Substring of the key name or its text."
            },
            "limit": {
                "type": "integer",
                "description": "Keys per page.",
                "minimum": 1,
                "maximum": 500,
                "default": 100
            },
            "cursor": {
                "type": "string",
                "description": "The nextCursor from a previous page."
            }
        },
        "required": [
            "locale"
        ]
    }
}

translation_brief

Code example
{
    "name": "translation_brief",
    "description": "Everything needed to translate one locale well: the style guide, the glossary terms that occur in this text, the CLDR categories the language uses, and for each string its developer context, length budget, placeholders, where it appears in the code, and what the target holds now. Free, and spends no credits.",
    "transports": [
        "local",
        "remote"
    ],
    "safety": "read",
    "scopes": [
        "strings:read",
        "glossary:read"
    ],
    "minimumRole": "VIEWER",
    "dryRunnable": false,
    "idempotent": true,
    "inputSchema": {
        "type": "object",
        "properties": {
            "project": {
                "type": "string",
                "description": "Project slug. Optional: the local server falls back to lingvo.yaml, and the remote server to this connection's project when it has exactly one."
            },
            "locale": {
                "type": "string",
                "description": "Target locale, e.g. ru."
            },
            "state": {
                "type": "string",
                "description": "Only strings whose target is in this state. EMPTY is what \"finish this language\" means.",
                "enum": [
                    "EMPTY",
                    "TRANSLATED",
                    "APPROVED"
                ]
            },
            "review": {
                "type": "string",
                "description": "Only strings at this point in review. CHANGES_REQUESTED is what \"fix what review sent back\" means.",
                "enum": [
                    "NONE",
                    "PENDING",
                    "CHANGES_REQUESTED",
                    "APPROVED"
                ]
            },
            "stale": {
                "type": "boolean",
                "description": "Only strings whose source changed after the translation was written.",
                "default": false
            },
            "tag": {
                "type": "string",
                "description": "Only strings carrying this tag."
            },
            "file": {
                "type": "string",
                "description": "Only strings in this file, by path."
            },
            "ref_locales": {
                "type": "string",
                "description": "Comma-separated sibling locales to show alongside, at most three. Reading the German is often faster than reading the English."
            },
            "limit": {
                "type": "integer",
                "description": "Strings per page.",
                "minimum": 1,
                "maximum": 500,
                "default": 100
            },
            "cursor": {
                "type": "string",
                "description": "The nextCursor from a previous page."
            }
        },
        "required": [
            "locale"
        ]
    }
}

get_key

Code example
{
    "name": "get_key",
    "description": "One key in every language, with its context and length limit.",
    "transports": [
        "remote"
    ],
    "safety": "read",
    "scopes": [
        "strings:read"
    ],
    "minimumRole": "VIEWER",
    "dryRunnable": false,
    "idempotent": true,
    "inputSchema": {
        "type": "object",
        "properties": {
            "project": {
                "type": "string",
                "description": "Project slug. Optional: the local server falls back to lingvo.yaml, and the remote server to this connection's project when it has exactly one."
            },
            "key": {
                "type": "string",
                "description": "Key name."
            }
        },
        "required": [
            "key"
        ]
    }
}

search_strings

Code example
{
    "name": "search_strings",
    "description": "Find keys whose name or text matches a query, in one locale.",
    "transports": [
        "remote"
    ],
    "safety": "read",
    "scopes": [
        "strings:read"
    ],
    "minimumRole": "VIEWER",
    "dryRunnable": false,
    "idempotent": true,
    "inputSchema": {
        "type": "object",
        "properties": {
            "project": {
                "type": "string",
                "description": "Project slug. Optional: the local server falls back to lingvo.yaml, and the remote server to this connection's project when it has exactly one."
            },
            "locale": {
                "type": "string",
                "description": "Target locale, e.g. de."
            },
            "query": {
                "type": "string",
                "description": "What to look for, in key names and text."
            }
        },
        "required": [
            "locale",
            "query"
        ]
    }
}

locale_info

Code example
{
    "name": "locale_info",
    "description": "The CLDR plural categories a locale actually uses, and its writing direction.",
    "transports": [
        "local",
        "remote"
    ],
    "safety": "read",
    "scopes": [],
    "minimumRole": "VIEWER",
    "dryRunnable": false,
    "idempotent": true,
    "inputSchema": {
        "type": "object",
        "properties": {
            "locale": {
                "type": "string",
                "description": "A BCP-47 tag, e.g. ru."
            }
        },
        "required": [
            "locale"
        ]
    }
}

list_glossary

Code example
{
    "name": "list_glossary",
    "description": "The project's glossary: terms, their required translations, and the do-not-translate list.",
    "transports": [
        "local",
        "remote"
    ],
    "safety": "read",
    "scopes": [
        "glossary:read"
    ],
    "minimumRole": "VIEWER",
    "dryRunnable": false,
    "idempotent": true,
    "inputSchema": {
        "type": "object",
        "properties": {
            "project": {
                "type": "string",
                "description": "Project slug. Optional: the local server falls back to lingvo.yaml, and the remote server to this connection's project when it has exactly one."
            },
            "locale": {
                "type": "string",
                "description": "Target locale. Omit for every language's terms."
            }
        },
        "required": []
    }
}

run_qa

Code example
{
    "name": "run_qa",
    "description": "Run the QA checks. Read-only, free, and the same findings the dashboard shows.",
    "transports": [
        "local",
        "remote"
    ],
    "safety": "read",
    "scopes": [
        "qa:run"
    ],
    "minimumRole": "VIEWER",
    "dryRunnable": false,
    "idempotent": true,
    "inputSchema": {
        "type": "object",
        "properties": {
            "project": {
                "type": "string",
                "description": "Project slug. Optional: the local server falls back to lingvo.yaml, and the remote server to this connection's project when it has exactly one."
            },
            "locale": {
                "type": "string",
                "description": "Limit to one locale."
            }
        },
        "required": []
    }
}

estimate_cost

Code example
{
    "name": "estimate_cost",
    "description": "What a machine-translation batch would cost in credits. Free, and changes nothing.",
    "transports": [
        "remote"
    ],
    "safety": "read",
    "scopes": [
        "strings:read"
    ],
    "minimumRole": "VIEWER",
    "dryRunnable": false,
    "idempotent": true,
    "inputSchema": {
        "type": "object",
        "properties": {
            "project": {
                "type": "string",
                "description": "Project slug. Optional: the local server falls back to lingvo.yaml, and the remote server to this connection's project when it has exactly one."
            },
            "locale": {
                "type": "string",
                "description": "Target locale, e.g. de."
            },
            "provider": {
                "type": "string",
                "description": "Provider id, e.g. deepl."
            }
        },
        "required": [
            "locale",
            "provider"
        ]
    }
}

pull_strings

Code example
{
    "name": "pull_strings",
    "description": "Every string in one locale, as entries. No files: the caller writes them out itself.",
    "transports": [
        "remote"
    ],
    "safety": "read",
    "scopes": [
        "files:write"
    ],
    "minimumRole": "TRANSLATOR",
    "dryRunnable": false,
    "idempotent": true,
    "inputSchema": {
        "type": "object",
        "properties": {
            "project": {
                "type": "string",
                "description": "Project slug. Optional: the local server falls back to lingvo.yaml, and the remote server to this connection's project when it has exactly one."
            },
            "file": {
                "type": "string",
                "description": "File path, as the project lists it."
            },
            "locale": {
                "type": "string",
                "description": "Locale to read."
            }
        },
        "required": [
            "file",
            "locale"
        ]
    }
}

propose_translation

Code example
{
    "name": "propose_translation",
    "description": "Suggest a translation. It waits for a person to accept it.",
    "transports": [
        "local",
        "remote"
    ],
    "safety": "propose",
    "scopes": [
        "strings:write"
    ],
    "minimumRole": "TRANSLATOR",
    "dryRunnable": false,
    "idempotent": true,
    "inputSchema": {
        "type": "object",
        "properties": {
            "project": {
                "type": "string",
                "description": "Project slug. Optional: the local server falls back to lingvo.yaml, and the remote server to this connection's project when it has exactly one."
            },
            "locale": {
                "type": "string",
                "description": "Target locale, e.g. de."
            },
            "key": {
                "type": "string",
                "description": "Key name."
            },
            "value": {
                "type": "string",
                "description": "The proposed text."
            },
            "rationale": {
                "type": "string",
                "description": "Why you chose this wording, in one or two sentences. At most 500 characters; longer is refused rather than cut in half."
            },
            "confidence": {
                "type": "string",
                "description": "How sure you are. A reviewer deciding four thousand strings reads the low ones first, and this is the only signal that can tell them which those are.",
                "enum": [
                    "high",
                    "medium",
                    "low"
                ]
            }
        },
        "required": [
            "locale",
            "key",
            "value"
        ]
    }
}

propose_plural

Code example
{
    "name": "propose_plural",
    "description": "Suggest a plural translation. Every category the language uses must be present; a partial set is refused rather than stored.",
    "transports": [
        "local",
        "remote"
    ],
    "safety": "propose",
    "scopes": [
        "strings:write"
    ],
    "minimumRole": "TRANSLATOR",
    "dryRunnable": false,
    "idempotent": true,
    "inputSchema": {
        "type": "object",
        "properties": {
            "project": {
                "type": "string",
                "description": "Project slug. Optional: the local server falls back to lingvo.yaml, and the remote server to this connection's project when it has exactly one."
            },
            "locale": {
                "type": "string",
                "description": "Target locale, e.g. ru."
            },
            "key": {
                "type": "string",
                "description": "Key name."
            },
            "forms": {
                "type": "object",
                "description": "CLDR category to text, e.g. {\"one\":\"…\",\"few\":\"…\",\"other\":\"…\"}. Call locale_info first: a partial set looks finished and breaks only for certain numbers.",
                "additionalProperties": {
                    "type": "string"
                }
            },
            "rationale": {
                "type": "string",
                "description": "Why you chose this wording, in one or two sentences. At most 500 characters; longer is refused rather than cut in half."
            },
            "confidence": {
                "type": "string",
                "description": "How sure you are. A reviewer deciding four thousand strings reads the low ones first, and this is the only signal that can tell them which those are.",
                "enum": [
                    "high",
                    "medium",
                    "low"
                ]
            }
        },
        "required": [
            "locale",
            "key",
            "forms"
        ]
    }
}

comment

Code example
{
    "name": "comment",
    "description": "Ask a question about a string. Changes no translation.",
    "transports": [
        "remote"
    ],
    "safety": "propose",
    "scopes": [
        "strings:write"
    ],
    "minimumRole": "TRANSLATOR",
    "dryRunnable": false,
    "idempotent": false,
    "inputSchema": {
        "type": "object",
        "properties": {
            "project": {
                "type": "string",
                "description": "Project slug. Optional: the local server falls back to lingvo.yaml, and the remote server to this connection's project when it has exactly one."
            },
            "key": {
                "type": "string",
                "description": "Key name."
            },
            "body": {
                "type": "string",
                "description": "The question."
            }
        },
        "required": [
            "key",
            "body"
        ]
    }
}

add_key

Code example
{
    "name": "add_key",
    "description": "Add a new source string. Needs the connection to borrow an owner or admin.",
    "transports": [
        "remote"
    ],
    "safety": "structural",
    "scopes": [
        "strings:write"
    ],
    "minimumRole": "ADMIN",
    "dryRunnable": false,
    "idempotent": false,
    "inputSchema": {
        "type": "object",
        "properties": {
            "project": {
                "type": "string",
                "description": "Project slug. Optional: the local server falls back to lingvo.yaml, and the remote server to this connection's project when it has exactly one."
            },
            "file": {
                "type": "string",
                "description": "File path the key belongs in, as the project lists it."
            },
            "key": {
                "type": "string",
                "description": "Key name."
            },
            "value": {
                "type": "string",
                "description": "The source text."
            },
            "context": {
                "type": "string",
                "description": "What this string is and where it appears, for whoever translates it."
            },
            "max_length": {
                "type": "integer",
                "description": "Characters the control can hold.",
                "minimum": 1
            },
            "tags": {
                "type": "string",
                "description": "Comma-separated tags."
            }
        },
        "required": [
            "file",
            "key",
            "value"
        ]
    }
}

set_key_context

Code example
{
    "name": "set_key_context",
    "description": "Write down what an existing string is for: its developer context, its length budget, its tags. The single highest-value thing a coding agent can do, because it is the only moment the answer is in front of anybody.",
    "transports": [
        "local",
        "remote"
    ],
    "safety": "structural",
    "scopes": [
        "strings:write"
    ],
    "minimumRole": "ADMIN",
    "dryRunnable": false,
    "idempotent": true,
    "inputSchema": {
        "type": "object",
        "properties": {
            "project": {
                "type": "string",
                "description": "Project slug. Optional: the local server falls back to lingvo.yaml, and the remote server to this connection's project when it has exactly one."
            },
            "key": {
                "type": "string",
                "description": "Key name."
            },
            "context": {
                "type": "string",
                "description": "What this string is and where it appears — the note a translator reads before writing anything. Omit to leave the stored note alone."
            },
            "max_length": {
                "type": "integer",
                "description": "Characters the control can hold. Omit to leave it alone.",
                "minimum": 1
            },
            "tags": {
                "type": "string",
                "description": "Comma-separated tags. Omit to leave them alone."
            }
        },
        "required": [
            "key"
        ]
    }
}

push_strings

Code example
{
    "name": "push_strings",
    "description": "Replace a file's strings from entries. Obsoleting keys requires confirm_obsolete_count to match exactly what this push would remove.",
    "transports": [
        "remote"
    ],
    "safety": "structural",
    "scopes": [
        "files:write"
    ],
    "minimumRole": "TRANSLATOR",
    "dryRunnable": false,
    "idempotent": true,
    "inputSchema": {
        "type": "object",
        "properties": {
            "project": {
                "type": "string",
                "description": "Project slug. Optional: the local server falls back to lingvo.yaml, and the remote server to this connection's project when it has exactly one."
            },
            "file": {
                "type": "string",
                "description": "File path, as the project lists it."
            },
            "locale": {
                "type": "string",
                "description": "Locale these entries are in."
            },
            "entries": {
                "type": "object",
                "description": "Key name to text.",
                "additionalProperties": {
                    "type": "string"
                }
            },
            "confirm_obsolete_count": {
                "type": "integer",
                "description": "How many keys this push should obsolete. Must equal what a dry run reported, exactly; any obsoletion at all requires it.",
                "minimum": 0
            }
        },
        "required": [
            "file",
            "locale",
            "entries"
        ]
    }
}

machine_translate

Code example
{
    "name": "machine_translate",
    "description": "Translate the empty strings in a locale with a machine provider. Costs credits, and returns a job handle rather than holding the connection open.",
    "transports": [
        "remote"
    ],
    "safety": "spend",
    "scopes": [
        "mt:spend"
    ],
    "minimumRole": "ADMIN",
    "dryRunnable": false,
    "idempotent": false,
    "inputSchema": {
        "type": "object",
        "properties": {
            "project": {
                "type": "string",
                "description": "Project slug. Optional: the local server falls back to lingvo.yaml, and the remote server to this connection's project when it has exactly one."
            },
            "locale": {
                "type": "string",
                "description": "Target locale, e.g. de."
            },
            "provider": {
                "type": "string",
                "description": "Provider id, e.g. deepl."
            }
        },
        "required": [
            "locale",
            "provider"
        ]
    }
}

pull

Code example
{
    "name": "pull",
    "description": "Write translations from the server into the repository. Defaults to a dry run.",
    "transports": [
        "local"
    ],
    "safety": "write",
    "scopes": [
        "files:write"
    ],
    "minimumRole": "TRANSLATOR",
    "dryRunnable": true,
    "idempotent": false,
    "inputSchema": {
        "type": "object",
        "properties": {
            "dry_run": {
                "type": "boolean",
                "description": "Set false to actually write files.",
                "default": true
            },
            "locale": {
                "type": "string",
                "description": "Limit to one locale."
            }
        },
        "required": []
    }
}

push

Code example
{
    "name": "push",
    "description": "Upload source strings from the repository. Defaults to a dry run. Never obsoletes keys unless obsolete_missing is true AND confirm_obsolete_count matches the plan.",
    "transports": [
        "local"
    ],
    "safety": "structural",
    "scopes": [
        "files:write"
    ],
    "minimumRole": "TRANSLATOR",
    "dryRunnable": true,
    "idempotent": false,
    "inputSchema": {
        "type": "object",
        "properties": {
            "dry_run": {
                "type": "boolean",
                "description": "Set false to actually push.",
                "default": true
            },
            "obsolete_missing": {
                "type": "boolean",
                "description": "Mark server keys missing from the repository as obsolete.",
                "default": false
            },
            "confirm_obsolete_count": {
                "type": "integer",
                "description": "Must equal the number a dry run reported, exactly.",
                "minimum": 0
            }
        },
        "required": []
    }
}

get_source_change

Code example
{
    "name": "get_source_change",
    "description": "Read the exact current source and a target's recorded earlier source. Unknown history stays unknown. No writes or credits.",
    "transports": [
        "local",
        "remote"
    ],
    "safety": "read",
    "scopes": [
        "strings:read"
    ],
    "minimumRole": "VIEWER",
    "dryRunnable": false,
    "idempotent": true,
    "inputSchema": {
        "type": "object",
        "properties": {
            "project": {
                "type": "string",
                "description": "Project slug. Optional: the local server falls back to lingvo.yaml, and the remote server to this connection's project when it has exactly one."
            },
            "key_id": {
                "type": "string",
                "description": "Stable key UUID from a brief or key list."
            },
            "locale": {
                "type": "string",
                "description": "Target locale, e.g. de."
            }
        },
        "required": [
            "key_id",
            "locale"
        ]
    }
}

propose_translation_for_source

Code example
{
    "name": "propose_translation_for_source",
    "description": "Suggest a translation bound to the exact source read. A changed source refuses before replacing another proposal. Reread and regenerate after a conflict. It waits for human acceptance.",
    "transports": [
        "local",
        "remote"
    ],
    "safety": "propose",
    "scopes": [
        "strings:read",
        "strings:write"
    ],
    "minimumRole": "TRANSLATOR",
    "dryRunnable": false,
    "idempotent": false,
    "inputSchema": {
        "type": "object",
        "properties": {
            "project": {
                "type": "string",
                "description": "Project slug. Optional: the local server falls back to lingvo.yaml, and the remote server to this connection's project when it has exactly one."
            },
            "source_view": {
                "type": "object",
                "properties": {
                    "sourceRevisionId": {
                        "type": "string",
                        "description": "Exact source snapshot UUID returned by the read."
                    },
                    "keyId": {
                        "type": "string",
                        "description": "Stable key UUID returned by the read."
                    },
                    "sourceLocale": {
                        "type": "string",
                        "description": "Canonical source locale returned by the read."
                    },
                    "sourceVersion": {
                        "type": "integer",
                        "description": "Source epoch returned by the read, including zero.",
                        "minimum": 0
                    },
                    "isPlural": {
                        "type": "boolean",
                        "description": "Source shape returned by the read."
                    }
                },
                "required": [
                    "sourceRevisionId",
                    "keyId",
                    "sourceLocale",
                    "sourceVersion",
                    "isPlural"
                ],
                "description": "Copy the complete view from sourceSnapshot.view unchanged. If unknown, reread; never invent or refresh a claim during submission."
            },
            "locale": {
                "type": "string",
                "description": "Target locale."
            },
            "value": {
                "type": "string",
                "description": "The proposed target text."
            },
            "rationale": {
                "type": "string",
                "description": "Why this wording fits. At most 500 characters."
            },
            "confidence": {
                "type": "string",
                "description": "How sure you are.",
                "enum": [
                    "high",
                    "medium",
                    "low"
                ]
            }
        },
        "required": [
            "source_view",
            "locale",
            "value"
        ]
    }
}

propose_plural_for_source

Code example
{
    "name": "propose_plural_for_source",
    "description": "Suggest a plural translation bound to the exact source read. A changed source refuses before replacing another proposal. Reread and regenerate after a conflict. It waits for human acceptance.",
    "transports": [
        "local",
        "remote"
    ],
    "safety": "propose",
    "scopes": [
        "strings:read",
        "strings:write"
    ],
    "minimumRole": "TRANSLATOR",
    "dryRunnable": false,
    "idempotent": false,
    "inputSchema": {
        "type": "object",
        "properties": {
            "project": {
                "type": "string",
                "description": "Project slug. Optional: the local server falls back to lingvo.yaml, and the remote server to this connection's project when it has exactly one."
            },
            "source_view": {
                "type": "object",
                "properties": {
                    "sourceRevisionId": {
                        "type": "string",
                        "description": "Exact source snapshot UUID returned by the read."
                    },
                    "keyId": {
                        "type": "string",
                        "description": "Stable key UUID returned by the read."
                    },
                    "sourceLocale": {
                        "type": "string",
                        "description": "Canonical source locale returned by the read."
                    },
                    "sourceVersion": {
                        "type": "integer",
                        "description": "Source epoch returned by the read, including zero.",
                        "minimum": 0
                    },
                    "isPlural": {
                        "type": "boolean",
                        "description": "Source shape returned by the read."
                    }
                },
                "required": [
                    "sourceRevisionId",
                    "keyId",
                    "sourceLocale",
                    "sourceVersion",
                    "isPlural"
                ],
                "description": "Copy the complete view from sourceSnapshot.view unchanged. If unknown, reread; never invent or refresh a claim during submission."
            },
            "locale": {
                "type": "string",
                "description": "Target locale."
            },
            "forms": {
                "type": "object",
                "description": "Complete CLDR category to text map. Call locale_info for required categories.",
                "additionalProperties": {
                    "type": "string"
                }
            },
            "rationale": {
                "type": "string",
                "description": "Why this wording fits. At most 500 characters."
            },
            "confidence": {
                "type": "string",
                "description": "How sure you are.",
                "enum": [
                    "high",
                    "medium",
                    "low"
                ]
            }
        },
        "required": [
            "source_view",
            "locale",
            "forms"
        ]
    }
}

Prompts and resources

Prompts provide a workflow starting point; they do not grant permissions. translate_locale takes project and locale, while fix_qa_findings and review_proposals take project. A review prompt does not introduce an approval tool.

translate_locale

Code example
{
    "name": "translate_locale",
    "description": "Translate a language, in the order that matters, without inventing plurals.",
    "arguments": [
        "project",
        "locale"
    ]
}

fix_qa_findings

Code example
{
    "name": "fix_qa_findings",
    "description": "Work through this project's QA findings, errors first.",
    "arguments": [
        "project"
    ]
}

review_proposals

Code example
{
    "name": "review_proposals",
    "description": "Review what agents have proposed, and reject what is wrong.",
    "arguments": [
        "project"
    ]
}

lingvo://project/{slug}/glossary

Code example
{
    "uriTemplate": "lingvo://project/{slug}/glossary",
    "description": "Terms this project requires or forbids.",
    "scope": "glossary:read"
}

lingvo://project/{slug}/readiness

Code example
{
    "uriTemplate": "lingvo://project/{slug}/readiness",
    "description": "Can this project ship, and what is in the way.",
    "scope": "strings:read"
}

lingvo://project/{slug}/style-guide

Code example
{
    "uriTemplate": "lingvo://project/{slug}/style-guide",
    "description": "How this product is written. Standing instructions, set by the team.",
    "scope": "strings:read"
}

lingvo://locale/{tag}/plurals

Code example
{
    "uriTemplate": "lingvo://locale/{tag}/plurals",
    "description": "The CLDR plural categories a locale really uses. Substitute a BCP-47 tag for {tag}."
}

Project resources are listed only for reachable projects and permitted scopes. The locale plural URI is a template: replace {tag} with a real BCP-47 locale such as ru before reading it. Never send the literal braces as a locale.

Troubleshooting

Client tool approval refused: a connected server does not mean the client may call it. Approve the intended read in an interactive session. For an unattended status check, configure approval for only project_status under your client’s documented tool policy. This does not grant Lingvo scopes or project access. A successful client exit can still contain a refused tool result, with no Lingvo API request.

Email verification required: sign in to Lingvo as the account that owns the CLI credential or agent connection. Open the verification notice (under more notices if needed), request a link and confirm your address. Then retry the refused operation; do not rotate tokens to bypass verification. Lingvo-funded translation requires a verified account. BYOK, manual work, import, export, review and QA remain available.

No tools appear: confirm the executable path, Java runtime, transport and client support. Run lingvo --version from the same environment. For local MCP, verify the working directory and keep logs off stdout. Restart the client after changing configuration.

Authentication refused: local MCP uses device/session/API credentials; hosted MCP needs its lgm_ connection token. A literal $LINGVO_AGENT_TOKEN in a JSON file is not guaranteed to expand. Follow your client’s secret syntax, and never share the completed config.

A project is unavailable: check the slug, membership and connection/token allowlist. With several allowed remote projects, specify project explicitly. An empty list is not permission to create new projects automatically.

A write or spend is refused: inspect tool scopes, minimum role, connection autonomy and budgets. Proposal review is a human step. Preview support is tool-specific. Use estimate_cost before a hosted machine translation call.

A request timed out after a mutation: inspect current proposals, translations, jobs and usage before retrying. Do not assume an HTTP timeout means the operation never ran. When reporting a problem, include versions, tool name and redacted error; omit tokens and customer text.

CLI guide

Agent workflow overview