Announcing CIMD support for MCP Client registration
Learn more

Lokalise MCP vs Lokalise API for AI Agents

TL;DR

  • Lokalise's official Model Context Protocol (MCP) server is cloud-hosted, in beta, and documents 28 actions. Webhooks, translation-level endpoints, branches, and snapshots are API-only.
  • MCP accepts OAuth 2 or an API token in an apikey header. The REST API accepts tokens or OAuth 2, but OAuth apps need Lokalise support to register.
  • Both paths share one rate budget, 6 requests per second per token and IP, because MCP runs on the REST API.
  • In a multi-tenant agent, every user brings their own Lokalise credential on either path, and neither path stores, rotates, or revokes it.
  • Scalekit's Lokalise connector keeps each user's API key in a token vault, ships 109 prebuilt tools, and serves scoped Virtual MCP servers, so the choice doesn't change your auth infrastructure.

Why this choice isn't obvious for Lokalise agents

Your agent needs to work inside Lokalise: find untranslated keys, open translation tasks, pull files before a release. Lokalise now runs an official MCP server next to the REST API it has maintained for years. Both are official, and both hit the same backend and the same rate limits. They still put your agent on different capability surfaces, different auth paths, and different maintenance obligations. The gap widens once the agent runs headless, for many users, across many tenants. Here's the decision framework.

What Lokalise MCP and Lokalise API actually are

Both paths share a backend and a permission model. The difference is who designs each call: Lokalise, or your team.

Lokalise MCP

Lokalise hosts the MCP server itself, and it is still in beta. It ships as two toolkits on separate endpoints: Project Management (PM) at /mcp/project-management for projects, tasks, contributors, languages, files, keys, and glossary, and Software Development (SD) at /mcp/software-development for projects, tasks, keys, and screenshots. Any team on a plan with API access can use it, though Lokalise documents it for Lokalise Expert and not Lokalise Vantage.

Clients authenticate with OAuth 2, which Lokalise recommends, or with a personal API token in an apikey header. Either way, the agent inherits the permissions of the user behind the token.

Lokalise API

The REST API (APIv2) is the full platform surface: projects, keys, translations, files, tasks, contributors, glossary, screenshots, webhooks, snapshots, orders, and team administration, plus branch-aware endpoints, an over-the-air (OTA) API, and audit logs.

It authenticates two ways. A personal API token, read-only or read/write, goes in the X-Api-Token header. To act on behalf of other users, Lokalise supports the OAuth 2 Authorization Code flow, with access tokens that usually expire after an hour and a refresh-token grant to renew them.

Comparing them where it matters for agents

Four dimensions decide the choice: capability coverage, the auth path, what you own in production, and where each path wins.

What your agent can actually do

The MCP toolkits cover the everyday developer and localization-manager loop. The gaps appear when an agent needs to react, clean up, or work at scale.

Capability
Lokalise MCP
Lokalise API
List projects and progress stats
Yes
Yes
List and filter keys
Yes
Yes, offset or cursor pagination
Create keys in bulk
Yes, SD toolkit
Yes
Update keys, single or bulk
Yes
Yes
Translation-level edits and review flags
No
Yes
Create tasks, including AI translation
Yes
Yes
Upload translation files
Yes, PM toolkit
Yes, async with process polling
Export translation files
Partial, see below
Yes, sync or async
Create and update glossary terms
Yes
Yes, plus delete
Delete keys, languages, or projects
No
Yes
Webhooks
No
Yes
Branches, snapshots, OTA, team admin
No
Yes

Where the MCP surface stops

The MCP surface is almost entirely additive. The only delete among its documented actions removes a screenshot. That suits IDE agents and blocks cleanup or migration agents. Event-driven work is API-only as well: there are no webhook tools, and the documented actions include no way to check an upload's queued process.

Exports are the ambiguous case. Lokalise's product page and launch post describe file downloads in the SD toolkit, but the Help Center's action table leaves them out. Call tools/list on that endpoint before your agent depends on it. Lokalise's own guidance is explicit that MCP does not expose every REST operation.

The auth path MCP puts you on

The MCP server prefers OAuth 2. In Claude Code, you add each toolkit endpoint, restart, and accept the authentication prompt; the client holds the resulting token. The alternative is a personal API token in the apikey header. A read-only token covers listing keys and checking progress, and anything that creates, updates, or uploads needs a read/write token.

