@i18n-agent/mcp-client 1.8.401 → 1.8.403
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/mcp-client.js +421 -1
- package/package.json +1 -1
package/mcp-client.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Integrates with Claude Code CLI to provide translation capabilities
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
const MCP_CLIENT_VERSION = '1.8.
|
|
8
|
+
const MCP_CLIENT_VERSION = '1.8.403';
|
|
9
9
|
|
|
10
10
|
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
11
11
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
@@ -373,6 +373,82 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
373
373
|
required: ['jobId'],
|
|
374
374
|
},
|
|
375
375
|
},
|
|
376
|
+
{
|
|
377
|
+
name: 'upload_translations',
|
|
378
|
+
description: 'Upload existing translations for reuse to reduce translation costs. Supports two modes: (1) Single file mode - upload a translated i18n file (JSON, YAML, PO, XLIFF, etc.) using filePath/fileContent params. (2) Parallel document mode - upload source + target document pairs (MD, TXT, HTML) using sourceFilePath/targetFilePath params for sentence-aligned extraction. Namespace is auto-detected from file path or can be explicitly provided.',
|
|
379
|
+
inputSchema: {
|
|
380
|
+
type: 'object',
|
|
381
|
+
properties: {
|
|
382
|
+
// Single file mode parameters
|
|
383
|
+
filePath: {
|
|
384
|
+
type: 'string',
|
|
385
|
+
description: 'Path to translated i18n file (for single file mode). Use this OR sourceFilePath/targetFilePath.',
|
|
386
|
+
},
|
|
387
|
+
fileContent: {
|
|
388
|
+
type: 'string',
|
|
389
|
+
description: 'File content as string (for single file mode, required if filePath is not provided)',
|
|
390
|
+
},
|
|
391
|
+
// Parallel document mode parameters
|
|
392
|
+
sourceFilePath: {
|
|
393
|
+
type: 'string',
|
|
394
|
+
description: 'Path to source language document (for parallel mode). Use with targetFilePath.',
|
|
395
|
+
},
|
|
396
|
+
sourceFileContent: {
|
|
397
|
+
type: 'string',
|
|
398
|
+
description: 'Source document content as string (for parallel mode)',
|
|
399
|
+
},
|
|
400
|
+
targetFilePath: {
|
|
401
|
+
type: 'string',
|
|
402
|
+
description: 'Path to target language document (for parallel mode). Use with sourceFilePath.',
|
|
403
|
+
},
|
|
404
|
+
targetFileContent: {
|
|
405
|
+
type: 'string',
|
|
406
|
+
description: 'Target document content as string (for parallel mode)',
|
|
407
|
+
},
|
|
408
|
+
// Common parameters
|
|
409
|
+
fileType: {
|
|
410
|
+
type: 'string',
|
|
411
|
+
description: 'File format. Single file mode: json, yaml, yml, po, pot, mo, xml, arb, strings, stringsdict, plist, properties, xliff, xlf, resx. Parallel mode: md, markdown, txt, html, htm, json, yaml, yml. Default: auto',
|
|
412
|
+
default: 'auto',
|
|
413
|
+
},
|
|
414
|
+
sourceLocale: {
|
|
415
|
+
type: 'string',
|
|
416
|
+
description: 'Source language code (e.g., "en", "en-US")',
|
|
417
|
+
},
|
|
418
|
+
targetLocale: {
|
|
419
|
+
type: 'string',
|
|
420
|
+
description: 'Target language code (e.g., "es", "fr", "ja")',
|
|
421
|
+
},
|
|
422
|
+
namespace: {
|
|
423
|
+
type: 'string',
|
|
424
|
+
description: 'Namespace identifier for translation tracking (auto-detected from file path if not provided)',
|
|
425
|
+
},
|
|
426
|
+
},
|
|
427
|
+
required: ['sourceLocale', 'targetLocale'],
|
|
428
|
+
},
|
|
429
|
+
},
|
|
430
|
+
{
|
|
431
|
+
name: 'list_uploaded_translations',
|
|
432
|
+
description: 'List all uploaded translation files in a namespace, showing file names, language pairs, translation counts, and upload dates. Helps track what translations are available for reuse.',
|
|
433
|
+
inputSchema: {
|
|
434
|
+
type: 'object',
|
|
435
|
+
properties: {
|
|
436
|
+
namespace: {
|
|
437
|
+
type: 'string',
|
|
438
|
+
description: 'Namespace identifier',
|
|
439
|
+
},
|
|
440
|
+
sourceLocale: {
|
|
441
|
+
type: 'string',
|
|
442
|
+
description: 'Filter by source language (optional)',
|
|
443
|
+
},
|
|
444
|
+
targetLocale: {
|
|
445
|
+
type: 'string',
|
|
446
|
+
description: 'Filter by target language (optional)',
|
|
447
|
+
},
|
|
448
|
+
},
|
|
449
|
+
required: ['namespace'],
|
|
450
|
+
},
|
|
451
|
+
},
|
|
376
452
|
],
|
|
377
453
|
};
|
|
378
454
|
});
|
|
@@ -413,6 +489,12 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
413
489
|
case 'download_translations':
|
|
414
490
|
return await handleDownloadTranslations(args);
|
|
415
491
|
|
|
492
|
+
case 'upload_translations':
|
|
493
|
+
return await handleUploadTranslations(args);
|
|
494
|
+
|
|
495
|
+
case 'list_uploaded_translations':
|
|
496
|
+
return await handleListUploadedTranslations(args);
|
|
497
|
+
|
|
416
498
|
default:
|
|
417
499
|
throw new McpError(
|
|
418
500
|
ErrorCode.MethodNotFound,
|
|
@@ -1873,6 +1955,344 @@ async function handleDownloadTranslations(args) {
|
|
|
1873
1955
|
}
|
|
1874
1956
|
}
|
|
1875
1957
|
|
|
1958
|
+
async function handleUploadTranslations(args) {
|
|
1959
|
+
const {
|
|
1960
|
+
// Single file mode
|
|
1961
|
+
filePath,
|
|
1962
|
+
fileContent,
|
|
1963
|
+
// Parallel document mode
|
|
1964
|
+
sourceFilePath,
|
|
1965
|
+
sourceFileContent,
|
|
1966
|
+
targetFilePath,
|
|
1967
|
+
targetFileContent,
|
|
1968
|
+
// Common
|
|
1969
|
+
fileType = 'auto',
|
|
1970
|
+
sourceLocale,
|
|
1971
|
+
targetLocale,
|
|
1972
|
+
namespace
|
|
1973
|
+
} = args;
|
|
1974
|
+
|
|
1975
|
+
if (!sourceLocale || !targetLocale) {
|
|
1976
|
+
throw new Error('sourceLocale and targetLocale are required');
|
|
1977
|
+
}
|
|
1978
|
+
|
|
1979
|
+
// Detect mode based on parameters provided
|
|
1980
|
+
const hasParallelParams = sourceFilePath || sourceFileContent || targetFilePath || targetFileContent;
|
|
1981
|
+
const hasSingleFileParams = filePath || fileContent;
|
|
1982
|
+
|
|
1983
|
+
if (hasParallelParams && hasSingleFileParams) {
|
|
1984
|
+
throw new Error('Cannot mix single file mode (filePath/fileContent) with parallel mode (sourceFilePath/targetFilePath). Use one mode at a time.');
|
|
1985
|
+
}
|
|
1986
|
+
|
|
1987
|
+
if (!hasParallelParams && !hasSingleFileParams) {
|
|
1988
|
+
throw new Error('Either provide filePath/fileContent (single file mode) OR sourceFilePath/targetFilePath (parallel document mode)');
|
|
1989
|
+
}
|
|
1990
|
+
|
|
1991
|
+
// Route to appropriate handler
|
|
1992
|
+
if (hasParallelParams) {
|
|
1993
|
+
return await handleParallelDocumentUpload(args);
|
|
1994
|
+
} else {
|
|
1995
|
+
return await handleSingleFileUpload(args);
|
|
1996
|
+
}
|
|
1997
|
+
}
|
|
1998
|
+
|
|
1999
|
+
// Single file upload handler (for translated i18n files)
|
|
2000
|
+
async function handleSingleFileUpload(args) {
|
|
2001
|
+
const {
|
|
2002
|
+
filePath,
|
|
2003
|
+
fileContent,
|
|
2004
|
+
fileType = 'auto',
|
|
2005
|
+
sourceLocale,
|
|
2006
|
+
targetLocale,
|
|
2007
|
+
namespace
|
|
2008
|
+
} = args;
|
|
2009
|
+
|
|
2010
|
+
if (!filePath && !fileContent) {
|
|
2011
|
+
throw new Error('Either filePath or fileContent must be provided');
|
|
2012
|
+
}
|
|
2013
|
+
|
|
2014
|
+
// Auto-detect namespace if not provided
|
|
2015
|
+
let finalNamespace = namespace;
|
|
2016
|
+
let detectionInfo = null;
|
|
2017
|
+
|
|
2018
|
+
if (!namespace && filePath) {
|
|
2019
|
+
const detection = detectNamespaceFromPath(filePath);
|
|
2020
|
+
if (detection.suggestion && detection.confidence > 0.5) {
|
|
2021
|
+
finalNamespace = detection.suggestion;
|
|
2022
|
+
detectionInfo = detection;
|
|
2023
|
+
console.error(`🎯 [MCP CLIENT] Auto-detected namespace: "${finalNamespace}" (confidence: ${Math.round(detection.confidence * 100)}%, source: ${detection.source})`);
|
|
2024
|
+
}
|
|
2025
|
+
}
|
|
2026
|
+
|
|
2027
|
+
if (!finalNamespace) {
|
|
2028
|
+
const suggestionText = filePath
|
|
2029
|
+
? getNamespaceSuggestionText(filePath, path.basename(filePath))
|
|
2030
|
+
: getNamespaceSuggestionText(null, null);
|
|
2031
|
+
|
|
2032
|
+
throw new Error(`namespace is required for translation upload.\n\n${suggestionText}`);
|
|
2033
|
+
}
|
|
2034
|
+
|
|
2035
|
+
// Read file content if path provided
|
|
2036
|
+
let content = fileContent;
|
|
2037
|
+
if (filePath && !fileContent) {
|
|
2038
|
+
try {
|
|
2039
|
+
content = fs.readFileSync(filePath, 'utf8');
|
|
2040
|
+
} catch (error) {
|
|
2041
|
+
throw new Error(`Failed to read file: ${error.message}`);
|
|
2042
|
+
}
|
|
2043
|
+
}
|
|
2044
|
+
|
|
2045
|
+
// Detect file type if auto
|
|
2046
|
+
const detectedFileType = fileType === 'auto' ? path.extname(filePath || 'file').slice(1) || 'json' : fileType;
|
|
2047
|
+
|
|
2048
|
+
// Build request to backend endpoint
|
|
2049
|
+
const requestData = {
|
|
2050
|
+
apiKey: API_KEY,
|
|
2051
|
+
namespace: finalNamespace,
|
|
2052
|
+
fileName: filePath ? path.basename(filePath) : 'uploaded-file',
|
|
2053
|
+
fileContent: content,
|
|
2054
|
+
fileType: detectedFileType,
|
|
2055
|
+
sourceLocale,
|
|
2056
|
+
targetLocale
|
|
2057
|
+
};
|
|
2058
|
+
|
|
2059
|
+
try {
|
|
2060
|
+
const response = await axios.post(`${MCP_SERVER_URL.replace('/mcp', '')}/namespaces/${finalNamespace}/translations/upload`,
|
|
2061
|
+
requestData.fileContent,
|
|
2062
|
+
{
|
|
2063
|
+
headers: {
|
|
2064
|
+
'Content-Type': 'text/plain',
|
|
2065
|
+
'X-API-Key': API_KEY,
|
|
2066
|
+
'X-Source-Locale': sourceLocale,
|
|
2067
|
+
'X-Target-Locale': targetLocale,
|
|
2068
|
+
'X-File-Name': requestData.fileName,
|
|
2069
|
+
'X-File-Type': detectedFileType
|
|
2070
|
+
},
|
|
2071
|
+
timeout: 60000
|
|
2072
|
+
}
|
|
2073
|
+
);
|
|
2074
|
+
|
|
2075
|
+
if (response.data.error) {
|
|
2076
|
+
throw new Error(`Upload error: ${response.data.error.message || response.data.error}`);
|
|
2077
|
+
}
|
|
2078
|
+
|
|
2079
|
+
const result = response.data;
|
|
2080
|
+
|
|
2081
|
+
return {
|
|
2082
|
+
content: [{
|
|
2083
|
+
type: 'text',
|
|
2084
|
+
text: `✅ Translation Upload Successful\n\n` +
|
|
2085
|
+
`📂 Namespace: ${finalNamespace}${detectionInfo ? ` (auto-detected)` : ''}\n` +
|
|
2086
|
+
`📄 File: ${requestData.fileName}\n` +
|
|
2087
|
+
`🌍 Languages: ${sourceLocale} → ${targetLocale}\n` +
|
|
2088
|
+
`✨ Translation Pairs Stored: ${result.pairsStored || 0}\n` +
|
|
2089
|
+
`🔄 Translation Pairs Updated: ${result.pairsUpdated || 0}\n\n` +
|
|
2090
|
+
`💡 These translations will be automatically reused when translating files in the "${finalNamespace}" namespace, reducing costs and ensuring consistency.`
|
|
2091
|
+
}]
|
|
2092
|
+
};
|
|
2093
|
+
} catch (error) {
|
|
2094
|
+
console.error('Upload translations error:', error);
|
|
2095
|
+
|
|
2096
|
+
// Handle 401 unauthorized
|
|
2097
|
+
if (error.response?.status === 401) {
|
|
2098
|
+
throw new Error(`❌ Invalid API key (401)\nPlease check your API key at https://app.i18nagent.ai`);
|
|
2099
|
+
}
|
|
2100
|
+
|
|
2101
|
+
// Handle 404 namespace not found
|
|
2102
|
+
if (error.response?.status === 404) {
|
|
2103
|
+
throw new Error(`❌ Namespace "${finalNamespace}" not found. Create it first by translating a file with this namespace.`);
|
|
2104
|
+
}
|
|
2105
|
+
|
|
2106
|
+
// Handle 409 duplicate
|
|
2107
|
+
if (error.response?.status === 409) {
|
|
2108
|
+
const errorData = error.response.data;
|
|
2109
|
+
throw new Error(`⚠️ Duplicate file detected\n${errorData.message || 'This file was already uploaded'}`);
|
|
2110
|
+
}
|
|
2111
|
+
|
|
2112
|
+
throw new Error(`Unable to upload translations: ${error.message}`);
|
|
2113
|
+
}
|
|
2114
|
+
}
|
|
2115
|
+
|
|
2116
|
+
// Parallel document upload handler (for source + target document pairs)
|
|
2117
|
+
async function handleParallelDocumentUpload(args) {
|
|
2118
|
+
const {
|
|
2119
|
+
sourceFilePath,
|
|
2120
|
+
sourceFileContent,
|
|
2121
|
+
targetFilePath,
|
|
2122
|
+
targetFileContent,
|
|
2123
|
+
fileType = 'auto',
|
|
2124
|
+
sourceLocale,
|
|
2125
|
+
targetLocale,
|
|
2126
|
+
namespace
|
|
2127
|
+
} = args;
|
|
2128
|
+
|
|
2129
|
+
// Validation
|
|
2130
|
+
if (!sourceFilePath && !sourceFileContent) {
|
|
2131
|
+
throw new Error('Either sourceFilePath or sourceFileContent must be provided');
|
|
2132
|
+
}
|
|
2133
|
+
if (!targetFilePath && !targetFileContent) {
|
|
2134
|
+
throw new Error('Either targetFilePath or targetFileContent must be provided');
|
|
2135
|
+
}
|
|
2136
|
+
|
|
2137
|
+
// Auto-detect namespace (prefer source file path)
|
|
2138
|
+
let finalNamespace = namespace;
|
|
2139
|
+
if (!namespace && sourceFilePath) {
|
|
2140
|
+
const detection = detectNamespaceFromPath(sourceFilePath);
|
|
2141
|
+
if (detection.suggestion && detection.confidence > 0.5) {
|
|
2142
|
+
finalNamespace = detection.suggestion;
|
|
2143
|
+
console.error(`🎯 [MCP CLIENT] Auto-detected namespace: "${finalNamespace}"`);
|
|
2144
|
+
}
|
|
2145
|
+
}
|
|
2146
|
+
|
|
2147
|
+
if (!finalNamespace) {
|
|
2148
|
+
const suggestionText = getNamespaceSuggestionText(sourceFilePath || targetFilePath, null);
|
|
2149
|
+
throw new Error(`namespace is required for parallel document upload.\n\n${suggestionText}`);
|
|
2150
|
+
}
|
|
2151
|
+
|
|
2152
|
+
// Read files
|
|
2153
|
+
let sourceContent = sourceFileContent;
|
|
2154
|
+
let targetContent = targetFileContent;
|
|
2155
|
+
|
|
2156
|
+
if (sourceFilePath && !sourceFileContent) {
|
|
2157
|
+
sourceContent = fs.readFileSync(sourceFilePath, 'utf8');
|
|
2158
|
+
}
|
|
2159
|
+
if (targetFilePath && !targetFileContent) {
|
|
2160
|
+
targetContent = fs.readFileSync(targetFilePath, 'utf8');
|
|
2161
|
+
}
|
|
2162
|
+
|
|
2163
|
+
// Detect file type
|
|
2164
|
+
const detectedFileType = fileType === 'auto'
|
|
2165
|
+
? path.extname(sourceFilePath || 'file').slice(1) || 'md'
|
|
2166
|
+
: fileType;
|
|
2167
|
+
|
|
2168
|
+
// Build request
|
|
2169
|
+
const formData = new FormData();
|
|
2170
|
+
formData.append('sourceFile', new Blob([sourceContent]), sourceFilePath ? path.basename(sourceFilePath) : 'source.md');
|
|
2171
|
+
formData.append('targetFile', new Blob([targetContent]), targetFilePath ? path.basename(targetFilePath) : 'target.md');
|
|
2172
|
+
formData.append('sourceLanguage', sourceLocale);
|
|
2173
|
+
formData.append('targetLanguage', targetLocale);
|
|
2174
|
+
formData.append('namespace', finalNamespace);
|
|
2175
|
+
|
|
2176
|
+
try {
|
|
2177
|
+
const response = await axios.post(`${MCP_SERVER_URL.replace('/mcp', '')}/translations/upload-parallel`,
|
|
2178
|
+
formData,
|
|
2179
|
+
{
|
|
2180
|
+
headers: {
|
|
2181
|
+
'X-API-Key': API_KEY,
|
|
2182
|
+
...formData.getHeaders()
|
|
2183
|
+
},
|
|
2184
|
+
timeout: 120000
|
|
2185
|
+
}
|
|
2186
|
+
);
|
|
2187
|
+
|
|
2188
|
+
if (response.data.error) {
|
|
2189
|
+
throw new Error(`Upload error: ${response.data.error.message || response.data.error}`);
|
|
2190
|
+
}
|
|
2191
|
+
|
|
2192
|
+
const result = response.data;
|
|
2193
|
+
|
|
2194
|
+
return {
|
|
2195
|
+
content: [{
|
|
2196
|
+
type: 'text',
|
|
2197
|
+
text: `✅ Parallel Document Upload Successful\n\n` +
|
|
2198
|
+
`📂 Namespace: ${finalNamespace}\n` +
|
|
2199
|
+
`📄 Source: ${sourceFilePath ? path.basename(sourceFilePath) : 'source content'}\n` +
|
|
2200
|
+
`📄 Target: ${targetFilePath ? path.basename(targetFilePath) : 'target content'}\n` +
|
|
2201
|
+
`🌍 Languages: ${sourceLocale} → ${targetLocale}\n` +
|
|
2202
|
+
`✨ Translation Pairs Extracted: ${result.pairsStored || 0}\n` +
|
|
2203
|
+
`🔄 Translation Pairs Updated: ${result.pairsUpdated || 0}\n\n` +
|
|
2204
|
+
`💡 These aligned translations will be automatically reused when translating similar documents.`
|
|
2205
|
+
}]
|
|
2206
|
+
};
|
|
2207
|
+
} catch (error) {
|
|
2208
|
+
console.error('Upload parallel documents error:', error);
|
|
2209
|
+
|
|
2210
|
+
if (error.response?.status === 401) {
|
|
2211
|
+
throw new Error(`❌ Invalid API key (401)`);
|
|
2212
|
+
}
|
|
2213
|
+
|
|
2214
|
+
if (error.response?.status === 404) {
|
|
2215
|
+
throw new Error(`❌ Namespace "${finalNamespace}" not found`);
|
|
2216
|
+
}
|
|
2217
|
+
|
|
2218
|
+
throw new Error(`Unable to upload parallel documents: ${error.message}`);
|
|
2219
|
+
}
|
|
2220
|
+
}
|
|
2221
|
+
|
|
2222
|
+
async function handleListUploadedTranslations(args) {
|
|
2223
|
+
const {
|
|
2224
|
+
namespace,
|
|
2225
|
+
sourceLocale,
|
|
2226
|
+
targetLocale
|
|
2227
|
+
} = args;
|
|
2228
|
+
|
|
2229
|
+
if (!namespace) {
|
|
2230
|
+
throw new Error('namespace is required');
|
|
2231
|
+
}
|
|
2232
|
+
|
|
2233
|
+
// Build query parameters
|
|
2234
|
+
const params = new URLSearchParams();
|
|
2235
|
+
if (sourceLocale) params.append('sourceLocale', sourceLocale);
|
|
2236
|
+
if (targetLocale) params.append('targetLocale', targetLocale);
|
|
2237
|
+
|
|
2238
|
+
try {
|
|
2239
|
+
const response = await axios.get(
|
|
2240
|
+
`${MCP_SERVER_URL.replace('/mcp', '')}/namespaces/${namespace}/translations/files?${params.toString()}`,
|
|
2241
|
+
{
|
|
2242
|
+
headers: {
|
|
2243
|
+
'X-API-Key': API_KEY
|
|
2244
|
+
},
|
|
2245
|
+
timeout: 30000
|
|
2246
|
+
}
|
|
2247
|
+
);
|
|
2248
|
+
|
|
2249
|
+
if (response.data.error) {
|
|
2250
|
+
throw new Error(`List error: ${response.data.error.message || response.data.error}`);
|
|
2251
|
+
}
|
|
2252
|
+
|
|
2253
|
+
const result = response.data;
|
|
2254
|
+
|
|
2255
|
+
if (!result.files || result.files.length === 0) {
|
|
2256
|
+
return {
|
|
2257
|
+
content: [{
|
|
2258
|
+
type: 'text',
|
|
2259
|
+
text: `📂 Namespace: ${namespace}\n\n` +
|
|
2260
|
+
`No uploaded translation files found.\n\n` +
|
|
2261
|
+
`💡 Use upload_translations to upload translation files for reuse.`
|
|
2262
|
+
}]
|
|
2263
|
+
};
|
|
2264
|
+
}
|
|
2265
|
+
|
|
2266
|
+
const filesList = result.files.map((file, idx) =>
|
|
2267
|
+
`${idx + 1}. ${file.originalFileName}\n` +
|
|
2268
|
+
` 🌍 ${file.sourceLocale} → ${file.targetLocale}\n` +
|
|
2269
|
+
` ✨ ${file.pairsExtracted} pairs\n` +
|
|
2270
|
+
` 📅 Uploaded: ${new Date(file.createdAt).toLocaleDateString()}`
|
|
2271
|
+
).join('\n\n');
|
|
2272
|
+
|
|
2273
|
+
return {
|
|
2274
|
+
content: [{
|
|
2275
|
+
type: 'text',
|
|
2276
|
+
text: `📂 Namespace: ${namespace}\n` +
|
|
2277
|
+
`📊 Total Files: ${result.totalFiles}\n\n` +
|
|
2278
|
+
`Uploaded Translation Files:\n\n${filesList}`
|
|
2279
|
+
}]
|
|
2280
|
+
};
|
|
2281
|
+
} catch (error) {
|
|
2282
|
+
console.error('List uploaded translations error:', error);
|
|
2283
|
+
|
|
2284
|
+
if (error.response?.status === 401) {
|
|
2285
|
+
throw new Error(`❌ Invalid API key (401)`);
|
|
2286
|
+
}
|
|
2287
|
+
|
|
2288
|
+
if (error.response?.status === 404) {
|
|
2289
|
+
throw new Error(`❌ Namespace "${namespace}" not found`);
|
|
2290
|
+
}
|
|
2291
|
+
|
|
2292
|
+
throw new Error(`Unable to list uploaded translations: ${error.message}`);
|
|
2293
|
+
}
|
|
2294
|
+
}
|
|
2295
|
+
|
|
1876
2296
|
// Start the server
|
|
1877
2297
|
async function main() {
|
|
1878
2298
|
const transport = new StdioServerTransport();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@i18n-agent/mcp-client",
|
|
3
|
-
"version": "1.8.
|
|
3
|
+
"version": "1.8.403",
|
|
4
4
|
"description": "🌍 i18n-agent MCP Client - 48 languages, AI-powered translation for Claude, Claude Code, Cursor, VS Code, Codex. Get API key at https://app.i18nagent.ai",
|
|
5
5
|
"main": "mcp-client.js",
|
|
6
6
|
"bin": {
|