lokalise-mcp
Version:
The Lokalise MCP Server brings Lokalise's localization power to Claude and AI assistants—manage projects, keys, and translations by chat.
135 lines (134 loc) • 5.28 kB
JavaScript
import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
import { formatErrorForMcpResource } from "../../shared/utils/error.util.js";
import { Logger } from "../../shared/utils/logger.util.js";
import glossaryController from "./glossary.controller.js";
/**
* Glossary MCP resources implementation.
* Generated on 2025-07-10 for Glossary terms management for consistent translations.
*/
const logger = Logger.forContext("domains/glossary/glossary.resource.ts");
/**
* Handle collection resource requests
*/
async function handleCollectionResource(projectId, params) {
const methodLogger = logger.forMethod("handleCollectionResource");
// Extract query parameters
const limitParam = params.get("limit");
const limit = limitParam ? Number.parseInt(limitParam, 10) : 100;
const cursor = params.get("cursor") || undefined;
methodLogger.debug("Fetching glossary terms collection", {
projectId,
limit,
cursor,
});
// Call controller
const result = await glossaryController.listGlossaryTerms({
projectId,
limit,
cursor,
});
return {
contents: [
{
uri: `lokalise://glossary-terms/${projectId}`,
mimeType: "text/markdown",
text: result.content,
description: `Glossary terms for project ${projectId}`,
},
],
};
}
/**
* Handle detail resource requests
*/
async function handleDetailResource(projectId, termId) {
const methodLogger = logger.forMethod("handleDetailResource");
methodLogger.debug("Fetching glossary term details", { projectId, termId });
// Parse term ID
const parsedTermId = Number.parseInt(termId, 10);
if (Number.isNaN(parsedTermId)) {
throw new Error(`Invalid term ID: ${termId}. Must be a number.`);
}
// Call controller
const result = await glossaryController.getGlossaryTerm({
projectId,
termId: parsedTermId,
});
return {
contents: [
{
uri: `lokalise://glossary-terms/${projectId}/${termId}`,
mimeType: "text/markdown",
text: result.content,
description: `Glossary term ${termId} details`,
},
],
};
}
/**
* Register all MCP resources for the glossary domain
* @param server The MCP server instance to register resources with
*/
function registerResources(server) {
const registerLogger = Logger.forContext("glossary.resource.ts", "registerResources");
registerLogger.debug("Registering glossary domain resources...");
// Collection resource
server.resource("lokalise-glossary-terms", new ResourceTemplate("lokalise://glossary-terms/{projectId}", {
list: undefined,
}), {
description: "Browse glossary terms for a project. Supports cursor pagination and provides information about term properties, translations, and usage guidelines. Essential for maintaining translation consistency.",
}, async (uri) => {
try {
const pathParts = uri.pathname.split("/").filter(Boolean);
if (pathParts.length !== 2 || pathParts[0] !== "glossary-terms") {
throw new Error("Invalid resource URI. Expected lokalise://glossary-terms/<project-id>");
}
return await handleCollectionResource(pathParts[1], uri.searchParams);
}
catch (error) {
logger.error("Failed to handle glossary terms collection resource", {
error,
uri: uri.toString(),
});
return formatErrorForMcpResource(error, uri.toString());
}
});
// Detail resource
server.resource("lokalise-glossary-term-details", new ResourceTemplate("lokalise://glossary-terms/{projectId}/{termId}", {
list: undefined,
}), {
description: "Get comprehensive details about a specific glossary term including all translations, properties (case-sensitive, translatable, forbidden), tags, and usage context. Use this to understand how a term should be handled across different languages.",
}, async (uri) => {
try {
const pathParts = uri.pathname.split("/").filter(Boolean);
if (pathParts.length !== 3 || pathParts[0] !== "glossary-terms") {
throw new Error("Invalid resource URI. Expected lokalise://glossary-terms/<project-id>/<term-id>");
}
return await handleDetailResource(pathParts[1], pathParts[2]);
}
catch (error) {
logger.error("Failed to handle glossary term detail resource", {
error,
uri: uri.toString(),
});
return formatErrorForMcpResource(error, uri.toString());
}
});
registerLogger.debug("Glossary domain resources registered successfully");
}
/**
* Get metadata about the glossary domain resources
*/
function getMeta() {
return {
name: "glossary",
description: "Glossary terms management for consistent translations MCP resources",
version: "1.0.0",
resourcesCount: 2,
};
}
const glossaryResource = {
registerResources,
getMeta,
};
export default glossaryResource;