@sonenta/mcp 0.38.0 → 0.40.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 CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Model Context Protocol server for **Sonenta** translation management — **pure TypeScript**, no Python, no `uv`, no bundled wheel. Runs on Node ≥18.
4
4
 
5
- Wires Claude Desktop and other MCP clients into your Sonenta project's keys, translations, accessibility surfaces, source-health, and glossary tools — plus **agent-observability** tools (`session_start` / `annotate` / `human_needed` / `session_end`) that surface an agent's run as a live, timestamped thread in the Sonenta dashboard, and **prompt-library** reads (`list_prompts` / `resolve_prompt`) so agents can discover and reuse the project's curated prompts.
5
+ Wires Claude Desktop and other MCP clients into your Sonenta project's keys, translations, accessibility surfaces, source-health, and glossary tools — plus **agent-observability** tools (`session_start` / `annotate` / `human_needed` / `session_end`) that surface an agent's run as a live, timestamped thread in the Sonenta dashboard, and **prompt-library** reads (`list_prompts` / `resolve_prompt`) so agents can discover and reuse the project's curated prompts. `propose_translation(s)` carry ICU/CLDR `plural_forms`, and `plural_categories` returns the plural categories a language requires (babel-authoritative).
6
6
 
7
7
  ## Use
8
8
 
@@ -19562,6 +19562,63 @@ var init_schemas_observability = __esm({
19562
19562
  }
19563
19563
  });
19564
19564
 
19565
+ // src/tools/schemas.plurals.ts
19566
+ function extendProposeTranslation() {
19567
+ const s = clone2(SCHEMAS["propose_translation"]);
19568
+ const props = s.inputSchema["properties"];
19569
+ props["plural_forms"] = PLURAL_FORMS_PROPERTY;
19570
+ s.inputSchema["required"] = ["namespace", "key", "language_code"];
19571
+ s.description += " For a PLURAL key, pass `plural_forms` (a CLDR category->string map covering exactly the target language's required categories) instead of a single `value`.";
19572
+ return s;
19573
+ }
19574
+ function extendProposeBulk() {
19575
+ const s = clone2(SCHEMAS["propose_translations_bulk"]);
19576
+ const items = s.inputSchema["properties"]["items"];
19577
+ const item = items["items"];
19578
+ item["properties"]["plural_forms"] = PLURAL_FORMS_PROPERTY;
19579
+ item["required"] = ["namespace", "key", "language_code"];
19580
+ s.description += " Each item may carry `plural_forms` (a CLDR category->string map) for plural keys instead of `value`.";
19581
+ return s;
19582
+ }
19583
+ var PLURAL_FORMS_PROPERTY, clone2, PLURALS_EXTENDED_SCHEMAS, PLURAL_CATEGORIES_SCHEMAS, PLURALS_NATIVE_TOOL_NAMES, PLURALS_EXTENDED_TOOL_NAMES;
19584
+ var init_schemas_plurals = __esm({
19585
+ "src/tools/schemas.plurals.ts"() {
19586
+ "use strict";
19587
+ init_schemas_generated();
19588
+ PLURAL_FORMS_PROPERTY = {
19589
+ type: "object",
19590
+ additionalProperties: { type: "string" },
19591
+ description: 'For PLURAL keys only: a map of CLDR plural category -> rendered string, e.g. {"one":"{{count}} file","other":"{{count}} files"}. Provide EXACTLY the categories the TARGET language requires (call plural_categories to get them); `other` is always required. Keep the count variable in every form. When set, `value` may be omitted (it mirrors plural_forms.other). Supplying it for a non-plural key is rejected.'
19592
+ };
19593
+ clone2 = (s) => JSON.parse(JSON.stringify(s));
19594
+ PLURALS_EXTENDED_SCHEMAS = {
19595
+ propose_translation: extendProposeTranslation(),
19596
+ propose_translations_bulk: extendProposeBulk()
19597
+ };
19598
+ PLURAL_CATEGORIES_SCHEMAS = {
19599
+ plural_categories: {
19600
+ description: "Get the CLDR plural categories a language REQUIRES (babel-authoritative \u2014 the canonical source, not an LLM guess), so you author exactly the right plural forms per target locale. Pass `code` for one language or `codes` for several. Returns the ordered categories plus an example integer per category. Read-only, free (0 credits). Use this before writing plural_forms via propose_translation(s).",
19601
+ inputSchema: {
19602
+ type: "object",
19603
+ properties: {
19604
+ code: {
19605
+ type: "string",
19606
+ description: "A single BCP-47 language code, e.g. ru, ar, fr-CA. Falls back to the base language then to ['other']."
19607
+ },
19608
+ codes: {
19609
+ type: "array",
19610
+ items: { type: "string" },
19611
+ description: "Several BCP-47 codes for a bulk lookup, e.g. ['ru','ar','fr']. Takes precedence over `code`."
19612
+ }
19613
+ }
19614
+ }
19615
+ }
19616
+ };
19617
+ PLURALS_NATIVE_TOOL_NAMES = Object.keys(PLURAL_CATEGORIES_SCHEMAS);
19618
+ PLURALS_EXTENDED_TOOL_NAMES = Object.keys(PLURALS_EXTENDED_SCHEMAS);
19619
+ }
19620
+ });
19621
+
19565
19622
  // src/tools/schemas.prompts.ts
