@i18n-agent/mcp-client 1.7.8 → 1.8.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.
Files changed (4) hide show
  1. package/README.md +45 -29
  2. package/install.js +41 -25
  3. package/mcp-client.js +137 -15
  4. package/package.json +1 -1
package/README.md CHANGED
@@ -13,7 +13,7 @@ Professional translation service client for Claude, Cursor, VS Code, and other A
13
13
  - **🔄 Timeout Improvements**: Extended timeouts (5-10 min) for large translations
14
14
  - **📊 Progress Tracking**: Real-time job status and completion monitoring
15
15
  - **💰 Credit Tracking**: Real-time credit balance and word count estimates
16
- - **🌐 30+ Languages**: Multi-tier language support with quality ratings
16
+ - **🌐 48 Languages**: Comprehensive language support with regional variants
17
17
  - **🔧 Easy Setup**: One-command installation for major AI IDEs
18
18
 
19
19
  ## 🚀 Quick Installation
@@ -71,7 +71,7 @@ List supported languages with quality ratings
71
71
 
72
72
  ### Content Analysis
73
73
  ```
74
- Analyze content for translation readiness and get improvement suggestions
74
+ Analyze "Hello world! This is a test." for translation to Spanish
75
75
  ```
76
76
 
77
77
  ## 🛠 Supported AI IDEs
@@ -83,41 +83,54 @@ Analyze content for translation readiness and get improvement suggestions
83
83
  | **VS Code** | ✅ Auto-configured | `~/.vscode/mcp_settings.json` |
84
84
  | **Other MCP IDEs** | 🔧 Manual setup | Varies |
85
85
 
86
- ## 🌐 Language Support
87
- - **en**: English
88
- - **fr**: French
86
+ ## 🌐 Language Support (48 Languages)
87
+ - **bg**: Bulgarian
88
+ - **ca**: Catalan
89
+ - **cs**: Czech
90
+ - **da**: Danish
89
91
  - **de**: German
92
+ - **el**: Greek
93
+ - **en**: English
94
+ - **en-AU**: English (Australia)
95
+ - **en-CA**: English (Canada)
96
+ - **en-GB**: English (United Kingdom)
97
+ - **en-US**: English (United States)
90
98
  - **es**: Spanish
99
+ - **es-MX**: Spanish (Mexico)
100
+ - **et**: Estonian
101
+ - **fi**: Finnish
102
+ - **fr**: French
103
+ - **fr-CA**: French (Canada)
104
+ - **hi**: Hindi
105
+ - **hr**: Croatian
106
+ - **hu**: Hungarian
107
+ - **id**: Indonesian
108
+ - **is**: Icelandic
91
109
  - **it**: Italian
92
- - **pt**: Portuguese
93
- - **ru**: Russian
94
110
  - **ja**: Japanese
95
111
  - **ko**: Korean
96
- - **zh-CN**: Chinese (Simplified)
112
+ - **lt**: Lithuanian
113
+ - **lv**: Latvian
114
+ - **ms**: Malay
97
115
  - **nl**: Dutch
98
- - **pl**: Polish
99
- - **cs**: Czech
100
- - **ar**: Arabic
101
- - **he**: Hebrew
102
- - **hi**: Hindi
103
- - **zh-TW**: Chinese (Traditional)
104
- - **sv**: Swedish
105
- - **da**: Danish
106
116
  - **no**: Norwegian
107
- - **fi**: Finnish
108
- - **tr**: Turkish
109
- - **hu**: Hungarian
110
- - **th**: Thai
111
- - **vi**: Vietnamese
112
- - **uk**: Ukrainian
113
- - **bg**: Bulgarian
117
+ - **pl**: Polish
118
+ - **pt**: Portuguese
119
+ - **pt-BR**: Portuguese (Brazil)
114
120
  - **ro**: Romanian
115
- - **hr**: Croatian
121
+ - **ru**: Russian
116
122
  - **sk**: Slovak
117
123
  - **sl**: Slovenian
118
- - **et**: Estonian
119
- - **lv**: Latvian
120
- - **lt**: Lithuanian
124
+ - **sr**: Serbian
125
+ - **sv**: Swedish
126
+ - **th**: Thai
127
+ - **tl**: Filipino
128
+ - **tr**: Turkish
129
+ - **uk**: Ukrainian
130
+ - **vi**: Vietnamese
131
+ - **zh-Hans**: Chinese (Simplified)
132
+ - **zh-Hant-HK**: Chinese (Traditional, Hong Kong)
133
+ - **zh-Hant-TW**: Chinese (Traditional, Taiwan)
121
134
 
