@pipeworx/mcp-libretranslate 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Pipeworx
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,57 @@
1
+ # mcp-libretranslate
2
+
3
+ LibreTranslate MCP — open-source machine translation (BYO endpoint)
4
+
5
+ Part of [Pipeworx](https://pipeworx.io) — an MCP gateway connecting AI agents to 250+ live data sources.
6
+
7
+ ## Tools
8
+
9
+ | Tool | Description |
10
+ |------|-------------|
11
+ | `detect_language` | Detect the source language of a piece of text. Returns ranked language candidates with confidence. |
12
+ | `list_languages` | List languages supported by the configured LibreTranslate instance. |
13
+
14
+ ## Quick Start
15
+
16
+ Add to your MCP client (Claude Desktop, Cursor, Windsurf, etc.):
17
+
18
+ ```json
19
+ {
20
+ "mcpServers": {
21
+ "libretranslate": {
22
+ "url": "https://gateway.pipeworx.io/libretranslate/mcp"
23
+ }
24
+ }
25
+ }
26
+ ```
27
+
28
+ Or connect to the full Pipeworx gateway for access to all 250+ data sources:
29
+
30
+ ```json
31
+ {
32
+ "mcpServers": {
33
+ "pipeworx": {
34
+ "url": "https://gateway.pipeworx.io/mcp"
35
+ }
36
+ }
37
+ }
38
+ ```
39
+
40
+ ## Using with ask_pipeworx
41
+
42
+ Instead of calling tools directly, you can ask questions in plain English:
43
+
44
+ ```
45
+ ask_pipeworx({ question: "your question about Libretranslate data" })
46
+ ```
47
+
48
+ The gateway picks the right tool and fills the arguments automatically.
49
+
50
+ ## More
51
+
52
+ - [All tools and guides](https://github.com/pipeworx-io/examples)
53
+ - [pipeworx.io](https://pipeworx.io)
54
+
55
+ ## License
56
+
57
+ MIT
package/package.json ADDED
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "@pipeworx/mcp-libretranslate",
3
+ "version": "0.1.0",
4
+ "description": "LibreTranslate MCP — open-source machine translation (BYO endpoint)",
5
+ "type": "module",
6
+ "main": "src/index.ts",
7
+ "types": "src/index.ts",
8
+ "keywords": ["mcp", "mcp-server", "model-context-protocol", "pipeworx", "libretranslate"],
9
+ "license": "MIT",
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "https://github.com/pipeworx-io/mcp-libretranslate"
13
+ },
14
+ "scripts": {
15
+ "typecheck": "tsc --noEmit"
16
+ },
17
+ "devDependencies": {
18
+ "typescript": "^5.7.0"
19
+ }
20
+ }
package/server.json ADDED
@@ -0,0 +1,18 @@
1
+ {
2
+ "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
3
+ "name": "io.github.pipeworx-io/libretranslate",
4
+ "title": "Libretranslate",
5
+ "description": "LibreTranslate MCP — open-source machine translation (BYO endpoint)",
6
+ "version": "0.1.0",
7
+ "websiteUrl": "https://pipeworx.io/packs/libretranslate",
8
+ "repository": {
9
+ "url": "https://github.com/pipeworx-io/mcp-libretranslate",
10
+ "source": "github"
11
+ },
12
+ "remotes": [
13
+ {
14
+ "type": "streamable-http",
15
+ "url": "https://gateway.pipeworx.io/libretranslate/mcp"
16
+ }
17
+ ]
18
+ }
package/src/index.ts ADDED
@@ -0,0 +1,189 @@
1
+ interface McpToolDefinition {
2
+ name: string;
3
+ description: string;
4
+ inputSchema: {
5
+ type: 'object';
6
+ properties: Record<string, unknown>;
7
+ required?: string[];
8
+ };
9
+ }
10
+
11
+ interface McpToolExport {
12
+ tools: McpToolDefinition[];
13
+ callTool: (name: string, args: Record<string, unknown>) => Promise<unknown>;
14
+ meter?: { credits: number };
15
+ cost?: Record<string, unknown>;
16
+ provider?: string;
17
+ }
18
+
19
+ /**
20
+ * LibreTranslate MCP — open-source machine translation (BYO endpoint)
21
+ *
22
+ * Important: the free public LibreTranslate instances have largely shut down
23
+ * or migrated to paid plans. This pack is a thin abstraction — you point it
24
+ * at any LibreTranslate-compatible instance:
25
+ * - self-hosted (https://github.com/LibreTranslate/LibreTranslate)
26
+ * - paid: https://libretranslate.com (BYO their API key)
27
+ * - a community instance that's still up
28
+ *
29
+ * API (LibreTranslate v1): https://github.com/LibreTranslate/LibreTranslate#api
30
+ *
31
+ * Tools:
32
+ * - translate: translate text between languages
33
+ * - detect_language: detect source language of a text
34
+ * - list_languages: languages supported by the configured instance
35
+ */
36
+
37
+
38
+ const tools: McpToolExport['tools'] = [
39
+ {
40
+ name: 'translate',
41
+ description:
42
+ 'Translate text. Source can be "auto" to auto-detect. Returns translated text and the detected source (if applicable).',
43
+ inputSchema: {
44
+ type: 'object',
45
+ properties: {
46
+ text: { type: 'string', description: 'Text to translate' },
47
+ source: { type: 'string', description: 'Source language code or "auto" (default "auto")' },
48
+ target: { type: 'string', description: 'Target language code (e.g., "es", "fr", "ja")' },
49
+ format: { type: 'string', description: 'text (default) | html', enum: ['text', 'html'] },
50
+ },
51
+ required: ['text', 'target'],
52
+ },
53
+ },
54
+ {
55
+ name: 'detect_language',
56
+ description: 'Detect the source language of a piece of text. Returns ranked language candidates with confidence.',
57
+ inputSchema: {
58
+ type: 'object',
59
+ properties: {
60
+ text: { type: 'string', description: 'Text to analyze' },
61
+ },
62
+ required: ['text'],
63
+ },
64
+ },
65
+ {
66
+ name: 'list_languages',
67
+ description: 'List languages supported by the configured LibreTranslate instance.',
68
+ inputSchema: { type: 'object', properties: {}, required: [] },
69
+ },
70
+ ];
71
+
72
+ async function callTool(name: string, args: Record<string, unknown>): Promise<unknown> {
73
+ const endpoint = resolveEndpoint(args);
74
+ const apiKey = (args._apiKey as string | undefined)?.trim();
75
+
76
+ switch (name) {
77
+ case 'translate':
78
+ return translate(
79
+ endpoint,
80
+ apiKey,
81
+ reqStr(args, 'text', '"hello world"'),
82
+ (args.source as string) ?? 'auto',
83
+ reqStr(args, 'target', '"es"'),
84
+ (args.format as string) ?? 'text',
85
+ );
86
+ case 'detect_language':
87
+ return detectLanguage(endpoint, apiKey, reqStr(args, 'text', '"bonjour le monde"'));
88
+ case 'list_languages':
89
+ return listLanguages(endpoint, apiKey);
90
+ default:
91
+ throw new Error(`Unknown tool: ${name}`);
92
+ }
93
+ }
94
+
95
+ function reqStr(args: Record<string, unknown>, key: string, example: string): string {
96
+ const v = args[key];
97
+ if (typeof v !== 'string' || !v.trim()) {
98
+ throw new Error(`Required argument "${key}" is missing or empty. Pass a string like ${example}.`);
99
+ }
100
+ return v;
101
+ }
102
+
103
+ function resolveEndpoint(args: Record<string, unknown>): string {
104
+ const ep = (args._endpoint as string | undefined)?.trim();
105
+ if (!ep) {
106
+ throw new Error(
107
+ 'LibreTranslate requires a LibreTranslate-compatible endpoint URL. Set it via the gateway PLATFORM_LIBRETRANSLATE_ENDPOINT env var, or pass ?_endpoint=https://your-instance/ on the gateway URL. Public free instances have largely shut down — self-host or use libretranslate.com (paid).',
108
+ );
109
+ }
110
+ return ep.replace(/\/+$/, '');
111
+ }
112
+
113
+ async function ltPost<T>(endpoint: string, path: string, body: Record<string, string>, apiKey?: string): Promise<T> {
114
+ const params = new URLSearchParams(body);
115
+ if (apiKey) params.set('api_key', apiKey);
116
+
117
+ const res = await fetch(`${endpoint}${path}`, {
118
+ method: 'POST',
119
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded', Accept: 'application/json' },
120
+ body: params.toString(),
121
+ });
122
+ if (res.status === 401 || res.status === 403) throw new Error('LibreTranslate: unauthorized — check the API key');
123
+ if (res.status === 429) throw new Error('LibreTranslate: rate-limit (HTTP 429)');
124
+ if (!res.ok) {
125
+ const text = await res.text();
126
+ throw new Error(`LibreTranslate error: ${res.status} ${text.slice(0, 200)}`);
127
+ }
128
+ return res.json() as Promise<T>;
129
+ }
130
+
131
+ async function ltGet<T>(endpoint: string, path: string, apiKey?: string): Promise<T> {
132
+ const url = apiKey ? `${endpoint}${path}?api_key=${encodeURIComponent(apiKey)}` : `${endpoint}${path}`;
133
+ const res = await fetch(url, { headers: { Accept: 'application/json' } });
134
+ if (!res.ok) {
135
+ const text = await res.text();
136
+ throw new Error(`LibreTranslate error: ${res.status} ${text.slice(0, 200)}`);
137
+ }
138
+ return res.json() as Promise<T>;
139
+ }
140
+
141
+ async function translate(
142
+ endpoint: string,
143
+ apiKey: string | undefined,
144
+ text: string,
145
+ source: string,
146
+ target: string,
147
+ format: string,
148
+ ) {
149
+ const data = await ltPost<{ translatedText?: string; detectedLanguage?: { confidence?: number; language?: string } }>(
150
+ endpoint,
151
+ '/translate',
152
+ { q: text, source, target, format },
153
+ apiKey,
154
+ );
155
+ return {
156
+ text,
157
+ source,
158
+ target,
159
+ format,
160
+ translated_text: data.translatedText ?? null,
161
+ detected_source: data.detectedLanguage?.language ?? null,
162
+ detected_confidence: data.detectedLanguage?.confidence ?? null,
163
+ };
164
+ }
165
+
166
+ async function detectLanguage(endpoint: string, apiKey: string | undefined, text: string) {
167
+ const data = await ltPost<{ language?: string; confidence?: number }[]>(endpoint, '/detect', { q: text }, apiKey);
168
+ return {
169
+ text,
170
+ candidates: (Array.isArray(data) ? data : []).map((d) => ({
171
+ language: d.language ?? null,
172
+ confidence: d.confidence ?? null,
173
+ })),
174
+ };
175
+ }
176
+
177
+ async function listLanguages(endpoint: string, apiKey: string | undefined) {
178
+ const data = await ltGet<{ code?: string; name?: string; targets?: string[] }[]>(endpoint, '/languages', apiKey);
179
+ return {
180
+ count: data.length,
181
+ languages: data.map((l) => ({
182
+ code: l.code ?? null,
183
+ name: l.name ?? null,
184
+ target_codes: l.targets ?? [],
185
+ })),
186
+ };
187
+ }
188
+
189
+ export default { tools, callTool, meter: { credits: 1 } } satisfies McpToolExport;
package/tsconfig.json ADDED
@@ -0,0 +1,14 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "strict": true,
7
+ "esModuleInterop": true,
8
+ "skipLibCheck": true,
9
+ "outDir": "dist",
10
+ "rootDir": "src",
11
+ "declaration": true
12
+ },
13
+ "include": ["src"]
14
+ }