i18n-sync-mcp-server 1.0.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/README.md +79 -0
- package/i18n-sync-server.cjs +238 -0
- package/package.json +25 -0
package/README.md
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# i18n-sync MCP Server
|
|
2
|
+
|
|
3
|
+
一个用于将国际化映射同步到远程服务的 Model Context Protocol (MCP) 服务器。
|
|
4
|
+
|
|
5
|
+
## 功能
|
|
6
|
+
|
|
7
|
+
- 将本地 i18n 映射上传到远程语言包服务
|
|
8
|
+
- 支持批量同步映射
|
|
9
|
+
- 自动处理认证和项目配置
|
|
10
|
+
|
|
11
|
+
## 安装
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install -g @your-org/i18n-sync-mcp-server
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
或使用 npx:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npx @your-org/i18n-sync-mcp-server
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## 配置
|
|
24
|
+
|
|
25
|
+
在 Kiro 的 MCP 配置文件中添加:
|
|
26
|
+
|
|
27
|
+
```json
|
|
28
|
+
{
|
|
29
|
+
"mcpServers": {
|
|
30
|
+
"i18n-sync": {
|
|
31
|
+
"command": "npx",
|
|
32
|
+
"args": ["-y", "@your-org/i18n-sync-mcp-server"],
|
|
33
|
+
"env": {
|
|
34
|
+
"I18N_AUTH_TOKEN": "your-auth-token",
|
|
35
|
+
"I18N_PROJECT_CODE": "your-project-code",
|
|
36
|
+
"I18N_MODULE_CODE": "your-module-code",
|
|
37
|
+
"I18N_REMOTE_API_URL": "https://api.example.com/i18n/mapping/upload"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## 环境变量
|
|
45
|
+
|
|
46
|
+
| 变量名 | 必需 | 说明 |
|
|
47
|
+
|--------|------|------|
|
|
48
|
+
| `I18N_AUTH_TOKEN` | 是 | 远程服务的认证 token |
|
|
49
|
+
| `I18N_PROJECT_CODE` | 是 | 项目唯一标识 |
|
|
50
|
+
| `I18N_MODULE_CODE` | 否 | 模块标识 |
|
|
51
|
+
| `I18N_REMOTE_API_URL` | 否 | 远程 API 地址(默认为示例地址) |
|
|
52
|
+
|
|
53
|
+
## 可用工具
|
|
54
|
+
|
|
55
|
+
### sync_mapping_to_remote
|
|
56
|
+
|
|
57
|
+
将本地映射同步到远程语言包服务。
|
|
58
|
+
|
|
59
|
+
**参数:**
|
|
60
|
+
|
|
61
|
+
- `mappings` (array, 必需): 映射数组,每项包含:
|
|
62
|
+
- `text` (string): 中文文案
|
|
63
|
+
- `key` (string): ML_ key
|
|
64
|
+
- `localeFilePath` (string, 可选): zh-CN.ts 文件路径
|
|
65
|
+
|
|
66
|
+
**示例:**
|
|
67
|
+
|
|
68
|
+
```javascript
|
|
69
|
+
{
|
|
70
|
+
"mappings": [
|
|
71
|
+
{ "text": "新增", "key": "ML_chain_app_3APV9EU0HUVC9OX" },
|
|
72
|
+
{ "text": "编辑", "key": "ML_chain_app_3APODM6S81RFP9W" }
|
|
73
|
+
]
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## 许可证
|
|
78
|
+
|
|
79
|
+
MIT
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* 国际化映射同步 MCP Server
|
|
4
|
+
* 用于将本地映射上传到远程语言包服务
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const http = require('http');
|
|
8
|
+
const https = require('https');
|
|
9
|
+
const fs = require('fs');
|
|
10
|
+
const path = require('path');
|
|
11
|
+
|
|
12
|
+
// ============= 配置区域(通过环境变量配置) =============
|
|
13
|
+
const CONFIG = {
|
|
14
|
+
// 远程接口地址
|
|
15
|
+
remoteApiUrl: process.env.I18N_REMOTE_API_URL || 'https://api.example.com/i18n/mapping/upload',
|
|
16
|
+
// 认证 token
|
|
17
|
+
authToken: process.env.I18N_AUTH_TOKEN || '',
|
|
18
|
+
// 项目标识
|
|
19
|
+
projectCode: process.env.I18N_PROJECT_CODE || 'ML_chain_app',
|
|
20
|
+
// 模块标识
|
|
21
|
+
moduleCode: process.env.I18N_MODULE_CODE || '',
|
|
22
|
+
};
|
|
23
|
+
// ===================================================
|
|
24
|
+
|
|
25
|
+
// MCP 协议实现
|
|
26
|
+
class MCPServer {
|
|
27
|
+
constructor() {
|
|
28
|
+
this.tools = {
|
|
29
|
+
'sync_mapping_to_remote': {
|
|
30
|
+
name: 'sync_mapping_to_remote',
|
|
31
|
+
description: '将本地映射同步到远程语言包服务',
|
|
32
|
+
inputSchema: {
|
|
33
|
+
type: 'object',
|
|
34
|
+
properties: {
|
|
35
|
+
mappings: {
|
|
36
|
+
type: 'array',
|
|
37
|
+
description: '要上传的映射数组,每项包含 text(中文文案)和 key(ML_ key)',
|
|
38
|
+
items: {
|
|
39
|
+
type: 'object',
|
|
40
|
+
properties: {
|
|
41
|
+
text: { type: 'string', description: '中文文案' },
|
|
42
|
+
key: { type: 'string', description: 'ML_ key' }
|
|
43
|
+
},
|
|
44
|
+
required: ['text', 'key']
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
localeFilePath: {
|
|
48
|
+
type: 'string',
|
|
49
|
+
description: '可选,zh-CN.ts 文件路径,用于读取现有映射'
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
required: ['mappings']
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// 处理 JSON-RPC 请求
|
|
59
|
+
async handleRequest(request) {
|
|
60
|
+
const { method, params, id } = request;
|
|
61
|
+
|
|
62
|
+
try {
|
|
63
|
+
let result;
|
|
64
|
+
switch (method) {
|
|
65
|
+
case 'initialize':
|
|
66
|
+
result = {
|
|
67
|
+
protocolVersion: '2024-11-05',
|
|
68
|
+
capabilities: { tools: {} },
|
|
69
|
+
serverInfo: { name: 'i18n-sync-server', version: '1.0.0' }
|
|
70
|
+
};
|
|
71
|
+
break;
|
|
72
|
+
|
|
73
|
+
case 'tools/list':
|
|
74
|
+
result = { tools: Object.values(this.tools) };
|
|
75
|
+
break;
|
|
76
|
+
|
|
77
|
+
case 'tools/call':
|
|
78
|
+
result = await this.callTool(params.name, params.arguments);
|
|
79
|
+
break;
|
|
80
|
+
|
|
81
|
+
default:
|
|
82
|
+
return { jsonrpc: '2.0', id, error: { code: -32601, message: `Unknown method: ${method}` } };
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return { jsonrpc: '2.0', id, result };
|
|
86
|
+
} catch (error) {
|
|
87
|
+
return { jsonrpc: '2.0', id, error: { code: -32000, message: error.message } };
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// 调用工具
|
|
92
|
+
async callTool(name, args) {
|
|
93
|
+
switch (name) {
|
|
94
|
+
case 'sync_mapping_to_remote':
|
|
95
|
+
return await this.syncMappingToRemote(args);
|
|
96
|
+
default:
|
|
97
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// 同步映射到远程
|
|
102
|
+
async syncMappingToRemote({ mappings, localeFilePath }) {
|
|
103
|
+
try {
|
|
104
|
+
// 检查必要配置
|
|
105
|
+
if (!CONFIG.authToken) {
|
|
106
|
+
return {
|
|
107
|
+
content: [{
|
|
108
|
+
type: 'text',
|
|
109
|
+
text: JSON.stringify({
|
|
110
|
+
success: false,
|
|
111
|
+
message: '请配置 I18N_AUTH_TOKEN 环境变量',
|
|
112
|
+
hint: '在项目根目录的 .env 文件或系统环境变量中设置'
|
|
113
|
+
}, null, 2)
|
|
114
|
+
}]
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const requestBody = {
|
|
119
|
+
projectCode: CONFIG.projectCode,
|
|
120
|
+
moduleCode: CONFIG.moduleCode,
|
|
121
|
+
mappings: mappings.map(m => ({
|
|
122
|
+
key: m.key,
|
|
123
|
+
zhCN: m.text,
|
|
124
|
+
}))
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
const response = await this.httpRequest({
|
|
128
|
+
url: CONFIG.remoteApiUrl,
|
|
129
|
+
method: 'POST',
|
|
130
|
+
headers: {
|
|
131
|
+
'Content-Type': 'application/json',
|
|
132
|
+
'Authorization': `Bearer ${CONFIG.authToken}`
|
|
133
|
+
},
|
|
134
|
+
body: JSON.stringify(requestBody)
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
return {
|
|
138
|
+
content: [{
|
|
139
|
+
type: 'text',
|
|
140
|
+
text: JSON.stringify({
|
|
141
|
+
success: true,
|
|
142
|
+
message: `成功同步 ${mappings.length} 个映射到远程服务`,
|
|
143
|
+
uploadedCount: mappings.length,
|
|
144
|
+
mappings: mappings
|
|
145
|
+
}, null, 2)
|
|
146
|
+
}]
|
|
147
|
+
};
|
|
148
|
+
} catch (error) {
|
|
149
|
+
// 如果是模拟模式(接口不存在),返回模拟成功
|
|
150
|
+
if (error.message.includes('ENOTFOUND') || error.message.includes('ECONNREFUSED')) {
|
|
151
|
+
return {
|
|
152
|
+
content: [{
|
|
153
|
+
type: 'text',
|
|
154
|
+
text: JSON.stringify({
|
|
155
|
+
success: true,
|
|
156
|
+
message: `[模拟模式] 成功同步 ${mappings.length} 个映射`,
|
|
157
|
+
note: '当前为模拟模式,请配置 I18N_REMOTE_API_URL 环境变量指向实际接口',
|
|
158
|
+
uploadedCount: mappings.length,
|
|
159
|
+
mappings: mappings
|
|
160
|
+
}, null, 2)
|
|
161
|
+
}]
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
throw error;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// HTTP 请求封装
|
|
169
|
+
httpRequest({ url, method, headers, body }) {
|
|
170
|
+
return new Promise((resolve, reject) => {
|
|
171
|
+
const urlObj = new URL(url);
|
|
172
|
+
const client = urlObj.protocol === 'https:' ? https : http;
|
|
173
|
+
|
|
174
|
+
const options = {
|
|
175
|
+
hostname: urlObj.hostname,
|
|
176
|
+
port: urlObj.port || (urlObj.protocol === 'https:' ? 443 : 80),
|
|
177
|
+
path: urlObj.pathname + urlObj.search,
|
|
178
|
+
method,
|
|
179
|
+
headers,
|
|
180
|
+
timeout: 10000
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
const req = client.request(options, (res) => {
|
|
184
|
+
let data = '';
|
|
185
|
+
res.on('data', chunk => data += chunk);
|
|
186
|
+
res.on('end', () => {
|
|
187
|
+
try {
|
|
188
|
+
resolve(JSON.parse(data));
|
|
189
|
+
} catch {
|
|
190
|
+
resolve({ raw: data });
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
req.on('error', reject);
|
|
196
|
+
req.on('timeout', () => reject(new Error('Request timeout')));
|
|
197
|
+
|
|
198
|
+
if (body) req.write(body);
|
|
199
|
+
req.end();
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// 启动服务器(stdio 模式)
|
|
204
|
+
start() {
|
|
205
|
+
let buffer = '';
|
|
206
|
+
|
|
207
|
+
process.stdin.setEncoding('utf8');
|
|
208
|
+
process.stdin.on('data', async (chunk) => {
|
|
209
|
+
buffer += chunk;
|
|
210
|
+
|
|
211
|
+
const lines = buffer.split('\n');
|
|
212
|
+
buffer = lines.pop() || '';
|
|
213
|
+
|
|
214
|
+
for (const line of lines) {
|
|
215
|
+
if (!line.trim()) continue;
|
|
216
|
+
|
|
217
|
+
try {
|
|
218
|
+
const request = JSON.parse(line);
|
|
219
|
+
const response = await this.handleRequest(request);
|
|
220
|
+
process.stdout.write(JSON.stringify(response) + '\n');
|
|
221
|
+
} catch (error) {
|
|
222
|
+
const errorResponse = {
|
|
223
|
+
jsonrpc: '2.0',
|
|
224
|
+
id: null,
|
|
225
|
+
error: { code: -32700, message: 'Parse error' }
|
|
226
|
+
};
|
|
227
|
+
process.stdout.write(JSON.stringify(errorResponse) + '\n');
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
process.stderr.write('i18n-sync-server started\n');
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// 启动服务器
|
|
237
|
+
const server = new MCPServer();
|
|
238
|
+
server.start();
|
package/package.json
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "i18n-sync-mcp-server",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "MCP server for syncing i18n mappings to remote service",
|
|
5
|
+
"main": "i18n-sync-server.cjs",
|
|
6
|
+
"bin": {
|
|
7
|
+
"i18n-sync-server": "./i18n-sync-server.cjs"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"start": "node i18n-sync-server.cjs"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [
|
|
13
|
+
"mcp",
|
|
14
|
+
"model-context-protocol",
|
|
15
|
+
"i18n",
|
|
16
|
+
"internationalization",
|
|
17
|
+
"vue",
|
|
18
|
+
"translation"
|
|
19
|
+
],
|
|
20
|
+
"author": "GK",
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": ">=14.0.0"
|
|
24
|
+
}
|
|
25
|
+
}
|