122
135
  ## 📁 Supported File Formats
123
136
 
@@ -128,8 +141,11 @@ Analyze content for translation readiness and get improvement suggestions
128
141
  | CSV | `.csv` | Handles quoted fields, commas |
129
142
  | XML/HTML | `.xml`, `.html` | Extracts text content |
130
143
  | Markdown | `.md` | Preserves formatting, skips code |
131
- | Properties | `.properties` | Key-value pairs |
144
+ | Properties | `.properties` | Java properties key-value pairs |
132
145
  | Plain Text | `.txt` | Direct translation |
146
+ | PDF | `.pdf` | Text extraction and translation |
147
+ | Word | `.docx`, `.doc` | Document translation |
148
+ | Gettext | `.po`, `.pot`, `.mo` | Localization file formats |
133
149
 
134
150
  ## 🔧 Manual Setup
135
151
 
@@ -347,7 +363,7 @@ Translate files while preserving structure and format.
347
363
  - `outputFormat` (string): Output format (same, json, yaml, txt)
348
364
 
349
365
  ### analyze_content
350
- Analyze content for translation readiness and get improvement suggestions before translation.
366
+ Analyze content for translation readiness and get improvement suggestions before translation. This helps identify potential issues and optimize content before spending credits on translation.
351
367
 
352
368
  **Parameters:**
353
369
  - `content` (string/array/object): Content to analyze
package/install.js CHANGED
@@ -41,9 +41,15 @@ Features:
41
41
  ✨ Text translation with cultural context
42
42
  📁 File translation (JSON, YAML, CSV, MD, etc.)
43
43
  💰 Credit balance checking
44
- 🌐 30+ language support with quality tiers
44
+ 🌐 48 languages supported with regional variants
45
45
  `);
46
46
 
47
+ const getMcpClientPaths = () => {
48
+ const mcpClientPath = path.resolve(__dirname, 'mcp-client.js');
49
+ const packageDir = path.dirname(mcpClientPath);
50
+ return { mcpClientPath, packageDir };
51
+ };
52
+
47
53
  async function detectAvailableIDEs() {
48
54
  const available = [];
49
55
 
@@ -58,13 +64,14 @@ async function detectAvailableIDEs() {
58
64
  }
59
65
 
60
66
  function createMCPConfig() {
61
- const mcpClientPath = path.resolve(__dirname, 'mcp-client.js');
62
-
67
+ const { mcpClientPath, packageDir } = getMcpClientPaths();
68
+
63
69
  return {
64
70
  mcpServers: {
65
71
  "i18n-agent": {
66
72
  command: "node",
67
73
  args: [mcpClientPath],
74
+ cwd: packageDir,
68
75
  env: {
69
76
  MCP_SERVER_URL: "https://mcp.i18nagent.ai",
70
77
  API_KEY: ""
@@ -90,25 +97,27 @@ function detectNodeEnvironment() {
90
97
  function createWrapperScript(targetDir) {
91
98
  const nodeEnv = detectNodeEnvironment();
92
99
  const wrapperPath = path.join(targetDir, 'run-mcp.sh');
93
- const mcpClientPath = path.join(targetDir, 'node_modules', '@i18n-agent', 'mcp-client', 'mcp-client.js');
94
-
100
+ const { mcpClientPath, packageDir } = getMcpClientPaths();
101
+
102
+ fs.mkdirSync(targetDir, { recursive: true });
103
+
95
104
  let wrapperContent;
96
-
105
+
97
106
  if (nodeEnv.isNvm) {
98
107
  // For nvm users, we need to set up the PATH properly
99
108
  wrapperContent = `#!/bin/bash
100
109
  # Wrapper script for i18n-agent MCP client (handles nvm environments)
101
110
  export PATH="${path.dirname(nodeEnv.nodePath)}:$PATH"
102
- cd "${targetDir}"
111
+ cd "${packageDir}"
103
112
  exec node "${mcpClientPath}"`;
104
113
  } else {
105
114
  // For system node installations
106
115
  wrapperContent = `#!/bin/bash
107
116
  # Wrapper script for i18n-agent MCP client
