@syntholoc/mcp 0.3.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -0
- package/dist/build-server.js +1 -1
- package/dist/{chunk-MUY33R6O.js → chunk-P7LZNIW2.js} +116 -68
- package/dist/index.js +1 -1
- package/package.json +5 -2
package/README.md
CHANGED
|
@@ -113,6 +113,27 @@ Translation runs asynchronously and returns a job id; a `wait_for_job` tool
|
|
|
113
113
|
blocks until completion, so you can chain "translate → wait → export" in a
|
|
114
114
|
single request.
|
|
115
115
|
|
|
116
|
+
## Contributing: adding a tool
|
|
117
|
+
|
|
118
|
+
Tools are authored by hand — the curated descriptions, input aliases, and
|
|
119
|
+
validation are what make an LLM use them well, so they are deliberately not
|
|
120
|
+
generated one-per-operation. Two mechanisms keep the manual layer honest:
|
|
121
|
+
|
|
122
|
+
- **Generated input shapes.** `bun run codegen` emits zod schemas for every
|
|
123
|
+
GraphQL input type into `src/generated/input-schemas.ts` from the API's
|
|
124
|
+
committed SDL. Compose a schema's `.shape` instead of re-typing a mutation's
|
|
125
|
+
fields, then curate on top — see `configure_llm_provider` in
|
|
126
|
+
`src/tools/providers.ts`, which spreads `ConfigureProviderInputSchema().shape`
|
|
127
|
+
and tightens the API's free-form `type: String` down to a concrete enum.
|
|
128
|
+
- **Drift guard.** `src/operation-coverage.spec.ts` fails the build when an
|
|
129
|
+
operation exported by `@syntholoc/sdk` is not surfaced by any tool or resource
|
|
130
|
+
(or explicitly exempted). Add an operation to the SDK and you must either wire
|
|
131
|
+
up a tool/resource or record why it is MCP-exempt.
|
|
132
|
+
|
|
133
|
+
Every tool set has contract tests (`src/tools/*.spec.ts`) that pin both the
|
|
134
|
+
GraphQL operation + variables a tool emits and the JSON it returns, via an
|
|
135
|
+
in-memory MCP client against a mock GraphQL client (`src/spec-helpers.ts`).
|
|
136
|
+
|
|
116
137
|
## License
|
|
117
138
|
|
|
118
139
|
MIT
|
package/dist/build-server.js
CHANGED
|
@@ -115,6 +115,12 @@ function registerPrompts(server) {
|
|
|
115
115
|
` - If a locale's ON-DISK code differs from its BCP-47 code (e.g. "zh-CN" stored as "cn", "pt-BR" as "pt"),`,
|
|
116
116
|
' add `languagesMapping`, e.g. { "two_letters_code": { "zh-CN": "cn", "pt-BR": "pt" } }.',
|
|
117
117
|
' - Do NOT invent fields like `i18nDir`, `format: "nested-dirs"`, or `localeMapping` \u2014 they are not read.',
|
|
118
|
+
" - CRITICAL: `.syntholoc/config.json` MUST be committed and tracked \u2014 it is the mapping source of",
|
|
119
|
+
" truth the server reads from the branch. NEVER add `.syntholoc` (or the config file) to `.gitignore`.",
|
|
120
|
+
" If `.gitignore` already ignores it (a common reflex, next to `.claude`), remove that line. After",
|
|
121
|
+
" committing, VERIFY it is tracked (e.g. `git ls-files .syntholoc/config.json` returns the path, or",
|
|
122
|
+
" `git check-ignore` reports nothing) \u2014 an ignored config means every sync/pull/write-back resolves",
|
|
123
|
+
" zero files and silently opens no PR.",
|
|
118
124
|
" c. Connect it with `connect_repository`. Ask the user which method they prefer:",
|
|
119
125
|
" - GitHub App (no token, recommended): `get_github_app_install_url` \u2192 give the URL to the user",
|
|
120
126
|
" to open and authorize (you cannot click it for them; you may offer to open it via the shell).",
|
|
@@ -440,8 +446,12 @@ function registerGitTools(server, gql) {
|
|
|
440
446
|
provider: z3.enum(["GITHUB", "GITLAB", "BITBUCKET"]).default("GITHUB"),
|
|
441
447
|
fullName: z3.string().describe('owner/repo, e.g. "acme/webapp".'),
|
|
442
448
|
branch: z3.string().optional().describe('Source branch (default "main").'),
|
|
443
|
-
files: z3.array(fileMapping).optional().describe(
|
|
444
|
-
|
|
449
|
+
files: z3.array(fileMapping).optional().describe(
|
|
450
|
+
"Crowdin-style source\u2192translation mappings. Fallback only \u2014 an in-repo `.syntholoc/config.json` wins."
|
|
451
|
+
),
|
|
452
|
+
paths: z3.array(z3.string()).optional().describe(
|
|
453
|
+
"Simple mode: source file paths/globs to track (use instead of `files`). Fallback for in-repo config."
|
|
454
|
+
),
|
|
445
455
|
installationId: z3.number().int().optional().describe("GitHub App installation id. Mutually exclusive with `token`."),
|
|
446
456
|
token: z3.string().optional().describe("Access token (PAT mode), stored encrypted. Mutually exclusive with `installationId`."),
|
|
447
457
|
translationBranch: z3.string().optional().describe("Branch translations are committed to (default l10n_<branch>)."),
|
|
@@ -507,7 +517,7 @@ function registerGitTools(server, gql) {
|
|
|
507
517
|
"pull_translations",
|
|
508
518
|
{
|
|
509
519
|
title: "Pull translations",
|
|
510
|
-
description: "
|
|
520
|
+
description: "Queues a pull of translation files from the connected repo, importing them per locale. Returns the tracking job ids \u2014 the import itself runs in the background. `autoApprove` lands them as APPROVED; `conflict` is OVERWRITE | SKIP_EXISTING | KEEP_APPROVED.",
|
|
511
521
|
inputSchema: {
|
|
512
522
|
projectId: z3.string(),
|
|
513
523
|
repositoryId: z3.string(),
|
|
@@ -900,6 +910,21 @@ function resolveLocaleCodes(raw) {
|
|
|
900
910
|
return out;
|
|
901
911
|
}
|
|
902
912
|
|
|
913
|
+
// ../../packages/shared/src/constants.ts
|
|
914
|
+
var ORG_PLANS = ["FREE", "PRO", "ENTERPRISE"];
|
|
915
|
+
function isPaidPlan(plan) {
|
|
916
|
+
switch (plan) {
|
|
917
|
+
case "PRO":
|
|
918
|
+
case "ENTERPRISE":
|
|
919
|
+
return true;
|
|
920
|
+
case "FREE":
|
|
921
|
+
return false;
|
|
922
|
+
default:
|
|
923
|
+
return false;
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
var PAID_PLANS = ORG_PLANS.filter(isPaidPlan);
|
|
927
|
+
|
|
903
928
|
// src/tools/locales.ts
|
|
904
929
|
function registerLocaleTools(server, gql) {
|
|
905
930
|
server.registerTool(
|
|
@@ -1081,8 +1106,27 @@ function registerProjectTools(server, gql) {
|
|
|
1081
1106
|
}
|
|
1082
1107
|
|
|
1083
1108
|
// src/tools/providers.ts
|
|
1084
|
-
import { z as
|
|
1109
|
+
import { z as z10 } from "zod";
|
|
1085
1110
|
import { CONFIGURE_LLM_PROVIDER, LIST_LLM_PROVIDERS } from "@syntholoc/sdk";
|
|
1111
|
+
|
|
1112
|
+
// src/generated/input-schemas.ts
|
|
1113
|
+
import { z as z9 } from "zod";
|
|
1114
|
+
var isDefinedNonNullAny = (v) => v !== void 0 && v !== null;
|
|
1115
|
+
var definedNonNullAnySchema = z9.any().refine((v) => isDefinedNonNullAny(v));
|
|
1116
|
+
var CoverageCategorySchema = z9.enum(["DYNAMIC", "NOT_CAPTURED", "NOT_IN_CODE", "SCREENSHOT", "SERVER", "TEST", "UNKNOWN"]);
|
|
1117
|
+
var QaCriticScopeSchema = z9.enum(["ALL", "UNREVIEWED"]);
|
|
1118
|
+
var TranslateScopeSchema = z9.enum(["ALL", "DRAFT", "UNAPPROVED", "UNTRANSLATED"]);
|
|
1119
|
+
function ConfigureProviderInputSchema() {
|
|
1120
|
+
return z9.object({
|
|
1121
|
+
apiKey: z9.string(),
|
|
1122
|
+
baseUrl: z9.string().nullish(),
|
|
1123
|
+
defaultModel: z9.string().nullish(),
|
|
1124
|
+
label: z9.string(),
|
|
1125
|
+
type: z9.string()
|
|
1126
|
+
});
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1129
|
+
// src/tools/providers.ts
|
|
1086
1130
|
function registerProviderTools(server, gql) {
|
|
1087
1131
|
server.registerTool(
|
|
1088
1132
|
"list_llm_providers",
|
|
@@ -1099,12 +1143,12 @@ function registerProviderTools(server, gql) {
|
|
|
1099
1143
|
{
|
|
1100
1144
|
title: "Configure LLM provider",
|
|
1101
1145
|
description: "Adds a BYOK LLM provider (OPENROUTER | OPENAI | ANTHROPIC). The key is stored encrypted at rest.",
|
|
1146
|
+
// Base field shapes (apiKey/label/baseUrl/defaultModel) are generated from
|
|
1147
|
+
// the GraphQL ConfigureProviderInput; we curate `type` from the API's
|
|
1148
|
+
// free-form String down to the concrete provider set.
|
|
1102
1149
|
inputSchema: {
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
apiKey: z9.string(),
|
|
1106
|
-
baseUrl: z9.string().optional(),
|
|
1107
|
-
defaultModel: z9.string().optional()
|
|
1150
|
+
...ConfigureProviderInputSchema().shape,
|
|
1151
|
+
type: z10.enum(["OPENROUTER", "OPENAI", "ANTHROPIC"])
|
|
1108
1152
|
},
|
|
1109
1153
|
annotations: { openWorldHint: true }
|
|
1110
1154
|
},
|
|
@@ -1113,15 +1157,19 @@ function registerProviderTools(server, gql) {
|
|
|
1113
1157
|
}
|
|
1114
1158
|
|
|
1115
1159
|
// src/tools/qa.ts
|
|
1116
|
-
import { z as
|
|
1160
|
+
import { z as z11 } from "zod";
|
|
1117
1161
|
import { LIST_QA_ISSUES as LIST_QA_ISSUES2, RUN_LOCALE_QA, RUN_QA } from "@syntholoc/sdk";
|
|
1118
1162
|
function registerQaTools(server, gql) {
|
|
1119
1163
|
server.registerTool(
|
|
1120
1164
|
"run_locale_qa",
|
|
1121
1165
|
{
|
|
1122
1166
|
title: "Run locale QA",
|
|
1123
|
-
description: "Queues an LLM QA-critic pass over a locale's non-approved translations. Returns tracking `jobIds`.",
|
|
1124
|
-
inputSchema: {
|
|
1167
|
+
description: "Queues an LLM QA-critic pass over a locale's non-approved translations. `scope` UNREVIEWED (default) critiques only translations not yet reviewed at their current text; ALL re-critiques every one. Returns tracking `jobIds`.",
|
|
1168
|
+
inputSchema: {
|
|
1169
|
+
projectId: z11.string(),
|
|
1170
|
+
localeId: z11.string(),
|
|
1171
|
+
scope: z11.enum(["UNREVIEWED", "ALL"]).optional()
|
|
1172
|
+
},
|
|
1125
1173
|
annotations: { openWorldHint: true }
|
|
1126
1174
|
},
|
|
1127
1175
|
async (vars) => jsonResult((await gql.request(RUN_LOCALE_QA, vars)).runLocaleQa)
|
|
@@ -1131,7 +1179,7 @@ function registerQaTools(server, gql) {
|
|
|
1131
1179
|
{
|
|
1132
1180
|
title: "Run QA on a translation",
|
|
1133
1181
|
description: "Runs QA on one translation and returns its score and issues (synchronous).",
|
|
1134
|
-
inputSchema: { projectId:
|
|
1182
|
+
inputSchema: { projectId: z11.string(), translationId: z11.string() },
|
|
1135
1183
|
annotations: { openWorldHint: true }
|
|
1136
1184
|
},
|
|
1137
1185
|
async (vars) => jsonResult((await gql.request(RUN_QA, vars)).runQa)
|
|
@@ -1142,11 +1190,11 @@ function registerQaTools(server, gql) {
|
|
|
1142
1190
|
title: "List QA issues",
|
|
1143
1191
|
description: "Open QA issues for a locale, plus the issue-type facets (filter tabs).",
|
|
1144
1192
|
inputSchema: {
|
|
1145
|
-
projectId:
|
|
1146
|
-
localeId:
|
|
1147
|
-
type:
|
|
1148
|
-
skip:
|
|
1149
|
-
take:
|
|
1193
|
+
projectId: z11.string(),
|
|
1194
|
+
localeId: z11.string(),
|
|
1195
|
+
type: z11.string().optional(),
|
|
1196
|
+
skip: z11.number().int().min(0).default(0),
|
|
1197
|
+
take: z11.number().int().min(1).max(100).default(25)
|
|
1150
1198
|
},
|
|
1151
1199
|
annotations: { readOnlyHint: true, openWorldHint: true }
|
|
1152
1200
|
},
|
|
@@ -1155,7 +1203,7 @@ function registerQaTools(server, gql) {
|
|
|
1155
1203
|
}
|
|
1156
1204
|
|
|
1157
1205
|
// src/tools/styleguides.ts
|
|
1158
|
-
import { z as
|
|
1206
|
+
import { z as z12 } from "zod";
|
|
1159
1207
|
import { CREATE_STYLE_GUIDE, GENERATE_STYLE_GUIDE, LIST_STYLE_GUIDES as LIST_STYLE_GUIDES2 } from "@syntholoc/sdk";
|
|
1160
1208
|
function registerStyleGuideTools(server, gql) {
|
|
1161
1209
|
server.registerTool(
|
|
@@ -1163,7 +1211,7 @@ function registerStyleGuideTools(server, gql) {
|
|
|
1163
1211
|
{
|
|
1164
1212
|
title: "List style guides",
|
|
1165
1213
|
description: "Lists style guides (project-scoped if projectId given, else org-wide).",
|
|
1166
|
-
inputSchema: { projectId:
|
|
1214
|
+
inputSchema: { projectId: z12.string().optional() },
|
|
1167
1215
|
annotations: { readOnlyHint: true, openWorldHint: true }
|
|
1168
1216
|
},
|
|
1169
1217
|
async ({ projectId }) => jsonResult((await gql.request(LIST_STYLE_GUIDES2, { projectId })).styleGuides)
|
|
@@ -1173,7 +1221,7 @@ function registerStyleGuideTools(server, gql) {
|
|
|
1173
1221
|
{
|
|
1174
1222
|
title: "Generate style guide (draft)",
|
|
1175
1223
|
description: "Drafts a tone/rules/prompt-fragment style guide from the project (optionally per locale). Returns a draft \u2014 persist it with create_style_guide.",
|
|
1176
|
-
inputSchema: { projectId:
|
|
1224
|
+
inputSchema: { projectId: z12.string(), localeCode: z12.string().optional() },
|
|
1177
1225
|
annotations: { openWorldHint: true }
|
|
1178
1226
|
},
|
|
1179
1227
|
async ({ projectId, localeCode }) => jsonResult((await gql.request(GENERATE_STYLE_GUIDE, { input: { projectId, localeCode } })).generateStyleGuide)
|
|
@@ -1184,12 +1232,12 @@ function registerStyleGuideTools(server, gql) {
|
|
|
1184
1232
|
title: "Create style guide",
|
|
1185
1233
|
description: "Persists a style guide (tone, rules JSON, prompt fragment), project- or locale-scoped.",
|
|
1186
1234
|
inputSchema: {
|
|
1187
|
-
name:
|
|
1188
|
-
projectId:
|
|
1189
|
-
localeCode:
|
|
1190
|
-
tone:
|
|
1191
|
-
promptFragment:
|
|
1192
|
-
rules:
|
|
1235
|
+
name: z12.string(),
|
|
1236
|
+
projectId: z12.string().optional(),
|
|
1237
|
+
localeCode: z12.string().optional(),
|
|
1238
|
+
tone: z12.string().optional(),
|
|
1239
|
+
promptFragment: z12.string().optional(),
|
|
1240
|
+
rules: z12.array(z12.string()).optional()
|
|
1193
1241
|
},
|
|
1194
1242
|
annotations: { openWorldHint: true }
|
|
1195
1243
|
},
|
|
@@ -1198,7 +1246,7 @@ function registerStyleGuideTools(server, gql) {
|
|
|
1198
1246
|
}
|
|
1199
1247
|
|
|
1200
1248
|
// src/tools/tm.ts
|
|
1201
|
-
import { z as
|
|
1249
|
+
import { z as z13 } from "zod";
|
|
1202
1250
|
import { TM_ENTRIES, TM_SEARCH, TM_STATS as TM_STATS2 } from "@syntholoc/sdk";
|
|
1203
1251
|
function registerTmTools(server, gql) {
|
|
1204
1252
|
server.registerTool(
|
|
@@ -1207,10 +1255,10 @@ function registerTmTools(server, gql) {
|
|
|
1207
1255
|
title: "Search translation memory",
|
|
1208
1256
|
description: "Concordance search \u2014 the nearest prior translations for a source string in a target locale, with cosine distance (0 = identical). Scope to a project with `projectId` (includes its group siblings); omit for the whole organization. Requires an embedding-capable provider.",
|
|
1209
1257
|
inputSchema: {
|
|
1210
|
-
sourceText:
|
|
1211
|
-
targetLocale:
|
|
1212
|
-
projectId:
|
|
1213
|
-
limit:
|
|
1258
|
+
sourceText: z13.string(),
|
|
1259
|
+
targetLocale: z13.string(),
|
|
1260
|
+
projectId: z13.string().optional(),
|
|
1261
|
+
limit: z13.number().int().min(1).max(20).default(5)
|
|
1214
1262
|
},
|
|
1215
1263
|
annotations: { readOnlyHint: true, openWorldHint: true }
|
|
1216
1264
|
},
|
|
@@ -1221,7 +1269,7 @@ function registerTmTools(server, gql) {
|
|
|
1221
1269
|
{
|
|
1222
1270
|
title: "Translation memory stats",
|
|
1223
1271
|
description: "Entry counts per target locale (org-wide, or for a project with `projectId`).",
|
|
1224
|
-
inputSchema: { projectId:
|
|
1272
|
+
inputSchema: { projectId: z13.string().optional() },
|
|
1225
1273
|
annotations: { readOnlyHint: true, openWorldHint: true }
|
|
1226
1274
|
},
|
|
1227
1275
|
async ({ projectId }) => jsonResult((await gql.request(TM_STATS2, { projectId })).tmStats)
|
|
@@ -1232,10 +1280,10 @@ function registerTmTools(server, gql) {
|
|
|
1232
1280
|
title: "Browse translation memory",
|
|
1233
1281
|
description: "Lists stored TM entries (paginated, newest first), optionally filtered by project and locale.",
|
|
1234
1282
|
inputSchema: {
|
|
1235
|
-
projectId:
|
|
1236
|
-
targetLocale:
|
|
1237
|
-
skip:
|
|
1238
|
-
take:
|
|
1283
|
+
projectId: z13.string().optional(),
|
|
1284
|
+
targetLocale: z13.string().optional(),
|
|
1285
|
+
skip: z13.number().int().min(0).default(0),
|
|
1286
|
+
take: z13.number().int().min(1).max(100).default(25)
|
|
1239
1287
|
},
|
|
1240
1288
|
annotations: { readOnlyHint: true, openWorldHint: true }
|
|
1241
1289
|
},
|
|
@@ -1244,7 +1292,7 @@ function registerTmTools(server, gql) {
|
|
|
1244
1292
|
}
|
|
1245
1293
|
|
|
1246
1294
|
// src/tools/translations.ts
|
|
1247
|
-
import { z as
|
|
1295
|
+
import { z as z14 } from "zod";
|
|
1248
1296
|
import {
|
|
1249
1297
|
APPROVE_TRANSLATION,
|
|
1250
1298
|
EXPORT_LOCALE,
|
|
@@ -1263,9 +1311,9 @@ function registerTranslationTools(server, gql) {
|
|
|
1263
1311
|
title: "Translate locale",
|
|
1264
1312
|
description: "Queues AI translation of a locale (scope ALL | UNAPPROVED | UNTRANSLATED) and returns the tracking `jobIds`. Executes immediately and unconditionally \u2014 the batch threshold is a client-side policy for PROACTIVE syncs, not for this tool.",
|
|
1265
1313
|
inputSchema: {
|
|
1266
|
-
projectId:
|
|
1267
|
-
localeId:
|
|
1268
|
-
scope:
|
|
1314
|
+
projectId: z14.string(),
|
|
1315
|
+
localeId: z14.string(),
|
|
1316
|
+
scope: z14.enum(["ALL", "UNAPPROVED", "UNTRANSLATED"]).default("UNTRANSLATED")
|
|
1269
1317
|
},
|
|
1270
1318
|
annotations: { openWorldHint: true }
|
|
1271
1319
|
},
|
|
@@ -1276,7 +1324,7 @@ function registerTranslationTools(server, gql) {
|
|
|
1276
1324
|
{
|
|
1277
1325
|
title: "Translate key",
|
|
1278
1326
|
description: "Queues AI translation of a single key into a locale. Returns tracking `jobIds`.",
|
|
1279
|
-
inputSchema: { projectId:
|
|
1327
|
+
inputSchema: { projectId: z14.string(), keyId: z14.string(), localeId: z14.string() },
|
|
1280
1328
|
annotations: { openWorldHint: true }
|
|
1281
1329
|
},
|
|
1282
1330
|
async (vars) => jsonResult((await gql.request(TRANSLATE_KEY, vars)).translateKey)
|
|
@@ -1287,11 +1335,11 @@ function registerTranslationTools(server, gql) {
|
|
|
1287
1335
|
title: "Set translation",
|
|
1288
1336
|
description: "Manually sets the translation text for a key in a locale.",
|
|
1289
1337
|
inputSchema: {
|
|
1290
|
-
projectId:
|
|
1291
|
-
keyId:
|
|
1292
|
-
localeId:
|
|
1293
|
-
text:
|
|
1294
|
-
origin:
|
|
1338
|
+
projectId: z14.string(),
|
|
1339
|
+
keyId: z14.string(),
|
|
1340
|
+
localeId: z14.string(),
|
|
1341
|
+
text: z14.string(),
|
|
1342
|
+
origin: z14.string().optional()
|
|
1295
1343
|
},
|
|
1296
1344
|
annotations: { idempotentHint: true, openWorldHint: true }
|
|
1297
1345
|
},
|
|
@@ -1305,10 +1353,10 @@ function registerTranslationTools(server, gql) {
|
|
|
1305
1353
|
title: "List translations",
|
|
1306
1354
|
description: "Lists translations for a locale with status, origin, model and QA score.",
|
|
1307
1355
|
inputSchema: {
|
|
1308
|
-
projectId:
|
|
1309
|
-
localeId:
|
|
1310
|
-
skip:
|
|
1311
|
-
take:
|
|
1356
|
+
projectId: z14.string(),
|
|
1357
|
+
localeId: z14.string(),
|
|
1358
|
+
skip: z14.number().int().min(0).default(0),
|
|
1359
|
+
take: z14.number().int().min(1).max(200).default(25)
|
|
1312
1360
|
},
|
|
1313
1361
|
annotations: { readOnlyHint: true, openWorldHint: true }
|
|
1314
1362
|
},
|
|
@@ -1319,7 +1367,7 @@ function registerTranslationTools(server, gql) {
|
|
|
1319
1367
|
{
|
|
1320
1368
|
title: "Approve translation",
|
|
1321
1369
|
description: "Marks a translation APPROVED.",
|
|
1322
|
-
inputSchema: { projectId:
|
|
1370
|
+
inputSchema: { projectId: z14.string(), translationId: z14.string() },
|
|
1323
1371
|
annotations: { idempotentHint: true, openWorldHint: true }
|
|
1324
1372
|
},
|
|
1325
1373
|
async ({ projectId, translationId }) => jsonResult((await gql.request(APPROVE_TRANSLATION, { projectId, id: translationId })).approveTranslation)
|
|
@@ -1329,7 +1377,7 @@ function registerTranslationTools(server, gql) {
|
|
|
1329
1377
|
{
|
|
1330
1378
|
title: "Reject translation",
|
|
1331
1379
|
description: "Marks a translation REJECTED (queued for re-translation).",
|
|
1332
|
-
inputSchema: { projectId:
|
|
1380
|
+
inputSchema: { projectId: z14.string(), translationId: z14.string() },
|
|
1333
1381
|
annotations: { idempotentHint: true, openWorldHint: true }
|
|
1334
1382
|
},
|
|
1335
1383
|
async ({ projectId, translationId }) => jsonResult((await gql.request(REJECT_TRANSLATION, { projectId, id: translationId })).rejectTranslation)
|
|
@@ -1340,12 +1388,12 @@ function registerTranslationTools(server, gql) {
|
|
|
1340
1388
|
title: "Export locale",
|
|
1341
1389
|
description: 'Exports a locale to a file string in the chosen format \u2014 the basis for writing translations back into local files. Set `onlyApproved` to exclude drafts. For a multi-file project prefer `sourceFile` (the real path, e.g. "messages/en/home.json") to export exactly that file with file-local key names \u2014 reliable. `keyPrefix` is the legacy name-prefix heuristic.',
|
|
1342
1390
|
inputSchema: {
|
|
1343
|
-
projectId:
|
|
1344
|
-
localeId:
|
|
1345
|
-
format:
|
|
1346
|
-
onlyApproved:
|
|
1347
|
-
sourceFile:
|
|
1348
|
-
keyPrefix:
|
|
1391
|
+
projectId: z14.string(),
|
|
1392
|
+
localeId: z14.string(),
|
|
1393
|
+
format: z14.enum(FORMATS2).default("JSON"),
|
|
1394
|
+
onlyApproved: z14.boolean().optional(),
|
|
1395
|
+
sourceFile: z14.string().optional().describe('Real source file path to export, e.g. "messages/en/home.json" (reliable, preferred).'),
|
|
1396
|
+
keyPrefix: z14.string().optional().describe('Legacy namespace prefix, e.g. "home".')
|
|
1349
1397
|
},
|
|
1350
1398
|
annotations: { readOnlyHint: true, openWorldHint: true }
|
|
1351
1399
|
},
|
|
@@ -1357,14 +1405,14 @@ function registerTranslationTools(server, gql) {
|
|
|
1357
1405
|
title: "Import translations",
|
|
1358
1406
|
description: "Imports ready-made translations for a locale (paste file content). `autoApprove` lands them as APPROVED; `conflict` is OVERWRITE | SKIP_EXISTING | KEEP_APPROVED; `dryRun` previews. For a multi-file / namespaced project pass `keyPrefix` (the namespace) to match prefixed source keys.",
|
|
1359
1407
|
inputSchema: {
|
|
1360
|
-
projectId:
|
|
1361
|
-
localeId:
|
|
1362
|
-
content:
|
|
1363
|
-
format:
|
|
1364
|
-
keyPrefix:
|
|
1365
|
-
autoApprove:
|
|
1366
|
-
conflict:
|
|
1367
|
-
dryRun:
|
|
1408
|
+
projectId: z14.string(),
|
|
1409
|
+
localeId: z14.string(),
|
|
1410
|
+
content: z14.string(),
|
|
1411
|
+
format: z14.enum(FORMATS2),
|
|
1412
|
+
keyPrefix: z14.string().optional().describe('Namespace prefix, e.g. "home" (per-file, multi-file projects).'),
|
|
1413
|
+
autoApprove: z14.boolean().default(false),
|
|
1414
|
+
conflict: z14.enum(["OVERWRITE", "SKIP_EXISTING", "KEEP_APPROVED"]).default("OVERWRITE"),
|
|
1415
|
+
dryRun: z14.boolean().default(false)
|
|
1368
1416
|
},
|
|
1369
1417
|
annotations: { idempotentHint: true, openWorldHint: true }
|
|
1370
1418
|
},
|
|
@@ -1407,7 +1455,7 @@ function registerAllTools(server, gql, opts = {}) {
|
|
|
1407
1455
|
}
|
|
1408
1456
|
|
|
1409
1457
|
// package.json
|
|
1410
|
-
var version = "0.
|
|
1458
|
+
var version = "0.4.0";
|
|
1411
1459
|
|
|
1412
1460
|
// src/build-server.ts
|
|
1413
1461
|
function buildMcpServer(gql, opts = {}) {
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@syntholoc/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Syntholoc MCP server — manage AI localization and translation from Codex, Claude Code, and other MCP clients.",
|
|
5
5
|
"homepage": "https://syntholoc.com",
|
|
6
6
|
"keywords": [
|
|
@@ -47,14 +47,17 @@
|
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
49
|
"@modelcontextprotocol/sdk": "1.22.0",
|
|
50
|
-
"@syntholoc/sdk": "0.3.
|
|
50
|
+
"@syntholoc/sdk": "0.3.1",
|
|
51
51
|
"zod": "3.25.76"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
|
+
"@graphql-codegen/cli": "7.1.2",
|
|
55
|
+
"@graphql-codegen/typescript": "5.0.2",
|
|
54
56
|
"@syntholoc/shared": "0.1.0",
|
|
55
57
|
"@types/bun": "1.3.14",
|
|
56
58
|
"@types/node": "22.19.21",
|
|
57
59
|
"graphql": "16.14.2",
|
|
60
|
+
"graphql-codegen-typescript-validation-schema": "0.19.0",
|
|
58
61
|
"tsup": "8.5.1",
|
|
59
62
|
"typescript": "6.0.3"
|
|
60
63
|
}
|