localization-mcp-server 1.0.0 → 1.0.2
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/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/permissions.d.ts +8 -0
- package/dist/permissions.d.ts.map +1 -1
- package/dist/permissions.js +2 -0
- package/dist/permissions.js.map +1 -1
- package/dist/setup.d.ts +2 -0
- package/dist/setup.d.ts.map +1 -0
- package/dist/setup.js +87 -0
- package/dist/setup.js.map +1 -0
- package/dist/tools/project-management.d.ts.map +1 -1
- package/dist/tools/project-management.js +250 -42
- package/dist/tools/project-management.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +9 -0
- package/src/permissions.ts +2 -0
- package/src/setup.ts +100 -0
- package/src/tools/project-management.ts +290 -67
package/dist/index.js
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
const args = process.argv.slice(2);
|
|
3
|
+
if (args[0] === "setup") {
|
|
4
|
+
const { runSetup } = await import("./setup.js");
|
|
5
|
+
await runSetup(args.slice(1));
|
|
6
|
+
process.exit(0);
|
|
7
|
+
}
|
|
2
8
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
9
|
import { createServer } from "./server.js";
|
|
4
10
|
// Load .env from the mcp-server directory (one level above dist/)
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAEnC,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,OAAO,EAAE,CAAC;IACxB,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,CAAC;IAChD,MAAM,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,kEAAkE;AAClE,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,EAAE,CAAC;IAC1C,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAC;IACnD,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,CAAC;IAC9C,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,CAAC;IAClD,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1D,MAAM,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,SAAS,EAAE,IAAI,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;AAC5D,CAAC;AAED,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC;IAC3B,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,uFAAuF,CACxF,CAAC;AACJ,CAAC;AAED,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC;IAC7B,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,+EAA+E,CAChF,CAAC;AACJ,CAAC;AAED,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;AAC9B,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;AAE7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC"}
|
package/dist/permissions.d.ts
CHANGED
|
@@ -111,6 +111,14 @@ export declare const TOOL_REGISTRY: {
|
|
|
111
111
|
readonly env: "both";
|
|
112
112
|
readonly access: "read";
|
|
113
113
|
};
|
|
114
|
+
readonly compare_local_vs_server: {
|
|
115
|
+
readonly env: "both";
|
|
116
|
+
readonly access: "read";
|
|
117
|
+
};
|
|
118
|
+
readonly validate_keys: {
|
|
119
|
+
readonly env: "both";
|
|
120
|
+
readonly access: "read";
|
|
121
|
+
};
|
|
114
122
|
};
|
|
115
123
|
export type ToolName = keyof typeof TOOL_REGISTRY;
|
|
116
124
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"permissions.d.ts","sourceRoot":"","sources":["../src/permissions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,YAAY,CAAC;AACnD,MAAM,MAAM,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AACtC,MAAM,MAAM,OAAO,GAAG,SAAS,GAAG,YAAY,GAAG,MAAM,CAAC;AAExD,MAAM,WAAW,QAAQ;IACvB,GAAG,EAAE,OAAO,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,eAAO,MAAM,aAAa
|
|
1
|
+
{"version":3,"file":"permissions.d.ts","sourceRoot":"","sources":["../src/permissions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,YAAY,CAAC;AACnD,MAAM,MAAM,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AACtC,MAAM,MAAM,OAAO,GAAG,SAAS,GAAG,YAAY,GAAG,MAAM,CAAC;AAExD,MAAM,WAAW,QAAQ;IACvB,GAAG,EAAE,OAAO,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyBmB,CAAC;AAE9C,MAAM,MAAM,QAAQ,GAAG,MAAM,OAAO,aAAa,CAAC;AAElD;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,WAAW,GAAG,IAAI,CAQzD"}
|
package/dist/permissions.js
CHANGED
|
@@ -54,6 +54,8 @@ export const TOOL_REGISTRY = {
|
|
|
54
54
|
// ── Read-only export / analysis ───────────────────────────────────────────
|
|
55
55
|
export_namespace: { env: "both", access: "read" },
|
|
56
56
|
get_namespace_coverage: { env: "both", access: "read" },
|
|
57
|
+
compare_local_vs_server: { env: "both", access: "read" },
|
|
58
|
+
validate_keys: { env: "both", access: "read" },
|
|
57
59
|
};
|
|
58
60
|
/**
|
|
59
61
|
* Guard for write operations. Call at the start of every write tool handler.
|
package/dist/permissions.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"permissions.js","sourceRoot":"","sources":["../src/permissions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAWH;;;GAGG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,uEAAuE;IACvE,aAAa,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE;IAC9C,mBAAmB,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE;IACpD,sBAAsB,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE;IACvD,iBAAiB,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE;IAClD,oBAAoB,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE;IACrD,qBAAqB,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE;IACtD,cAAc,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE;IAC/C,0BAA0B,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE;IAC3D,uEAAuE;IACvE,YAAY,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE;IACjD,aAAa,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE;IAClD,eAAe,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE;IACpD,kBAAkB,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE;IACvD,WAAW,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE;IAChD,eAAe,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE;IACpD,6EAA6E;IAC7E,gBAAgB,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE;IAClD,aAAa,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE;IAC/C,6EAA6E;IAC7E,gBAAgB,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE;IACjD,sBAAsB,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE;
|
|
1
|
+
{"version":3,"file":"permissions.js","sourceRoot":"","sources":["../src/permissions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAWH;;;GAGG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,uEAAuE;IACvE,aAAa,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE;IAC9C,mBAAmB,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE;IACpD,sBAAsB,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE;IACvD,iBAAiB,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE;IAClD,oBAAoB,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE;IACrD,qBAAqB,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE;IACtD,cAAc,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE;IAC/C,0BAA0B,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE;IAC3D,uEAAuE;IACvE,YAAY,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE;IACjD,aAAa,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE;IAClD,eAAe,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE;IACpD,kBAAkB,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE;IACvD,WAAW,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE;IAChD,eAAe,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE;IACpD,6EAA6E;IAC7E,gBAAgB,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE;IAClD,aAAa,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE;IAC/C,6EAA6E;IAC7E,gBAAgB,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE;IACjD,sBAAsB,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE;IACvD,uBAAuB,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE;IACxD,aAAa,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE;CACH,CAAC;AAI9C;;;;;;;;;GASG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAgB;IACjD,IAAI,GAAG,KAAK,YAAY,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CACb,2BAA2B;YACzB,kDAAkD;YAClD,uEAAuE,CAC1E,CAAC;IACJ,CAAC;AACH,CAAC"}
|
package/dist/setup.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":"AA0DA,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAyC5D"}
|
package/dist/setup.js
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { execSync } from "child_process";
|
|
2
|
+
const BOLD = "\x1b[1m";
|
|
3
|
+
const GREEN = "\x1b[32m";
|
|
4
|
+
const RED = "\x1b[31m";
|
|
5
|
+
const YELLOW = "\x1b[33m";
|
|
6
|
+
const RESET = "\x1b[0m";
|
|
7
|
+
const ok = (msg) => console.log(`${GREEN}✓${RESET} ${msg}`);
|
|
8
|
+
const fail = (msg) => console.error(`${RED}✗${RESET} ${msg}`);
|
|
9
|
+
const warn = (msg) => console.log(`${YELLOW}!${RESET} ${msg}`);
|
|
10
|
+
function parseArgs(args) {
|
|
11
|
+
const tokenIdx = args.indexOf("--token");
|
|
12
|
+
const backendIdx = args.indexOf("--backend-url");
|
|
13
|
+
return {
|
|
14
|
+
token: tokenIdx !== -1 ? args[tokenIdx + 1] : undefined,
|
|
15
|
+
backendUrl: backendIdx !== -1 ? args[backendIdx + 1] : undefined,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
function checkClaudeCli() {
|
|
19
|
+
try {
|
|
20
|
+
execSync("claude --version", { stdio: "pipe" });
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function removeOldRegistration() {
|
|
28
|
+
try {
|
|
29
|
+
execSync('claude mcp remove "localization" -s user', { stdio: "pipe" });
|
|
30
|
+
ok("Removed old registration");
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
// Not registered yet — fine
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function register(token, backendUrl) {
|
|
37
|
+
execSync(`claude mcp add "localization" -s user -e MCP_TOKEN=${token} -e BACKEND_URL=${backendUrl} -- npx -y localization-mcp-server`, { stdio: "pipe" });
|
|
38
|
+
}
|
|
39
|
+
async function verifyToken(token, backendUrl) {
|
|
40
|
+
try {
|
|
41
|
+
const response = await fetch(`${backendUrl}/translations/projects`, {
|
|
42
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
43
|
+
signal: AbortSignal.timeout(10_000),
|
|
44
|
+
});
|
|
45
|
+
return response.ok;
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
export async function runSetup(args) {
|
|
52
|
+
console.log(`\n${BOLD}Localization MCP — setup${RESET}\n`);
|
|
53
|
+
const { token, backendUrl = "http://localhost:8080" } = parseArgs(args);
|
|
54
|
+
if (!token) {
|
|
55
|
+
fail("Missing --token. Run the command generated by the admin panel.");
|
|
56
|
+
process.exit(1);
|
|
57
|
+
}
|
|
58
|
+
// 1. Check Claude CLI
|
|
59
|
+
if (!checkClaudeCli()) {
|
|
60
|
+
fail("Claude CLI not found. Install it from https://claude.ai/code");
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
63
|
+
ok("Claude CLI found");
|
|
64
|
+
// 2. Remove old registration
|
|
65
|
+
removeOldRegistration();
|
|
66
|
+
// 3. Register with correct token
|
|
67
|
+
try {
|
|
68
|
+
register(token, backendUrl);
|
|
69
|
+
ok("MCP server registered");
|
|
70
|
+
}
|
|
71
|
+
catch (e) {
|
|
72
|
+
fail(`Failed to register MCP server: ${e}`);
|
|
73
|
+
process.exit(1);
|
|
74
|
+
}
|
|
75
|
+
// 4. Verify token works
|
|
76
|
+
const valid = await verifyToken(token, backendUrl);
|
|
77
|
+
if (!valid) {
|
|
78
|
+
fail("Token verification failed — the token may be expired or the server is unreachable.");
|
|
79
|
+
warn("MCP is registered but will not work until the token is valid.");
|
|
80
|
+
warn("Re-run this command with a fresh token from the admin panel.");
|
|
81
|
+
process.exit(1);
|
|
82
|
+
}
|
|
83
|
+
ok("Token verified");
|
|
84
|
+
console.log(`\n${GREEN}${BOLD}Setup complete.${RESET}`);
|
|
85
|
+
console.log("Restart Claude for the changes to take effect.\n");
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=setup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup.js","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"project-management.d.ts","sourceRoot":"","sources":["../../src/tools/project-management.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"project-management.d.ts","sourceRoot":"","sources":["../../src/tools/project-management.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AA4BpE,wBAAgB,8BAA8B,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA4rBtE"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import { readFileSync } from "fs";
|
|
2
3
|
import { apiGet, apiPost, ApiError } from "../api-client.js";
|
|
3
4
|
import { logWrite } from "../logger.js";
|
|
4
5
|
export function registerProjectManagementTools(server) {
|
|
@@ -185,28 +186,65 @@ export function registerProjectManagementTools(server) {
|
|
|
185
186
|
}
|
|
186
187
|
});
|
|
187
188
|
// ─── bulk_import ───────────────────────────────────────────────────────────
|
|
188
|
-
server.tool("bulk_import",
|
|
189
|
+
server.tool("bulk_import", [
|
|
190
|
+
"Import multiple translation keys into the sandbox at once.",
|
|
191
|
+
"Accepts either inline JSON (translations parameter) or a path to a JSON file on disk (filePath parameter).",
|
|
192
|
+
"File format: { \"locale\": { \"key\": \"value\" } } — same as inline translations.",
|
|
193
|
+
"Use filePath when the payload is large (>100 keys) to avoid inline JSON size limits.",
|
|
194
|
+
"All writes go to sandbox — production is unchanged until you promote.",
|
|
195
|
+
"Run compare_local_vs_server first to avoid re-importing keys that already exist.",
|
|
196
|
+
].join(" "), {
|
|
189
197
|
projectSlug: z.string().describe("Project slug"),
|
|
190
198
|
namespace: z.string().describe("Namespace slug — must already exist (use create_namespace first)"),
|
|
191
199
|
translations: z
|
|
192
200
|
.record(z.string(), z.record(z.string(), z.string()))
|
|
193
|
-
.
|
|
201
|
+
.optional()
|
|
202
|
+
.describe('Inline locale → key → value map. Use this for small payloads. Example: { "en": { "save": "Save" }, "nb-NO": { "save": "Lagre" } }'),
|
|
203
|
+
filePath: z
|
|
204
|
+
.string()
|
|
205
|
+
.optional()
|
|
206
|
+
.describe('Absolute path to a JSON file on disk. Format: { "locale": { "key": "value" } }. Use this for large translation files instead of inline JSON.'),
|
|
194
207
|
dryRun: z
|
|
195
208
|
.boolean()
|
|
196
209
|
.default(false)
|
|
197
210
|
.describe("If true, validate and preview what would be imported without writing anything"),
|
|
198
|
-
}, async ({ projectSlug, namespace, translations, dryRun }) => {
|
|
211
|
+
}, async ({ projectSlug, namespace, translations, filePath, dryRun }) => {
|
|
199
212
|
try {
|
|
200
|
-
//
|
|
201
|
-
|
|
213
|
+
// Resolve translations — from inline or file
|
|
214
|
+
let resolvedTranslations;
|
|
215
|
+
if (filePath) {
|
|
216
|
+
try {
|
|
217
|
+
const raw = readFileSync(filePath, "utf-8");
|
|
218
|
+
resolvedTranslations = JSON.parse(raw);
|
|
219
|
+
}
|
|
220
|
+
catch (e) {
|
|
221
|
+
return {
|
|
222
|
+
content: [{
|
|
223
|
+
type: "text",
|
|
224
|
+
text: `❌ Could not read file: ${filePath}\n${String(e)}`,
|
|
225
|
+
}],
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
else if (translations) {
|
|
230
|
+
resolvedTranslations = translations;
|
|
231
|
+
}
|
|
232
|
+
else {
|
|
233
|
+
return {
|
|
234
|
+
content: [{
|
|
235
|
+
type: "text",
|
|
236
|
+
text: `❌ Provide either "translations" (inline JSON) or "filePath" (path to JSON file).`,
|
|
237
|
+
}],
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
// Validate locale codes against the project
|
|
202
241
|
const project = await apiGet(`/translations/projects/${projectSlug}`);
|
|
203
242
|
const validLocales = new Set(project.locales.map((l) => l.code));
|
|
204
|
-
const requestedLocales = Object.keys(
|
|
243
|
+
const requestedLocales = Object.keys(resolvedTranslations);
|
|
205
244
|
const unknownLocales = requestedLocales.filter((l) => !validLocales.has(l));
|
|
206
245
|
if (unknownLocales.length > 0) {
|
|
207
246
|
return {
|
|
208
|
-
content: [
|
|
209
|
-
{
|
|
247
|
+
content: [{
|
|
210
248
|
type: "text",
|
|
211
249
|
text: [
|
|
212
250
|
`❌ Import aborted — locale codes do not match the project.`,
|
|
@@ -217,75 +255,67 @@ export function registerProjectManagementTools(server) {
|
|
|
217
255
|
`Call get_project_details to get the exact locale codes. Do not guess or remap them.`,
|
|
218
256
|
`If the locale does not exist in the project yet, call create_locale first.`,
|
|
219
257
|
].join("\n"),
|
|
220
|
-
},
|
|
221
|
-
],
|
|
258
|
+
}],
|
|
222
259
|
};
|
|
223
260
|
}
|
|
224
|
-
// Collect all unique keys
|
|
261
|
+
// Collect all unique keys
|
|
225
262
|
const allKeys = new Set();
|
|
226
|
-
for (const localeMap of Object.values(
|
|
263
|
+
for (const localeMap of Object.values(resolvedTranslations)) {
|
|
227
264
|
for (const key of Object.keys(localeMap)) {
|
|
228
265
|
allKeys.add(key);
|
|
229
266
|
}
|
|
230
267
|
}
|
|
231
268
|
if (dryRun) {
|
|
232
|
-
const perLocale = requestedLocales.map((l) => ` ${l}: ${Object.keys(
|
|
269
|
+
const perLocale = requestedLocales.map((l) => ` ${l}: ${Object.keys(resolvedTranslations[l]).length} values`);
|
|
233
270
|
return {
|
|
234
|
-
content: [
|
|
235
|
-
{
|
|
271
|
+
content: [{
|
|
236
272
|
type: "text",
|
|
237
273
|
text: [
|
|
238
274
|
`DRY RUN — nothing written`,
|
|
239
275
|
``,
|
|
240
276
|
`Would import to sandbox: ${projectSlug}/${namespace}`,
|
|
277
|
+
` Source: ${filePath ?? "inline"}`,
|
|
241
278
|
` Unique keys: ${allKeys.size}`,
|
|
242
279
|
` Locales:`,
|
|
243
280
|
...perLocale,
|
|
244
281
|
].join("\n"),
|
|
245
|
-
},
|
|
246
|
-
],
|
|
282
|
+
}],
|
|
247
283
|
};
|
|
248
284
|
}
|
|
249
285
|
const basePath = `/translations/projects/${projectSlug}/sandbox/namespaces/${namespace}/entries`;
|
|
250
286
|
// Group values per key across all locales, then upsert each key once
|
|
251
287
|
const keyMap = new Map();
|
|
252
|
-
for (const [locale, localeMap] of Object.entries(
|
|
288
|
+
for (const [locale, localeMap] of Object.entries(resolvedTranslations)) {
|
|
253
289
|
for (const [key, value] of Object.entries(localeMap)) {
|
|
254
290
|
if (!keyMap.has(key))
|
|
255
291
|
keyMap.set(key, {});
|
|
256
292
|
keyMap.get(key)[locale] = value;
|
|
257
293
|
}
|
|
258
294
|
}
|
|
259
|
-
let
|
|
260
|
-
let updated = 0;
|
|
295
|
+
let upserted = 0;
|
|
261
296
|
let failed = 0;
|
|
262
297
|
const errors = [];
|
|
263
298
|
const { apiPatch } = await import("../api-client.js");
|
|
264
299
|
for (const [key, values] of keyMap.entries()) {
|
|
265
300
|
try {
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
// Key does not exist yet — create it
|
|
301
|
+
await apiPatch(`${basePath}/${encodeURIComponent(key)}`, { values });
|
|
302
|
+
upserted++;
|
|
303
|
+
}
|
|
304
|
+
catch (err) {
|
|
305
|
+
// PATCH acts as upsert — if it fails, try POST (key may not exist on older API versions)
|
|
306
|
+
if (err instanceof ApiError && err.status === 404) {
|
|
307
|
+
try {
|
|
274
308
|
await apiPost(basePath, { key, values });
|
|
275
|
-
|
|
309
|
+
upserted++;
|
|
276
310
|
}
|
|
277
|
-
|
|
278
|
-
|
|
311
|
+
catch (postErr) {
|
|
312
|
+
failed++;
|
|
313
|
+
errors.push(` ${key}: ${postErr instanceof ApiError ? `${postErr.status} ${postErr.message}` : String(postErr)}`);
|
|
279
314
|
}
|
|
280
315
|
}
|
|
281
|
-
}
|
|
282
|
-
catch (err) {
|
|
283
|
-
failed++;
|
|
284
|
-
if (err instanceof ApiError) {
|
|
285
|
-
errors.push(` ${key}: ${err.status} ${err.message}`);
|
|
286
|
-
}
|
|
287
316
|
else {
|
|
288
|
-
|
|
317
|
+
failed++;
|
|
318
|
+
errors.push(` ${key}: ${err instanceof ApiError ? `${err.status} ${err.message}` : String(err)}`);
|
|
289
319
|
}
|
|
290
320
|
if (failed > 5) {
|
|
291
321
|
errors.push(` ... and more errors (stopping early)`);
|
|
@@ -293,12 +323,12 @@ export function registerProjectManagementTools(server) {
|
|
|
293
323
|
}
|
|
294
324
|
}
|
|
295
325
|
}
|
|
296
|
-
logWrite("bulk_import", { projectSlug, namespace, keyCount: keyMap.size }, {
|
|
326
|
+
logWrite("bulk_import", { projectSlug, namespace, keyCount: keyMap.size, source: filePath ?? "inline" }, { upserted, failed });
|
|
297
327
|
const lines = [
|
|
298
328
|
`Bulk import to sandbox: ${projectSlug}/${namespace}`,
|
|
299
|
-
`
|
|
300
|
-
`
|
|
301
|
-
` Failed:
|
|
329
|
+
` Source: ${filePath ?? "inline"}`,
|
|
330
|
+
` Upserted: ${upserted}`,
|
|
331
|
+
` Failed: ${failed}`,
|
|
302
332
|
];
|
|
303
333
|
if (errors.length > 0) {
|
|
304
334
|
lines.push(``, `Errors:`, ...errors);
|
|
@@ -312,6 +342,184 @@ export function registerProjectManagementTools(server) {
|
|
|
312
342
|
return errorContent(error);
|
|
313
343
|
}
|
|
314
344
|
});
|
|
345
|
+
// ─── compare_local_vs_server ───────────────────────────────────────────────
|
|
346
|
+
server.tool("compare_local_vs_server", [
|
|
347
|
+
"Compare a local translation map against a namespace on the server.",
|
|
348
|
+
"Returns: keys only in local (need importing), keys only on server (not in local), keys with different values (conflicts), and a count of matching keys.",
|
|
349
|
+
"Run this BEFORE bulk_import to avoid re-importing keys that already exist with the same values.",
|
|
350
|
+
"Accepts either an inline translations map or a filePath to a JSON file on disk.",
|
|
351
|
+
].join(" "), {
|
|
352
|
+
projectSlug: z.string().describe("Project slug"),
|
|
353
|
+
namespace: z.string().describe("Namespace slug"),
|
|
354
|
+
translations: z
|
|
355
|
+
.record(z.string(), z.record(z.string(), z.string()))
|
|
356
|
+
.optional()
|
|
357
|
+
.describe('Inline locale → key → value map to compare against server'),
|
|
358
|
+
filePath: z
|
|
359
|
+
.string()
|
|
360
|
+
.optional()
|
|
361
|
+
.describe('Absolute path to a JSON file on disk. Format: { "locale": { "key": "value" } }'),
|
|
362
|
+
env: z
|
|
363
|
+
.enum(["sandbox", "production"])
|
|
364
|
+
.default("sandbox")
|
|
365
|
+
.describe("Which environment to compare against (default: sandbox)"),
|
|
366
|
+
}, async ({ projectSlug, namespace, translations, filePath, env }) => {
|
|
367
|
+
try {
|
|
368
|
+
// Resolve local translations
|
|
369
|
+
let local;
|
|
370
|
+
if (filePath) {
|
|
371
|
+
try {
|
|
372
|
+
local = JSON.parse(readFileSync(filePath, "utf-8"));
|
|
373
|
+
}
|
|
374
|
+
catch (e) {
|
|
375
|
+
return {
|
|
376
|
+
content: [{ type: "text", text: `❌ Could not read file: ${filePath}\n${String(e)}` }],
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
else if (translations) {
|
|
381
|
+
local = translations;
|
|
382
|
+
}
|
|
383
|
+
else {
|
|
384
|
+
return {
|
|
385
|
+
content: [{ type: "text", text: `❌ Provide either "translations" (inline) or "filePath".` }],
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
// Fetch all server entries
|
|
389
|
+
const basePath = env === "sandbox"
|
|
390
|
+
? `/translations/projects/${projectSlug}/sandbox/namespaces/${namespace}/entries`
|
|
391
|
+
: `/translations/projects/${projectSlug}/namespaces/${namespace}/entries`;
|
|
392
|
+
const allEntries = [];
|
|
393
|
+
let page = 1;
|
|
394
|
+
while (true) {
|
|
395
|
+
const data = await apiGet(basePath, { page, limit: 100 });
|
|
396
|
+
allEntries.push(...data.data);
|
|
397
|
+
if (page >= data.meta.totalPages)
|
|
398
|
+
break;
|
|
399
|
+
page++;
|
|
400
|
+
}
|
|
401
|
+
const serverKeys = new Map();
|
|
402
|
+
for (const entry of allEntries) {
|
|
403
|
+
serverKeys.set(entry.key, entry.values);
|
|
404
|
+
}
|
|
405
|
+
// Collect all local keys across all locales
|
|
406
|
+
const localKeys = new Map();
|
|
407
|
+
for (const [locale, map] of Object.entries(local)) {
|
|
408
|
+
for (const [key, value] of Object.entries(map)) {
|
|
409
|
+
if (!localKeys.has(key))
|
|
410
|
+
localKeys.set(key, {});
|
|
411
|
+
localKeys.get(key)[locale] = value;
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
const onlyLocal = [];
|
|
415
|
+
const onlyServer = [];
|
|
416
|
+
const conflicts = [];
|
|
417
|
+
let matching = 0;
|
|
418
|
+
for (const [key, localValues] of localKeys.entries()) {
|
|
419
|
+
if (!serverKeys.has(key)) {
|
|
420
|
+
onlyLocal.push(key);
|
|
421
|
+
}
|
|
422
|
+
else {
|
|
423
|
+
const serverValues = serverKeys.get(key);
|
|
424
|
+
let hasConflict = false;
|
|
425
|
+
for (const [locale, localVal] of Object.entries(localValues)) {
|
|
426
|
+
const serverVal = serverValues[locale];
|
|
427
|
+
if (serverVal !== undefined && serverVal !== localVal) {
|
|
428
|
+
conflicts.push({ key, locale, local: localVal, server: serverVal });
|
|
429
|
+
hasConflict = true;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
if (!hasConflict)
|
|
433
|
+
matching++;
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
for (const key of serverKeys.keys()) {
|
|
437
|
+
if (!localKeys.has(key)) {
|
|
438
|
+
onlyServer.push(key);
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
const lines = [
|
|
442
|
+
`Compare: local${filePath ? ` (${filePath})` : ""} vs ${projectSlug}/${namespace} [${env}]`,
|
|
443
|
+
``,
|
|
444
|
+
` ✅ Matching (same values): ${matching}`,
|
|
445
|
+
` ➕ Only in local (need import): ${onlyLocal.length}`,
|
|
446
|
+
` 📦 Only on server (not local): ${onlyServer.length}`,
|
|
447
|
+
` ⚠️ Conflicts (different values): ${conflicts.length}`,
|
|
448
|
+
];
|
|
449
|
+
if (onlyLocal.length > 0) {
|
|
450
|
+
lines.push(``, `Keys only in local (first 20):`);
|
|
451
|
+
onlyLocal.slice(0, 20).forEach((k) => lines.push(` • ${k}`));
|
|
452
|
+
if (onlyLocal.length > 20)
|
|
453
|
+
lines.push(` ... and ${onlyLocal.length - 20} more`);
|
|
454
|
+
lines.push(``, `→ Run bulk_import to add these to the server.`);
|
|
455
|
+
}
|
|
456
|
+
if (conflicts.length > 0) {
|
|
457
|
+
lines.push(``, `Conflicts (first 10):`);
|
|
458
|
+
conflicts.slice(0, 10).forEach((c) => lines.push(` • ${c.key} [${c.locale}]\n local: "${c.local}"\n server: "${c.server}"`));
|
|
459
|
+
if (conflicts.length > 10)
|
|
460
|
+
lines.push(` ... and ${conflicts.length - 10} more`);
|
|
461
|
+
}
|
|
462
|
+
if (onlyLocal.length === 0 && conflicts.length === 0) {
|
|
463
|
+
lines.push(``, `✅ Local and server are in sync — no import needed.`);
|
|
464
|
+
}
|
|
465
|
+
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
466
|
+
}
|
|
467
|
+
catch (error) {
|
|
468
|
+
return errorContent(error);
|
|
469
|
+
}
|
|
470
|
+
});
|
|
471
|
+
// ─── validate_keys ─────────────────────────────────────────────────────────
|
|
472
|
+
server.tool("validate_keys", [
|
|
473
|
+
"Check whether a list of translation keys exist in a namespace.",
|
|
474
|
+
"Returns: found keys, missing keys.",
|
|
475
|
+
"Use this to verify that all t() calls in a component are backed by server entries.",
|
|
476
|
+
].join(" "), {
|
|
477
|
+
projectSlug: z.string().describe("Project slug"),
|
|
478
|
+
namespace: z.string().describe("Namespace slug"),
|
|
479
|
+
keys: z.array(z.string()).min(1).describe("List of translation keys to check"),
|
|
480
|
+
env: z
|
|
481
|
+
.enum(["sandbox", "production"])
|
|
482
|
+
.default("sandbox")
|
|
483
|
+
.describe("Which environment to check against (default: sandbox)"),
|
|
484
|
+
}, async ({ projectSlug, namespace, keys, env }) => {
|
|
485
|
+
try {
|
|
486
|
+
const basePath = env === "sandbox"
|
|
487
|
+
? `/translations/projects/${projectSlug}/sandbox/namespaces/${namespace}/entries`
|
|
488
|
+
: `/translations/projects/${projectSlug}/namespaces/${namespace}/entries`;
|
|
489
|
+
// Fetch all entries to build a key set
|
|
490
|
+
const allEntries = [];
|
|
491
|
+
let page = 1;
|
|
492
|
+
while (true) {
|
|
493
|
+
const data = await apiGet(basePath, { page, limit: 100 });
|
|
494
|
+
allEntries.push(...data.data);
|
|
495
|
+
if (page >= data.meta.totalPages)
|
|
496
|
+
break;
|
|
497
|
+
page++;
|
|
498
|
+
}
|
|
499
|
+
const serverKeySet = new Set(allEntries.map((e) => e.key));
|
|
500
|
+
const found = keys.filter((k) => serverKeySet.has(k));
|
|
501
|
+
const missing = keys.filter((k) => !serverKeySet.has(k));
|
|
502
|
+
const lines = [
|
|
503
|
+
`Validate keys in ${projectSlug}/${namespace} [${env}]`,
|
|
504
|
+
``,
|
|
505
|
+
` Checked: ${keys.length}`,
|
|
506
|
+
` Found: ${found.length}`,
|
|
507
|
+
` Missing: ${missing.length}`,
|
|
508
|
+
];
|
|
509
|
+
if (missing.length > 0) {
|
|
510
|
+
lines.push(``, `Missing keys:`);
|
|
511
|
+
missing.forEach((k) => lines.push(` ✗ ${k}`));
|
|
512
|
+
lines.push(``, `→ Use set_translation or bulk_import to add missing keys.`);
|
|
513
|
+
}
|
|
514
|
+
else {
|
|
515
|
+
lines.push(``, `✅ All keys exist on the server.`);
|
|
516
|
+
}
|
|
517
|
+
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
518
|
+
}
|
|
519
|
+
catch (error) {
|
|
520
|
+
return errorContent(error);
|
|
521
|
+
}
|
|
522
|
+
});
|
|
315
523
|
// ─── get_namespace_coverage ────────────────────────────────────────────────
|
|
316
524
|
server.tool("get_namespace_coverage", [
|
|
317
525
|
"Show per-locale fill statistics for a namespace.",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"project-management.js","sourceRoot":"","sources":["../../src/tools/project-management.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"project-management.js","sourceRoot":"","sources":["../../src/tools/project-management.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const args = process.argv.slice(2);
|
|
4
|
+
|
|
5
|
+
if (args[0] === "setup") {
|
|
6
|
+
const { runSetup } = await import("./setup.js");
|
|
7
|
+
await runSetup(args.slice(1));
|
|
8
|
+
process.exit(0);
|
|
9
|
+
}
|
|
10
|
+
|
|
2
11
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
12
|
import { createServer } from "./server.js";
|
|
4
13
|
|
package/src/permissions.ts
CHANGED
|
@@ -64,6 +64,8 @@ export const TOOL_REGISTRY = {
|
|
|
64
64
|
// ── Read-only export / analysis ───────────────────────────────────────────
|
|
65
65
|
export_namespace: { env: "both", access: "read" },
|
|
66
66
|
get_namespace_coverage: { env: "both", access: "read" },
|
|
67
|
+
compare_local_vs_server: { env: "both", access: "read" },
|
|
68
|
+
validate_keys: { env: "both", access: "read" },
|
|
67
69
|
} as const satisfies Record<string, ToolMeta>;
|
|
68
70
|
|
|
69
71
|
export type ToolName = keyof typeof TOOL_REGISTRY;
|
package/src/setup.ts
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { execSync } from "child_process";
|
|
2
|
+
|
|
3
|
+
const BOLD = "\x1b[1m";
|
|
4
|
+
const GREEN = "\x1b[32m";
|
|
5
|
+
const RED = "\x1b[31m";
|
|
6
|
+
const YELLOW = "\x1b[33m";
|
|
7
|
+
const RESET = "\x1b[0m";
|
|
8
|
+
|
|
9
|
+
const ok = (msg: string) => console.log(`${GREEN}✓${RESET} ${msg}`);
|
|
10
|
+
const fail = (msg: string) => console.error(`${RED}✗${RESET} ${msg}`);
|
|
11
|
+
const warn = (msg: string) => console.log(`${YELLOW}!${RESET} ${msg}`);
|
|
12
|
+
|
|
13
|
+
function parseArgs(args: string[]): { token?: string; backendUrl?: string } {
|
|
14
|
+
const tokenIdx = args.indexOf("--token");
|
|
15
|
+
const backendIdx = args.indexOf("--backend-url");
|
|
16
|
+
return {
|
|
17
|
+
token: tokenIdx !== -1 ? args[tokenIdx + 1] : undefined,
|
|
18
|
+
backendUrl: backendIdx !== -1 ? args[backendIdx + 1] : undefined,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function checkClaudeCli(): boolean {
|
|
23
|
+
try {
|
|
24
|
+
execSync("claude --version", { stdio: "pipe" });
|
|
25
|
+
return true;
|
|
26
|
+
} catch {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function removeOldRegistration(): void {
|
|
32
|
+
try {
|
|
33
|
+
execSync('claude mcp remove "localization" -s user', { stdio: "pipe" });
|
|
34
|
+
ok("Removed old registration");
|
|
35
|
+
} catch {
|
|
36
|
+
// Not registered yet — fine
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function register(token: string, backendUrl: string): void {
|
|
41
|
+
execSync(
|
|
42
|
+
`claude mcp add "localization" -s user -e MCP_TOKEN=${token} -e BACKEND_URL=${backendUrl} -- npx -y localization-mcp-server`,
|
|
43
|
+
{ stdio: "pipe" },
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async function verifyToken(token: string, backendUrl: string): Promise<boolean> {
|
|
48
|
+
try {
|
|
49
|
+
const response = await fetch(`${backendUrl}/translations/projects`, {
|
|
50
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
51
|
+
signal: AbortSignal.timeout(10_000),
|
|
52
|
+
});
|
|
53
|
+
return response.ok;
|
|
54
|
+
} catch {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export async function runSetup(args: string[]): Promise<void> {
|
|
60
|
+
console.log(`\n${BOLD}Localization MCP — setup${RESET}\n`);
|
|
61
|
+
|
|
62
|
+
const { token, backendUrl = "http://localhost:8080" } = parseArgs(args);
|
|
63
|
+
|
|
64
|
+
if (!token) {
|
|
65
|
+
fail("Missing --token. Run the command generated by the admin panel.");
|
|
66
|
+
process.exit(1);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// 1. Check Claude CLI
|
|
70
|
+
if (!checkClaudeCli()) {
|
|
71
|
+
fail("Claude CLI not found. Install it from https://claude.ai/code");
|
|
72
|
+
process.exit(1);
|
|
73
|
+
}
|
|
74
|
+
ok("Claude CLI found");
|
|
75
|
+
|
|
76
|
+
// 2. Remove old registration
|
|
77
|
+
removeOldRegistration();
|
|
78
|
+
|
|
79
|
+
// 3. Register with correct token
|
|
80
|
+
try {
|
|
81
|
+
register(token, backendUrl);
|
|
82
|
+
ok("MCP server registered");
|
|
83
|
+
} catch (e) {
|
|
84
|
+
fail(`Failed to register MCP server: ${e}`);
|
|
85
|
+
process.exit(1);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// 4. Verify token works
|
|
89
|
+
const valid = await verifyToken(token, backendUrl);
|
|
90
|
+
if (!valid) {
|
|
91
|
+
fail("Token verification failed — the token may be expired or the server is unreachable.");
|
|
92
|
+
warn("MCP is registered but will not work until the token is valid.");
|
|
93
|
+
warn("Re-run this command with a fresh token from the admin panel.");
|
|
94
|
+
process.exit(1);
|
|
95
|
+
}
|
|
96
|
+
ok("Token verified");
|
|
97
|
+
|
|
98
|
+
console.log(`\n${GREEN}${BOLD}Setup complete.${RESET}`);
|
|
99
|
+
console.log("Restart Claude for the changes to take effect.\n");
|
|
100
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
+
import { readFileSync } from "fs";
|
|
3
4
|
import { apiGet, apiPost, ApiError } from "../api-client.js";
|
|
4
5
|
import { logWrite } from "../logger.js";
|
|
5
6
|
|
|
@@ -247,54 +248,86 @@ export function registerProjectManagementTools(server: McpServer): void {
|
|
|
247
248
|
// ─── bulk_import ───────────────────────────────────────────────────────────
|
|
248
249
|
server.tool(
|
|
249
250
|
"bulk_import",
|
|
250
|
-
|
|
251
|
+
[
|
|
252
|
+
"Import multiple translation keys into the sandbox at once.",
|
|
253
|
+
"Accepts either inline JSON (translations parameter) or a path to a JSON file on disk (filePath parameter).",
|
|
254
|
+
"File format: { \"locale\": { \"key\": \"value\" } } — same as inline translations.",
|
|
255
|
+
"Use filePath when the payload is large (>100 keys) to avoid inline JSON size limits.",
|
|
256
|
+
"All writes go to sandbox — production is unchanged until you promote.",
|
|
257
|
+
"Run compare_local_vs_server first to avoid re-importing keys that already exist.",
|
|
258
|
+
].join(" "),
|
|
251
259
|
{
|
|
252
260
|
projectSlug: z.string().describe("Project slug"),
|
|
253
261
|
namespace: z.string().describe("Namespace slug — must already exist (use create_namespace first)"),
|
|
254
262
|
translations: z
|
|
255
|
-
.record(
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
.
|
|
263
|
+
.record(z.string(), z.record(z.string(), z.string()))
|
|
264
|
+
.optional()
|
|
265
|
+
.describe('Inline locale → key → value map. Use this for small payloads. Example: { "en": { "save": "Save" }, "nb-NO": { "save": "Lagre" } }'),
|
|
266
|
+
filePath: z
|
|
267
|
+
.string()
|
|
268
|
+
.optional()
|
|
269
|
+
.describe('Absolute path to a JSON file on disk. Format: { "locale": { "key": "value" } }. Use this for large translation files instead of inline JSON.'),
|
|
260
270
|
dryRun: z
|
|
261
271
|
.boolean()
|
|
262
272
|
.default(false)
|
|
263
273
|
.describe("If true, validate and preview what would be imported without writing anything"),
|
|
264
274
|
},
|
|
265
|
-
async ({ projectSlug, namespace, translations, dryRun }) => {
|
|
275
|
+
async ({ projectSlug, namespace, translations, filePath, dryRun }) => {
|
|
266
276
|
try {
|
|
267
|
-
//
|
|
268
|
-
|
|
277
|
+
// Resolve translations — from inline or file
|
|
278
|
+
let resolvedTranslations: Record<string, Record<string, string>>;
|
|
279
|
+
|
|
280
|
+
if (filePath) {
|
|
281
|
+
try {
|
|
282
|
+
const raw = readFileSync(filePath, "utf-8");
|
|
283
|
+
resolvedTranslations = JSON.parse(raw);
|
|
284
|
+
} catch (e) {
|
|
285
|
+
return {
|
|
286
|
+
content: [{
|
|
287
|
+
type: "text" as const,
|
|
288
|
+
text: `❌ Could not read file: ${filePath}\n${String(e)}`,
|
|
289
|
+
}],
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
} else if (translations) {
|
|
293
|
+
resolvedTranslations = translations;
|
|
294
|
+
} else {
|
|
295
|
+
return {
|
|
296
|
+
content: [{
|
|
297
|
+
type: "text" as const,
|
|
298
|
+
text: `❌ Provide either "translations" (inline JSON) or "filePath" (path to JSON file).`,
|
|
299
|
+
}],
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// Validate locale codes against the project
|
|
269
304
|
const project = await apiGet<{ locales: { code: string; isDefault: boolean }[] }>(
|
|
270
305
|
`/translations/projects/${projectSlug}`,
|
|
271
306
|
);
|
|
272
307
|
const validLocales = new Set(project.locales.map((l) => l.code));
|
|
273
|
-
const requestedLocales = Object.keys(
|
|
308
|
+
const requestedLocales = Object.keys(resolvedTranslations);
|
|
274
309
|
const unknownLocales = requestedLocales.filter((l) => !validLocales.has(l));
|
|
275
310
|
|
|
276
311
|
if (unknownLocales.length > 0) {
|
|
277
312
|
return {
|
|
278
|
-
content: [
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
},
|
|
291
|
-
],
|
|
313
|
+
content: [{
|
|
314
|
+
type: "text" as const,
|
|
315
|
+
text: [
|
|
316
|
+
`❌ Import aborted — locale codes do not match the project.`,
|
|
317
|
+
``,
|
|
318
|
+
`Unknown codes: ${unknownLocales.map((l) => `"${l}"`).join(", ")}`,
|
|
319
|
+
`Valid locales for "${projectSlug}": ${[...validLocales].join(", ")}`,
|
|
320
|
+
``,
|
|
321
|
+
`Call get_project_details to get the exact locale codes. Do not guess or remap them.`,
|
|
322
|
+
`If the locale does not exist in the project yet, call create_locale first.`,
|
|
323
|
+
].join("\n"),
|
|
324
|
+
}],
|
|
292
325
|
};
|
|
293
326
|
}
|
|
294
327
|
|
|
295
|
-
// Collect all unique keys
|
|
328
|
+
// Collect all unique keys
|
|
296
329
|
const allKeys = new Set<string>();
|
|
297
|
-
for (const localeMap of Object.values(
|
|
330
|
+
for (const localeMap of Object.values(resolvedTranslations)) {
|
|
298
331
|
for (const key of Object.keys(localeMap)) {
|
|
299
332
|
allKeys.add(key);
|
|
300
333
|
}
|
|
@@ -302,22 +335,21 @@ export function registerProjectManagementTools(server: McpServer): void {
|
|
|
302
335
|
|
|
303
336
|
if (dryRun) {
|
|
304
337
|
const perLocale = requestedLocales.map(
|
|
305
|
-
(l) => ` ${l}: ${Object.keys(
|
|
338
|
+
(l) => ` ${l}: ${Object.keys(resolvedTranslations[l]).length} values`,
|
|
306
339
|
);
|
|
307
340
|
return {
|
|
308
|
-
content: [
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
],
|
|
341
|
+
content: [{
|
|
342
|
+
type: "text" as const,
|
|
343
|
+
text: [
|
|
344
|
+
`DRY RUN — nothing written`,
|
|
345
|
+
``,
|
|
346
|
+
`Would import to sandbox: ${projectSlug}/${namespace}`,
|
|
347
|
+
` Source: ${filePath ?? "inline"}`,
|
|
348
|
+
` Unique keys: ${allKeys.size}`,
|
|
349
|
+
` Locales:`,
|
|
350
|
+
...perLocale,
|
|
351
|
+
].join("\n"),
|
|
352
|
+
}],
|
|
321
353
|
};
|
|
322
354
|
}
|
|
323
355
|
|
|
@@ -325,15 +357,14 @@ export function registerProjectManagementTools(server: McpServer): void {
|
|
|
325
357
|
|
|
326
358
|
// Group values per key across all locales, then upsert each key once
|
|
327
359
|
const keyMap = new Map<string, Record<string, string>>();
|
|
328
|
-
for (const [locale, localeMap] of Object.entries(
|
|
360
|
+
for (const [locale, localeMap] of Object.entries(resolvedTranslations)) {
|
|
329
361
|
for (const [key, value] of Object.entries(localeMap)) {
|
|
330
362
|
if (!keyMap.has(key)) keyMap.set(key, {});
|
|
331
363
|
keyMap.get(key)![locale] = value;
|
|
332
364
|
}
|
|
333
365
|
}
|
|
334
366
|
|
|
335
|
-
let
|
|
336
|
-
let updated = 0;
|
|
367
|
+
let upserted = 0;
|
|
337
368
|
let failed = 0;
|
|
338
369
|
const errors: string[] = [];
|
|
339
370
|
|
|
@@ -341,25 +372,21 @@ export function registerProjectManagementTools(server: McpServer): void {
|
|
|
341
372
|
|
|
342
373
|
for (const [key, values] of keyMap.entries()) {
|
|
343
374
|
try {
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
// Key does not exist yet — create it
|
|
375
|
+
await apiPatch<unknown>(`${basePath}/${encodeURIComponent(key)}`, { values });
|
|
376
|
+
upserted++;
|
|
377
|
+
} catch (err) {
|
|
378
|
+
// PATCH acts as upsert — if it fails, try POST (key may not exist on older API versions)
|
|
379
|
+
if (err instanceof ApiError && err.status === 404) {
|
|
380
|
+
try {
|
|
351
381
|
await apiPost<unknown>(basePath, { key, values });
|
|
352
|
-
|
|
353
|
-
}
|
|
354
|
-
|
|
382
|
+
upserted++;
|
|
383
|
+
} catch (postErr) {
|
|
384
|
+
failed++;
|
|
385
|
+
errors.push(` ${key}: ${postErr instanceof ApiError ? `${postErr.status} ${postErr.message}` : String(postErr)}`);
|
|
355
386
|
}
|
|
356
|
-
}
|
|
357
|
-
} catch (err) {
|
|
358
|
-
failed++;
|
|
359
|
-
if (err instanceof ApiError) {
|
|
360
|
-
errors.push(` ${key}: ${err.status} ${err.message}`);
|
|
361
387
|
} else {
|
|
362
|
-
|
|
388
|
+
failed++;
|
|
389
|
+
errors.push(` ${key}: ${err instanceof ApiError ? `${err.status} ${err.message}` : String(err)}`);
|
|
363
390
|
}
|
|
364
391
|
if (failed > 5) {
|
|
365
392
|
errors.push(` ... and more errors (stopping early)`);
|
|
@@ -368,23 +395,20 @@ export function registerProjectManagementTools(server: McpServer): void {
|
|
|
368
395
|
}
|
|
369
396
|
}
|
|
370
397
|
|
|
371
|
-
logWrite("bulk_import", { projectSlug, namespace, keyCount: keyMap.size }, {
|
|
398
|
+
logWrite("bulk_import", { projectSlug, namespace, keyCount: keyMap.size, source: filePath ?? "inline" }, { upserted, failed });
|
|
372
399
|
|
|
373
400
|
const lines = [
|
|
374
401
|
`Bulk import to sandbox: ${projectSlug}/${namespace}`,
|
|
375
|
-
`
|
|
376
|
-
`
|
|
377
|
-
` Failed:
|
|
402
|
+
` Source: ${filePath ?? "inline"}`,
|
|
403
|
+
` Upserted: ${upserted}`,
|
|
404
|
+
` Failed: ${failed}`,
|
|
378
405
|
];
|
|
379
406
|
|
|
380
407
|
if (errors.length > 0) {
|
|
381
408
|
lines.push(``, `Errors:`, ...errors);
|
|
382
409
|
}
|
|
383
410
|
|
|
384
|
-
lines.push(
|
|
385
|
-
``,
|
|
386
|
-
`Use get_translation_diff to review all pending changes before promoting.`,
|
|
387
|
-
);
|
|
411
|
+
lines.push(``, `Use get_translation_diff to review all pending changes before promoting.`);
|
|
388
412
|
|
|
389
413
|
return {
|
|
390
414
|
content: [{ type: "text" as const, text: lines.join("\n") }],
|
|
@@ -395,6 +419,205 @@ export function registerProjectManagementTools(server: McpServer): void {
|
|
|
395
419
|
},
|
|
396
420
|
);
|
|
397
421
|
|
|
422
|
+
// ─── compare_local_vs_server ───────────────────────────────────────────────
|
|
423
|
+
server.tool(
|
|
424
|
+
"compare_local_vs_server",
|
|
425
|
+
[
|
|
426
|
+
"Compare a local translation map against a namespace on the server.",
|
|
427
|
+
"Returns: keys only in local (need importing), keys only on server (not in local), keys with different values (conflicts), and a count of matching keys.",
|
|
428
|
+
"Run this BEFORE bulk_import to avoid re-importing keys that already exist with the same values.",
|
|
429
|
+
"Accepts either an inline translations map or a filePath to a JSON file on disk.",
|
|
430
|
+
].join(" "),
|
|
431
|
+
{
|
|
432
|
+
projectSlug: z.string().describe("Project slug"),
|
|
433
|
+
namespace: z.string().describe("Namespace slug"),
|
|
434
|
+
translations: z
|
|
435
|
+
.record(z.string(), z.record(z.string(), z.string()))
|
|
436
|
+
.optional()
|
|
437
|
+
.describe('Inline locale → key → value map to compare against server'),
|
|
438
|
+
filePath: z
|
|
439
|
+
.string()
|
|
440
|
+
.optional()
|
|
441
|
+
.describe('Absolute path to a JSON file on disk. Format: { "locale": { "key": "value" } }'),
|
|
442
|
+
env: z
|
|
443
|
+
.enum(["sandbox", "production"])
|
|
444
|
+
.default("sandbox")
|
|
445
|
+
.describe("Which environment to compare against (default: sandbox)"),
|
|
446
|
+
},
|
|
447
|
+
async ({ projectSlug, namespace, translations, filePath, env }) => {
|
|
448
|
+
try {
|
|
449
|
+
// Resolve local translations
|
|
450
|
+
let local: Record<string, Record<string, string>>;
|
|
451
|
+
|
|
452
|
+
if (filePath) {
|
|
453
|
+
try {
|
|
454
|
+
local = JSON.parse(readFileSync(filePath, "utf-8"));
|
|
455
|
+
} catch (e) {
|
|
456
|
+
return {
|
|
457
|
+
content: [{ type: "text" as const, text: `❌ Could not read file: ${filePath}\n${String(e)}` }],
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
} else if (translations) {
|
|
461
|
+
local = translations;
|
|
462
|
+
} else {
|
|
463
|
+
return {
|
|
464
|
+
content: [{ type: "text" as const, text: `❌ Provide either "translations" (inline) or "filePath".` }],
|
|
465
|
+
};
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
// Fetch all server entries
|
|
469
|
+
const basePath =
|
|
470
|
+
env === "sandbox"
|
|
471
|
+
? `/translations/projects/${projectSlug}/sandbox/namespaces/${namespace}/entries`
|
|
472
|
+
: `/translations/projects/${projectSlug}/namespaces/${namespace}/entries`;
|
|
473
|
+
|
|
474
|
+
const allEntries: TranslationEntry[] = [];
|
|
475
|
+
let page = 1;
|
|
476
|
+
while (true) {
|
|
477
|
+
const data = await apiGet<EntriesPage>(basePath, { page, limit: 100 });
|
|
478
|
+
allEntries.push(...data.data);
|
|
479
|
+
if (page >= data.meta.totalPages) break;
|
|
480
|
+
page++;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
const serverKeys = new Map<string, Record<string, string>>();
|
|
484
|
+
for (const entry of allEntries) {
|
|
485
|
+
serverKeys.set(entry.key, entry.values);
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
// Collect all local keys across all locales
|
|
489
|
+
const localKeys = new Map<string, Record<string, string>>();
|
|
490
|
+
for (const [locale, map] of Object.entries(local)) {
|
|
491
|
+
for (const [key, value] of Object.entries(map)) {
|
|
492
|
+
if (!localKeys.has(key)) localKeys.set(key, {});
|
|
493
|
+
localKeys.get(key)![locale] = value;
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
const onlyLocal: string[] = [];
|
|
498
|
+
const onlyServer: string[] = [];
|
|
499
|
+
const conflicts: { key: string; locale: string; local: string; server: string }[] = [];
|
|
500
|
+
let matching = 0;
|
|
501
|
+
|
|
502
|
+
for (const [key, localValues] of localKeys.entries()) {
|
|
503
|
+
if (!serverKeys.has(key)) {
|
|
504
|
+
onlyLocal.push(key);
|
|
505
|
+
} else {
|
|
506
|
+
const serverValues = serverKeys.get(key)!;
|
|
507
|
+
let hasConflict = false;
|
|
508
|
+
for (const [locale, localVal] of Object.entries(localValues)) {
|
|
509
|
+
const serverVal = serverValues[locale];
|
|
510
|
+
if (serverVal !== undefined && serverVal !== localVal) {
|
|
511
|
+
conflicts.push({ key, locale, local: localVal, server: serverVal });
|
|
512
|
+
hasConflict = true;
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
if (!hasConflict) matching++;
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
for (const key of serverKeys.keys()) {
|
|
520
|
+
if (!localKeys.has(key)) {
|
|
521
|
+
onlyServer.push(key);
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
const lines = [
|
|
526
|
+
`Compare: local${filePath ? ` (${filePath})` : ""} vs ${projectSlug}/${namespace} [${env}]`,
|
|
527
|
+
``,
|
|
528
|
+
` ✅ Matching (same values): ${matching}`,
|
|
529
|
+
` ➕ Only in local (need import): ${onlyLocal.length}`,
|
|
530
|
+
` 📦 Only on server (not local): ${onlyServer.length}`,
|
|
531
|
+
` ⚠️ Conflicts (different values): ${conflicts.length}`,
|
|
532
|
+
];
|
|
533
|
+
|
|
534
|
+
if (onlyLocal.length > 0) {
|
|
535
|
+
lines.push(``, `Keys only in local (first 20):`);
|
|
536
|
+
onlyLocal.slice(0, 20).forEach((k) => lines.push(` • ${k}`));
|
|
537
|
+
if (onlyLocal.length > 20) lines.push(` ... and ${onlyLocal.length - 20} more`);
|
|
538
|
+
lines.push(``, `→ Run bulk_import to add these to the server.`);
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
if (conflicts.length > 0) {
|
|
542
|
+
lines.push(``, `Conflicts (first 10):`);
|
|
543
|
+
conflicts.slice(0, 10).forEach((c) =>
|
|
544
|
+
lines.push(` • ${c.key} [${c.locale}]\n local: "${c.local}"\n server: "${c.server}"`),
|
|
545
|
+
);
|
|
546
|
+
if (conflicts.length > 10) lines.push(` ... and ${conflicts.length - 10} more`);
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
if (onlyLocal.length === 0 && conflicts.length === 0) {
|
|
550
|
+
lines.push(``, `✅ Local and server are in sync — no import needed.`);
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
return { content: [{ type: "text" as const, text: lines.join("\n") }] };
|
|
554
|
+
} catch (error) {
|
|
555
|
+
return errorContent(error);
|
|
556
|
+
}
|
|
557
|
+
},
|
|
558
|
+
);
|
|
559
|
+
|
|
560
|
+
// ─── validate_keys ─────────────────────────────────────────────────────────
|
|
561
|
+
server.tool(
|
|
562
|
+
"validate_keys",
|
|
563
|
+
[
|
|
564
|
+
"Check whether a list of translation keys exist in a namespace.",
|
|
565
|
+
"Returns: found keys, missing keys.",
|
|
566
|
+
"Use this to verify that all t() calls in a component are backed by server entries.",
|
|
567
|
+
].join(" "),
|
|
568
|
+
{
|
|
569
|
+
projectSlug: z.string().describe("Project slug"),
|
|
570
|
+
namespace: z.string().describe("Namespace slug"),
|
|
571
|
+
keys: z.array(z.string()).min(1).describe("List of translation keys to check"),
|
|
572
|
+
env: z
|
|
573
|
+
.enum(["sandbox", "production"])
|
|
574
|
+
.default("sandbox")
|
|
575
|
+
.describe("Which environment to check against (default: sandbox)"),
|
|
576
|
+
},
|
|
577
|
+
async ({ projectSlug, namespace, keys, env }) => {
|
|
578
|
+
try {
|
|
579
|
+
const basePath =
|
|
580
|
+
env === "sandbox"
|
|
581
|
+
? `/translations/projects/${projectSlug}/sandbox/namespaces/${namespace}/entries`
|
|
582
|
+
: `/translations/projects/${projectSlug}/namespaces/${namespace}/entries`;
|
|
583
|
+
|
|
584
|
+
// Fetch all entries to build a key set
|
|
585
|
+
const allEntries: TranslationEntry[] = [];
|
|
586
|
+
let page = 1;
|
|
587
|
+
while (true) {
|
|
588
|
+
const data = await apiGet<EntriesPage>(basePath, { page, limit: 100 });
|
|
589
|
+
allEntries.push(...data.data);
|
|
590
|
+
if (page >= data.meta.totalPages) break;
|
|
591
|
+
page++;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
const serverKeySet = new Set(allEntries.map((e) => e.key));
|
|
595
|
+
const found = keys.filter((k) => serverKeySet.has(k));
|
|
596
|
+
const missing = keys.filter((k) => !serverKeySet.has(k));
|
|
597
|
+
|
|
598
|
+
const lines = [
|
|
599
|
+
`Validate keys in ${projectSlug}/${namespace} [${env}]`,
|
|
600
|
+
``,
|
|
601
|
+
` Checked: ${keys.length}`,
|
|
602
|
+
` Found: ${found.length}`,
|
|
603
|
+
` Missing: ${missing.length}`,
|
|
604
|
+
];
|
|
605
|
+
|
|
606
|
+
if (missing.length > 0) {
|
|
607
|
+
lines.push(``, `Missing keys:`);
|
|
608
|
+
missing.forEach((k) => lines.push(` ✗ ${k}`));
|
|
609
|
+
lines.push(``, `→ Use set_translation or bulk_import to add missing keys.`);
|
|
610
|
+
} else {
|
|
611
|
+
lines.push(``, `✅ All keys exist on the server.`);
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
return { content: [{ type: "text" as const, text: lines.join("\n") }] };
|
|
615
|
+
} catch (error) {
|
|
616
|
+
return errorContent(error);
|
|
617
|
+
}
|
|
618
|
+
},
|
|
619
|
+
);
|
|
620
|
+
|
|
398
621
|
// ─── get_namespace_coverage ────────────────────────────────────────────────
|
|
399
622
|
server.tool(
|
|
400
623
|
"get_namespace_coverage",
|