UNPKG

@translated/lara-mcp

Version:

Lara API official MCP server

219 lines (218 loc) 9.15 kB
#!/usr/bin/env node import { Server } from "@modelcontextprotocol/sdk/server/index.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { CallToolRequestSchema, ListResourcesRequestSchema, ListToolsRequestSchema, ReadResourceRequestSchema, } from "@modelcontextprotocol/sdk/types.js"; import { Credentials, Translator } from "@translated/lara"; import { z } from "zod"; import { zodToJsonSchema } from "zod-to-json-schema"; import { translateHandler, translateSchema } from "./tools/translate.js"; import { listMemories, listMemoriesSchema, } from "./tools/list_memories.js"; import { listLanguages, listLanguagesSchema } from "./tools/list_languages.js"; import { addTranslationSchema, addTranslation, } from "./tools/add_translation.js"; import { createMemorySchema, createMemory, } from "./tools/create_memory.js"; import { deleteMemorySchema, deleteMemory, } from "./tools/delete_memory.js"; import { deleteTranslationSchema, deleteTranslation, } from "./tools/delete_translation.js"; import { updateMemorySchema, updateMemory, } from "./tools/update_memory.tool.js"; import { importTmx, importTmxSchema } from "./tools/import_tmx.js"; import { checkImportStatus, checkImportStatusSchema, } from "./tools/check_import_status.js"; const LARA_ACCESS_KEY_ID = process.env.LARA_ACCESS_KEY_ID; const LARA_ACCESS_KEY_SECRET = process.env.LARA_ACCESS_KEY_SECRET; if (!LARA_ACCESS_KEY_ID || !LARA_ACCESS_KEY_SECRET) { throw new Error("LARA_ACCESS_KEY_ID and LARA_ACCESS_KEY_SECRET must be set"); } const credentials = new Credentials(LARA_ACCESS_KEY_ID, LARA_ACCESS_KEY_SECRET); const lara = new Translator(credentials); const server = new Server({ name: "Lara Translate", version: "0.0.10", }, { capabilities: { tools: {}, resources: {} }, }); server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: [ { name: "translate", description: "Translate text between languages with support for language detection, context-aware translations and translation memories using Lara Translate.", inputSchema: zodToJsonSchema(translateSchema), }, { name: "create_memory", description: "Create a translation memory with a custom name in your Lara Translate account. Translation memories store pairs of source and target text segments (translation units) for reuse in future translations.", inputSchema: zodToJsonSchema(createMemorySchema), }, { name: "delete_memory", description: "Deletes a translation memory from your Lara Translate account.", inputSchema: zodToJsonSchema(deleteMemorySchema), }, { name: "update_memory", description: "Updates a translation memory in your Lara Translate account.", inputSchema: zodToJsonSchema(updateMemorySchema), }, { name: "add_translation", description: "Adds a translation to a translation memory in your Lara Translate account.", inputSchema: zodToJsonSchema(addTranslationSchema), }, { name: "delete_translation", description: "Deletes a translation from a translation memory from your Lara Translate account.", inputSchema: zodToJsonSchema(deleteTranslationSchema), }, { name: "import_tmx", description: "Imports a TMX file into a translation memory in your Lara Translate account.", inputSchema: zodToJsonSchema(importTmxSchema), }, { name: "check_import_status", description: "Checks the status of a TMX file import job in your Lara Translate account.", inputSchema: zodToJsonSchema(checkImportStatusSchema), }, { name: "list_memories", description: "Lists all translation memories in your Lara Translate account.", inputSchema: zodToJsonSchema(listMemoriesSchema), }, { name: "list_languages", description: "Lists all supported languages in your Lara Translate account.", inputSchema: zodToJsonSchema(listLanguagesSchema), }, ], }; }); server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; try { switch (name) { case "translate": { const result = await translateHandler(args, lara); return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }], }; } case "create_memory": { const result = await createMemory(args, lara); return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }], }; } case "delete_memory": { const result = await deleteMemory(args, lara); return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }], }; } case "update_memory": { const result = await updateMemory(args, lara); return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }], }; } case "add_translation": { const result = await addTranslation(args, lara); return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }], }; } case "delete_translation": { const result = await deleteTranslation(args, lara); return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }], }; } case "import_tmx": { const result = await importTmx(args, lara); return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }], }; } case "check_import_status": { const result = await checkImportStatus(args, lara); return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }], }; } case "list_memories": { const result = await listMemories(lara); return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }], }; } case "list_languages": { const result = await listLanguages(lara); return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }], }; } default: throw new Error(`Unknown tool: ${name}`); } } catch (error) { if (error instanceof z.ZodError) { throw new Error(`Invalid input: ${JSON.stringify(error.errors)}`); } throw error; } }); server.setRequestHandler(ListResourcesRequestSchema, async () => { return { resources: [ { name: "Translation Memories", description: "List of translation memories in your Lara Translate account.", uri: "memories://list", }, { name: "Supported Languages", description: "List of Lara Translate supported languages.", uri: "languages://list", } ], }; }); server.setRequestHandler(ReadResourceRequestSchema, async (request) => { const { uri } = request.params; try { switch (uri) { case "memories://list": { const memories = await listMemories(lara); return { contents: [{ uri: uri, text: JSON.stringify(memories, null, 2) }] }; } case "languages://list": { const languages = await listLanguages(lara); return { contents: [{ uri: uri, text: JSON.stringify(languages, null, 2) }] }; } default: throw new Error(`Unknown resource: ${uri}`); } } catch (error) { if (error instanceof z.ZodError) { throw new Error(`Invalid input: ${JSON.stringify(error.errors)}`); } throw error; } }); const transport = new StdioServerTransport(); server.connect(transport).catch((error) => { console.error("Server error:", error); process.exit(1); });