@i18n-agent/mcp-client 1.1.2 → 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.
Files changed (2) hide show
  1. package/mcp-client.js +72 -35
  2. 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 {
@@ -17,8 +19,6 @@ import axios from 'axios';
17
19
  import fs from 'fs';
18
20
  import path from 'path';
19
21
 
20
- const MCP_CLIENT_VERSION = '1.1.2';
21
-
22
22
  const server = new Server(
23
23
  {
24
24
  name: 'i18n-agent',
@@ -243,7 +243,6 @@ async function handleTranslateText(args) {
243
243
  };
244
244
 
245
245
  try {
246
- console.error(`[MCP v${MCP_CLIENT_VERSION}/STDIO/translate_text] Request: ${texts.length} texts, ${totalChars} chars to ${MCP_SERVER_URL}`);
247
246
  const response = await axios.post(MCP_SERVER_URL, mcpRequest, {
248
247
  headers: {
249
248
  'Content-Type': 'application/json',
@@ -308,30 +307,47 @@ async function handleTranslateText(args) {
308
307
  };
309
308
  }
310
309
 
311
- // Check for payment required error
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
312
317
  if (error.response?.status === 402) {
313
- console.error(`[MCP v${MCP_CLIENT_VERSION}/STDIO/translate_text] Payment required (402)`);
314
- throw new Error(`⚠️ Insufficient credits. Please top up at https://app.i18nagent.ai [MCP v${MCP_CLIENT_VERSION}/STDIO]`);
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);
315
329
  }
316
330
 
317
- // Check if it's actually a service unavailable error (503, timeout, connection issues)
331
+ // Check if it's actually a service unavailable error (only for real infrastructure issues)
318
332
  if (error.code === 'ECONNREFUSED' ||
319
333
  error.code === 'ETIMEDOUT' ||
320
- error.response?.status === 503 ||
334
+ error.code === 'ENOTFOUND' ||
335
+ (error.response?.status === 503 && totalChars <= 50000) ||
321
336
  error.response?.status === 502 ||
322
337
  error.response?.status === 504) {
323
- console.error(`[MCP v${MCP_CLIENT_VERSION}/STDIO/translate_text] Infrastructure error:`, {
324
- code: error.code,
325
- status: error.response?.status,
326
- message: error.message,
327
- url: MCP_SERVER_URL
328
- });
329
- throw new Error(`Translation service unavailable [MCP v${MCP_CLIENT_VERSION}/STDIO/translate_text]: ${error.message}`);
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]`);
330
343
  }
331
344
 
332
- // For other errors (401, 404, etc), add context but don't mark as unavailable
333
- console.error(`[MCP v${MCP_CLIENT_VERSION}/STDIO/translate_text] Error:`, error.message);
334
- throw error;
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]`);
335
351
  }
336
352
  }
337
353
 
@@ -469,7 +485,6 @@ async function handleTranslateFile(args) {
469
485
  };
470
486
 
471
487
  try {
472
- console.error(`[MCP v${MCP_CLIENT_VERSION}/STDIO/translate_file] Request: ${content?.length || 0} chars to ${MCP_SERVER_URL}`);
473
488
  const response = await axios.post(MCP_SERVER_URL, mcpRequest, {
474
489
  headers: {
475
490
  'Content-Type': 'application/json',
@@ -502,6 +517,8 @@ async function handleTranslateFile(args) {
502
517
  return result;
503
518
 
504
519
  } catch (error) {
520
+ // Debug info will be included in error messages for visibility
521
+
505
522
  if (error.code === 'ECONNABORTED') {
506
523
  return {
507
524
  content: [
@@ -524,30 +541,50 @@ async function handleTranslateFile(args) {
524
541
  };
525
542
  }
526
543
 
527
- // Check for payment required error
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
528
551
  if (error.response?.status === 402) {
529
- console.error(`[MCP v${MCP_CLIENT_VERSION}/STDIO/translate_file] Payment required (402)`);
530
- throw new Error(`⚠️ Insufficient credits. Please top up at https://app.i18nagent.ai [MCP v${MCP_CLIENT_VERSION}/STDIO]`);
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]`);
531
554
  }
532
555
 
533
- // Check if it's actually a service unavailable error
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)
534
569
  if (error.code === 'ECONNREFUSED' ||
535
570
  error.code === 'ETIMEDOUT' ||
536
- error.response?.status === 503 ||
571
+ error.code === 'ENOTFOUND' ||
572
+ (error.response?.status === 503 && content.length <= 50000) ||
537
573
  error.response?.status === 502 ||
538
574
  error.response?.status === 504) {
539
- console.error(`[MCP v${MCP_CLIENT_VERSION}/STDIO/translate_file] Infrastructure error:`, {
540
- code: error.code,
541
- status: error.response?.status,
542
- message: error.message,
543
- url: MCP_SERVER_URL
544
- });
545
- throw new Error(`Translation service unavailable [MCP v${MCP_CLIENT_VERSION}/STDIO/translate_file]: ${error.message}`);
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]`);
546
580
  }
547
581
 
548
- // For other errors, add context but don't mark as unavailable
549
- console.error(`[MCP v${MCP_CLIENT_VERSION}/STDIO/translate_file] Error:`, error.message);
550
- throw error;
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]`);
551
588
  }
552
589
  }
553
590
 
@@ -627,7 +664,7 @@ async function pollTranslationJob(jobId, estimatedTime) {
627
664
  async function handleGetCredits(args) {
628
665
  try {
629
666
  // Get team info first using the API key
630
- const teamResponse = await axios.get(`https://platform.i18nagent.ai/api/teams/by-api-key/${API_KEY}`, {
667
+ const teamResponse = await axios.get(`https://app.i18nagent.ai/api/teams/by-api-key/${API_KEY}`, {
631
668
  headers: {
632
669
  'Content-Type': 'application/json'
633
670
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@i18n-agent/mcp-client",
3
- "version": "1.1.2",
3
+ "version": "1.1.3",
4
4
  "description": "MCP client for i18n-agent translation service - supports Claude, Cursor, VS Code, and other AI IDEs",
5
5
  "main": "mcp-client.js",
6
6
  "bin": {