@syntholoc/mcp 0.1.0 → 0.1.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.
@@ -1,6 +1,35 @@
1
1
  // src/build-server.ts
2
2
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
3
 
4
+ // src/filter.ts
5
+ function wildcardToRegExp(pattern) {
6
+ const escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*");
7
+ return new RegExp(`^${escaped}$`);
8
+ }
9
+ function matchesAnyPattern(name, patterns) {
10
+ return patterns.some((re) => re.test(name));
11
+ }
12
+ function applyToolFilter(server, opts) {
13
+ const patterns = (opts.toolFilter ?? []).filter(Boolean).map(wildcardToRegExp);
14
+ if (!opts.readOnly && patterns.length === 0) return server;
15
+ const original = server.registerTool.bind(server);
16
+ const filtered = (name, config, handler) => {
17
+ const readOnly = config.annotations?.readOnlyHint;
18
+ if (opts.readOnly && !readOnly) return void 0;
19
+ if (patterns.length > 0 && !matchesAnyPattern(name, patterns)) {
20
+ return void 0;
21
+ }
22
+ return original(name, config, handler);
23
+ };
24
+ server.registerTool = filtered;
25
+ return server;
26
+ }
27
+ function parseList(value) {
28
+ if (!value) return void 0;
29
+ const items = value.split(",").map((s) => s.trim()).filter(Boolean);
30
+ return items.length > 0 ? items : void 0;
31
+ }
32
+
4
33
  // src/prompts.ts
5
34
  import { z } from "zod";