In both modes, permissions follow the user who authorized the connection. If that user has no access to a project, neither does the agent. What the user can't do, the agent can't do.

The auth path the API puts you on

Personal API tokens are self-serve and fit headless jobs: no redirect, no refresh cycle. The cost is scope. A token carries its creator's project permissions, narrowed only by its read-only or read/write type, so least privilege depends on who issued it.

OAuth 2 is the per-user delegation path, and it has friction for agent builders. There is no self-serve app registration; you contact Lokalise support with your app details and the scopes you need. Only the Authorization Code grant is supported, and access tokens expire after about an hour.

Per-user isolation is required on both paths

Both paths require per-user credential isolation in a multi-tenant B2B agent. MCP's OAuth flow gives you a token per user. The API gives you a credential per user. In neither case does the path itself solve storage, rotation, or revocation; those are infrastructure problems regardless of which path you choose. The failure modes are covered in access control for multi-tenant AI agents.

What you own in production on MCP

Lokalise owns hosting, tool definitions, and schema updates, and new tools arrive without a redeploy on your side. You still own the credential the client holds and the rate budget, because MCP calls count against the same limits as your REST integrations.

You also own change management. The server is in beta, and Lokalise plans to add toolkits, including translator-focused ones, so the tool list your agent sees will shift. Audit coverage has a plan boundary too: Lokalise's Audit Log records MCP actions on Enterprise plans, and elsewhere your trail depends on Lokalise's activity records plus whatever your client keeps.

What you own in production on the API

Everything. Pagination metadata arrives in response headers, including the X-Pagination-Next-Cursor value that cursor pagination on keys and translations depends on. Uploads return a queued process you poll until it finishes. Synchronous downloads stop at 10,000 key-language pairs, so larger projects need the async endpoint and another poll.

Webhooks are unsigned: Lokalise sends a shared secret in X-Secret, expects a 2xx within 8 seconds, and disables the handler after 24 hours of failed retries. Then there are the 429s, at 6 requests per second per token or 10 concurrent requests per project, and the retry logic they demand.

When to use Lokalise MCP

  • A developer in Claude Code, Cursor, or Windsurf is adding keys, attaching screenshots, or checking locale coverage without leaving the editor.
  • A localization manager wants tasks, assignees, and glossary updates handled in natural language, with a person reviewing each step.
  • You are prototyping a Lokalise agent and want tool definitions that Lokalise maintains.
  • The agent orchestrates several tools and benefits from standard MCP tool discovery across all of them.

When to use the Lokalise API

  • The agent runs headless: a nightly job that queues AI translation tasks, or a CI step that pulls translations before a release.
  • The agent reacts to Lokalise events such as project.task.closed or project.translation.updated through webhooks.
  • The workflow needs branches, a snapshot before a bulk edit, cleanup deletes, or OTA bundle publishing.
  • You are migrating thousands of keys and need batching, cursor pagination, and deterministic retries.

The credential problem that exists on both paths

Choose either path and the credential count comes out the same: one Lokalise credential per user, per tenant.

N users means N Lokalise credentials

Take a localization agent serving 40 customer workspaces with 5 users each. That's 200 Lokalise credentials, whether they came from MCP OAuth or personal API tokens. Each one must be encrypted at rest, isolated per tenant, kept out of prompts and logs, and revoked when its owner leaves. OAuth tokens add a refresh cycle; Lokalise's REST access tokens last about an hour. API tokens skip refresh, but they are static secrets someone has to rotate and revoke by hand. Neither MCP nor the API gives you a vault, a rotation policy, or a revocation flow.

Where Scalekit fits

Scalekit's Lokalise connector moves that work into the infrastructure layer. Each user adds their Lokalise API token once through a Scalekit-hosted page. Scalekit stores it in its token vault as a connected account and injects it into every call, so credentials never touch the agent runtime. The MCP vs API decision no longer changes your auth infrastructure. For the tradeoffs between the two credential types, read OAuth vs API keys for AI agents.

How to connect a Lokalise agent through Scalekit

