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 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":";AACA,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"}
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"}
@@ -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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuBmB,CAAC;AAE9C,MAAM,MAAM,QAAQ,GAAG,MAAM,OAAO,aAAa,CAAC;AAElD;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,WAAW,GAAG,IAAI,CAQzD"}
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"}
@@ -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.
@@ -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;CACZ,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"}
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"}
@@ -0,0 +1,2 @@
1
+ export declare function runSetup(args: string[]): Promise<void>;
2
+ //# sourceMappingURL=setup.d.ts.map
@@ -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;AA2BpE,wBAAgB,8BAA8B,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA8dtE"}
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", "Import multiple translation keys into the sandbox at once from a JSON map. Input format: { \"locale\": { \"key\": \"value\" } }. All writes go to sandbox — production is unchanged until you promote. Use this to migrate a module's local translation files to the server.", {
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
- .describe('Locale → key → value map. Example: { "en": { "save": "Save" }, "nb-NO": { "save": "Lagre" } }'),
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
- // Validate locale codes against the project. Unknown codes are rejected — not remapped.
201
- // Agent must call get_project_details first to get the exact codes for this project.
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(translations);
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 across all locales
261
+ // Collect all unique keys
225
262
  const allKeys = new Set();
226
- for (const localeMap of Object.values(translations)) {
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(translations[l]).length} values`);
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(translations)) {
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 created = 0;
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
- // Try PATCH (update) first faster if key exists
267
- try {
268
- await apiPatch(`${basePath}/${encodeURIComponent(key)}`, { values });
269
- updated++;
270
- }
271
- catch (patchErr) {
272
- if (patchErr instanceof ApiError && patchErr.status === 404) {
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
- created++;
309
+ upserted++;
276
310
  }
277
- else {
278
- throw patchErr;
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
- errors.push(` ${key}: ${String(err)}`);
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 }, { created, updated, failed });
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
- ` Created: ${created}`,
300
- ` Updated: ${updated}`,
301
- ` Failed: ${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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "localization-mcp-server",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "MCP server for the localization system — controlled AI access to translations",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
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
 
@@ -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
- "Import multiple translation keys into the sandbox at once from a JSON map. Input format: { \"locale\": { \"key\": \"value\" } }. All writes go to sandbox — production is unchanged until you promote. Use this to migrate a module's local translation files to the server.",
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
- z.string(),
257
- z.record(z.string(), z.string()),
258
- )
259
- .describe('Locale → key → value map. Example: { "en": { "save": "Save" }, "nb-NO": { "save": "Lagre" } }'),
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
- // Validate locale codes against the project. Unknown codes are rejected — not remapped.
268
- // Agent must call get_project_details first to get the exact codes for this project.
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(translations);
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
- type: "text" as const,
281
- text: [
282
- `❌ Import aborted — locale codes do not match the project.`,
283
- ``,
284
- `Unknown codes: ${unknownLocales.map((l) => `"${l}"`).join(", ")}`,
285
- `Valid locales for "${projectSlug}": ${[...validLocales].join(", ")}`,
286
- ``,
287
- `Call get_project_details to get the exact locale codes. Do not guess or remap them.`,
288
- `If the locale does not exist in the project yet, call create_locale first.`,
289
- ].join("\n"),
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 across all locales
328
+ // Collect all unique keys
296
329
  const allKeys = new Set<string>();
297
- for (const localeMap of Object.values(translations)) {
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(translations[l]).length} values`,
338
+ (l) => ` ${l}: ${Object.keys(resolvedTranslations[l]).length} values`,
306
339
  );
307
340
  return {
308
- content: [
309
- {
310
- type: "text" as const,
311
- text: [
312
- `DRY RUN — nothing written`,
313
- ``,
314
- `Would import to sandbox: ${projectSlug}/${namespace}`,
315
- ` Unique keys: ${allKeys.size}`,
316
- ` Locales:`,
317
- ...perLocale,
318
- ].join("\n"),
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(translations)) {
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 created = 0;
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
- // Try PATCH (update) first faster if key exists
345
- try {
346
- await apiPatch<unknown>(`${basePath}/${encodeURIComponent(key)}`, { values });
347
- updated++;
348
- } catch (patchErr) {
349
- if (patchErr instanceof ApiError && patchErr.status === 404) {
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
- created++;
353
- } else {
354
- throw patchErr;
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
- errors.push(` ${key}: ${String(err)}`);
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 }, { created, updated, failed });
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
- ` Created: ${created}`,
376
- ` Updated: ${updated}`,
377
- ` Failed: ${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",