6
35
  function userMessage(text) {
@@ -67,7 +96,20 @@ function registerPrompts(server) {
67
96
 
68
97
  // src/resources.ts
69
98
  import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
70
- import { CONFIG_RESOURCE, PROJECTS_RESOURCE, PROJECT_RESOURCE } from "@syntholoc/sdk";
99
+ import {
100
+ CONFIG_RESOURCE,
101
+ LIST_GLOSSARY,
102
+ LIST_JOBS,
103
+ LIST_KEYS,
104
+ LIST_LOCALES,
105
+ LIST_QA_ISSUES,
106
+ LIST_STYLE_GUIDES,
107
+ MY_ORGANIZATIONS,
108
+ PROJECT_ANALYTICS,
109
+ TM_STATS,
110
+ PROJECT_RESOURCE,
111
+ PROJECTS_RESOURCE
112
+ } from "@syntholoc/sdk";
71
113
  function json(uri, data) {
72
114
  return { contents: [{ uri: uri.href, mimeType: "application/json", text: JSON.stringify(data, null, 2) }] };
73
115
  }
@@ -82,6 +124,16 @@ function registerResources(server, gql) {
82
124
  },
83
125
  async (uri) => json(uri, (await gql.request(CONFIG_RESOURCE)).appInfo)
84
126
  );
127
+ server.registerResource(
128
+ "organizations",
129
+ "syntholoc://organizations",
130
+ {
131
+ title: "Organizations",
132
+ description: "Organizations you belong to (id, name, slug, your role). Pin one for a request with the `syntholoc-org-id` header; otherwise the earliest org is used.",
133
+ mimeType: "application/json"
134
+ },
135
+ async (uri) => json(uri, (await gql.request(MY_ORGANIZATIONS)).myProjects.map((g) => ({ ...g.organization, viewerRole: g.viewerRole })))
136
+ );
85
137
  server.registerResource(
86
138
  "projects",
87
139
  "syntholoc://projects",
@@ -102,11 +154,99 @@ function registerResources(server, gql) {
102
154
  },
103
155
  async (uri, { projectId }) => json(uri, await gql.request(PROJECT_RESOURCE, { id: String(projectId) }))
104
156
  );
157
+ server.registerResource(
158
+ "project-keys",
159
+ new ResourceTemplate("syntholoc://project/{projectId}/keys", { list: void 0 }),
160
+ {
161
+ title: "Project source keys",
162
+ description: "Source keys in a project (first 100).",
163
+ mimeType: "application/json"
164
+ },
165
+ async (uri, { projectId }) => json(uri, (await gql.request(LIST_KEYS, { projectId: String(projectId), skip: 0, take: 100 })).keys)
166
+ );
167
+ server.registerResource(
168
+ "project-locales",
169
+ new ResourceTemplate("syntholoc://project/{projectId}/locales", { list: void 0 }),
170
+ {
171
+ title: "Project locales",
172
+ description: "Target locales configured for a project.",
173
+ mimeType: "application/json"
174
+ },
175
+ async (uri, { projectId }) => json(uri, (await gql.request(LIST_LOCALES, { projectId: String(projectId) })).locales)
176
+ );
177
+ server.registerResource(
178
+ "project-progress",
179
+ new ResourceTemplate("syntholoc://project/{projectId}/progress", { list: void 0 }),
180
+ {
181
+ title: "Project progress",
182
+ description: "Per-locale translation progress and open QA issues for a project.",
183
+ mimeType: "application/json"
184
+ },
185
+ async (uri, { projectId }) => json(uri, (await gql.request(PROJECT_ANALYTICS, { projectId: String(projectId) })).projectAnalytics)
186
+ );
187
+ server.registerResource(
188
+ "project-jobs",
189
+ new ResourceTemplate("syntholoc://project/{projectId}/jobs", { list: void 0 }),
190
+ {
191
+ title: "Project jobs",
192
+ description: "Recent background jobs (translate / QA / git sync) for a project.",
193
+ mimeType: "application/json"
194
+ },
195
+ async (uri, { projectId }) => json(uri, (await gql.request(LIST_JOBS, { projectId: String(projectId), skip: 0, take: 25 })).jobs)
196
+ );
197
+ server.registerResource(
198
+ "project-qa-issues",
199
+ new ResourceTemplate("syntholoc://project/{projectId}/locale/{localeId}/qa-issues", { list: void 0 }),
200
+ {
201
+ title: "Locale QA issues",
202
+ description: "Open QA issues for a locale, with issue-type facets.",
203
+ mimeType: "application/json"
204
+ },
205
+ async (uri, { projectId, localeId }) => json(
206
+ uri,
207
+ await gql.request(LIST_QA_ISSUES, {
208
+ projectId: String(projectId),
209
+ localeId: String(localeId),
210
+ skip: 0,
211
+ take: 25
212
+ })
213
+ )
214
+ );
215
+ server.registerResource(
216
+ "glossary",
217
+ "syntholoc://glossary",
218
+ {
219
+ title: "Glossary",
220
+ description: "Organization-wide glossary terms (first 100).",
221
+ mimeType: "application/json"
222
+ },
223
+ async (uri) => json(uri, (await gql.request(LIST_GLOSSARY, { skip: 0, take: 100 })).glossaryTerms)
224
+ );
225
+ server.registerResource(
226
+ "style-guides",
227
+ "syntholoc://style-guides",
228
+ {
229
+ title: "Style guides",
230
+ description: "Organization-wide style guides.",
231
+ mimeType: "application/json"
232
+ },
233
+ async (uri) => json(uri, (await gql.request(LIST_STYLE_GUIDES, {})).styleGuides)
234
+ );
235
+ server.registerResource(
236
+ "tm",
237
+ "syntholoc://tm",
238
+ {
239
+ title: "Translation memory",
240
+ description: "Organization-wide Translation Memory coverage: entry counts per target locale.",
241
+ mimeType: "application/json"
242
+ },
243
+ async (uri) => json(uri, (await gql.request(TM_STATS, {})).tmStats)
244
+ );
105
245
  }
106
246
 
107
247
  // src/tools/analytics.ts
108
248
  import { z as z2 } from "zod";
109
- import { COST_ANALYTICS, LOCALE_PROGRESS, PROJECT_ANALYTICS, USAGE } from "@syntholoc/sdk";
249
+ import { COST_ANALYTICS, LOCALE_PROGRESS, PROJECT_ANALYTICS as PROJECT_ANALYTICS2, USAGE } from "@syntholoc/sdk";
110
250
 
111
251
  // src/util.ts
112
252
  function jsonResult(data) {
@@ -123,7 +263,7 @@ function registerAnalyticsTools(server, gql) {
123
263
  inputSchema: { projectId: z2.string() },
124
264
  annotations: { readOnlyHint: true, openWorldHint: true }
125
265
  },
126
- async ({ projectId }) => jsonResult((await gql.request(PROJECT_ANALYTICS, { projectId })).projectAnalytics)
266
+ async ({ projectId }) => jsonResult((await gql.request(PROJECT_ANALYTICS2, { projectId })).projectAnalytics)
127
267
  );