108
- cd "${targetDir}"
117
+ cd "${packageDir}"
109
118
  exec node "${mcpClientPath}"`;
110
119
  }
111
-
120
+
112
121
  fs.writeFileSync(wrapperPath, wrapperContent, { mode: 0o755 });
113
122
  return wrapperPath;
114
123
  }
@@ -139,7 +148,7 @@ function updateClaudeConfig(configPath) {
139
148
  // Create wrapper script for nvm users
140
149
  console.log(' 🔧 Detected nvm environment, creating wrapper script...');
141
150
  const wrapperPath = createWrapperScript(claudeDir);
142
-
151
+
143
152
  config.mcpServers["i18n-agent"] = {
144
153
  command: wrapperPath,
145
154
  env: {
@@ -149,17 +158,8 @@ function updateClaudeConfig(configPath) {
149
158
  };
150
159
  } else {
151
160
  // Standard configuration for system node
152
- const mcpClientPath = path.join(claudeDir, 'node_modules', '@i18n-agent', 'mcp-client', 'mcp-client.js');
153
-
154
- config.mcpServers["i18n-agent"] = {
155
- command: "node",
156
- args: [mcpClientPath],
157
- cwd: claudeDir,
158
- env: {
159
- MCP_SERVER_URL: "https://mcp.i18nagent.ai",
160
- API_KEY: ""
161
- }
162
- };
161
+ const baseConfig = createMCPConfig();
162
+ config.mcpServers["i18n-agent"] = baseConfig.mcpServers["i18n-agent"];
163
163
  }
164
164
 
165
165
  // Write updated config
@@ -170,12 +170,28 @@ function updateClaudeConfig(configPath) {
170
170
  }
171
171
 
172
172
  function updateGenericMCPConfig(configPath) {
173
- const config = createMCPConfig();
174
-
173
+ let config = {};
174
+
175
+ if (fs.existsSync(configPath)) {
176
+ try {
177
+ const existing = fs.readFileSync(configPath, 'utf8');
178
+ config = JSON.parse(existing);
179
+ } catch (error) {
180
+ console.warn(`Warning: Could not parse existing config at ${configPath}`);
181
+ }
182
+ }
183
+
184
+ if (!config.mcpServers) {
185
+ config.mcpServers = {};
186
+ }
187
+
188
+ const baseConfig = createMCPConfig();
189
+ config.mcpServers["i18n-agent"] = baseConfig.mcpServers["i18n-agent"];
190
+
175
191
  // Write config
176
192
  fs.mkdirSync(path.dirname(configPath), { recursive: true });
177
193
  fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
178
-
194
+
179
195
  return config;
180
196
  }
181
197
 
@@ -274,4 +290,4 @@ if (import.meta.url === `file://${process.argv[1]}`) {
274
290
  main();
275
291
  }
276
292
 
277
- export { main, IDE_CONFIGS, createMCPConfig };
293
+ export { main, IDE_CONFIGS, createMCPConfig };
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.7.8';
8
+ const MCP_CLIENT_VERSION = '1.8.0';
9
9
 
10
10
  import { Server } from '@modelcontextprotocol/sdk/server/index.js';
11
11
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
@@ -117,8 +117,8 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
117
117
  },
118
118
  fileType: {
119
119
  type: 'string',
120
- description: 'File type: json, yaml, yml, xml, csv, txt, md, html, properties',
121
- enum: ['json', 'yaml', 'yml', 'xml', 'csv', 'txt', 'md', 'html', 'properties', 'auto'],
120
+ description: 'File type: json, yaml, yml, xml, csv, txt, md, html, properties (Java), pdf, docx, doc, po (gettext), pot (gettext), mo (gettext), auto',
121
+ enum: ['json', 'yaml', 'yml', 'xml', 'csv', 'txt', 'md', 'html', 'properties', 'pdf', 'docx', 'doc', 'po', 'pot', 'mo', 'auto'],
122
122
  default: 'auto',
123
123
  },
124
124
  targetLanguages: {
@@ -164,6 +164,46 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
164
164
  required: ['targetLanguages'],
165
165
  },
166
166
  },