Every path below follows the same shape: create the connection once, connect each user once, then call tools through execute_tool, a framework adapter, or a Virtual MCP server. Create the Lokalise connection under AgentKit > Connections using the Lokalise connector docs, then set SCALEKIT_ENVIRONMENT_URL, SCALEKIT_CLIENT_ID, and SCALEKIT_CLIENT_SECRET. The connection_name in code must match the connection name in the dashboard exactly; a mismatch is the most common integration error.

Connect each user's Lokalise account

Before the agent acts for a user, confirm their connected account is ACTIVE. If it isn't, send them the authorization link. For an API-key connector like Lokalise, that link opens a hosted form that collects their token, so your code never handles it.

import os from typing import Optional from scalekit import ScalekitClient scalekit_client = ScalekitClient( env_url=os.environ["SCALEKIT_ENVIRONMENT_URL"], client_id=os.environ["SCALEKIT_CLIENT_ID"], client_secret=os.environ["SCALEKIT_CLIENT_SECRET"], ) actions = scalekit_client.actions # Must match the connection name in AgentKit > Connections exactly CONNECTION_NAME = "lokalise" def lokalise_connect_link(user_id: str) -> Optional[str]: """Return a hosted-page link if this user still needs to add a Lokalise API token.""" account = actions.get_or_create_connected_account( connection_name=CONNECTION_NAME, identifier=user_id, ).connected_account if account.status == "ACTIVE": return None return actions.get_authorization_link( connection_name=CONNECTION_NAME, identifier=user_id, ).link

Run a deterministic pipeline without a model

Not every Lokalise workflow needs a model in the loop. A nightly job that finds untranslated keys and queues an AI translation task is a fixed sequence, so it calls execute_tool directly. It pages with offsets on purpose: Lokalise returns the next cursor in a response header, and tool results carry the response body, not headers.

import time from scalekit.common.exceptions import ScalekitToolRateLimitException PROJECT_ID = "3002780358964f9bab5a92.87762498" # your Lokalise project ID TARGET_LANGS = ["de", "fr", "ja"] def run_tool(user_id: str, tool_name: str, tool_input: dict, max_attempts: int = 4) -> dict: for attempt in range(max_attempts): try: result = actions.execute_tool( tool_input=tool_input, tool_name=tool_name, connection_name=CONNECTION_NAME, identifier=user_id, ) print(f"{tool_name} execution_id={result.execution_id}") # trace it in AgentKit logs return result.data or {} except ScalekitToolRateLimitException: # Lokalise returned 429 (6 requests per second per token): back off 1s, 2s, 4s if attempt == max_attempts - 1: raise time.sleep(2 ** attempt) return {} def untranslated_key_ids(user_id: str) -> list[int]: key_ids, page, limit = [], 1, 500 while True: data = run_tool(user_id, "lokalise_list_keys", { "project_id": PROJECT_ID, "filter_untranslated": 1, "pagination": "offset", "limit": limit, "page": page, }) keys = data.get("keys", []) key_ids.extend(key["key_id"] for key in keys) if len(keys) < limit: return key_ids page += 1 def queue_ai_translation(user_id: str) -> None: key_ids = untranslated_key_ids(user_id) if not key_ids: return data = run_tool(user_id, "lokalise_create_task", { "project_id": PROJECT_ID, "title": "Nightly AI translation pass", "task_type": "automatic_translation", "keys": key_ids, # AI tasks take languages only; users and groups must be omitted "languages": [{"language_iso": lang} for lang in TARGET_LANGS], }) print("Created task:", data.get("task", {}).get("task_id")) queue_ai_translation("user_123")

Node.js teams make the same call with executeTool, passing the connection name as connector. Save the file with an .mts extension so top-level await works.