19566
19623
  var PROJECT_UUID2, PROMPTS_SCHEMAS, PROMPTS_TOOL_NAMES;
19567
19624
  var init_schemas_prompts = __esm({
@@ -19674,6 +19731,7 @@ var init_registry = __esm({
19674
19731
  init_helpers2();
19675
19732
  init_schemas_generated();
19676
19733
  init_schemas_observability();
19734
+ init_schemas_plurals();
19677
19735
  init_schemas_prompts();
19678
19736
  A11Y_SURFACES = ["aria_label", "alt_text", "screen_reader", "plain_language"];
19679
19737
  has = (args, k) => k in args;
@@ -19820,13 +19878,14 @@ var init_registry = __esm({
19820
19878
  // ---- translations & publish ----
19821
19879
  async propose_translation(args, client) {
19822
19880
  const p = resolveProjectUuid(args, client);
19881
+ if (!has(args, "value") && !has(args, "plural_forms"))
19882
+ throw new ToolValidationError("provide value, or plural_forms for a plural key");
19823
19883
  const body = {
19824
19884
  namespace: args["namespace"],
19825
19885
  key: args["key"],
19826
- language_code: args["language_code"],
19827
- value: args["value"]
19886
+ language_code: args["language_code"]
19828
19887
  };
19829
- copyPresent(body, args, ["status"]);
19888
+ copyPresent(body, args, ["value", "status", "plural_forms"]);
19830
19889
  return client.put(`/v1/mcp/projects/${p}/translations`, body);
19831
19890
  },
19832
19891
  async propose_translations_bulk(args, client) {
@@ -20248,12 +20307,29 @@ var init_registry = __esm({
20248
20307
  }
20249
20308
  if ("count" in args) params["count"] = args["count"];
20250
20309
  return client.get(`/v1/mcp/projects/${p}/prompts/resolve`, params);
20310
+ },
20311
+ // ---- plurals: required CLDR categories per language (read-only, task 1620) ----
20312
+ // Global reference route (/v1/mcp/languages/...), NOT project-scoped.
20313
+ async plural_categories(args, client) {
20314
+ const codes = args["codes"];
20315
+ if (Array.isArray(codes) && codes.length) {
20316
+ return client.get("/v1/mcp/languages/plural-categories", {
20317
+ codes: codes.map(str).join(",")
20318
+ });
20319
+ }
20320
+ if (truthy(args, "code")) {
20321
+ return client.get(`/v1/mcp/languages/${encodeURIComponent(str(args["code"]))}/plural-categories`);
20322
+ }
20323
+ throw new ToolValidationError("pass either code (single) or codes (bulk list)");
20251
20324
  }
20252
20325
  };
20253
20326
  TOOLS = Object.entries({
20254
20327
  ...SCHEMAS,
20328
+ ...PLURALS_EXTENDED_SCHEMAS,
20329
+ // override propose_translation(s) with the plural_forms superset
20255
20330
  ...OBSERVABILITY_SCHEMAS,
20256
- ...PROMPTS_SCHEMAS
20331
+ ...PROMPTS_SCHEMAS,
20332
+ ...PLURAL_CATEGORIES_SCHEMAS
20257
20333
  }).map(([name, schema]) => {
20258
20334
  const handler = HANDLERS[name];
20259
20335
  if (!handler) throw new Error(`registry: no handler ported for tool '${name}'`);
@@ -20344,7 +20420,7 @@ var init_server3 = __esm({
20344
20420
  init_errors3();
20345
20421
  init_helpers2();
20346
20422
  init_registry();
20347
- VERSION = "0.38.0";
20423
+ VERSION = "0.40.0";
20348
20424
  }
20349
20425
  });
20350
20426