167
+ {
168
+ name: 'analyze_content',
169
+ description: 'Analyze content for translation readiness and get improvement suggestions. Returns detailed analysis including content type, quality score, and specific recommendations. Costs the same credits as translation.',
170
+ inputSchema: {
171
+ type: 'object',
172
+ properties: {
173
+ content: {
174
+ type: ['string', 'array', 'object'],
175
+ description: 'Content to analyze (text string, array of texts, or structured object)',
176
+ },
177
+ fileType: {
178
+ type: 'string',
179
+ description: 'Optional file type if content is from a file (json, yaml, xml, etc.)',
180
+ },
181
+ sourceLanguage: {
182
+ type: 'string',
183
+ description: 'Source language code (auto-detected if not provided)',
184
+ },
185
+ targetLanguage: {
186
+ type: 'string',
187
+ description: 'Target language code for translation',
188
+ },
189
+ industry: {
190
+ type: 'string',
191
+ description: 'Industry context (e.g., "technology", "healthcare", "finance")',
192
+ default: 'general',
193
+ },
194
+ targetAudience: {
195
+ type: 'string',
196
+ description: 'Target audience (e.g., "general", "technical", "professional")',
197
+ default: 'general',
198
+ },
199
+ region: {
200
+ type: 'string',
201
+ description: 'Specific region for localization (e.g., "Spain", "Mexico", "Brazil")',
202
+ },
203
+ },
204
+ required: ['content', 'targetLanguage'],
205
+ },
206
+ },
167
207
  {
168
208
  name: 'get_credits',
169
209
  description: 'Get remaining credits for the user and approximate word count available at 0.001 credits per word',
@@ -265,15 +305,18 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
265
305
  case 'translate_file':
266
306
  return await handleTranslateFile(args);
267
307
 
308
+ case 'analyze_content':
309
+ return await handleAnalyzeContent(args);
310
+
268
311
  case 'get_credits':
269
312
  return await handleGetCredits(args);
270
-
313
+
271
314
  /*
272
315
  * TOKEN USAGE TOOLS - BLOCKED FOR SECURITY
273
316
  * These cases are intentionally removed to prevent access to sensitive analytics data
274
317
  * through MCP interfaces. See tool definition comments above for details.
275
318
  */
276
-
319
+
277
320
  case 'check_translation_status':
278
321
  return await handleCheckTranslationStatus(args);
279
322
 
@@ -911,10 +954,86 @@ async function pollTranslationJob(jobId, estimatedTime) {
911
954
  throw new Error(`Translation job ${jobId} timed out after ${maxPolls * pollInterval / 1000} seconds. Please retry with a smaller chunk or split the content into multiple requests.`);
912
955
  }
913
956
 
957
+ async function handleAnalyzeContent(args) {
958
+ const {
959
+ content,
960
+ fileType,
961
+ sourceLanguage,
962
+ targetLanguage,
963
+ industry = 'general',
964
+ targetAudience = 'general',
965
+ region
966
+ } = args;
967
+
968
+ if (!content) {
969
+ throw new Error('content is required');
970
+ }
971
+
972
+ if (!targetLanguage) {
973
+ throw new Error('targetLanguage is required');
974
+ }
975
+
976
+ // Use MCP JSON-RPC protocol for analyze_content
977
+ const mcpRequest = {
978
+ jsonrpc: '2.0',
979
+ id: Date.now(),
980
+ method: 'tools/call',
981
+ params: {
982
+ name: 'analyze_content',
983
+ arguments: {
984
+ apiKey: API_KEY,
985
+ content,
986
+ fileType,
987
+ sourceLanguage,
988
+ targetLanguage,
989
+ industry,
990
+ targetAudience,
991
+ region
992
+ }
993
+ }
994
+ };
995
+
996
+ try {
997
+ const response = await axios.post(MCP_SERVER_URL, mcpRequest, {
998
+ headers: {
999
+ 'Content-Type': 'application/json',
1000
+ },
1001
+ timeout: 60000, // 1 minute timeout for analysis
1002
+ });
1003
+
1004
+ if (response.data.error) {
1005
+ const errorMsg = response.data.error.message || response.data.error;
1006
+ throw new Error(`Content analysis error: ${errorMsg}`);
1007
+ }
1008
+
1009
+ return response.data.result;
1010
+ } catch (error) {
1011
+ // Handle 401 unauthorized
1012
+ if (error.response?.status === 401) {
1013
+ const authErrorDetails = error.response.data?.message || error.response.data?.result?.content?.[0]?.text || error.message;
1014
+ throw new Error(`❌ Invalid API key (401)\nDetails: ${authErrorDetails}\nPlease check your API key at https://app.i18nagent.ai\n[MCP v${MCP_CLIENT_VERSION}/STDIO/analyze_content]`);
1015
+ }
1016
+
1017
+ // Handle 402 payment required
1018
+ if (error.response?.status === 402) {
1019
+ const creditErrorDetails = error.response.data?.message || error.response.data?.result?.content?.[0]?.text || error.message;
1020
+ throw new Error(`⚠️ Insufficient credits (402)\nDetails: ${creditErrorDetails}\nPlease top up at https://app.i18nagent.ai\n[MCP v${MCP_CLIENT_VERSION}/STDIO/analyze_content]`);
1021
+ }
1022
+
1023
+ // Handle 503 service unavailable
1024
+ if (error.response?.status === 503) {
1025
+ throw new Error(`i18n-agent encountered unexpected problem, and we are working on it, try again later.`);
1026
+ }
1027
+
1028
+ console.error('Content analysis error:', error);
1029
+ throw new Error(`Unable to analyze content: ${error.message}`);
1030
+ }
1031
+ }
1032
+
914
1033
  async function handleGetCredits(args) {
915
1034
  const { apiKey } = args;
916
1035
  const creditsApiKey = apiKey || API_KEY;
917
-
1036
+
918
1037
  // Use MCP JSON-RPC protocol for get_credits
919
1038
  const mcpRequest = {
920
1039
  jsonrpc: '2.0',
@@ -927,7 +1046,7 @@ async function handleGetCredits(args) {
927
1046
  }
928
1047
  }
929
1048
  };
930
-
1049
+
931
1050
  try {
932
1051
  const response = await axios.post(MCP_SERVER_URL, mcpRequest, {
933
1052
  headers: {
@@ -938,13 +1057,13 @@ async function handleGetCredits(args) {
938
1057
 
939
1058
  if (response.data.error) {
940
1059
  const errorMsg = response.data.error.message || response.data.error;
941
- const isAuthError = errorMsg.toString().toLowerCase().includes('api key') ||
1060
+ const isAuthError = errorMsg.toString().toLowerCase().includes('api key') ||
942
1061
  errorMsg.toString().toLowerCase().includes('api_key') ||
943
1062
  errorMsg.toString().toLowerCase().includes('unauthorized');
944
- const isCreditError = errorMsg.toString().toLowerCase().includes('credit') ||
1063
+ const isCreditError = errorMsg.toString().toLowerCase().includes('credit') ||
945
1064
  errorMsg.toString().toLowerCase().includes('quota') ||
946
1065
  errorMsg.toString().toLowerCase().includes('limit exceeded');
947
-
1066
+
948
1067
  let finalErrorMsg = `Credits service error: ${errorMsg}`;
949
1068
  if (!isAuthError && !isCreditError) {
950
1069
  finalErrorMsg += `. Please check the service status or contact support.`;
@@ -955,12 +1074,12 @@ async function handleGetCredits(args) {
955
1074
  const result = response.data.result;
956
1075
  if (result && result.content && result.content[0]) {
957
1076
  const textContent = result.content[0].text;
958
-
1077
+
959
1078
  // Try to parse as JSON for structured data
960
1079
  try {
961
1080
  const parsed = JSON.parse(textContent);
962
1081
  const approximateWordsAvailable = parsed.credits ? Math.floor(parsed.credits * 1000) : 0;
963
-
1082
+
964
1083
  return {
965
1084
  content: [
966
1085
  {
@@ -979,7 +1098,7 @@ async function handleGetCredits(args) {
979
1098
  return result;
980
1099
  }
981
1100
  }
982
-
1101
+
983
1102
  return result;
984
1103
  } catch (error) {
985
1104
  // Handle 401 unauthorized
@@ -987,7 +1106,7 @@ async function handleGetCredits(args) {
987
1106
  const creditsAuthErrorDetails = error.response.data?.message || error.response.data?.result?.content?.[0]?.text || error.message;
988
1107
  throw new Error(`❌ Invalid API key (401)\nDetails: ${creditsAuthErrorDetails}\nPlease check your API key at https://app.i18nagent.ai\n[MCP v${MCP_CLIENT_VERSION}/STDIO/get_credits]`);
989
1108
  }
990
-
1109
+
991
1110
  console.error('Credits check error:', error);
992
1111
  throw new Error(`Unable to check credits: ${error.message}`);
993
1112
  }
@@ -1469,7 +1588,10 @@ async function handleDownloadTranslations(args) {
1469
1588
  method: 'tools/call',
1470
1589
  params: {
1471
1590
  name: 'download_translations',
1472
- arguments: { jobId }
1591
+ arguments: {
1592
+ apiKey: API_KEY,
1593
+ jobId
1594
+ }
1473
1595
  }
1474
1596
  };
1475
1597
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@i18n-agent/mcp-client",
3
- "version": "1.7.8",
3
+ "version": "1.8.0",
4
4
  "description": "MCP client for i18n-agent translation service with async job support and enhanced progress tracking - supports Claude, Cursor, VS Code, and other AI IDEs",
5
5
  "main": "mcp-client.js",
6
6
  "bin": {