@better-i18n/mcp 0.10.0 → 0.11.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/dist/client.d.ts +14 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +10 -4
- package/dist/client.js.map +1 -1
- package/dist/http.d.ts +18 -0
- package/dist/http.d.ts.map +1 -0
- package/dist/http.js +143 -0
- package/dist/http.js.map +1 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +23 -139
- package/dist/index.js.map +1 -1
- package/dist/server.d.ts +29 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +132 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/createKeys.d.ts +1 -1
- package/dist/tools/createKeys.d.ts.map +1 -1
- package/dist/tools/createKeys.js +20 -30
- package/dist/tools/createKeys.js.map +1 -1
- package/dist/tools/deleteKeys.d.ts.map +1 -1
- package/dist/tools/deleteKeys.js +1 -7
- package/dist/tools/deleteKeys.js.map +1 -1
- package/dist/tools/updateKeys.d.ts +2 -2
- package/dist/tools/updateKeys.d.ts.map +1 -1
- package/dist/tools/updateKeys.js +25 -37
- package/dist/tools/updateKeys.js.map +1 -1
- package/dist/worker.d.ts +44 -0
- package/dist/worker.d.ts.map +1 -0
- package/dist/worker.js +264 -0
- package/dist/worker.js.map +1 -0
- package/package.json +7 -4
package/dist/client.d.ts
CHANGED
|
@@ -6,6 +6,20 @@ export interface ClientConfig {
|
|
|
6
6
|
apiUrl: string;
|
|
7
7
|
apiKey: string;
|
|
8
8
|
debug?: boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Custom fetch function (e.g. Service Binding's fetch for Worker-to-Worker calls).
|
|
11
|
+
* When provided, bypasses the global fetch.
|
|
12
|
+
*/
|
|
13
|
+
customFetch?: (input: Request | string | URL, init?: RequestInit) => Promise<Response>;
|
|
14
|
+
/**
|
|
15
|
+
* Service auth for MCP Worker → API Worker calls via Service Binding.
|
|
16
|
+
* When provided, sends X-MCP-Service-Key + X-MCP-User-Id headers
|
|
17
|
+
* instead of x-api-key.
|
|
18
|
+
*/
|
|
19
|
+
serviceAuth?: {
|
|
20
|
+
serviceKey: string;
|
|
21
|
+
userId: string;
|
|
22
|
+
};
|
|
9
23
|
}
|
|
10
24
|
/**
|
|
11
25
|
* Type-safe tRPC client for MCP server usage.
|
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAExD,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAExD,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB;;;OAGG;IACH,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,GAAG,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IACvF;;;;OAIG;IACH,WAAW,CAAC,EAAE;QACZ,UAAU,EAAE,MAAM,CAAC;QACnB,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;CACH;AAED;;;GAGG;AACH,MAAM,MAAM,gBAAgB,GAAG,SAAS,CAAC;AAEzC;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,YAAY,GAAG;IAAE,cAAc,CAAC,EAAE,MAAM,CAAA;CAAE,GACjD,gBAAgB,CAgFlB"}
|
package/dist/client.js
CHANGED
|
@@ -29,9 +29,14 @@ export function createBetterI18nClient(config) {
|
|
|
29
29
|
httpBatchLink({
|
|
30
30
|
url,
|
|
31
31
|
headers: () => {
|
|
32
|
-
const headers =
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
const headers = config.serviceAuth
|
|
33
|
+
? {
|
|
34
|
+
"x-mcp-service-key": config.serviceAuth.serviceKey,
|
|
35
|
+
"x-mcp-user-id": config.serviceAuth.userId,
|
|
36
|
+
}
|
|
37
|
+
: {
|
|
38
|
+
"x-api-key": config.apiKey,
|
|
39
|
+
};
|
|
35
40
|
if (config.organizationId) {
|
|
36
41
|
headers["x-organization-id"] = config.organizationId;
|
|
37
42
|
}
|
|
@@ -52,7 +57,8 @@ export function createBetterI18nClient(config) {
|
|
|
52
57
|
console.error(`[better-i18n] → ${inputUrl}`);
|
|
53
58
|
}
|
|
54
59
|
}
|
|
55
|
-
const
|
|
60
|
+
const fetchFn = config.customFetch ?? fetch;
|
|
61
|
+
const response = await fetchFn(input, init);
|
|
56
62
|
if (config.debug && inputUrl === lastLoggedUrl) {
|
|
57
63
|
if (response.ok) {
|
|
58
64
|
console.error(`[better-i18n] ← ${response.status} OK`);
|
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/http.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Better i18n MCP Server — HTTP transport
|
|
4
|
+
*
|
|
5
|
+
* Streamable HTTP transport for OpenAI ChatGPT custom apps,
|
|
6
|
+
* Codex CLI, and Agents SDK integration.
|
|
7
|
+
*
|
|
8
|
+
* Authentication: Bearer token in Authorization header (API key).
|
|
9
|
+
* Each request creates a fresh, stateless MCP server instance
|
|
10
|
+
* authenticated with the provided API key.
|
|
11
|
+
*
|
|
12
|
+
* Usage:
|
|
13
|
+
* PORT=8808 better-i18n-mcp-http
|
|
14
|
+
*
|
|
15
|
+
* For stdio transport (Cursor, Claude Desktop), see index.ts.
|
|
16
|
+
*/
|
|
17
|
+
export {};
|
|
18
|
+
//# sourceMappingURL=http.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;;;;GAcG"}
|
package/dist/http.js
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Better i18n MCP Server — HTTP transport
|
|
4
|
+
*
|
|
5
|
+
* Streamable HTTP transport for OpenAI ChatGPT custom apps,
|
|
6
|
+
* Codex CLI, and Agents SDK integration.
|
|
7
|
+
*
|
|
8
|
+
* Authentication: Bearer token in Authorization header (API key).
|
|
9
|
+
* Each request creates a fresh, stateless MCP server instance
|
|
10
|
+
* authenticated with the provided API key.
|
|
11
|
+
*
|
|
12
|
+
* Usage:
|
|
13
|
+
* PORT=8808 better-i18n-mcp-http
|
|
14
|
+
*
|
|
15
|
+
* For stdio transport (Cursor, Claude Desktop), see index.ts.
|
|
16
|
+
*/
|
|
17
|
+
import { createServer } from "node:http";
|
|
18
|
+
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
19
|
+
import { resolveConfig, createConfiguredServer, createBetterI18nClient, } from "./server.js";
|
|
20
|
+
const config = resolveConfig();
|
|
21
|
+
const port = parseInt(process.env.PORT || "8808", 10);
|
|
22
|
+
const host = process.env.HOST || "0.0.0.0";
|
|
23
|
+
/**
|
|
24
|
+
* Extract Bearer token from Authorization header.
|
|
25
|
+
*/
|
|
26
|
+
function extractBearerToken(req) {
|
|
27
|
+
const auth = req.headers.authorization;
|
|
28
|
+
if (!auth?.startsWith("Bearer "))
|
|
29
|
+
return null;
|
|
30
|
+
return auth.slice(7);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Set CORS headers for browser-based clients.
|
|
34
|
+
*/
|
|
35
|
+
function setCorsHeaders(res) {
|
|
36
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
37
|
+
res.setHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, OPTIONS");
|
|
38
|
+
res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, Mcp-Session-Id, Mcp-Protocol-Version");
|
|
39
|
+
res.setHeader("Access-Control-Expose-Headers", "Mcp-Session-Id");
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Read and parse JSON body from an IncomingMessage.
|
|
43
|
+
*/
|
|
44
|
+
function readJsonBody(req) {
|
|
45
|
+
return new Promise((resolve, reject) => {
|
|
46
|
+
const chunks = [];
|
|
47
|
+
req.on("data", (chunk) => chunks.push(chunk));
|
|
48
|
+
req.on("end", () => {
|
|
49
|
+
try {
|
|
50
|
+
const body = Buffer.concat(chunks).toString("utf-8");
|
|
51
|
+
resolve(body ? JSON.parse(body) : undefined);
|
|
52
|
+
}
|
|
53
|
+
catch (err) {
|
|
54
|
+
reject(err);
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
req.on("error", reject);
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Handle an MCP request over HTTP.
|
|
62
|
+
* Creates a per-request MCP server authenticated with the caller's API key.
|
|
63
|
+
*/
|
|
64
|
+
async function handleMcpRequest(req, res, apiKey) {
|
|
65
|
+
const apiClient = createBetterI18nClient({
|
|
66
|
+
apiUrl: config.apiUrl,
|
|
67
|
+
apiKey,
|
|
68
|
+
debug: config.debug,
|
|
69
|
+
});
|
|
70
|
+
const server = createConfiguredServer(apiClient);
|
|
71
|
+
const transport = new StreamableHTTPServerTransport({
|
|
72
|
+
sessionIdGenerator: undefined, // stateless
|
|
73
|
+
enableJsonResponse: true,
|
|
74
|
+
});
|
|
75
|
+
await server.connect(transport);
|
|
76
|
+
// Pre-parse the body so the transport doesn't need to
|
|
77
|
+
const parsedBody = req.method === "POST" ? await readJsonBody(req) : undefined;
|
|
78
|
+
await transport.handleRequest(req, res, parsedBody);
|
|
79
|
+
// Clean up after the request
|
|
80
|
+
await transport.close();
|
|
81
|
+
await server.close();
|
|
82
|
+
}
|
|
83
|
+
const httpServer = createServer(async (req, res) => {
|
|
84
|
+
setCorsHeaders(res);
|
|
85
|
+
// Handle CORS preflight
|
|
86
|
+
if (req.method === "OPTIONS") {
|
|
87
|
+
res.writeHead(204);
|
|
88
|
+
res.end();
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
const url = new URL(req.url || "/", `http://${req.headers.host || "localhost"}`);
|
|
92
|
+
const pathname = url.pathname;
|
|
93
|
+
// Health check
|
|
94
|
+
if (pathname === "/health" && req.method === "GET") {
|
|
95
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
96
|
+
res.end(JSON.stringify({ status: "ok", transport: "streamable-http" }));
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
// MCP endpoint
|
|
100
|
+
if (pathname === "/mcp") {
|
|
101
|
+
// GET requests for SSE stream don't need auth (they use session ID)
|
|
102
|
+
// POST and DELETE need Bearer token
|
|
103
|
+
if (req.method === "POST" || req.method === "DELETE") {
|
|
104
|
+
const apiKey = extractBearerToken(req);
|
|
105
|
+
if (!apiKey) {
|
|
106
|
+
res.writeHead(401, { "Content-Type": "application/json" });
|
|
107
|
+
res.end(JSON.stringify({
|
|
108
|
+
error: "Missing Authorization header. Use: Authorization: Bearer <API_KEY>",
|
|
109
|
+
}));
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
try {
|
|
113
|
+
await handleMcpRequest(req, res, apiKey);
|
|
114
|
+
}
|
|
115
|
+
catch (err) {
|
|
116
|
+
console.error("[better-i18n-http] Error handling MCP request:", err);
|
|
117
|
+
if (!res.headersSent) {
|
|
118
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
119
|
+
res.end(JSON.stringify({ error: "Internal server error" }));
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
// GET for SSE — stateless mode doesn't support standalone SSE
|
|
125
|
+
if (req.method === "GET") {
|
|
126
|
+
res.writeHead(405, { "Content-Type": "application/json" });
|
|
127
|
+
res.end(JSON.stringify({
|
|
128
|
+
error: "SSE not supported in stateless mode. Use POST for requests.",
|
|
129
|
+
}));
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
// 404 for everything else
|
|
134
|
+
res.writeHead(404, { "Content-Type": "application/json" });
|
|
135
|
+
res.end(JSON.stringify({ error: "Not found" }));
|
|
136
|
+
});
|
|
137
|
+
httpServer.listen(port, host, () => {
|
|
138
|
+
console.error(`[better-i18n-http] Mode: ${config.isLocalDev ? "LOCAL DEV" : "PRODUCTION"}`);
|
|
139
|
+
console.error(`[better-i18n-http] API URL: ${config.apiUrl}`);
|
|
140
|
+
console.error(`[better-i18n-http] MCP HTTP server listening on http://${host}:${port}/mcp`);
|
|
141
|
+
console.error(`[better-i18n-http] Health check: http://${host}:${port}/health`);
|
|
142
|
+
});
|
|
143
|
+
//# sourceMappingURL=http.js.map
|
package/dist/http.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* Better i18n MCP Server
|
|
3
|
+
* Better i18n MCP Server — stdio transport
|
|
4
4
|
*
|
|
5
5
|
* Model Context Protocol server for Better i18n translation management.
|
|
6
6
|
* Enables AI assistants (Claude, ChatGPT, etc.) to manage translations
|
|
7
7
|
* directly from IDEs like Cursor.
|
|
8
|
+
*
|
|
9
|
+
* For HTTP transport (OpenAI, Codex, Agents SDK), see http.ts.
|
|
8
10
|
*/
|
|
9
11
|
export {};
|
|
10
12
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;;;;GAQG"}
|
package/dist/index.js
CHANGED
|
@@ -1,152 +1,36 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* Better i18n MCP Server
|
|
3
|
+
* Better i18n MCP Server — stdio transport
|
|
4
4
|
*
|
|
5
5
|
* Model Context Protocol server for Better i18n translation management.
|
|
6
6
|
* Enables AI assistants (Claude, ChatGPT, etc.) to manage translations
|
|
7
7
|
* directly from IDEs like Cursor.
|
|
8
|
+
*
|
|
9
|
+
* For HTTP transport (OpenAI, Codex, Agents SDK), see http.ts.
|
|
8
10
|
*/
|
|
9
|
-
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
10
11
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
import { listKeys } from "./tools/listKeys.js";
|
|
21
|
-
import { listProjects } from "./tools/listProjects.js";
|
|
22
|
-
import { publishTranslations } from "./tools/publishTranslations.js";
|
|
23
|
-
import { updateKeys } from "./tools/updateKeys.js";
|
|
24
|
-
class BetterI18nServer {
|
|
25
|
-
server;
|
|
26
|
-
apiClient;
|
|
27
|
-
constructor() {
|
|
28
|
-
this.server = new Server({
|
|
29
|
-
name: "better-i18n",
|
|
30
|
-
version: "0.0.1",
|
|
31
|
-
}, {
|
|
32
|
-
capabilities: {
|
|
33
|
-
tools: {},
|
|
34
|
-
},
|
|
35
|
-
});
|
|
36
|
-
this.apiClient = null;
|
|
37
|
-
}
|
|
38
|
-
async init() {
|
|
39
|
-
// Auto-detect if running from source (local dev) vs npm package (production)
|
|
40
|
-
const scriptPath = process.argv[1] || "";
|
|
41
|
-
const isLocalDev = scriptPath.includes("packages/mcp/src") ||
|
|
42
|
-
scriptPath.includes("better-i18n/packages/mcp");
|
|
43
|
-
// Read configuration from environment
|
|
44
|
-
const apiUrl = process.env.BETTER_I18N_API_URL ||
|
|
45
|
-
(isLocalDev ? "http://localhost:8787" : "https://dash.better-i18n.com");
|
|
46
|
-
const apiKey = process.env.BETTER_I18N_API_KEY;
|
|
47
|
-
const debug = process.env.BETTER_I18N_DEBUG === "true" || isLocalDev;
|
|
48
|
-
console.error(`[better-i18n] Mode: ${isLocalDev ? "LOCAL DEV" : "PRODUCTION"}`);
|
|
49
|
-
console.error(`[better-i18n] API URL: ${apiUrl}`);
|
|
50
|
-
if (!apiKey) {
|
|
51
|
-
console.error("[better-i18n] ERROR: BETTER_I18N_API_KEY environment variable is required");
|
|
52
|
-
console.error("[better-i18n] Get your API key from: https://dash.better-i18n.com/settings/api-keys");
|
|
53
|
-
process.exit(1);
|
|
54
|
-
}
|
|
55
|
-
// Create Better i18n API client
|
|
56
|
-
this.apiClient = createBetterI18nClient({ apiUrl, apiKey, debug });
|
|
57
|
-
this.setupHandlers();
|
|
58
|
-
console.error("[better-i18n] MCP Server ready");
|
|
59
|
-
}
|
|
60
|
-
setupHandlers() {
|
|
61
|
-
// List available tools
|
|
62
|
-
this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
63
|
-
tools: [
|
|
64
|
-
listProjects.definition,
|
|
65
|
-
getProject.definition,
|
|
66
|
-
addLanguage.definition,
|
|
67
|
-
listKeys.definition,
|
|
68
|
-
createKeys.definition,
|
|
69
|
-
updateKeys.definition,
|
|
70
|
-
deleteKeys.definition,
|
|
71
|
-
getPendingChanges.definition,
|
|
72
|
-
publishTranslations.definition,
|
|
73
|
-
getSyncs.definition,
|
|
74
|
-
getSync.definition,
|
|
75
|
-
],
|
|
76
|
-
}));
|
|
77
|
-
// Execute tools
|
|
78
|
-
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
79
|
-
const { name, arguments: args } = request.params;
|
|
80
|
-
if (!this.apiClient) {
|
|
81
|
-
throw new Error("API client not initialized. Call init() first.");
|
|
82
|
-
}
|
|
83
|
-
const client = this.apiClient;
|
|
84
|
-
try {
|
|
85
|
-
let result;
|
|
86
|
-
switch (name) {
|
|
87
|
-
case "listProjects":
|
|
88
|
-
result = await listProjects.execute(client, args);
|
|
89
|
-
break;
|
|
90
|
-
case "getProject":
|
|
91
|
-
result = await getProject.execute(client, args);
|
|
92
|
-
break;
|
|
93
|
-
case "addLanguage":
|
|
94
|
-
result = await addLanguage.execute(client, args);
|
|
95
|
-
break;
|
|
96
|
-
case "listKeys":
|
|
97
|
-
result = await listKeys.execute(client, args);
|
|
98
|
-
break;
|
|
99
|
-
case "createKeys":
|
|
100
|
-
result = await createKeys.execute(client, args);
|
|
101
|
-
break;
|
|
102
|
-
case "updateKeys":
|
|
103
|
-
result = await updateKeys.execute(client, args);
|
|
104
|
-
break;
|
|
105
|
-
case "deleteKeys":
|
|
106
|
-
result = await deleteKeys.execute(client, args);
|
|
107
|
-
break;
|
|
108
|
-
case "getSyncs":
|
|
109
|
-
result = await getSyncs.execute(client, args);
|
|
110
|
-
break;
|
|
111
|
-
case "getPendingChanges":
|
|
112
|
-
result = await getPendingChanges.execute(client, args);
|
|
113
|
-
break;
|
|
114
|
-
case "publishTranslations":
|
|
115
|
-
result = await publishTranslations.execute(client, args);
|
|
116
|
-
break;
|
|
117
|
-
case "getSync":
|
|
118
|
-
result = await getSync.execute(client, args);
|
|
119
|
-
break;
|
|
120
|
-
default:
|
|
121
|
-
throw new Error(`Unknown tool: ${name}`);
|
|
122
|
-
}
|
|
123
|
-
return result;
|
|
124
|
-
}
|
|
125
|
-
catch (error) {
|
|
126
|
-
return {
|
|
127
|
-
content: [
|
|
128
|
-
{
|
|
129
|
-
type: "text",
|
|
130
|
-
text: `Error executing ${name}: ${error instanceof Error ? error.message : String(error)}`,
|
|
131
|
-
},
|
|
132
|
-
],
|
|
133
|
-
isError: true,
|
|
134
|
-
};
|
|
135
|
-
}
|
|
136
|
-
});
|
|
137
|
-
}
|
|
138
|
-
async run() {
|
|
139
|
-
const transport = new StdioServerTransport();
|
|
140
|
-
await this.server.connect(transport);
|
|
141
|
-
console.error("[better-i18n] MCP Server running on stdio");
|
|
12
|
+
import { resolveConfig, createConfiguredServer, createBetterI18nClient, } from "./server.js";
|
|
13
|
+
async function main() {
|
|
14
|
+
const config = resolveConfig();
|
|
15
|
+
console.error(`[better-i18n] Mode: ${config.isLocalDev ? "LOCAL DEV" : "PRODUCTION"}`);
|
|
16
|
+
console.error(`[better-i18n] API URL: ${config.apiUrl}`);
|
|
17
|
+
if (!config.apiKey) {
|
|
18
|
+
console.error("[better-i18n] ERROR: BETTER_I18N_API_KEY environment variable is required");
|
|
19
|
+
console.error("[better-i18n] Get your API key from: https://dash.better-i18n.com/settings/api-keys");
|
|
20
|
+
process.exit(1);
|
|
142
21
|
}
|
|
22
|
+
const apiClient = createBetterI18nClient({
|
|
23
|
+
apiUrl: config.apiUrl,
|
|
24
|
+
apiKey: config.apiKey,
|
|
25
|
+
debug: config.debug,
|
|
26
|
+
});
|
|
27
|
+
const server = createConfiguredServer(apiClient);
|
|
28
|
+
console.error("[better-i18n] MCP Server ready");
|
|
29
|
+
const transport = new StdioServerTransport();
|
|
30
|
+
await server.connect(transport);
|
|
31
|
+
console.error("[better-i18n] MCP Server running on stdio");
|
|
143
32
|
}
|
|
144
|
-
|
|
145
|
-
const server = new BetterI18nServer();
|
|
146
|
-
server
|
|
147
|
-
.init()
|
|
148
|
-
.then(() => server.run())
|
|
149
|
-
.catch((error) => {
|
|
33
|
+
main().catch((error) => {
|
|
150
34
|
console.error("[better-i18n] Fatal error:", error);
|
|
151
35
|
process.exit(1);
|
|
152
36
|
});
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;;;;GAQG;AAEH,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EACL,aAAa,EACb,sBAAsB,EACtB,sBAAsB,GACvB,MAAM,aAAa,CAAC;AAErB,KAAK,UAAU,IAAI;IACjB,MAAM,MAAM,GAAG,aAAa,EAAE,CAAC;IAE/B,OAAO,CAAC,KAAK,CACX,uBAAuB,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,YAAY,EAAE,CACxE,CAAC;IACF,OAAO,CAAC,KAAK,CAAC,0BAA0B,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;IAEzD,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;QACnB,OAAO,CAAC,KAAK,CACX,2EAA2E,CAC5E,CAAC;QACF,OAAO,CAAC,KAAK,CACX,qFAAqF,CACtF,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,SAAS,GAAG,sBAAsB,CAAC;QACvC,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,KAAK,EAAE,MAAM,CAAC,KAAK;KACpB,CAAC,CAAC;IAEH,MAAM,MAAM,GAAG,sBAAsB,CAAC,SAAS,CAAC,CAAC;IAEjD,OAAO,CAAC,KAAK,CAAC,gCAAgC,CAAC,CAAC;IAEhD,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,OAAO,CAAC,KAAK,CAAC,2CAA2C,CAAC,CAAC;AAC7D,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,OAAO,CAAC,KAAK,CAAC,4BAA4B,EAAE,KAAK,CAAC,CAAC;IACnD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Shared MCP Server Factory
|
|
4
|
+
*
|
|
5
|
+
* Provides configuration resolution and server creation used by both
|
|
6
|
+
* stdio (index.ts) and HTTP (http.ts) transport entry points.
|
|
7
|
+
*/
|
|
8
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
9
|
+
import { createBetterI18nClient } from "./client.js";
|
|
10
|
+
export interface ServerConfig {
|
|
11
|
+
apiUrl: string;
|
|
12
|
+
apiKey: string;
|
|
13
|
+
debug: boolean;
|
|
14
|
+
isLocalDev: boolean;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Resolves configuration from environment variables.
|
|
18
|
+
* Returns null for apiKey if not set (caller decides how to handle).
|
|
19
|
+
*/
|
|
20
|
+
export declare function resolveConfig(): Omit<ServerConfig, "apiKey"> & {
|
|
21
|
+
apiKey: string | undefined;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Creates a fully configured MCP Server with all tool handlers registered.
|
|
25
|
+
* The server is NOT connected to any transport — caller handles that.
|
|
26
|
+
*/
|
|
27
|
+
export declare function createConfiguredServer(apiClient: ReturnType<typeof createBetterI18nClient>): Server;
|
|
28
|
+
export { createBetterI18nClient };
|
|
29
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":";AAEA;;;;;GAKG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAMnE,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAcrD,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;IACf,UAAU,EAAE,OAAO,CAAC;CACrB;AAED;;;GAGG;AACH,wBAAgB,aAAa,IAAI,IAAI,CAAC,YAAY,EAAE,QAAQ,CAAC,GAAG;IAC9D,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;CAC5B,CAaA;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,UAAU,CAAC,OAAO,sBAAsB,CAAC,GACnD,MAAM,CAoGR;AAED,OAAO,EAAE,sBAAsB,EAAE,CAAC"}
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Shared MCP Server Factory
|
|
4
|
+
*
|
|
5
|
+
* Provides configuration resolution and server creation used by both
|
|
6
|
+
* stdio (index.ts) and HTTP (http.ts) transport entry points.
|
|
7
|
+
*/
|
|
8
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
9
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
10
|
+
import { createBetterI18nClient } from "./client.js";
|
|
11
|
+
import { addLanguage } from "./tools/addLanguage.js";
|
|
12
|
+
import { createKeys } from "./tools/createKeys.js";
|
|
13
|
+
import { deleteKeys } from "./tools/deleteKeys.js";
|
|
14
|
+
import { getPendingChanges } from "./tools/getPendingChanges.js";
|
|
15
|
+
import { getProject } from "./tools/getProject.js";
|
|
16
|
+
import { getSync } from "./tools/getSync.js";
|
|
17
|
+
import { getSyncs } from "./tools/getSyncs.js";
|
|
18
|
+
import { listKeys } from "./tools/listKeys.js";
|
|
19
|
+
import { listProjects } from "./tools/listProjects.js";
|
|
20
|
+
import { publishTranslations } from "./tools/publishTranslations.js";
|
|
21
|
+
import { updateKeys } from "./tools/updateKeys.js";
|
|
22
|
+
/**
|
|
23
|
+
* Resolves configuration from environment variables.
|
|
24
|
+
* Returns null for apiKey if not set (caller decides how to handle).
|
|
25
|
+
*/
|
|
26
|
+
export function resolveConfig() {
|
|
27
|
+
const scriptPath = process.argv[1] || "";
|
|
28
|
+
const isLocalDev = scriptPath.includes("packages/mcp/src") ||
|
|
29
|
+
scriptPath.includes("better-i18n/packages/mcp");
|
|
30
|
+
const apiUrl = process.env.BETTER_I18N_API_URL ||
|
|
31
|
+
(isLocalDev ? "http://localhost:8787" : "https://dash.better-i18n.com");
|
|
32
|
+
const apiKey = process.env.BETTER_I18N_API_KEY;
|
|
33
|
+
const debug = process.env.BETTER_I18N_DEBUG === "true" || isLocalDev;
|
|
34
|
+
return { apiUrl, apiKey, debug, isLocalDev };
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Creates a fully configured MCP Server with all tool handlers registered.
|
|
38
|
+
* The server is NOT connected to any transport — caller handles that.
|
|
39
|
+
*/
|
|
40
|
+
export function createConfiguredServer(apiClient) {
|
|
41
|
+
const server = new Server({
|
|
42
|
+
name: "better-i18n",
|
|
43
|
+
version: "0.0.1",
|
|
44
|
+
}, {
|
|
45
|
+
capabilities: {
|
|
46
|
+
tools: {},
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
// Tool annotations for ChatGPT compatibility (readOnlyHint, openWorldHint, destructiveHint)
|
|
50
|
+
const readOnly = { readOnlyHint: true, openWorldHint: false, destructiveHint: false };
|
|
51
|
+
const write = { readOnlyHint: false, openWorldHint: false, destructiveHint: false };
|
|
52
|
+
const destructive = { readOnlyHint: false, openWorldHint: false, destructiveHint: true };
|
|
53
|
+
const annotate = (def, annotations) => ({
|
|
54
|
+
...def,
|
|
55
|
+
annotations,
|
|
56
|
+
});
|
|
57
|
+
// List available tools
|
|
58
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
59
|
+
tools: [
|
|
60
|
+
annotate(listProjects.definition, readOnly),
|
|
61
|
+
annotate(getProject.definition, readOnly),
|
|
62
|
+
annotate(addLanguage.definition, write),
|
|
63
|
+
annotate(listKeys.definition, readOnly),
|
|
64
|
+
annotate(createKeys.definition, write),
|
|
65
|
+
annotate(updateKeys.definition, write),
|
|
66
|
+
annotate(deleteKeys.definition, destructive),
|
|
67
|
+
annotate(getPendingChanges.definition, readOnly),
|
|
68
|
+
annotate(publishTranslations.definition, write),
|
|
69
|
+
annotate(getSyncs.definition, readOnly),
|
|
70
|
+
annotate(getSync.definition, readOnly),
|
|
71
|
+
],
|
|
72
|
+
}));
|
|
73
|
+
// Execute tools
|
|
74
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
75
|
+
const { name, arguments: args } = request.params;
|
|
76
|
+
try {
|
|
77
|
+
let result;
|
|
78
|
+
switch (name) {
|
|
79
|
+
case "listProjects":
|
|
80
|
+
result = await listProjects.execute(apiClient, args);
|
|
81
|
+
break;
|
|
82
|
+
case "getProject":
|
|
83
|
+
result = await getProject.execute(apiClient, args);
|
|
84
|
+
break;
|
|
85
|
+
case "addLanguage":
|
|
86
|
+
result = await addLanguage.execute(apiClient, args);
|
|
87
|
+
break;
|
|
88
|
+
case "listKeys":
|
|
89
|
+
result = await listKeys.execute(apiClient, args);
|
|
90
|
+
break;
|
|
91
|
+
case "createKeys":
|
|
92
|
+
result = await createKeys.execute(apiClient, args);
|
|
93
|
+
break;
|
|
94
|
+
case "updateKeys":
|
|
95
|
+
result = await updateKeys.execute(apiClient, args);
|
|
96
|
+
break;
|
|
97
|
+
case "deleteKeys":
|
|
98
|
+
result = await deleteKeys.execute(apiClient, args);
|
|
99
|
+
break;
|
|
100
|
+
case "getSyncs":
|
|
101
|
+
result = await getSyncs.execute(apiClient, args);
|
|
102
|
+
break;
|
|
103
|
+
case "getPendingChanges":
|
|
104
|
+
result = await getPendingChanges.execute(apiClient, args);
|
|
105
|
+
break;
|
|
106
|
+
case "publishTranslations":
|
|
107
|
+
result = await publishTranslations.execute(apiClient, args);
|
|
108
|
+
break;
|
|
109
|
+
case "getSync":
|
|
110
|
+
result = await getSync.execute(apiClient, args);
|
|
111
|
+
break;
|
|
112
|
+
default:
|
|
113
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
114
|
+
}
|
|
115
|
+
return result;
|
|
116
|
+
}
|
|
117
|
+
catch (error) {
|
|
118
|
+
return {
|
|
119
|
+
content: [
|
|
120
|
+
{
|
|
121
|
+
type: "text",
|
|
122
|
+
text: `Error executing ${name}: ${error instanceof Error ? error.message : String(error)}`,
|
|
123
|
+
},
|
|
124
|
+
],
|
|
125
|
+
isError: true,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
return server;
|
|
130
|
+
}
|
|
131
|
+
export { createBetterI18nClient };
|
|
132
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* createKeys MCP Tool
|
|
3
3
|
*
|
|
4
4
|
* Creates one or more translation keys with source text and optional translations.
|
|
5
|
-
*
|
|
5
|
+
* Uses compact schema matching the API: k=[{n, ns, v, t, nc}].
|
|
6
6
|
*/
|
|
7
7
|
import type { Tool } from "../types/index.js";
|
|
8
8
|
export declare const createKeys: Tool;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createKeys.d.ts","sourceRoot":"","sources":["../../src/tools/createKeys.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AASH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAsB9C,eAAO,MAAM,UAAU,EAAE,
|
|
1
|
+
{"version":3,"file":"createKeys.d.ts","sourceRoot":"","sources":["../../src/tools/createKeys.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AASH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAsB9C,eAAO,MAAM,UAAU,EAAE,IAqDxB,CAAC"}
|