@i18n-agent/mcp-client 1.1.1 → 1.1.3
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 +79 -12
- package/package.json +1 -1
package/mcp-client.js
CHANGED
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
* Integrates with Claude Code CLI to provide translation capabilities
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
const MCP_CLIENT_VERSION = '1.1.2';
|
|
9
|
+
|
|
8
10
|
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
9
11
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
10
12
|
import {
|
|
@@ -20,7 +22,7 @@ import path from 'path';
|
|
|
20
22
|
const server = new Server(
|
|
21
23
|
{
|
|
22
24
|
name: 'i18n-agent',
|
|
23
|
-
version:
|
|
25
|
+
version: MCP_CLIENT_VERSION,
|
|
24
26
|
},
|
|
25
27
|
{
|
|
26
28
|
capabilities: {
|
|
@@ -305,17 +307,47 @@ async function handleTranslateText(args) {
|
|
|
305
307
|
};
|
|
306
308
|
}
|
|
307
309
|
|
|
308
|
-
//
|
|
310
|
+
// Handle 401 unauthorized - invalid API key
|
|
311
|
+
if (error.response?.status === 401) {
|
|
312
|
+
const errorDetails = error.response.data?.message || error.response.data?.result?.content?.[0]?.text || error.message;
|
|
313
|
+
throw new Error(`❌ Invalid API key (401)\nDetails: ${errorDetails}\nPlease check your API key at https://app.i18nagent.ai\n[MCP v${MCP_CLIENT_VERSION}/STDIO/translate_text]`);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// Handle 402 payment required with user-friendly message
|
|
317
|
+
if (error.response?.status === 402) {
|
|
318
|
+
const errorDetails = error.response.data?.message || error.response.data?.result?.content?.[0]?.text || error.message;
|
|
319
|
+
throw new Error(`⚠️ Insufficient credits (402)\nDetails: ${errorDetails}\nPlease top up at https://app.i18nagent.ai\n[MCP v${MCP_CLIENT_VERSION}/STDIO/translate_text]`);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// Check if it's a large content issue
|
|
323
|
+
const totalChars = texts.reduce((sum, text) => sum + text.length, 0);
|
|
324
|
+
if (error.response?.status === 413 ||
|
|
325
|
+
(error.response?.status === 503 && totalChars > 50000)) {
|
|
326
|
+
const errorDetails = error.response?.data?.message || error.response?.data?.result?.content?.[0]?.text || error.message;
|
|
327
|
+
const errorMsg = `Content too large (${totalChars} characters, ${texts.length} texts)\nStatus: ${error.response?.status}\nDetails: ${errorDetails}\n\nPlease break into smaller batches:\n• Split into batches of 50-100 texts\n• Keep total size under 50KB per request\n• Process sequentially to avoid overload\n[MCP v${MCP_CLIENT_VERSION}/STDIO/translate_text]`;
|
|
328
|
+
throw new Error(errorMsg);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// Check if it's actually a service unavailable error (only for real infrastructure issues)
|
|
309
332
|
if (error.code === 'ECONNREFUSED' ||
|
|
310
333
|
error.code === 'ETIMEDOUT' ||
|
|
311
|
-
error.
|
|
334
|
+
error.code === 'ENOTFOUND' ||
|
|
335
|
+
(error.response?.status === 503 && totalChars <= 50000) ||
|
|
312
336
|
error.response?.status === 502 ||
|
|
313
337
|
error.response?.status === 504) {
|
|
314
|
-
|
|
338
|
+
const errorDetails = error.response?.data?.result?.content?.[0]?.text ||
|
|
339
|
+
error.response?.data?.error?.message ||
|
|
340
|
+
error.message;
|
|
341
|
+
const debugInfo = `Code: ${error.code || 'N/A'}\nStatus: ${error.response?.status || 'N/A'}\nStatusText: ${error.response?.statusText || 'N/A'}\nDetails: ${errorDetails}\nURL: ${error.config?.url || 'N/A'}\nTimestamp: ${new Date().toISOString()}`;
|
|
342
|
+
throw new Error(`Translation service error\n${debugInfo}\n[MCP v${MCP_CLIENT_VERSION}/STDIO/translate_text]`);
|
|
315
343
|
}
|
|
316
344
|
|
|
317
|
-
// For other errors
|
|
318
|
-
|
|
345
|
+
// For other errors, include all debug info in the error message
|
|
346
|
+
const errorDetails = error.response?.data?.result?.content?.[0]?.text ||
|
|
347
|
+
error.response?.data?.error?.message ||
|
|
348
|
+
error.message;
|
|
349
|
+
const debugInfo = `Status: ${error.response?.status || 'N/A'}\nStatusText: ${error.response?.statusText || 'N/A'}\nDetails: ${errorDetails}\nTimestamp: ${new Date().toISOString()}`;
|
|
350
|
+
throw new Error(`Error\n${debugInfo}\n[MCP v${MCP_CLIENT_VERSION}/STDIO/translate_text]`);
|
|
319
351
|
}
|
|
320
352
|
}
|
|
321
353
|
|
|
@@ -485,6 +517,8 @@ async function handleTranslateFile(args) {
|
|
|
485
517
|
return result;
|
|
486
518
|
|
|
487
519
|
} catch (error) {
|
|
520
|
+
// Debug info will be included in error messages for visibility
|
|
521
|
+
|
|
488
522
|
if (error.code === 'ECONNABORTED') {
|
|
489
523
|
return {
|
|
490
524
|
content: [
|
|
@@ -507,17 +541,50 @@ async function handleTranslateFile(args) {
|
|
|
507
541
|
};
|
|
508
542
|
}
|
|
509
543
|
|
|
510
|
-
//
|
|
544
|
+
// Handle 401 unauthorized - invalid API key
|
|
545
|
+
if (error.response?.status === 401) {
|
|
546
|
+
const errorDetails = error.response.data?.message || error.response.data?.result?.content?.[0]?.text || error.message;
|
|
547
|
+
throw new Error(`❌ Invalid API key (401)\nDetails: ${errorDetails}\nPlease check your API key at https://app.i18nagent.ai\n[MCP v${MCP_CLIENT_VERSION}/STDIO/translate_file]`);
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
// Handle 402 payment required with user-friendly message
|
|
551
|
+
if (error.response?.status === 402) {
|
|
552
|
+
const errorDetails = error.response.data?.message || error.response.data?.result?.content?.[0]?.text || error.message;
|
|
553
|
+
throw new Error(`⚠️ Insufficient credits (402)\nDetails: ${errorDetails}\nPlease top up at https://app.i18nagent.ai\n[MCP v${MCP_CLIENT_VERSION}/STDIO/translate_file]`);
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
// Check if it's a timeout issue (45-second server timeout) or large file issue
|
|
557
|
+
const errorDetails = error.response?.data?.result?.content?.[0]?.text ||
|
|
558
|
+
error.response?.data?.error?.message ||
|
|
559
|
+
error.message;
|
|
560
|
+
|
|
561
|
+
if (error.response?.status === 413 ||
|
|
562
|
+
(error.response?.status === 503 && content.length > 50000) ||
|
|
563
|
+
(error.response?.status === 503 && errorDetails.includes('timeout after 45 seconds'))) {
|
|
564
|
+
const errorMsg = `File too large or complex (${content.length} characters)\n\nThe server has a 45-second timeout. Your file requires more processing time.\n\nPlease break into smaller chunks:\n• Split files over 50KB into multiple parts\n• Translate sections separately (e.g., split by top-level keys for JSON)\n• Use translate_text for batches of 50-100 strings\n• Each chunk should process in under 45 seconds\n\nAlternatively, wait for async job support (coming soon).\n[MCP v${MCP_CLIENT_VERSION}/STDIO/translate_file]`;
|
|
565
|
+
throw new Error(errorMsg);
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
// Check if it's actually a service unavailable error (only for real infrastructure issues)
|
|
511
569
|
if (error.code === 'ECONNREFUSED' ||
|
|
512
570
|
error.code === 'ETIMEDOUT' ||
|
|
513
|
-
error.
|
|
571
|
+
error.code === 'ENOTFOUND' ||
|
|
572
|
+
(error.response?.status === 503 && content.length <= 50000) ||
|
|
514
573
|
error.response?.status === 502 ||
|
|
515
574
|
error.response?.status === 504) {
|
|
516
|
-
|
|
575
|
+
const errorDetails = error.response?.data?.result?.content?.[0]?.text ||
|
|
576
|
+
error.response?.data?.error?.message ||
|
|
577
|
+
error.message;
|
|
578
|
+
const debugInfo = `Code: ${error.code || 'N/A'}\nStatus: ${error.response?.status || 'N/A'}\nStatusText: ${error.response?.statusText || 'N/A'}\nDetails: ${errorDetails}\nURL: ${error.config?.url || 'N/A'}\nTimestamp: ${new Date().toISOString()}`;
|
|
579
|
+
throw new Error(`Translation service error\n${debugInfo}\n[MCP v${MCP_CLIENT_VERSION}/STDIO/translate_file]`);
|
|
517
580
|
}
|
|
518
581
|
|
|
519
|
-
// For other errors,
|
|
520
|
-
|
|
582
|
+
// For other errors, include all debug info in the error message
|
|
583
|
+
const errorDetails = error.response?.data?.result?.content?.[0]?.text ||
|
|
584
|
+
error.response?.data?.error?.message ||
|
|
585
|
+
error.message;
|
|
586
|
+
const debugInfo = `Status: ${error.response?.status || 'N/A'}\nStatusText: ${error.response?.statusText || 'N/A'}\nDetails: ${errorDetails}\nTimestamp: ${new Date().toISOString()}`;
|
|
587
|
+
throw new Error(`Error\n${debugInfo}\n[MCP v${MCP_CLIENT_VERSION}/STDIO/translate_file]`);
|
|
521
588
|
}
|
|
522
589
|
}
|
|
523
590
|
|
|
@@ -597,7 +664,7 @@ async function pollTranslationJob(jobId, estimatedTime) {
|
|
|
597
664
|
async function handleGetCredits(args) {
|
|
598
665
|
try {
|
|
599
666
|
// Get team info first using the API key
|
|
600
|
-
const teamResponse = await axios.get(`https://
|
|
667
|
+
const teamResponse = await axios.get(`https://app.i18nagent.ai/api/teams/by-api-key/${API_KEY}`, {
|
|
601
668
|
headers: {
|
|
602
669
|
'Content-Type': 'application/json'
|
|
603
670
|
},
|
package/package.json
CHANGED