128
268
  server.registerTool(
129
269
  "cost_analytics",
@@ -238,7 +378,7 @@ import { z as z4 } from "zod";
238
378
  import {
239
379
  CREATE_GLOSSARY_TERM,
240
380
  DELETE_GLOSSARY_TERM,
241
- LIST_GLOSSARY,
381
+ LIST_GLOSSARY as LIST_GLOSSARY2,
242
382
  SUGGEST_GLOSSARY_TERMS,
243
383
  UPDATE_GLOSSARY_TERM
244
384
  } from "@syntholoc/sdk";
@@ -255,7 +395,7 @@ function registerGlossaryTools(server, gql) {
255
395
  },
256
396
  annotations: { readOnlyHint: true, openWorldHint: true }
257
397
  },
258
- async (vars) => jsonResult((await gql.request(LIST_GLOSSARY, vars)).glossaryTerms)
398
+ async (vars) => jsonResult((await gql.request(LIST_GLOSSARY2, vars)).glossaryTerms)
259
399
  );
260
400
  server.registerTool(
261
401
  "upsert_glossary_term",
@@ -310,7 +450,7 @@ function registerGlossaryTools(server, gql) {
310
450
 
311
451
  // src/tools/jobs.ts
312
452
  import { z as z5 } from "zod";
313
- import { GET_JOB, LIST_JOBS, waitForJob } from "@syntholoc/sdk";
453
+ import { GET_JOB, LIST_JOBS as LIST_JOBS2, waitForJob } from "@syntholoc/sdk";
314
454
  function registerJobTools(server, gql) {
315
455
  server.registerTool(
316
456
  "get_job",
@@ -334,7 +474,7 @@ function registerJobTools(server, gql) {
334
474
  },
335
475
  annotations: { readOnlyHint: true, openWorldHint: true }
336
476
  },
337
- async (vars) => jsonResult((await gql.request(LIST_JOBS, vars)).jobs)
477
+ async (vars) => jsonResult((await gql.request(LIST_JOBS2, vars)).jobs)
338
478
  );
339
479
  server.registerTool(
340
480
  "wait_for_job",
@@ -361,7 +501,7 @@ import { z as z6 } from "zod";
361
501
  import {
362
502
  DELETE_KEY,
363
503
  IMPORT_SOURCE_STRINGS,
364
- LIST_KEYS,
504
+ LIST_KEYS as LIST_KEYS2,
365
505
  UPDATE_KEY,
366
506
  UPSERT_KEYS
367
507
  } from "@syntholoc/sdk";
@@ -382,7 +522,7 @@ function registerKeyTools(server, gql) {
382
522
  },
383
523
  annotations: { readOnlyHint: true, openWorldHint: true }
384
524
  },
385
- async (vars) => jsonResult((await gql.request(LIST_KEYS, vars)).keys)
525
+ async (vars) => jsonResult((await gql.request(LIST_KEYS2, vars)).keys)
386
526
  );
387
527
  server.registerTool(
388
528
  "upsert_keys",
@@ -452,7 +592,7 @@ function registerKeyTools(server, gql) {
452
592
 
453
593
  // src/tools/locales.ts
454
594
  import { z as z7 } from "zod";
455
- import { ADD_LOCALE, LIST_LOCALES, REMOVE_LOCALE, SEED_STARTER_LOCALES } from "@syntholoc/sdk";
595
+ import { ADD_LOCALE, LIST_LOCALES as LIST_LOCALES2, REMOVE_LOCALE, SEED_STARTER_LOCALES } from "@syntholoc/sdk";
456
596
  function registerLocaleTools(server, gql) {
457
597
  server.registerTool(
458
598
  "list_locales",
@@ -462,7 +602,7 @@ function registerLocaleTools(server, gql) {
462
602
  inputSchema: { projectId: z7.string() },
463
603
  annotations: { readOnlyHint: true, openWorldHint: true }
464
604
  },
465
- async ({ projectId }) => jsonResult((await gql.request(LIST_LOCALES, { projectId })).locales)
605
+ async ({ projectId }) => jsonResult((await gql.request(LIST_LOCALES2, { projectId })).locales)
466
606
  );
467
607
  server.registerTool(
468
608
  "add_locale",
@@ -505,8 +645,29 @@ function registerLocaleTools(server, gql) {
505
645
 
506
646
  // src/tools/projects.ts
507
647
  import { z as z8 } from "zod";
508
- import { CREATE_PROJECT, GET_PROJECT, LIST_PROJECTS, UPDATE_PROJECT } from "@syntholoc/sdk";
648
+ import {
649
+ CREATE_PROJECT,
650
+ GET_PROJECT,
651
+ LIST_PROJECTS,
652
+ MY_ORGANIZATIONS as MY_ORGANIZATIONS2,
653
+ UPDATE_PROJECT
654
+ } from "@syntholoc/sdk";
509
655
  function registerProjectTools(server, gql) {
656
+ server.registerTool(
657
+ "list_organizations",
658
+ {
659
+ title: "List organizations",
660
+ description: "Organizations you belong to (id, name, slug, your role). To act in a specific org, set the `syntholoc-org-id` request header (hosted transport); otherwise the earliest org is used.",
661
+ inputSchema: {},
662
+ annotations: { readOnlyHint: true, openWorldHint: true }
663
+ },
664
+ async () => jsonResult(
665
+ (await gql.request(MY_ORGANIZATIONS2)).myProjects.map((g) => ({
666
+ ...g.organization,
667
+ viewerRole: g.viewerRole
668
+ }))
669
+ )
670
+ );
510
671
  server.registerTool(
511
672
  "list_projects",
512
673
  {
@@ -604,7 +765,7 @@ function registerProviderTools(server, gql) {
604
765
 
605
766
  // src/tools/qa.ts
606
767
  import { z as z10 } from "zod";
607
- import { LIST_QA_ISSUES, RUN_LOCALE_QA, RUN_QA } from "@syntholoc/sdk";
768
+ import { LIST_QA_ISSUES as LIST_QA_ISSUES2, RUN_LOCALE_QA, RUN_QA } from "@syntholoc/sdk";
608
769
  function registerQaTools(server, gql) {
609
770
  server.registerTool(
610
771
  "run_locale_qa",
@@ -640,13 +801,13 @@ function registerQaTools(server, gql) {
640
801
  },
641
802
  annotations: { readOnlyHint: true, openWorldHint: true }
642
803
  },
643
- async (vars) => jsonResult(await gql.request(LIST_QA_ISSUES, vars))
804
+ async (vars) => jsonResult(await gql.request(LIST_QA_ISSUES2, vars))
644
805
  );
645
806
  }
646
807
 
647
808
  // src/tools/styleguides.ts
648
809
  import { z as z11 } from "zod";
649
- import { CREATE_STYLE_GUIDE, GENERATE_STYLE_GUIDE, LIST_STYLE_GUIDES } from "@syntholoc/sdk";
810
+ import { CREATE_STYLE_GUIDE, GENERATE_STYLE_GUIDE, LIST_STYLE_GUIDES as LIST_STYLE_GUIDES2 } from "@syntholoc/sdk";
650
811
  function registerStyleGuideTools(server, gql) {
651
812
  server.registerTool(
652
813
  "list_style_guides",
@@ -656,7 +817,7 @@ function registerStyleGuideTools(server, gql) {
656
817
  inputSchema: { projectId: z11.string().optional() },
657
818
  annotations: { readOnlyHint: true, openWorldHint: true }
658
819
  },
659
- async ({ projectId }) => jsonResult((await gql.request(LIST_STYLE_GUIDES, { projectId })).styleGuides)
820
+ async ({ projectId }) => jsonResult((await gql.request(LIST_STYLE_GUIDES2, { projectId })).styleGuides)
660
821
  );
661
822
  server.registerTool(
662
823
  "generate_style_guide",
@@ -687,8 +848,54 @@ function registerStyleGuideTools(server, gql) {
687
848
  );
688
849
  }
689
850
 
690
- // src/tools/translations.ts
851
+ // src/tools/tm.ts
691
852
  import { z as z12 } from "zod";
853
+ import { TM_ENTRIES, TM_SEARCH, TM_STATS as TM_STATS2 } from "@syntholoc/sdk";
854
+ function registerTmTools(server, gql) {
855
+ server.registerTool(
856
+ "tm_search",
857
+ {
858
+ title: "Search translation memory",
859
+ 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.",
860
+ inputSchema: {
861
+ sourceText: z12.string(),
862
+ targetLocale: z12.string(),
863
+ projectId: z12.string().optional(),
864
+ limit: z12.number().int().min(1).max(20).default(5)
865
+ },
866
+ annotations: { readOnlyHint: true, openWorldHint: true }
867
+ },
868
+ async ({ sourceText, targetLocale, projectId, limit }) => jsonResult((await gql.request(TM_SEARCH, { sourceText, targetLocale, projectId, limit })).tmSearch)
869
+ );
870
+ server.registerTool(
871
+ "tm_stats",
872
+ {
873
+ title: "Translation memory stats",
874
+ description: "Entry counts per target locale (org-wide, or for a project with `projectId`).",
875
+ inputSchema: { projectId: z12.string().optional() },
876
+ annotations: { readOnlyHint: true, openWorldHint: true }
877
+ },
878
+ async ({ projectId }) => jsonResult((await gql.request(TM_STATS2, { projectId })).tmStats)
879
+ );
880
+ server.registerTool(
881
+ "list_tm",
882
+ {
883
+ title: "Browse translation memory",
884
+ description: "Lists stored TM entries (paginated, newest first), optionally filtered by project and locale.",
885
+ inputSchema: {
886
+ projectId: z12.string().optional(),
887
+ targetLocale: z12.string().optional(),
888
+ skip: z12.number().int().min(0).default(0),
889
+ take: z12.number().int().min(1).max(100).default(25)
890
+ },
891
+ annotations: { readOnlyHint: true, openWorldHint: true }
892
+ },
893
+ async (vars) => jsonResult((await gql.request(TM_ENTRIES, vars)).tmEntries)
894
+ );
895
+ }
896
+
897
+ // src/tools/translations.ts
898
+ import { z as z13 } from "zod";
692
899
  import {
693
900
  APPROVE_TRANSLATION,
694
901
  EXPORT_LOCALE,
@@ -707,9 +914,9 @@ function registerTranslationTools(server, gql) {
707
914
  title: "Translate locale",
708
915
  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.",
709
916
  inputSchema: {
710
- projectId: z12.string(),
711
- localeId: z12.string(),
712
- scope: z12.enum(["ALL", "UNAPPROVED", "UNTRANSLATED"]).default("UNTRANSLATED")
917
+ projectId: z13.string(),
918
+ localeId: z13.string(),
919
+ scope: z13.enum(["ALL", "UNAPPROVED", "UNTRANSLATED"]).default("UNTRANSLATED")
713
920
  },
714
921
  annotations: { openWorldHint: true }
715
922
  },
@@ -720,7 +927,7 @@ function registerTranslationTools(server, gql) {
720
927
  {
721
928
  title: "Translate key",
722
929
  description: "Queues AI translation of a single key into a locale. Returns tracking `jobIds`.",
723
- inputSchema: { projectId: z12.string(), keyId: z12.string(), localeId: z12.string() },
930
+ inputSchema: { projectId: z13.string(), keyId: z13.string(), localeId: z13.string() },
724
931
  annotations: { openWorldHint: true }
725
932
  },
726
933
  async (vars) => jsonResult((await gql.request(TRANSLATE_KEY, vars)).translateKey)
@@ -731,11 +938,11 @@ function registerTranslationTools(server, gql) {
731
938
  title: "Set translation",
732
939
  description: "Manually sets the translation text for a key in a locale.",
733
940
  inputSchema: {
734
- projectId: z12.string(),
735
- keyId: z12.string(),
736
- localeId: z12.string(),
737
- text: z12.string(),
738
- origin: z12.string().optional()
941
+ projectId: z13.string(),
942
+ keyId: z13.string(),
943
+ localeId: z13.string(),
944
+ text: z13.string(),
945
+ origin: z13.string().optional()
739
946
  },
740
947
  annotations: { idempotentHint: true, openWorldHint: true }
741
948
  },
@@ -749,10 +956,10 @@ function registerTranslationTools(server, gql) {
749
956
  title: "List translations",
750
957
  description: "Lists translations for a locale with status, origin, model and QA score.",
751
958
  inputSchema: {
752
- projectId: z12.string(),
753
- localeId: z12.string(),
754
- skip: z12.number().int().min(0).default(0),
755
- take: z12.number().int().min(1).max(200).default(25)
959
+ projectId: z13.string(),
960
+ localeId: z13.string(),
961
+ skip: z13.number().int().min(0).default(0),
962
+ take: z13.number().int().min(1).max(200).default(25)
756
963
  },
757
964
  annotations: { readOnlyHint: true, openWorldHint: true }
758
965
  },
@@ -763,7 +970,7 @@ function registerTranslationTools(server, gql) {
763
970
  {
764
971
  title: "Approve translation",
765
972
  description: "Marks a translation APPROVED.",
766
- inputSchema: { projectId: z12.string(), translationId: z12.string() },
973
+ inputSchema: { projectId: z13.string(), translationId: z13.string() },
767
974
  annotations: { idempotentHint: true, openWorldHint: true }
768
975
  },
769
976
  async ({ projectId, translationId }) => jsonResult((await gql.request(APPROVE_TRANSLATION, { projectId, id: translationId })).approveTranslation)
@@ -773,7 +980,7 @@ function registerTranslationTools(server, gql) {
773
980
  {
774
981
  title: "Reject translation",
775
982
  description: "Marks a translation REJECTED (queued for re-translation).",
776
- inputSchema: { projectId: z12.string(), translationId: z12.string() },
983
+ inputSchema: { projectId: z13.string(), translationId: z13.string() },
777
984
  annotations: { idempotentHint: true, openWorldHint: true }
778
985
  },
779
986
  async ({ projectId, translationId }) => jsonResult((await gql.request(REJECT_TRANSLATION, { projectId, id: translationId })).rejectTranslation)
@@ -784,10 +991,10 @@ function registerTranslationTools(server, gql) {
784
991
  title: "Export locale",
785
992
  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.",
786
993
  inputSchema: {
787
- projectId: z12.string(),
788
- localeId: z12.string(),
789
- format: z12.enum(FORMATS2).default("JSON"),
790
- onlyApproved: z12.boolean().optional()
994
+ projectId: z13.string(),
995
+ localeId: z13.string(),
996
+ format: z13.enum(FORMATS2).default("JSON"),
997
+ onlyApproved: z13.boolean().optional()
791
998
  },
792
999
  annotations: { readOnlyHint: true, openWorldHint: true }
793
1000
  },
@@ -799,13 +1006,13 @@ function registerTranslationTools(server, gql) {
799
1006
  title: "Import translations",
800
1007
  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.",
801
1008
  inputSchema: {
802
- projectId: z12.string(),
803
- localeId: z12.string(),
804
- content: z12.string(),
805
- format: z12.enum(FORMATS2),
806
- autoApprove: z12.boolean().default(false),
807
- conflict: z12.enum(["OVERWRITE", "SKIP_EXISTING", "KEEP_APPROVED"]).default("OVERWRITE"),
808
- dryRun: z12.boolean().default(false)
1009
+ projectId: z13.string(),
1010
+ localeId: z13.string(),
1011
+ content: z13.string(),
1012
+ format: z13.enum(FORMATS2),
1013
+ autoApprove: z13.boolean().default(false),
1014
+ conflict: z13.enum(["OVERWRITE", "SKIP_EXISTING", "KEEP_APPROVED"]).default("OVERWRITE"),
1015
+ dryRun: z13.boolean().default(false)
809
1016
  },
810
1017
  annotations: { idempotentHint: true, openWorldHint: true }
811
1018
  },
@@ -820,31 +1027,44 @@ function registerTranslationTools(server, gql) {
820
1027
  }
821
1028
 
822
1029
  // src/tools/index.ts
823
- function registerAllTools(server, gql) {
824
- registerConfigTools(server, gql);
825
- registerProjectTools(server, gql);
826
- registerLocaleTools(server, gql);
827
- registerKeyTools(server, gql);
828
- registerTranslationTools(server, gql);
829
- registerQaTools(server, gql);
830
- registerGlossaryTools(server, gql);
831
- registerStyleGuideTools(server, gql);
832
- registerGitTools(server, gql);
833
- registerProviderTools(server, gql);
834
- registerJobTools(server, gql);
835
- registerAnalyticsTools(server, gql);
1030
+ var TOOL_SETS = {
1031
+ config: registerConfigTools,
1032
+ projects: registerProjectTools,
1033
+ locales: registerLocaleTools,
1034
+ keys: registerKeyTools,
1035
+ translations: registerTranslationTools,
1036
+ qa: registerQaTools,
1037
+ glossary: registerGlossaryTools,
1038
+ styleguides: registerStyleGuideTools,
1039
+ tm: registerTmTools,
1040
+ git: registerGitTools,
1041
+ providers: registerProviderTools,
1042
+ jobs: registerJobTools,
1043
+ analytics: registerAnalyticsTools
1044
+ };
1045
+ var TOOL_SET_NAMES = Object.keys(TOOL_SETS);
1046
+ function selectSets(requested) {
1047
+ if (!requested || requested.length === 0 || requested.includes("all")) return TOOL_SET_NAMES;
1048
+ return TOOL_SET_NAMES.filter((name) => requested.includes(name));
1049
+ }
1050
+ function registerAllTools(server, gql, opts = {}) {
1051
+ const target = applyToolFilter(server, opts);
1052
+ for (const name of selectSets(opts.toolSets)) {
1053
+ TOOL_SETS[name]?.(target, gql);
1054
+ }
836
1055
  }
837
1056
 
838
1057
  // src/build-server.ts
839
- function buildMcpServer(gql) {
1058
+ function buildMcpServer(gql, opts = {}) {
840
1059
  const server = new McpServer({ name: "syntholoc", version: "0.1.0" });
841
- registerAllTools(server, gql);
1060
+ registerAllTools(server, gql, opts);
842
1061
  registerResources(server, gql);
843
1062
  registerPrompts(server);
844
1063
  return server;
845
1064
  }
846
1065
 
847
1066
  export {
1067
+ parseList,
1068
+ TOOL_SET_NAMES,
848
1069
  buildMcpServer
849
1070
  };
850
- //# sourceMappingURL=chunk-N4PXYXAP.js.map
package/dist/index.js CHANGED
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
- buildMcpServer
4
- } from "./chunk-N4PXYXAP.js";
3
+ buildMcpServer,
4
+ parseList
5
+ } from "./chunk-QOVGANRN.js";
5
6
 
6
7
  // src/index.ts
7
8
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
@@ -10,16 +11,23 @@ import { GraphQLClient } from "@syntholoc/sdk";
10
11
  // src/config.ts
11
12
  function loadConfig(env = process.env) {
12
13
  return {
13
- apiUrl: env.SYNTHOLOC_API_URL ?? "http://localhost:4000/graphql",
14
+ apiUrl: env.SYNTHOLOC_API_URL ?? "https://api.syntholoc.com/graphql",
14
15
  apiKey: env.SYNTHOLOC_API_KEY
15
16
  };
16
17
  }
18
+ function loadToolOptions(env = process.env) {
19
+ return {
20
+ toolSets: parseList(env.SYNTHOLOC_TOOL_SETS),
21
+ readOnly: env.SYNTHOLOC_READ_ONLY === "true",
22
+ toolFilter: parseList(env.SYNTHOLOC_TOOL_FILTER)
23
+ };
24
+ }
17
25
 
18
26
  // src/index.ts
19
27
  async function main() {
20
28
  const config = loadConfig();
21
29
  const gql = new GraphQLClient(config);
22
- const server = buildMcpServer(gql);
30
+ const server = buildMcpServer(gql, loadToolOptions());
23
31
  await server.connect(new StdioServerTransport());
24
32
  console.error(`[syntholoc-mcp] ready (api: ${config.apiUrl}${config.apiKey ? "" : ", no API key set"})`);
25
33
  }
@@ -27,4 +35,3 @@ main().catch((err) => {
27
35
  console.error("[syntholoc-mcp] fatal:", err);
28
36
  process.exit(1);
29
37
  });
30
- //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@syntholoc/mcp",
3
- "version": "0.1.0",
4
- "description": "Syntholoc MCP server — use the localization platform from Claude Code.",
5
- "homepage": "https://github.com/SergiyIva/syntholoc/tree/main/apps/mcp#readme",
3
+ "version": "0.1.2",
4
+ "description": "Syntholoc MCP server — manage AI localization and translation from Claude Code.",
5
+ "homepage": "https://syntholoc.com",
6
6
  "keywords": [
7
7
  "syntholoc",
8
8
  "localization",
@@ -29,8 +29,7 @@
29
29
  }
30
30
  },
31
31
  "files": [
32
- "dist",
33
- "src"
32
+ "dist"
34
33
  ],
35
34
  "publishConfig": {
36
35
  "registry": "https://registry.npmjs.org",
@@ -47,7 +46,7 @@
47
46
  },
48
47
  "dependencies": {
49
48
  "@modelcontextprotocol/sdk": "1.22.0",
50
- "@syntholoc/sdk": "0.1.0",
49
+ "@syntholoc/sdk": "0.1.1",
51
50
  "zod": "3.25.76"
52
51
  },
53
52
  "devDependencies": {
@@ -1 +0,0 @@
1
- {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}