@sonenta/mcp 0.18.0 → 0.19.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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sonenta/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.19.0",
|
|
4
4
|
"description": "MCP server for Sonenta translation management \u2014 wires Claude Desktop and other MCP clients into your project's keys, missing-key feed, and translation drafts.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://sonenta.com",
|
|
Binary file
|
package/python/pyproject.toml
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "verbumia-mcp"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.19.0"
|
|
4
4
|
description = "Model Context Protocol server for Verbumia — list projects, missing keys, propose translations from Claude Desktop and other MCP clients."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.12,<3.14"
|
|
@@ -9,9 +9,9 @@ Tools (V1 MCP surface; glossary_* added 2026-05-24; reports + trash added 2026-0
|
|
|
9
9
|
- missing_keys_stats — count-only summary of missing events (drives pagination)
|
|
10
10
|
- acknowledge_missing_keys— batch-resolve missing events (cleanup the dashboard)
|
|
11
11
|
- create_namespace — idempotent namespace creation (slug validated, slug_invalid on bad input)
|
|
12
|
-
- create_key — idempotent key creation
|
|
12
|
+
- create_key — idempotent key creation; optionally seeds source value + sets semantic `type`
|
|
13
13
|
- create_keys_bulk — batch create_key (up to 500/call, per-item results)
|
|
14
|
-
- update_key — edit a key's SOURCE value in place (PATCH); demotes reviewed/approved targets to needs-review
|
|
14
|
+
- update_key — edit a key's SOURCE value / `type` / description in place (PATCH); demotes reviewed/approved targets to needs-review
|
|
15
15
|
- update_keys_bulk — batch update_key (up to 500/call, per-item results)
|
|
16
16
|
- propose_translation — submit a translation value (auto-creates the key if missing)
|
|
17
17
|
- propose_translations_bulk— batch propose_translation (up to 500/call, per-item results)
|
|
@@ -84,6 +84,30 @@ from .client import VerbumiaApiError, VerbumiaClient
|
|
|
84
84
|
# visible text. `surfaceKinds` in the variants matrix tags each as a11y.
|
|
85
85
|
A11Y_SURFACES = ("aria_label", "alt_text", "screen_reader", "plain_language")
|
|
86
86
|
|
|
87
|
+
# Key semantic types (a11y key.type pivot). Default "text". The type decides
|
|
88
|
+
# which a11y treatments a key offers (e.g. an `image` key's base value IS its
|
|
89
|
+
# alt text; a `button` offers aria_label) — the engine gates variant/a11y tools
|
|
90
|
+
# by type server-side, so listing these here is just for create/update_key.
|
|
91
|
+
KEY_TYPES = (
|
|
92
|
+
"text",
|
|
93
|
+
"heading",
|
|
94
|
+
"label",
|
|
95
|
+
"caption",
|
|
96
|
+
"badge",
|
|
97
|
+
"tooltip",
|
|
98
|
+
"error_message",
|
|
99
|
+
"toast",
|
|
100
|
+
"button",
|
|
101
|
+
"link",
|
|
102
|
+
"menu_item",
|
|
103
|
+
"input_placeholder",
|
|
104
|
+
"input_label",
|
|
105
|
+
"image",
|
|
106
|
+
"icon",
|
|
107
|
+
"meta_title",
|
|
108
|
+
"meta_description",
|
|
109
|
+
)
|
|
110
|
+
|
|
87
111
|
|
|
88
112
|
def _project_uuid(arguments: dict | None, client: VerbumiaClient) -> str:
|
|
89
113
|
"""Resolve project_uuid from per-call args or the configured env scope.
|
|
@@ -371,7 +395,8 @@ def register(server: Server, client: VerbumiaClient) -> tuple[Any, Any]:
|
|
|
371
395
|
"Returns created=false if the key already exists. When "
|
|
372
396
|
"source_value is supplied AND the project has a source "
|
|
373
397
|
"language, the value is also written as a source-language "
|
|
374
|
-
"translation in the same call."
|
|
398
|
+
"translation in the same call. Pass `type` (default 'text') to "
|
|
399
|
+
"set the key's semantic type, which decides its a11y treatments."
|
|
375
400
|
),
|
|
376
401
|
inputSchema={
|
|
377
402
|
"type": "object",
|
|
@@ -395,6 +420,12 @@ def register(server: Server, client: VerbumiaClient) -> tuple[Any, Any]:
|
|
|
395
420
|
"description": {"type": "string"},
|
|
396
421
|
"plurals": {"type": "boolean", "default": False},
|
|
397
422
|
"max_length": {"type": "integer", "minimum": 1},
|
|
423
|
+
"type": {
|
|
424
|
+
"type": "string",
|
|
425
|
+
"enum": list(KEY_TYPES),
|
|
426
|
+
"default": "text",
|
|
427
|
+
"description": "Semantic key type (default 'text'). Decides which a11y treatments apply — e.g. 'image' (base value is the alt text), 'icon' (base is the accessible name), 'button'/'link' (offer aria_label), 'heading'/'label' (plain_language/screen_reader).",
|
|
428
|
+
},
|
|
398
429
|
},
|
|
399
430
|
"required": ["namespace", "name"],
|
|
400
431
|
"additionalProperties": False,
|
|
@@ -465,6 +496,7 @@ def register(server: Server, client: VerbumiaClient) -> tuple[Any, Any]:
|
|
|
465
496
|
"description": {"type": "string"},
|
|
466
497
|
"plurals": {"type": "boolean", "default": False},
|
|
467
498
|
"max_length": {"type": "integer", "minimum": 1},
|
|
499
|
+
"type": {"type": "string", "enum": list(KEY_TYPES), "default": "text", "description": "Semantic key type (default 'text'); see create_key."},
|
|
468
500
|
},
|
|
469
501
|
"required": ["namespace", "name"],
|
|
470
502
|
"additionalProperties": False,
|
|
@@ -478,7 +510,8 @@ def register(server: Server, client: VerbumiaClient) -> tuple[Any, Any]:
|
|
|
478
510
|
Tool(
|
|
479
511
|
name="update_key",
|
|
480
512
|
description=(
|
|
481
|
-
"Edit a key
|
|
513
|
+
"Edit a key in place — its SOURCE-language value, its `type`, "
|
|
514
|
+
"and/or its description (pass at least one). Preserves the "
|
|
482
515
|
"key and its history (version bump + history revision + audit). "
|
|
483
516
|
"Address the key by EITHER key_uuid (preferred; from list_keys) "
|
|
484
517
|
"OR namespace + name — exactly one of the two. When the source "
|
|
@@ -516,8 +549,13 @@ def register(server: Server, client: VerbumiaClient) -> tuple[Any, Any]:
|
|
|
516
549
|
"type": "string",
|
|
517
550
|
"description": "Optional: also update the key's description.",
|
|
518
551
|
},
|
|
552
|
+
"type": {
|
|
553
|
+
"type": "string",
|
|
554
|
+
"enum": list(KEY_TYPES),
|
|
555
|
+
"description": "Optional: reclassify the key's semantic type (see create_key). Changing the type re-gates which a11y treatments the key offers.",
|
|
556
|
+
},
|
|
519
557
|
},
|
|
520
|
-
"required": [
|
|
558
|
+
"required": [],
|
|
521
559
|
"additionalProperties": False,
|
|
522
560
|
},
|
|
523
561
|
),
|
|
@@ -552,8 +590,9 @@ def register(server: Server, client: VerbumiaClient) -> tuple[Any, Any]:
|
|
|
552
590
|
"name": {"type": "string", "description": "Dot-notation key name (use with namespace)."},
|
|
553
591
|
"source_value": {"type": "string", "description": "New source-language value to write."},
|
|
554
592
|
"description": {"type": "string", "description": "Optional: also update the key's description."},
|
|
593
|
+
"type": {"type": "string", "enum": list(KEY_TYPES), "description": "Optional: reclassify the key's semantic type (see create_key)."},
|
|
555
594
|
},
|
|
556
|
-
"required": [
|
|
595
|
+
"required": [],
|
|
557
596
|
"additionalProperties": False,
|
|
558
597
|
},
|
|
559
598
|
},
|
|
@@ -1135,6 +1174,9 @@ def register(server: Server, client: VerbumiaClient) -> tuple[Any, Any]:
|
|
|
1135
1174
|
"locale lacks it), alt_missing (image key with no source alt_text), "
|
|
1136
1175
|
"reading_level_high (hard source text + no plain_language), "
|
|
1137
1176
|
"a11y_variant_absent (a require_surface is missing in the source). "
|
|
1177
|
+
"Gaps are TYPE-AWARE: only treatments relevant to each key's type are "
|
|
1178
|
+
"reported (e.g. alt_missing only on image keys, aria gaps only on "
|
|
1179
|
+
"buttons/links/inputs), so a text key is never flagged for aria/alt. "
|
|
1138
1180
|
"Defaults to the production version. Surfaced verbatim — use "
|
|
1139
1181
|
"list_a11y_gaps for just the actionable item list."
|
|
1140
1182
|
),
|
|
@@ -1409,12 +1451,15 @@ def register(server: Server, client: VerbumiaClient) -> tuple[Any, Any]:
|
|
|
1409
1451
|
Tool(
|
|
1410
1452
|
name="get_variants",
|
|
1411
1453
|
description=(
|
|
1412
|
-
"Read the full VARIANT MATRIX for one key (task 928): every
|
|
1413
|
-
"
|
|
1454
|
+
"Read the full VARIANT MATRIX for one key (task 928): every surface "
|
|
1455
|
+
"OFFERED for the key x every project language, with each cell's "
|
|
1414
1456
|
"{override, value, resolvedValue, status, drift, ...}. The response "
|
|
1415
|
-
"
|
|
1416
|
-
"
|
|
1417
|
-
"
|
|
1457
|
+
"lists `surfaces` and `surfaceKinds` ({surface: 'device'|'a11y'}) — "
|
|
1458
|
+
"these are the key's offered surfaces only: the project's active "
|
|
1459
|
+
"device surfaces plus the a11y treatments relevant to the key's TYPE "
|
|
1460
|
+
"(e.g. a text key shows no aria/alt). This is the source of truth for "
|
|
1461
|
+
"which surfaces set_variant will accept. Address by key_uuid (from "
|
|
1462
|
+
"list_keys). Surfaced verbatim."
|
|
1418
1463
|
),
|
|
1419
1464
|
inputSchema={
|
|
1420
1465
|
"type": "object",
|
|
@@ -1440,11 +1485,13 @@ def register(server: Server, client: VerbumiaClient) -> tuple[Any, Any]:
|
|
|
1440
1485
|
"tablet / custom like watch / tv) OR a11y (aria_label / alt_text / "
|
|
1441
1486
|
"screen_reader / plain_language). Address by key_uuid + locale CODE + "
|
|
1442
1487
|
"surface slug (the fields get_variants / list_keys already give you). "
|
|
1443
|
-
"Stored as a draft. 422
|
|
1444
|
-
"(see list_surfaces)
|
|
1445
|
-
"(
|
|
1446
|
-
"
|
|
1447
|
-
"
|
|
1488
|
+
"Stored as a draft. 422 unless the surface is OFFERED for this key — "
|
|
1489
|
+
"an active device surface (see list_surfaces) OR an a11y treatment "
|
|
1490
|
+
"relevant to the key's TYPE (e.g. no aria_label on a text key; see "
|
|
1491
|
+
"get_variants for the key's offered surfaces); 409 if the cell is "
|
|
1492
|
+
"already reviewed/approved (never overwritten). Returns {key_uuid, "
|
|
1493
|
+
"surface, language_code, value, status}. (For a11y specifically you "
|
|
1494
|
+
"can also use set_a11y_variant.)"
|
|
1448
1495
|
),
|
|
1449
1496
|
inputSchema={
|
|
1450
1497
|
"type": "object",
|
|
@@ -1627,7 +1674,7 @@ def register(server: Server, client: VerbumiaClient) -> tuple[Any, Any]:
|
|
|
1627
1674
|
"namespace": args["namespace"],
|
|
1628
1675
|
"name": args["name"],
|
|
1629
1676
|
}
|
|
1630
|
-
for opt in ("source_value", "description", "plurals", "max_length"):
|
|
1677
|
+
for opt in ("source_value", "description", "plurals", "max_length", "type"):
|
|
1631
1678
|
if opt in args:
|
|
1632
1679
|
body[opt] = args[opt]
|
|
1633
1680
|
data = await client.post(
|
|
@@ -1659,16 +1706,18 @@ def register(server: Server, client: VerbumiaClient) -> tuple[Any, Any]:
|
|
|
1659
1706
|
return _text(data)
|
|
1660
1707
|
if name == "update_key":
|
|
1661
1708
|
project_uuid = _project_uuid(args, client)
|
|
1662
|
-
if "source_value"
|
|
1663
|
-
return _err(
|
|
1709
|
+
if not any(k in args for k in ("source_value", "type", "description")):
|
|
1710
|
+
return _err(
|
|
1711
|
+
"nothing to update: pass at least one of source_value, type, description"
|
|
1712
|
+
)
|
|
1664
1713
|
has_uuid = bool(args.get("key_uuid"))
|
|
1665
1714
|
has_name = bool(args.get("namespace")) and bool(args.get("name"))
|
|
1666
1715
|
if has_uuid == has_name:
|
|
1667
1716
|
return _err(
|
|
1668
1717
|
"address the key by exactly one of key_uuid OR (namespace + name)"
|
|
1669
1718
|
)
|
|
1670
|
-
body: dict[str, Any] = {
|
|
1671
|
-
for opt in ("key_uuid", "namespace", "name", "description"):
|
|
1719
|
+
body: dict[str, Any] = {}
|
|
1720
|
+
for opt in ("source_value", "key_uuid", "namespace", "name", "description", "type"):
|
|
1672
1721
|
if opt in args:
|
|
1673
1722
|
body[opt] = args[opt]
|
|
1674
1723
|
data = await client.patch(
|
|
Binary file
|