@i18n-agent/mcp-client 1.9.8 → 1.11.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/CONTRIBUTING.md CHANGED
@@ -34,7 +34,7 @@ npm test
34
34
  node install.js
35
35
 
36
36
  # Test MCP client syntax
37
- node -c mcp-client.js
37
+ node -c i18n-agent.js
38
38
  ```
39
39
 
40
40
  ## šŸ“ Types of Contributions
@@ -72,7 +72,7 @@ npm test
72
72
  node install.js
73
73
 
74
74
  # Check for syntax errors
75
- node -c mcp-client.js
75
+ node -c i18n-agent.js
76
76
  node -c install.js
77
77
  ```
78
78
 
package/README.md CHANGED
@@ -20,7 +20,7 @@ Professional translation service client for Claude, Cursor, VS Code, and other A
20
20
 
21
21
  ```bash
22
22
  npm install -g @i18n-agent/mcp-client
23
- mcp-client
23
+ i18n-agent
24
24
  ```
25
25
 
26
26
  **Note:** Global installation is required due to npm bin naming limitations. The installer will detect all available AI IDEs and configure them automatically.
@@ -156,7 +156,7 @@ Edit `~/Library/Application Support/Claude/claude_desktop_config.json`:
156
156
  "mcpServers": {
157
157
  "i18n-agent": {
158
158
  "command": "node",
159
- "args": ["/path/to/mcp-client.js"],
159
+ "args": ["/path/to/i18n-agent.js"],
160
160
  "env": {
161
161
  "MCP_SERVER_URL": "https://mcp.i18nagent.ai",
162
162
  "API_KEY": "your-api-key-here"
@@ -174,7 +174,7 @@ Create `.cursor/mcp_settings.json` or `.vscode/mcp_settings.json`:
174
174
  "mcpServers": {
175
175
  "i18n-agent": {
176
176
  "command": "node",
177
- "args": ["/path/to/mcp-client.js"],
177
+ "args": ["/path/to/i18n-agent.js"],
178
178
  "env": {
179
179
  "MCP_SERVER_URL": "https://mcp.i18nagent.ai",
180
180
  "API_KEY": "your-api-key-here"
@@ -252,7 +252,7 @@ This usually happens with Node Version Managers (nvm, fnm, n). The installer now
252
252
  #!/bin/bash
253
253
  export PATH="$(dirname $(which node)):$PATH"
254
254
  cd ~/.claude
255
- exec node node_modules/@i18n-agent/mcp-client/mcp-client.js
255
+ exec node node_modules/@i18n-agent/mcp-client/i18n-agent.js
256
256
  ```
257
257
 
258
258
  Make it executable:
@@ -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.9.8';
8
+ const MCP_CLIENT_VERSION = '1.11.0';
9
9
 
10
10
  import { Server } from '@modelcontextprotocol/sdk/server/index.js';
11
11
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
@@ -43,6 +43,40 @@ if (!process.env.API_KEY) {
43
43
  const MCP_SERVER_URL = process.env.MCP_SERVER_URL;
44
44
  const API_KEY = process.env.API_KEY;
45
45
 
46
+ // Heavy load detection - matches error message from service-mcp error-message-sanitizer
47
+ // Exact message: 'Our system is under heavy load, please resume your job later.'
48
+ const HEAVY_LOAD_PATTERNS = [
49
+ /Our system is under heavy load/i,
50
+ /system is under heavy load.*resume.*later/i,
51
+ ];
52
+
53
+ const HEAVY_LOAD_MESSAGE = `ā³ System under heavy load
54
+
55
+ The translation service is experiencing high demand. Your job has been saved and can be resumed later.
56
+
57
+ āš ļø IMPORTANT FOR AI AGENTS:
58
+ • Do NOT retry or resume immediately - this will likely fail again
59
+ • Do NOT poll check_translation_status repeatedly
60
+ • Wait at least 5-10 minutes before attempting to resume
61
+ • The job is saved - no data is lost
62
+
63
+ šŸ”„ To resume later:
64
+ 1. Wait for system load to decrease (5-10 minutes minimum)
65
+ 2. Use resume_translation with the same jobId
66
+ 3. If it fails again, wait longer before retrying
67
+
68
+ šŸ’” Tip: Inform the user about the delay and let them decide when to retry.`;
69
+
70
+ /**
71
+ * Check if an error message indicates heavy system load
72
+ * @param {string} errorMessage - The error message to check
73
+ * @returns {boolean} - True if the error indicates heavy load
74
+ */
75
+ function isHeavyLoadError(errorMessage) {
76
+ if (!errorMessage) return false;
77
+ return HEAVY_LOAD_PATTERNS.some(pattern => pattern.test(errorMessage));
78
+ }
79
+
46
80
  // Available tools
47
81
  server.setRequestHandler(ListToolsRequestSchema, async () => {
48
82
  return {
@@ -689,26 +723,35 @@ async function handleTranslateText(args) {
689
723
  throw new Error(errorMsg);
690
724
  }
691
725
 
726
+ // Check for heavy load error (from service-mcp error-message-sanitizer)
727
+ const errorDetails = error.response?.data?.result?.content?.[0]?.text ||
728
+ error.response?.data?.error?.message ||
729
+ error.response?.data?.message ||
730
+ error.message;
731
+ if (isHeavyLoadError(errorDetails)) {
732
+ throw new Error(`${HEAVY_LOAD_MESSAGE}\n[MCP v${MCP_CLIENT_VERSION}/STDIO/translate_text]`);
733
+ }
734
+
692
735
  // Check if it's actually a service unavailable error (only for real infrastructure issues)
693
736
  if (error.response?.status === 503) {
694
737
  throw new Error(`i18n-agent encountered unexpected problem, and we are working on it, try again later.`);
695
738
  }
696
-
697
- if (error.code === 'ECONNREFUSED' ||
698
- error.code === 'ETIMEDOUT' ||
739
+
740
+ if (error.code === 'ECONNREFUSED' ||
741
+ error.code === 'ETIMEDOUT' ||
699
742
  error.code === 'ENOTFOUND' ||
700
743
  error.response?.status === 502 ||
701
744
  error.response?.status === 504) {
702
- const serviceErrorDetails = error.response?.data?.result?.content?.[0]?.text ||
703
- error.response?.data?.error?.message ||
745
+ const serviceErrorDetails = error.response?.data?.result?.content?.[0]?.text ||
746
+ error.response?.data?.error?.message ||
704
747
  error.message;
705
748
  const debugInfo = `Code: ${error.code || 'N/A'}\nStatus: ${error.response?.status || 'N/A'}\nStatusText: ${error.response?.statusText || 'N/A'}\nDetails: ${serviceErrorDetails}\nURL: ${error.config?.url || 'N/A'}\nTimestamp: ${new Date().toISOString()}`;
706
749
  throw new Error(`Translation service error\n${debugInfo}\n[MCP v${MCP_CLIENT_VERSION}/STDIO/translate_text]`);
707
750
  }
708
-
751
+
709
752
  // For other errors, include all debug info in the error message
710
- const generalErrorDetails = error.response?.data?.result?.content?.[0]?.text ||
711
- error.response?.data?.error?.message ||
753
+ const generalErrorDetails = error.response?.data?.result?.content?.[0]?.text ||
754
+ error.response?.data?.error?.message ||
712
755
  error.message;
713
756
  const debugInfo = `Status: ${error.response?.status || 'N/A'}\nStatusText: ${error.response?.statusText || 'N/A'}\nDetails: ${generalErrorDetails}\nTimestamp: ${new Date().toISOString()}`;
714
757
  throw new Error(`Error\n${debugInfo}\n[MCP v${MCP_CLIENT_VERSION}/STDIO/translate_text]`);
@@ -1046,26 +1089,31 @@ async function handleTranslateFile(args) {
1046
1089
  throw new Error(errorMsg);
1047
1090
  }
1048
1091
 
1092
+ // Check for heavy load error (from service-mcp error-message-sanitizer)
1093
+ if (isHeavyLoadError(timeoutErrorDetails)) {
1094
+ throw new Error(`${HEAVY_LOAD_MESSAGE}\n[MCP v${MCP_CLIENT_VERSION}/STDIO/translate_file]`);
1095
+ }
1096
+
1049
1097
  // Check if it's actually a service unavailable error (only for real infrastructure issues)
1050
1098
  if (error.response?.status === 503 && content.length <= 50000) {
1051
1099
  throw new Error(`i18n-agent encountered unexpected problem, and we are working on it, try again later.`);
1052
1100
  }
1053
-
1054
- if (error.code === 'ECONNREFUSED' ||
1055
- error.code === 'ETIMEDOUT' ||
1101
+
1102
+ if (error.code === 'ECONNREFUSED' ||
1103
+ error.code === 'ETIMEDOUT' ||
1056
1104
  error.code === 'ENOTFOUND' ||
1057
1105
  error.response?.status === 502 ||
1058
1106
  error.response?.status === 504) {
1059
- const serviceErrorDetails = error.response?.data?.result?.content?.[0]?.text ||
1060
- error.response?.data?.error?.message ||
1107
+ const serviceErrorDetails = error.response?.data?.result?.content?.[0]?.text ||
1108
+ error.response?.data?.error?.message ||
1061
1109
  error.message;
1062
1110
  const debugInfo = `Code: ${error.code || 'N/A'}\nStatus: ${error.response?.status || 'N/A'}\nStatusText: ${error.response?.statusText || 'N/A'}\nDetails: ${serviceErrorDetails}\nURL: ${error.config?.url || 'N/A'}\nTimestamp: ${new Date().toISOString()}`;
1063
1111
  throw new Error(`Translation service error\n${debugInfo}\n[MCP v${MCP_CLIENT_VERSION}/STDIO/translate_file]`);
1064
1112
  }
1065
-
1113
+
1066
1114
  // For other errors, include all debug info in the error message
1067
- const finalErrorDetails = error.response?.data?.result?.content?.[0]?.text ||
1068
- error.response?.data?.error?.message ||
1115
+ const finalErrorDetails = error.response?.data?.result?.content?.[0]?.text ||
1116
+ error.response?.data?.error?.message ||
1069
1117
  error.message;
1070
1118
  const debugInfo = `Status: ${error.response?.status || 'N/A'}\nStatusText: ${error.response?.statusText || 'N/A'}\nDetails: ${finalErrorDetails}\nTimestamp: ${new Date().toISOString()}`;
1071
1119
  throw new Error(`Error\n${debugInfo}\n[MCP v${MCP_CLIENT_VERSION}/STDIO/translate_file]`);
@@ -1122,48 +1170,64 @@ async function pollTranslationJob(jobId, estimatedTime) {
1122
1170
 
1123
1171
  if (response.data.error) {
1124
1172
  const errorMsg = response.data.error.message || response.data.error;
1125
- const isAuthError = errorMsg.toString().toLowerCase().includes('api key') ||
1173
+
1174
+ // Check for heavy load error - stop polling immediately
1175
+ if (isHeavyLoadError(errorMsg.toString())) {
1176
+ throw new Error(`${HEAVY_LOAD_MESSAGE}\n\nJob ID: ${jobId}\n[MCP v${MCP_CLIENT_VERSION}/pollTranslationJob]`);
1177
+ }
1178
+
1179
+ const isAuthError = errorMsg.toString().toLowerCase().includes('api key') ||
1126
1180
  errorMsg.toString().toLowerCase().includes('api_key') ||
1127
1181
  errorMsg.toString().toLowerCase().includes('unauthorized');
1128
- const isCreditError = errorMsg.toString().toLowerCase().includes('credit') ||
1182
+ const isCreditError = errorMsg.toString().toLowerCase().includes('credit') ||
1129
1183
  errorMsg.toString().toLowerCase().includes('quota') ||
1130
1184
  errorMsg.toString().toLowerCase().includes('limit exceeded');
1131
-
1185
+
1132
1186
  let finalErrorMsg = `Status check error: ${errorMsg}`;
1133
1187
  if (!isAuthError && !isCreditError) {
1134
1188
  finalErrorMsg += `. Please retry with a smaller chunk or split the content into multiple requests.`;
1135
1189
  }
1136
1190
  throw new Error(finalErrorMsg);
1137
1191
  }
1138
-
1192
+
1139
1193
  const result = response.data.result;
1140
1194
  if (result && result.content && result.content[0]) {
1141
1195
  const status = JSON.parse(result.content[0].text);
1142
-
1196
+
1143
1197
  if (status.status === 'completed') {
1144
1198
  return status.result;
1145
1199
  } else if (status.status === 'failed') {
1146
1200
  const errorMsg = status.error;
1147
- const isAuthError = errorMsg.toString().toLowerCase().includes('api key') ||
1201
+
1202
+ // Check for heavy load error - stop polling immediately
1203
+ if (isHeavyLoadError(errorMsg.toString())) {
1204
+ throw new Error(`${HEAVY_LOAD_MESSAGE}\n\nJob ID: ${jobId}\n[MCP v${MCP_CLIENT_VERSION}/pollTranslationJob]`);
1205
+ }
1206
+
1207
+ const isAuthError = errorMsg.toString().toLowerCase().includes('api key') ||
1148
1208
  errorMsg.toString().toLowerCase().includes('api_key') ||
1149
1209
  errorMsg.toString().toLowerCase().includes('unauthorized');
1150
- const isCreditError = errorMsg.toString().toLowerCase().includes('credit') ||
1210
+ const isCreditError = errorMsg.toString().toLowerCase().includes('credit') ||
1151
1211
  errorMsg.toString().toLowerCase().includes('quota') ||
1152
1212
  errorMsg.toString().toLowerCase().includes('limit exceeded');
1153
-
1213
+
1154
1214
  let finalErrorMsg = `Translation failed: ${errorMsg}`;
1155
1215
  if (!isAuthError && !isCreditError) {
1156
1216
  finalErrorMsg += `. Please retry with a smaller chunk or split the content into multiple requests.`;
1157
1217
  }
1158
1218
  throw new Error(finalErrorMsg);
1159
1219
  }
1160
-
1220
+
1161
1221
  // Still processing - continue polling
1162
1222
  console.error(`Translation progress: ${status.progress}% (${status.message})`);
1163
1223
  }
1164
1224
  } catch (error) {
1225
+ // Check for heavy load error - stop polling immediately (don't continue)
1226
+ if (isHeavyLoadError(error.message)) {
1227
+ throw error; // Re-throw heavy load error to stop polling
1228
+ }
1165
1229
  console.error(`Error polling job status: ${error.message}`);
1166
- // Continue polling even if status check fails
1230
+ // Continue polling for other transient errors
1167
1231
  }
1168
1232
  }
1169
1233
 
@@ -1727,6 +1791,17 @@ async function handleCheckTranslationStatus(args) {
1727
1791
  } catch (error) {
1728
1792
  console.error('Check translation status error:', error);
1729
1793
 
1794
+ // Extract error message from various response formats
1795
+ const errorDetails = error.response?.data?.result?.content?.[0]?.text ||
1796
+ error.response?.data?.error?.message ||
1797
+ error.response?.data?.message ||
1798
+ error.message;
1799
+
1800
+ // Check for heavy load error (from service-mcp error-message-sanitizer)
1801
+ if (isHeavyLoadError(errorDetails)) {
1802
+ throw new Error(`${HEAVY_LOAD_MESSAGE}\n\nJob ID: ${jobId}\n[MCP v${MCP_CLIENT_VERSION}/check_translation_status]`);
1803
+ }
1804
+
1730
1805
  // Handle 503 service unavailable
1731
1806
  if (error.response?.status === 503) {
1732
1807
  throw new Error(`i18n-agent encountered unexpected problem, and we are working on it, try again later.`);
@@ -1779,6 +1854,17 @@ async function handleResumeTranslation(args) {
1779
1854
  } catch (error) {
1780
1855
  console.error('Resume translation error:', error);
1781
1856
 
1857
+ // Extract error message from various response formats
1858
+ const errorDetails = error.response?.data?.result?.content?.[0]?.text ||
1859
+ error.response?.data?.error?.message ||
1860
+ error.response?.data?.message ||
1861
+ error.message;
1862
+
1863
+ // Check for heavy load error (from service-mcp error-message-sanitizer)
1864
+ if (isHeavyLoadError(errorDetails)) {
1865
+ throw new Error(`${HEAVY_LOAD_MESSAGE}\n\nJob ID: ${jobId}\n[MCP v${MCP_CLIENT_VERSION}/resume_translation]`);
1866
+ }
1867
+
1782
1868
  // Handle 503 service unavailable
1783
1869
  if (error.response?.status === 503) {
1784
1870
  throw new Error(`i18n-agent encountered unexpected problem, and we are working on it, try again later.`);
@@ -1930,6 +2016,17 @@ async function handleDownloadTranslations(args) {
1930
2016
  } catch (error) {
1931
2017
  console.error('Download translations error:', error);
1932
2018
 
2019
+ // Extract error message from various response formats
2020
+ const errorDetails = error.response?.data?.result?.content?.[0]?.text ||
2021
+ error.response?.data?.error?.message ||
2022
+ error.response?.data?.message ||
2023
+ error.message;
2024
+
2025
+ // Check for heavy load error (from service-mcp error-message-sanitizer)
2026
+ if (isHeavyLoadError(errorDetails)) {
2027
+ throw new Error(`${HEAVY_LOAD_MESSAGE}\n\nJob ID: ${jobId}\n[MCP v${MCP_CLIENT_VERSION}/download_translations]`);
2028
+ }
2029
+
1933
2030
  // Handle 503 service unavailable
1934
2031
  if (error.response?.status === 503) {
1935
2032
  throw new Error(`i18n-agent encountered unexpected problem, and we are working on it, try again later.`);
package/install.js CHANGED
@@ -83,9 +83,9 @@ Features:
83
83
  const getMcpClientPaths = () => {
84
84
  // Instead of using ephemeral npx cache, install to stable location
85
85
  const stableDir = path.join(os.homedir(), '.claude', 'mcp-servers', 'i18n-agent');
86
- const mcpClientPath = path.join(stableDir, 'mcp-client.js');
86
+ const mcpClientPath = path.join(stableDir, 'i18n-agent.js');
87
87
  const packageDir = stableDir;
88
- return { mcpClientPath, packageDir, sourceFile: path.resolve(__dirname, 'mcp-client.js') };
88
+ return { mcpClientPath, packageDir, sourceFile: path.resolve(__dirname, 'i18n-agent.js') };
89
89
  };
90
90
 
91
91
  function copyMcpClientToStableLocation() {
@@ -94,7 +94,7 @@ function copyMcpClientToStableLocation() {
94
94
  // Create stable directory
95
95
  fs.mkdirSync(paths.packageDir, { recursive: true });
96
96
 
97
- // Copy mcp-client.js to stable location
97
+ // Copy i18n-agent.js to stable location
98
98
  fs.copyFileSync(paths.sourceFile, paths.mcpClientPath);
99
99
 
100
100
  // Copy package.json to stable location
@@ -808,7 +808,7 @@ Step 2: Add API key to your IDE`);
808
808
  console.log(`
809
809
  For Claude Code CLI (recommended):
810
810
  claude mcp remove --scope user i18n-agent
811
- claude mcp add --transport stdio --scope user i18n-agent -e MCP_SERVER_URL=https://mcp.i18nagent.ai -e API_KEY=your_key_here -- node ~/.claude/mcp-servers/i18n-agent/mcp-client.js
811
+ claude mcp add --transport stdio --scope user i18n-agent -e MCP_SERVER_URL=https://mcp.i18nagent.ai -e API_KEY=your_key_here -- node ~/.claude/mcp-servers/i18n-agent/i18n-agent.js
812
812
  `);
813
813
  }
814
814
 
@@ -816,7 +816,7 @@ Step 2: Add API key to your IDE`);
816
816
  console.log(`
817
817
  For Codex CLI (recommended):
818
818
  codex mcp remove i18n-agent
819
- codex mcp add --env MCP_SERVER_URL=https://mcp.i18nagent.ai --env API_KEY=your_key_here i18n-agent node ~/.claude/mcp-servers/i18n-agent/mcp-client.js
819
+ codex mcp add --env MCP_SERVER_URL=https://mcp.i18nagent.ai --env API_KEY=your_key_here i18n-agent node ~/.claude/mcp-servers/i18n-agent/i18n-agent.js
820
820
  `);
821
821
  }
822
822
 
@@ -873,7 +873,7 @@ Try these commands in your AI IDE:
873
873
  const isMainModule = process.argv[1] && (
874
874
  import.meta.url === `file://${process.argv[1]}` ||
875
875
  import.meta.url.endsWith(process.argv[1]) ||
876
- process.argv[1].includes('mcp-client')
876
+ process.argv[1].includes('i18n-agent')
877
877
  );
878
878
 
879
879
  if (isMainModule) {
package/package.json CHANGED
@@ -1,16 +1,16 @@
1
1
  {
2
2
  "name": "@i18n-agent/mcp-client",
3
- "version": "1.9.8",
3
+ "version": "1.11.0",
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
- "main": "mcp-client.js",
5
+ "main": "i18n-agent.js",
6
6
  "bin": {
7
- "mcp-client": "install.js"
7
+ "i18n-agent": "install.js"
8
8
  },
9
9
  "type": "module",
10
10
  "scripts": {
11
11
  "install": "node install.js",
12
12
  "test": "node test.js",
13
- "postinstall": "echo '\nšŸŒ i18n-agent MCP Client installed successfully!\nšŸ’” Run: mcp-client (if installed globally) or node install.js\n'"
13
+ "postinstall": "echo '\nšŸŒ i18n-agent MCP Client installed successfully!\nšŸ’” Run: i18n-agent (if installed globally) or node install.js\n'"
14
14
  },
15
15
  "repository": {
16
16
  "type": "git",
@@ -42,7 +42,7 @@
42
42
  "node": ">=16.0.0"
43
43
  },
44
44
  "files": [
45
- "mcp-client.js",
45
+ "i18n-agent.js",
46
46
  "namespace-detector.js",
47
47
  "install.js",
48
48
  "README.md",