import { ScalekitClient } from '@scalekit-sdk/node' import 'dotenv/config' const scalekit = new ScalekitClient( process.env.SCALEKIT_ENVIRONMENT_URL!, process.env.SCALEKIT_CLIENT_ID!, process.env.SCALEKIT_CLIENT_SECRET!, ) const result = await scalekit.actions.executeTool({ toolName: 'lokalise_list_keys', toolInput: { project_id: '3002780358964f9bab5a92.87762498', filter_untranslated: 1, limit: 500, page: 1 }, identifier: 'user_123', connector: 'lokalise', // must match the connection name in AgentKit > Connections }) console.log(result.executionId, result.data)

Give a LangChain agent a scoped Lokalise surface

actions.langchain.get_tools doesn't hand the model a flat connector catalog. It retrieves the tools this user's connected account is authorized to call and returns them as native LangChain tools. Scope matters here because the connector ships 109 tools. At the roughly 200 tokens per tool Scalekit uses as a rule of thumb, that's over 20,000 tokens before the agent does any work, and Lokalise schemas run large: the async export tool alone takes 27 parameters. Filter with tool_names. Paging is a trap; a page_size of 100 silently drops 9 tools.

from langchain_core.messages import HumanMessage, ToolMessage from langchain_openai import ChatOpenAI LOKALISE_TOOLS = [ "lokalise_list_projects", "lokalise_list_keys", "lokalise_get_key", "lokalise_list_tasks", "lokalise_create_task", ] def run_localization_assistant(user_id: str, prompt: str) -> str: # Five tools this user's connected account can call, not the 109-tool catalog tools = actions.langchain.get_tools( identifier=user_id, connection_names=[CONNECTION_NAME], tool_names=LOKALISE_TOOLS, ) tool_map = {tool.name: tool for tool in tools} llm = ChatOpenAI(model="gpt-4o").bind_tools(tools) messages = [HumanMessage(prompt)] while True: response = llm.invoke(messages) messages.append(response) if not response.tool_calls: return response.content for call in response.tool_calls: result = tool_map[call["name"]].invoke(call["args"]) messages.append(ToolMessage(content=str(result), tool_call_id=call["id"])) print(run_localization_assistant( "user_123", "Which keys in the Checkout project are still untranslated, and is there an open task for them?", ))

Put Lokalise behind a Virtual MCP server

A Virtual MCP server gives you the MCP interface with no MCP server to deploy, host, or maintain. You define it once per agent role and choose which connections and tools it exposes. Everything else in the Lokalise catalog, including lokalise_delete_project, lokalise_create_order, and lokalise_create_payment_card, doesn't exist for that agent. This server pairs three Lokalise tools with Slack's slack_send_message for a release agent.

from scalekit.actions.models.mcp_config import McpConfigConnectionToolMapping # Run once per agent role, not once per user config = actions.mcp.create_config( name="localization-release-agent", connection_tool_mappings=[ McpConfigConnectionToolMapping( connection_name="lokalise", # dashboard connection names, matched exactly tools=["lokalise_list_projects", "lokalise_list_keys", "lokalise_create_task"], ), McpConfigConnectionToolMapping( connection_name="slack", tools=["slack_send_message"], ), ], ).config print(config.id, config.mcp_server_url) # store both; every user shares them

Mint a session token per user and run the agent

Before each run, confirm the user's connections are active and mint a short-lived session token. The URL stays static; the identity rides on the token. The agent loop is the LangChain loop from above, now running over MCP.

import asyncio from datetime import timedelta from langchain_core.messages import HumanMessage, ToolMessage from langchain_mcp_adapters.client import MultiServerMCPClient from langchain_openai import ChatOpenAI def mint_session_token(config_id: str, user_id: str) -> str: accounts = actions.mcp.list_mcp_connected_accounts( config_id=config_id, identifier=user_id, include_auth_link=True, ).connected_accounts pending = { account.connection_name: account.authentication_link for account in accounts if (account.connected_account_status or "").upper() != "ACTIVE" } if pending: raise RuntimeError(f"Connect these accounts first: {pending}") return actions.mcp.create_session_token( mcp_config_id=config_id, identifier=user_id, expiry=timedelta(minutes=30), # longer than the expected run ).token async def run_release_agent(config_id: str, mcp_url: str, user_id: str, prompt: str) -> str: token = mint_session_token(config_id, user_id) client = MultiServerMCPClient({ "scalekit": { "transport": "streamable_http", "url": mcp_url, "headers": {"Authorization": f"Bearer {token}"}, } }) tools = await client.get_tools() tool_map = {tool.name: tool for tool in tools} llm = ChatOpenAI(model="gpt-4o").bind_tools(tools) messages = [HumanMessage(prompt)] while True: response = await llm.ainvoke(messages) messages.append(response) if not response.tool_calls: return response.content for call in response.tool_calls: result = await tool_map[call["name"]].ainvoke(call["args"]) messages.append(ToolMessage(content=str(result), tool_call_id=call["id"])) print(asyncio.run(run_release_agent( config.id, config.mcp_server_url, "user_123", "Queue an AI translation task for untranslated Checkout keys in German, then post a summary in #localization.", )))

When the connector doesn't cover a Lokalise endpoint

The 109 tools skip branch management, the OTA API, and audit logs, and they can't finish cursor pagination. For those, actions.request proxies a raw call to the Lokalise API through the same connected account. You pass the path, Scalekit resolves the base URL and injects the user's token, and you get the full HTTP response back: a requests.Response in Python, an Axios response in Node.js. That makes X-Pagination-Next-Cursor readable. Proxy access is on by default, and the custom tools guide covers the pattern.

Why the Scalekit path holds up for Lokalise agents

Getting a first call working is the easy part. These properties decide whether a Lokalise agent survives production.

Tool-call logs you can trace per user

Every execute_tool call returns an execution_id, and the AgentKit dashboard shows each connected account's status and tool execution logs. When Lokalise rejects a call, the SDK raises a ScalekitTool* exception carrying the provider's error code, message, and that execution ID, so a failed nightly run traces to one user, one tool, and one call. Rate limits stay legible too: Scalekit tags its own 429s RATE_LIMITED and upstream ones TOOL_ERROR. Lokalise's own Audit Log for MCP actions needs an Enterprise plan. For the compliance angle, see audit trails for agent auth.

Virtual MCP for multi-tool, multi-tenant agents

A release agent rarely touches Lokalise alone. It reads keys, opens a task, posts to Slack, and maybe checks a pull request in GitHub. A Virtual MCP server turns that surface into one endpoint per agent role. One server definition serves every tenant, and each run gets a short-lived session token bound to one user's connected accounts, so there is no credential sharing between users and no per-user server configuration. Set up once per agent role; mint a token before each run. The endpoint is static; the identity is not.

Least privilege over a 109-tool catalog

Lokalise's API can spend money and destroy data, and the connector mirrors it. lokalise_empty_project deletes every key in a project, lokalise_create_order places a paid translation order, and lokalise_create_payment_card adds a billing card. A progress-reporting agent needs none of them. Scoping the catalog to 5 to 10 tools cuts tool-definition tokens by more than 90% and takes those actions out of the blast radius. The fix is not better prompting. It is surface reduction. For a deeper look at tool calling auth patterns and anti-patterns, that post covers the design principles behind catalog scoping.

Revoked credentials surface early

Users rotate Lokalise tokens and leave companies. Scalekit's connected_account.status_updated webhook fires on every status transition with the old and new status, so an agent can pause and prompt the user instead of failing mid-run. If a token is revoked inside Lokalise, the next call raises ScalekitToolUnauthorizedException; send the user back through get_authorization_link to add a fresh token. For patterns around secure token management for AI agents at scale, the full lifecycle is covered there.

Which one to build against

Lokalise's own guidance draws the line in the same place: MCP for interactive, conversational work, the REST API for production automation. If your agent works alongside a person, such as a developer adding keys from Cursor or a manager assigning tasks from Claude, start with the MCP server. If it runs headless, reacts to webhooks, manages branches, or moves thousands of keys, build on the API, because it is the only complete surface.

Scalekit narrows the gap from both sides: its Lokalise tools call the REST API, and a Virtual MCP server delivers a scoped slice of them over MCP. Either way, the credential problem is identical, and that is the part that needs production-grade infrastructure.

Build your Lokalise agent on Scalekit

If you're building Lokalise agents for many users and want a second pair of eyes on the auth design, talk to us for immediate help. To start on your own, the Lokalise connector docs list all 109 tools and their parameters, the connector catalog shows the other tools your agent can reach on the same auth plumbing, and pricing lays out the plans. For multi-tool patterns, start from the auto release notes agent or DevOps assistant agent templates. Other posts in this series compare GitHub MCP vs API and Slack MCP vs API.

No items found.
Agent
Auth Quickstart
On this page
Share this article
Agent
Auth Quickstart

Acquire enterprise customers with
‍zero upfront cost.

Every feature unlocked. No hidden fees.