@sonenta/mcp 0.37.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 +1 -1
- package/bin/sonenta-mcp.js +155 -5
- package/bin/sonenta-mcp.js.map +1 -1
- package/package.json +1 -1
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.
|
|
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
|
|
package/bin/sonenta-mcp.js
CHANGED
|
@@ -19562,6 +19562,115 @@ 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
|
+
|
|
19622
|
+
// src/tools/schemas.prompts.ts
|
|
19623
|
+
var PROJECT_UUID2, PROMPTS_SCHEMAS, PROMPTS_TOOL_NAMES;
|
|
19624
|
+
var init_schemas_prompts = __esm({
|
|
19625
|
+
"src/tools/schemas.prompts.ts"() {
|
|
19626
|
+
"use strict";
|
|
19627
|
+
PROJECT_UUID2 = {
|
|
19628
|
+
type: "string",
|
|
19629
|
+
description: "Project UUID. Required when multiple projects are configured (SONENTA_PROJECTS); defaults to the single configured project otherwise."
|
|
19630
|
+
};
|
|
19631
|
+
PROMPTS_SCHEMAS = {
|
|
19632
|
+
list_prompts: {
|
|
19633
|
+
description: "Browse the Sonenta prompt library (the global catalogue). Use this to discover the reusable, curated prompts available for a project before you write your own \u2014 filter by section / subsection / tier / phase to narrow down. Read-only, free (0 credits). Returns {items:[{key, i18n_key, section, subsection, tier, phase, agent, category, title, template, enabled}], total}. To get a single ready-to-use template with variables filled, use resolve_prompt instead.",
|
|
19634
|
+
inputSchema: {
|
|
19635
|
+
type: "object",
|
|
19636
|
+
properties: {
|
|
19637
|
+
project_uuid: PROJECT_UUID2,
|
|
19638
|
+
section: { type: "string", description: "Filter by top-level section." },
|
|
19639
|
+
subsection: { type: "string", description: "Filter by subsection within a section." },
|
|
19640
|
+
tier: { type: "string", description: "Filter by tier." },
|
|
19641
|
+
phase: { type: "string", description: "Filter by phase." },
|
|
19642
|
+
enabled: {
|
|
19643
|
+
type: "boolean",
|
|
19644
|
+
description: "If set, return only enabled (true) or only disabled (false) prompts; omit for all."
|
|
19645
|
+
}
|
|
19646
|
+
}
|
|
19647
|
+
}
|
|
19648
|
+
},
|
|
19649
|
+
resolve_prompt: {
|
|
19650
|
+
description: "Resolve the single best-matching prompt for a section and get its template ready to use, with catalogue variables filled in. Use this when you want THE prompt for a job rather than a list to pick from. `section` is required; narrow further with subsection / tier / phase, and pass language / namespace / count to shape the resolved variables. Read-only, free (0 credits). Returns {prompt:{key, i18n_key, template, resolved, variables_used}}; errors 404 if nothing matches.",
|
|
19651
|
+
inputSchema: {
|
|
19652
|
+
type: "object",
|
|
19653
|
+
properties: {
|
|
19654
|
+
project_uuid: PROJECT_UUID2,
|
|
19655
|
+
section: { type: "string", description: "Section to resolve a prompt for (REQUIRED)." },
|
|
19656
|
+
subsection: { type: "string", description: "Optional subsection to narrow the match." },
|
|
19657
|
+
tier: { type: "string", description: "Optional tier to narrow the match." },
|
|
19658
|
+
phase: { type: "string", description: "Optional phase to narrow the match." },
|
|
19659
|
+
language: { type: "string", description: "Optional language code used when filling template variables." },
|
|
19660
|
+
namespace: { type: "string", description: "Optional namespace used when filling template variables." },
|
|
19661
|
+
count: {
|
|
19662
|
+
type: "integer",
|
|
19663
|
+
description: "Optional count used by count-dependent template variables (default 0)."
|
|
19664
|
+
}
|
|
19665
|
+
},
|
|
19666
|
+
required: ["section"]
|
|
19667
|
+
}
|
|
19668
|
+
}
|
|
19669
|
+
};
|
|
19670
|
+
PROMPTS_TOOL_NAMES = Object.keys(PROMPTS_SCHEMAS);
|
|
19671
|
+
}
|
|
19672
|
+
});
|
|
19673
|
+
|
|
19565
19674
|
// src/tools/registry.ts
|
|
19566
19675
|
var registry_exports = {};
|
|
19567
19676
|
__export(registry_exports, {
|
|
@@ -19622,6 +19731,8 @@ var init_registry = __esm({
|
|
|
19622
19731
|
init_helpers2();
|
|
19623
19732
|
init_schemas_generated();
|
|
19624
19733
|
init_schemas_observability();
|
|
19734
|
+
init_schemas_plurals();
|
|
19735
|
+
init_schemas_prompts();
|
|
19625
19736
|
A11Y_SURFACES = ["aria_label", "alt_text", "screen_reader", "plain_language"];
|
|
19626
19737
|
has = (args, k) => k in args;
|
|
19627
19738
|
truthy = (args, k) => Boolean(args[k]);
|
|
@@ -19767,13 +19878,14 @@ var init_registry = __esm({
|
|
|
19767
19878
|
// ---- translations & publish ----
|
|
19768
19879
|
async propose_translation(args, client) {
|
|
19769
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");
|
|
19770
19883
|
const body = {
|
|
19771
19884
|
namespace: args["namespace"],
|
|
19772
19885
|
key: args["key"],
|
|
19773
|
-
language_code: args["language_code"]
|
|
19774
|
-
value: args["value"]
|
|
19886
|
+
language_code: args["language_code"]
|
|
19775
19887
|
};
|
|
19776
|
-
copyPresent(body, args, ["status"]);
|
|
19888
|
+
copyPresent(body, args, ["value", "status", "plural_forms"]);
|
|
19777
19889
|
return client.put(`/v1/mcp/projects/${p}/translations`, body);
|
|
19778
19890
|
},
|
|
19779
19891
|
async propose_translations_bulk(args, client) {
|
|
@@ -20175,11 +20287,49 @@ var init_registry = __esm({
|
|
|
20175
20287
|
const data = await client.post(`/v1/mcp/projects/${p}/agent/sessions/${sid}/end`, body);
|
|
20176
20288
|
if (client.sessionId === sid) client.clearSession();
|
|
20177
20289
|
return data;
|
|
20290
|
+
},
|
|
20291
|
+
// ---- prompt library (read-only, task 1618 / backend #230) ----
|
|
20292
|
+
async list_prompts(args, client) {
|
|
20293
|
+
const p = resolveProjectUuid(args, client);
|
|
20294
|
+
const params = {};
|
|
20295
|
+
for (const k of ["section", "subsection", "tier", "phase"]) {
|
|
20296
|
+
if (args[k]) params[k] = str(args[k]);
|
|
20297
|
+
}
|
|
20298
|
+
if ("enabled" in args) params["enabled"] = Boolean(args["enabled"]);
|
|
20299
|
+
return client.get(`/v1/mcp/projects/${p}/prompts/catalogue`, params);
|
|
20300
|
+
},
|
|
20301
|
+
async resolve_prompt(args, client) {
|
|
20302
|
+
const p = resolveProjectUuid(args, client);
|
|
20303
|
+
if (!truthy(args, "section")) throw new ToolValidationError("section is required");
|
|
20304
|
+
const params = { section: str(args["section"]) };
|
|
20305
|
+
for (const k of ["subsection", "tier", "phase", "language", "namespace"]) {
|
|
20306
|
+
if (args[k]) params[k] = str(args[k]);
|
|
20307
|
+
}
|
|
20308
|
+
if ("count" in args) params["count"] = args["count"];
|
|
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)");
|
|
20178
20324
|
}
|
|
20179
20325
|
};
|
|
20180
20326
|
TOOLS = Object.entries({
|
|
20181
20327
|
...SCHEMAS,
|
|
20182
|
-
...
|
|
20328
|
+
...PLURALS_EXTENDED_SCHEMAS,
|
|
20329
|
+
// override propose_translation(s) with the plural_forms superset
|
|
20330
|
+
...OBSERVABILITY_SCHEMAS,
|
|
20331
|
+
...PROMPTS_SCHEMAS,
|
|
20332
|
+
...PLURAL_CATEGORIES_SCHEMAS
|
|
20183
20333
|
}).map(([name, schema]) => {
|
|
20184
20334
|
const handler = HANDLERS[name];
|
|
20185
20335
|
if (!handler) throw new Error(`registry: no handler ported for tool '${name}'`);
|
|
@@ -20270,7 +20420,7 @@ var init_server3 = __esm({
|
|
|
20270
20420
|
init_errors3();
|
|
20271
20421
|
init_helpers2();
|
|
20272
20422
|
init_registry();
|
|
20273
|
-
VERSION = "0.
|
|
20423
|
+
VERSION = "0.40.0";
|
|
20274
20424
|
}
|
|
20275
20425
|
});
|
|
20276
20426
|
|