@i18n-agent/mcp-client 1.8.463 → 1.9.1
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/install.js +328 -11
- package/mcp-client.js +16 -33
- package/package.json +1 -1
package/install.js
CHANGED
|
@@ -153,21 +153,40 @@ function checkExistingApiKey(configPath) {
|
|
|
153
153
|
}
|
|
154
154
|
}
|
|
155
155
|
|
|
156
|
-
async function checkExistingApiKeys(availableIDEs) {
|
|
156
|
+
async function checkExistingApiKeys(availableIDEs, claudeCodeCLIAvailable = false, codexCLIAvailable = false) {
|
|
157
157
|
const withKeys = [];
|
|
158
158
|
const withoutKeys = [];
|
|
159
159
|
|
|
160
160
|
for (const ide of availableIDEs) {
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
161
|
+
let hasKey = false;
|
|
162
|
+
|
|
163
|
+
// Check CLI registrations first for native CLI tools
|
|
164
|
+
if (ide.key === 'claude-code' && claudeCodeCLIAvailable) {
|
|
165
|
+
const cliKey = getClaudeCodeExistingApiKey('i18n-agent');
|
|
166
|
+
if (cliKey) {
|
|
167
|
+
hasKey = true;
|
|
168
|
+
}
|
|
169
|
+
} else if (ide.key === 'codex' && codexCLIAvailable) {
|
|
170
|
+
const cliKey = getCodexExistingApiKey('i18n-agent');
|
|
171
|
+
if (cliKey) {
|
|
172
|
+
hasKey = true;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Fall back to config file check
|
|
177
|
+
if (!hasKey) {
|
|
178
|
+
// Also check ~/.claude.json for Claude Code CLI
|
|
179
|
+
if (ide.key === 'claude-code') {
|
|
180
|
+
const claudeJsonPath = path.join(os.homedir(), '.claude.json');
|
|
181
|
+
if (checkExistingApiKey(claudeJsonPath)) {
|
|
182
|
+
hasKey = true;
|
|
183
|
+
}
|
|
184
|
+
} else if (checkExistingApiKey(ide.configPath)) {
|
|
185
|
+
hasKey = true;
|
|
167
186
|
}
|
|
168
187
|
}
|
|
169
188
|
|
|
170
|
-
if (
|
|
189
|
+
if (hasKey) {
|
|
171
190
|
withKeys.push(ide);
|
|
172
191
|
} else {
|
|
173
192
|
withoutKeys.push(ide);
|
|
@@ -201,7 +220,7 @@ function detectNodeEnvironment() {
|
|
|
201
220
|
const nvmDir = process.env.NVM_DIR || path.join(os.homedir(), '.nvm');
|
|
202
221
|
const nodeVersion = process.version;
|
|
203
222
|
const nodePath = process.execPath;
|
|
204
|
-
|
|
223
|
+
|
|
205
224
|
return {
|
|
206
225
|
isNvm: nodePath.includes('.nvm') || nodePath.includes('nvm'),
|
|
207
226
|
nodePath,
|
|
@@ -209,6 +228,195 @@ function detectNodeEnvironment() {
|
|
|
209
228
|
};
|
|
210
229
|
}
|
|
211
230
|
|
|
231
|
+
// Detect if Codex CLI is available
|
|
232
|
+
function isCodexCLIAvailable() {
|
|
233
|
+
try {
|
|
234
|
+
execSync('codex --version', { stdio: 'pipe' });
|
|
235
|
+
return true;
|
|
236
|
+
} catch {
|
|
237
|
+
return false;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// Check if MCP server is already registered in Codex
|
|
242
|
+
function isCodexMCPRegistered(serverName) {
|
|
243
|
+
try {
|
|
244
|
+
const result = execSync(`codex mcp get ${serverName}`, { stdio: 'pipe' });
|
|
245
|
+
return true;
|
|
246
|
+
} catch {
|
|
247
|
+
return false;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// Install MCP server via Codex CLI native command
|
|
252
|
+
function installViaCodexCLI(existingApiKey = '') {
|
|
253
|
+
const { mcpClientPath, packageDir } = getMcpClientPaths();
|
|
254
|
+
const nodeEnv = detectNodeEnvironment();
|
|
255
|
+
|
|
256
|
+
// Determine node command - use absolute path for nvm
|
|
257
|
+
const nodeCmd = nodeEnv.isNvm ? nodeEnv.nodePath : 'node';
|
|
258
|
+
|
|
259
|
+
// Get existing API key from CLI registration BEFORE removing
|
|
260
|
+
if (!existingApiKey) {
|
|
261
|
+
existingApiKey = getCodexExistingApiKey('i18n-agent');
|
|
262
|
+
if (existingApiKey) {
|
|
263
|
+
console.log(' 🔑 Preserving existing API key from CLI registration');
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// Remove existing registration if present
|
|
268
|
+
if (isCodexMCPRegistered('i18n-agent')) {
|
|
269
|
+
try {
|
|
270
|
+
execSync('codex mcp remove i18n-agent', { stdio: 'pipe' });
|
|
271
|
+
console.log(' 🔄 Removed existing i18n-agent registration');
|
|
272
|
+
} catch {
|
|
273
|
+
// Ignore if removal fails
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// Build the command with env vars
|
|
278
|
+
const envArgs = [
|
|
279
|
+
'--env', `MCP_SERVER_URL=https://mcp.i18nagent.ai`
|
|
280
|
+
];
|
|
281
|
+
|
|
282
|
+
if (existingApiKey) {
|
|
283
|
+
envArgs.push('--env', `API_KEY=${existingApiKey}`);
|
|
284
|
+
} else {
|
|
285
|
+
envArgs.push('--env', 'API_KEY=');
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// Build the full command
|
|
289
|
+
// codex mcp add [--env KEY=VALUE]... <name> <command> [args...]
|
|
290
|
+
const cmdParts = [
|
|
291
|
+
'codex', 'mcp', 'add',
|
|
292
|
+
...envArgs,
|
|
293
|
+
'i18n-agent',
|
|
294
|
+
nodeCmd,
|
|
295
|
+
mcpClientPath
|
|
296
|
+
];
|
|
297
|
+
|
|
298
|
+
// Execute the command
|
|
299
|
+
execSync(cmdParts.join(' '), {
|
|
300
|
+
cwd: packageDir,
|
|
301
|
+
stdio: 'pipe'
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
return true;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// Detect if Claude Code CLI is available
|
|
308
|
+
function isClaudeCodeCLIAvailable() {
|
|
309
|
+
try {
|
|
310
|
+
execSync('claude mcp list', { stdio: 'pipe' });
|
|
311
|
+
return true;
|
|
312
|
+
} catch {
|
|
313
|
+
return false;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// Check if MCP server is already registered in Claude Code CLI
|
|
318
|
+
function isClaudeCodeMCPRegistered(serverName) {
|
|
319
|
+
try {
|
|
320
|
+
execSync(`claude mcp get ${serverName}`, { stdio: 'pipe' });
|
|
321
|
+
return true;
|
|
322
|
+
} catch {
|
|
323
|
+
return false;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// Get existing API key from Claude Code CLI registration
|
|
328
|
+
function getClaudeCodeExistingApiKey(serverName) {
|
|
329
|
+
try {
|
|
330
|
+
const output = execSync(`claude mcp get ${serverName}`, { stdio: 'pipe', encoding: 'utf8' });
|
|
331
|
+
// Parse output like: API_KEY=i18n_xxx
|
|
332
|
+
const match = output.match(/API_KEY=([^\s,\n]+)/);
|
|
333
|
+
if (match && match[1] && match[1] !== '') {
|
|
334
|
+
return match[1];
|
|
335
|
+
}
|
|
336
|
+
} catch {
|
|
337
|
+
// Server not registered
|
|
338
|
+
}
|
|
339
|
+
return '';
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// Get existing API key from Codex CLI registration
|
|
343
|
+
function getCodexExistingApiKey(serverName) {
|
|
344
|
+
try {
|
|
345
|
+
const output = execSync(`codex mcp list`, { stdio: 'pipe', encoding: 'utf8' });
|
|
346
|
+
// Parse output - Codex shows: API_KEY=i18n_xxx, MCP_SERVER_URL=...
|
|
347
|
+
const lines = output.split('\n');
|
|
348
|
+
for (const line of lines) {
|
|
349
|
+
if (line.includes(serverName)) {
|
|
350
|
+
const match = line.match(/API_KEY=([^\s,]+)/);
|
|
351
|
+
if (match && match[1] && match[1] !== '') {
|
|
352
|
+
return match[1];
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
} catch {
|
|
357
|
+
// Server not registered
|
|
358
|
+
}
|
|
359
|
+
return '';
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
// Install MCP server via Claude Code CLI native command
|
|
363
|
+
function installViaClaudeCodeCLI(existingApiKey = '', scope = 'user') {
|
|
364
|
+
const { mcpClientPath } = getMcpClientPaths();
|
|
365
|
+
const nodeEnv = detectNodeEnvironment();
|
|
366
|
+
|
|
367
|
+
// Determine node command - use absolute path for nvm
|
|
368
|
+
const nodeCmd = nodeEnv.isNvm ? nodeEnv.nodePath : 'node';
|
|
369
|
+
|
|
370
|
+
// Get existing API key from CLI registration BEFORE removing
|
|
371
|
+
if (!existingApiKey) {
|
|
372
|
+
existingApiKey = getClaudeCodeExistingApiKey('i18n-agent');
|
|
373
|
+
if (existingApiKey) {
|
|
374
|
+
console.log(' 🔑 Preserving existing API key from CLI registration');
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// Remove existing registration if present
|
|
379
|
+
if (isClaudeCodeMCPRegistered('i18n-agent')) {
|
|
380
|
+
try {
|
|
381
|
+
execSync(`claude mcp remove --scope ${scope} i18n-agent`, { stdio: 'pipe' });
|
|
382
|
+
console.log(' 🔄 Removed existing i18n-agent registration');
|
|
383
|
+
} catch {
|
|
384
|
+
// Ignore if removal fails
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
// Build env args using -e format (Claude uses -e, not --env)
|
|
389
|
+
// Note: -e args must come AFTER the server name
|
|
390
|
+
const envArgs = [
|
|
391
|
+
'-e', `MCP_SERVER_URL=https://mcp.i18nagent.ai`
|
|
392
|
+
];
|
|
393
|
+
|
|
394
|
+
if (existingApiKey) {
|
|
395
|
+
envArgs.push('-e', `API_KEY=${existingApiKey}`);
|
|
396
|
+
} else {
|
|
397
|
+
envArgs.push('-e', 'API_KEY=');
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
// Build the full command
|
|
401
|
+
// claude mcp add --transport stdio --scope user <name> -e KEY=VALUE -- <command> [args...]
|
|
402
|
+
// Note: <name> must come BEFORE -e options
|
|
403
|
+
const cmdParts = [
|
|
404
|
+
'claude', 'mcp', 'add',
|
|
405
|
+
'--transport', 'stdio',
|
|
406
|
+
'--scope', scope,
|
|
407
|
+
'i18n-agent', // Name must come before -e options
|
|
408
|
+
...envArgs,
|
|
409
|
+
'--', // Separator for command arguments
|
|
410
|
+
nodeCmd,
|
|
411
|
+
mcpClientPath
|
|
412
|
+
];
|
|
413
|
+
|
|
414
|
+
// Execute the command
|
|
415
|
+
execSync(cmdParts.join(' '), { stdio: 'pipe' });
|
|
416
|
+
|
|
417
|
+
return true;
|
|
418
|
+
}
|
|
419
|
+
|
|
212
420
|
function createWrapperScript(targetDir) {
|
|
213
421
|
const nodeEnv = detectNodeEnvironment();
|
|
214
422
|
const wrapperPath = path.join(targetDir, 'run-mcp.sh');
|
|
@@ -407,8 +615,12 @@ For manual setup instructions, visit: https://docs.i18nagent.ai/setup
|
|
|
407
615
|
});
|
|
408
616
|
console.log('');
|
|
409
617
|
|
|
618
|
+
// Check if native CLIs are available (needed for API key detection)
|
|
619
|
+
const codexCLIAvailable = isCodexCLIAvailable();
|
|
620
|
+
const claudeCodeCLIAvailable = isClaudeCodeCLIAvailable();
|
|
621
|
+
|
|
410
622
|
// Check for existing API keys BEFORE installation
|
|
411
|
-
const { withKeys, withoutKeys } = await checkExistingApiKeys(availableIDEs);
|
|
623
|
+
const { withKeys, withoutKeys } = await checkExistingApiKeys(availableIDEs, claudeCodeCLIAvailable, codexCLIAvailable);
|
|
412
624
|
|
|
413
625
|
if (withKeys.length > 0 && withoutKeys.length === 0) {
|
|
414
626
|
console.log(`✅ API Keys Already Configured:`);
|
|
@@ -448,11 +660,92 @@ For manual setup instructions, visit: https://docs.i18nagent.ai/setup
|
|
|
448
660
|
const idesWithApiKey = [];
|
|
449
661
|
const idesNeedingApiKey = [];
|
|
450
662
|
|
|
663
|
+
// Show native CLI detection message (CLIs already detected above)
|
|
664
|
+
if (codexCLIAvailable || claudeCodeCLIAvailable) {
|
|
665
|
+
console.log('🔧 Native CLI support detected:');
|
|
666
|
+
if (claudeCodeCLIAvailable) {
|
|
667
|
+
console.log(' - Claude Code CLI (`claude mcp add`)');
|
|
668
|
+
}
|
|
669
|
+
if (codexCLIAvailable) {
|
|
670
|
+
console.log(' - Codex CLI (`codex mcp add`)');
|
|
671
|
+
}
|
|
672
|
+
console.log('');
|
|
673
|
+
}
|
|
674
|
+
|
|
451
675
|
for (const ide of availableIDEs) {
|
|
452
676
|
try {
|
|
453
677
|
console.log(`⚙️ Configuring ${ide.name}...`);
|
|
454
678
|
|
|
455
679
|
let result;
|
|
680
|
+
|
|
681
|
+
// Special handling for Claude Code CLI - use native CLI if available
|
|
682
|
+
if (ide.key === 'claude-code' && claudeCodeCLIAvailable) {
|
|
683
|
+
// Get existing API key - check CLI registration first, then config file
|
|
684
|
+
let existingApiKey = getClaudeCodeExistingApiKey('i18n-agent');
|
|
685
|
+
if (!existingApiKey && fs.existsSync(ide.configPath)) {
|
|
686
|
+
try {
|
|
687
|
+
const content = fs.readFileSync(ide.configPath, 'utf8');
|
|
688
|
+
const config = JSON.parse(content);
|
|
689
|
+
existingApiKey = config.mcpServers?.["i18n-agent"]?.env?.API_KEY || '';
|
|
690
|
+
} catch {
|
|
691
|
+
// Ignore parse errors
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
try {
|
|
696
|
+
installViaClaudeCodeCLI(existingApiKey);
|
|
697
|
+
console.log(`✅ ${ide.name} configured via native CLI!`);
|
|
698
|
+
console.log(` Run 'claude mcp list' to verify\n`);
|
|
699
|
+
installCount++;
|
|
700
|
+
installedIDEs.push(ide);
|
|
701
|
+
|
|
702
|
+
// Track API key status
|
|
703
|
+
if (existingApiKey) {
|
|
704
|
+
idesWithApiKey.push(ide);
|
|
705
|
+
} else {
|
|
706
|
+
idesNeedingApiKey.push(ide);
|
|
707
|
+
}
|
|
708
|
+
continue;
|
|
709
|
+
} catch (cliError) {
|
|
710
|
+
console.log(` ⚠️ Native CLI failed, falling back to config file...`);
|
|
711
|
+
// Fall through to config file method
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
// Special handling for Codex - use native CLI if available
|
|
716
|
+
if (ide.key === 'codex' && codexCLIAvailable) {
|
|
717
|
+
// Get existing API key - check CLI registration first, then config file
|
|
718
|
+
let existingApiKey = getCodexExistingApiKey('i18n-agent');
|
|
719
|
+
if (!existingApiKey && fs.existsSync(ide.configPath)) {
|
|
720
|
+
try {
|
|
721
|
+
const content = fs.readFileSync(ide.configPath, 'utf8');
|
|
722
|
+
const config = JSON.parse(content);
|
|
723
|
+
existingApiKey = config.mcpServers?.["i18n-agent"]?.env?.API_KEY || '';
|
|
724
|
+
} catch {
|
|
725
|
+
// Ignore parse errors
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
try {
|
|
730
|
+
installViaCodexCLI(existingApiKey);
|
|
731
|
+
console.log(`✅ ${ide.name} configured via native CLI!`);
|
|
732
|
+
console.log(` Run 'codex mcp list' to verify\n`);
|
|
733
|
+
installCount++;
|
|
734
|
+
installedIDEs.push(ide);
|
|
735
|
+
|
|
736
|
+
// Track API key status
|
|
737
|
+
if (existingApiKey) {
|
|
738
|
+
idesWithApiKey.push(ide);
|
|
739
|
+
} else {
|
|
740
|
+
idesNeedingApiKey.push(ide);
|
|
741
|
+
}
|
|
742
|
+
continue;
|
|
743
|
+
} catch (cliError) {
|
|
744
|
+
console.log(` ⚠️ Native CLI failed, falling back to config file...`);
|
|
745
|
+
// Fall through to config file method
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
|
|
456
749
|
if (ide.key === 'claude' || ide.key === 'claude-code') {
|
|
457
750
|
result = updateClaudeConfig(ide.configPath, ide.key);
|
|
458
751
|
} else {
|
|
@@ -495,6 +788,12 @@ For manual setup instructions, visit: https://docs.i18nagent.ai/setup
|
|
|
495
788
|
});
|
|
496
789
|
console.log('');
|
|
497
790
|
|
|
791
|
+
// Check if CLIs need API key
|
|
792
|
+
const codexNeedsKey = idesNeedingApiKey.some(ide => ide.key === 'codex');
|
|
793
|
+
const claudeCodeNeedsKey = idesNeedingApiKey.some(ide => ide.key === 'claude-code');
|
|
794
|
+
const showCodexInstructions = codexNeedsKey && codexCLIAvailable;
|
|
795
|
+
const showClaudeCodeInstructions = claudeCodeNeedsKey && claudeCodeCLIAvailable;
|
|
796
|
+
|
|
498
797
|
// Show setup instructions only for IDEs that need them
|
|
499
798
|
console.log(`🔑 Setup Instructions
|
|
500
799
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
@@ -503,7 +802,25 @@ Step 1: Get your API key
|
|
|
503
802
|
👉 Sign up or log in
|
|
504
803
|
👉 Copy your API key (starts with "i18n_")
|
|
505
804
|
|
|
506
|
-
Step 2: Add API key to
|
|
805
|
+
Step 2: Add API key to your IDE`);
|
|
806
|
+
|
|
807
|
+
if (showClaudeCodeInstructions) {
|
|
808
|
+
console.log(`
|
|
809
|
+
For Claude Code CLI (recommended):
|
|
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
|
|
812
|
+
`);
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
if (showCodexInstructions) {
|
|
816
|
+
console.log(`
|
|
817
|
+
For Codex CLI (recommended):
|
|
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
|
|
820
|
+
`);
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
console.log(` For config file method:
|
|
507
824
|
Open the config file and edit the "API_KEY" field:
|
|
508
825
|
|
|
509
826
|
"mcpServers": {
|
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
|
+
const MCP_CLIENT_VERSION = '1.9.1';
|
|
9
9
|
|
|
10
10
|
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
11
11
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
@@ -49,7 +49,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
49
49
|
tools: [
|
|
50
50
|
{
|
|
51
51
|
name: 'translate_text',
|
|
52
|
-
description: '
|
|
52
|
+
description: 'Translate text content with cultural adaptation using AI subagents. Supports single or multi-language translation via targetLanguages parameter (string for single, array for multiple). For large requests (>100 texts or >50,000 characters), returns a jobId for async processing. Use check_translation_status to monitor progress and download results. Set pseudoTranslation=true for testing i18n implementations without AI cost.',
|
|
53
53
|
inputSchema: {
|
|
54
54
|
type: 'object',
|
|
55
55
|
properties: {
|
|
@@ -59,7 +59,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
59
59
|
description: 'Array of source texts to translate (any language)',
|
|
60
60
|
},
|
|
61
61
|
targetLanguages: {
|
|
62
|
-
description: '
|
|
62
|
+
description: 'Target language(s) - provide a single string (e.g., "es") OR an array (e.g., ["es", "fr", "zh-CN"]) for multi-language translation. Use specific locale codes like "en-US" or "en-GB" instead of generic "en".',
|
|
63
63
|
oneOf: [
|
|
64
64
|
{ type: 'string' },
|
|
65
65
|
{ type: 'array', items: { type: 'string' } }
|
|
@@ -144,7 +144,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
144
144
|
},
|
|
145
145
|
{
|
|
146
146
|
name: 'translate_file',
|
|
147
|
-
description: '
|
|
147
|
+
description: 'Translate file content while preserving structure and format. Supports single or multi-language translation via targetLanguages parameter (string for single, array for multiple). Supports JSON, YAML, XML, CSV, TXT, MD, and other text files. Always returns a jobId for async processing - use check_translation_status to monitor progress and download_translations to get results. Set pseudoTranslation=true for testing i18n implementations without AI cost.',
|
|
148
148
|
inputSchema: {
|
|
149
149
|
type: 'object',
|
|
150
150
|
properties: {
|
|
@@ -163,7 +163,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
163
163
|
default: 'auto',
|
|
164
164
|
},
|
|
165
165
|
targetLanguages: {
|
|
166
|
-
description: '
|
|
166
|
+
description: 'Target language(s) - provide a single string (e.g., "es") OR an array (e.g., ["es", "fr", "zh-CN"]) for multi-language translation. Use specific locale codes like "en-US" or "en-GB" instead of generic "en".',
|
|
167
167
|
oneOf: [
|
|
168
168
|
{ type: 'string' },
|
|
169
169
|
{ type: 'array', items: { type: 'string' } }
|
|
@@ -555,17 +555,9 @@ async function handleTranslateText(args) {
|
|
|
555
555
|
// Namespace is optional for text translation, but recommended for organizational tracking
|
|
556
556
|
|
|
557
557
|
// Normalize targetLanguages - accept both string and array
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
if (typeof rawTargetLanguages === 'string') {
|
|
562
|
-
// Single language provided as string - convert to array for internal processing
|
|
563
|
-
targetLanguages = [rawTargetLanguages];
|
|
564
|
-
targetLanguage = rawTargetLanguages;
|
|
565
|
-
} else if (Array.isArray(rawTargetLanguages) && rawTargetLanguages.length === 1) {
|
|
566
|
-
// Single language provided as array - extract for backward compatibility
|
|
567
|
-
targetLanguage = rawTargetLanguages[0];
|
|
568
|
-
}
|
|
558
|
+
const targetLanguages = typeof rawTargetLanguages === 'string'
|
|
559
|
+
? [rawTargetLanguages]
|
|
560
|
+
: rawTargetLanguages;
|
|
569
561
|
|
|
570
562
|
if (!targetLanguages?.length) {
|
|
571
563
|
throw new Error('targetLanguages parameter is required (can be a string for single language or array for multiple languages)');
|
|
@@ -585,7 +577,6 @@ async function handleTranslateText(args) {
|
|
|
585
577
|
arguments: {
|
|
586
578
|
apiKey: API_KEY,
|
|
587
579
|
texts: texts,
|
|
588
|
-
targetLanguage: targetLanguage,
|
|
589
580
|
targetLanguages: targetLanguages,
|
|
590
581
|
sourceLanguage: sourceLanguage && sourceLanguage !== 'auto' ? sourceLanguage : undefined,
|
|
591
582
|
targetAudience: targetAudience,
|
|
@@ -640,12 +631,12 @@ async function handleTranslateText(args) {
|
|
|
640
631
|
// Extract the actual translation result from the job result
|
|
641
632
|
if (jobResult && jobResult.content && jobResult.content[0]) {
|
|
642
633
|
const translationData = JSON.parse(jobResult.content[0].text);
|
|
643
|
-
return formatTranslationResult(translationData, texts,
|
|
634
|
+
return formatTranslationResult(translationData, texts, targetLanguages, sourceLanguage, targetAudience, industry, region);
|
|
644
635
|
}
|
|
645
636
|
return jobResult;
|
|
646
637
|
} else {
|
|
647
638
|
// Regular synchronous result
|
|
648
|
-
return formatTranslationResult(parsed, texts,
|
|
639
|
+
return formatTranslationResult(parsed, texts, targetLanguages, sourceLanguage, targetAudience, industry, region);
|
|
649
640
|
}
|
|
650
641
|
} catch {
|
|
651
642
|
// Not JSON or error parsing - return as-is
|
|
@@ -894,17 +885,9 @@ async function handleTranslateFile(args) {
|
|
|
894
885
|
}
|
|
895
886
|
|
|
896
887
|
// Normalize targetLanguages - accept both string and array
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
if (typeof rawTargetLanguages === 'string') {
|
|
901
|
-
// Single language provided as string - convert to array for internal processing
|
|
902
|
-
targetLanguages = [rawTargetLanguages];
|
|
903
|
-
targetLanguage = rawTargetLanguages;
|
|
904
|
-
} else if (Array.isArray(rawTargetLanguages) && rawTargetLanguages.length === 1) {
|
|
905
|
-
// Single language provided as array - extract for backward compatibility
|
|
906
|
-
targetLanguage = rawTargetLanguages[0];
|
|
907
|
-
}
|
|
888
|
+
const targetLanguages = typeof rawTargetLanguages === 'string'
|
|
889
|
+
? [rawTargetLanguages]
|
|
890
|
+
: rawTargetLanguages;
|
|
908
891
|
|
|
909
892
|
if (!targetLanguages?.length) {
|
|
910
893
|
throw new Error('targetLanguages parameter is required (can be a string for single language or array for multiple languages)');
|
|
@@ -939,7 +922,6 @@ async function handleTranslateFile(args) {
|
|
|
939
922
|
};
|
|
940
923
|
|
|
941
924
|
// Add optional parameters only if defined
|
|
942
|
-
if (targetLanguage !== undefined) requestArgs.targetLanguage = targetLanguage;
|
|
943
925
|
if (targetLanguages !== undefined) requestArgs.targetLanguages = targetLanguages;
|
|
944
926
|
if (region !== undefined) requestArgs.region = region;
|
|
945
927
|
if (context !== undefined) requestArgs.context = context;
|
|
@@ -1078,14 +1060,15 @@ async function handleTranslateFile(args) {
|
|
|
1078
1060
|
}
|
|
1079
1061
|
|
|
1080
1062
|
// Format translation result for consistent output
|
|
1081
|
-
function formatTranslationResult(parsedResult, texts,
|
|
1063
|
+
function formatTranslationResult(parsedResult, texts, targetLanguages, sourceLanguage, targetAudience, industry, region) {
|
|
1064
|
+
const targetLangsDisplay = Array.isArray(targetLanguages) ? targetLanguages.join(', ') : targetLanguages;
|
|
1082
1065
|
return {
|
|
1083
1066
|
translatedTexts: parsedResult?.translatedTexts || [],
|
|
1084
1067
|
content: [
|
|
1085
1068
|
{
|
|
1086
1069
|
type: 'text',
|
|
1087
1070
|
text: `Translation Results:\n\n` +
|
|
1088
|
-
`🌍 ${parsedResult?.sourceLanguage || sourceLanguage || 'Auto-detected'} → ${parsedResult?.
|
|
1071
|
+
`🌍 ${parsedResult?.sourceLanguage || sourceLanguage || 'Auto-detected'} → ${parsedResult?.targetLanguages?.join(', ') || targetLangsDisplay}\n` +
|
|
1089
1072
|
`👥 Audience: ${parsedResult?.targetAudience || targetAudience}\n` +
|
|
1090
1073
|
`🏭 Industry: ${parsedResult?.industry || industry}\n` +
|
|
1091
1074
|
`${parsedResult?.region || region ? `📍 Region: ${parsedResult?.region || region}\n` : ''}` +
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@i18n-agent/mcp-client",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.9.1",
|
|
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": {
|