@sonenta/mcp 0.17.0 → 0.18.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.18.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.18.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"
|
|
@@ -35,15 +35,24 @@ Tools (V1 MCP surface; glossary_* added 2026-05-24; reports + trash added 2026-0
|
|
|
35
35
|
- list_a11y_gaps — actionable a11y gaps (filtered items[] of a11y_report)
|
|
36
36
|
- set_a11y_variant — upsert one a11y variant override (key, language, surface)
|
|
37
37
|
- delete_a11y_variant — delete one a11y variant override (cell re-inherits base value)
|
|
38
|
+
- list_surfaces — list the project's configurable surfaces (device + a11y; #928)
|
|
39
|
+
- create_surface — create a custom DEVICE surface (a11y is a fixed set)
|
|
40
|
+
- update_surface — rename / toggle-active a surface (deactivate is soft)
|
|
41
|
+
- delete_surface — delete a custom surface (builtins: deactivate only)
|
|
42
|
+
- get_variants — full variant matrix for one key (every active surface x language; #928)
|
|
43
|
+
- set_variant — upsert one variant override for ANY active surface (device or a11y)
|
|
44
|
+
- delete_variant — delete one variant override for any surface (cell re-inherits base)
|
|
38
45
|
|
|
39
46
|
A11y (accessibility) tools (a11y V1) extend the variant engine with four SEMANTIC
|
|
40
47
|
surfaces — aria_label / alt_text / screen_reader / plain_language — orthogonal to
|
|
41
|
-
the visible text. The report hits `/v1/mcp/projects/{id}/a11y-report
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
48
|
+
the visible text. The report hits `/v1/mcp/projects/{id}/a11y-report`. Variant
|
|
49
|
+
writes (set_variant / delete_variant, and the a11y-named set_a11y_variant /
|
|
50
|
+
delete_a11y_variant) use the mcp:* code-addressed GENERIC route
|
|
51
|
+
`/v1/mcp/projects/{id}/keys/{key_uuid}/variants/{language_code}/{surface}`, which
|
|
52
|
+
accepts any surface ACTIVE for the project (device or a11y; #928) — locale
|
|
53
|
+
reinjected straight from a report/matrix item. estimate/generate/translate are
|
|
54
|
+
billed in credits. All are thin HTTP wrappers surfaced verbatim. Every tool is
|
|
55
|
+
reachable with the same `mcp:*` key as the rest of the MCP surface.
|
|
47
56
|
|
|
48
57
|
list_keys and list_untranslated_keys accept `include_glossary_hints=true` to
|
|
49
58
|
attach backend-matched `glossary_hints[]` per key. All glossary matching is
|
|
@@ -1287,6 +1296,216 @@ def register(server: Server, client: VerbumiaClient) -> tuple[Any, Any]:
|
|
|
1287
1296
|
"additionalProperties": False,
|
|
1288
1297
|
},
|
|
1289
1298
|
),
|
|
1299
|
+
Tool(
|
|
1300
|
+
name="list_surfaces",
|
|
1301
|
+
description=(
|
|
1302
|
+
"List the project's configurable SURFACES (task 928): the device "
|
|
1303
|
+
"and a11y surfaces variants can be authored for. Returns "
|
|
1304
|
+
"{surfaces:[{slug, label, kind, builtin, active}]} where kind is "
|
|
1305
|
+
"'device' or 'a11y'. An un-customized project lazily defaults to the "
|
|
1306
|
+
"builtins — device: desktop/mobile/tablet; a11y: aria_label/alt_text/"
|
|
1307
|
+
"screen_reader/plain_language — all active. Only ACTIVE surfaces accept "
|
|
1308
|
+
"variant writes and get published to the CDN."
|
|
1309
|
+
),
|
|
1310
|
+
inputSchema={
|
|
1311
|
+
"type": "object",
|
|
1312
|
+
"properties": {
|
|
1313
|
+
"project_uuid": {
|
|
1314
|
+
"type": "string",
|
|
1315
|
+
"description": "Project UUID. Required when multiple projects are configured (SONENTA_PROJECTS); defaults to the single configured project otherwise.",
|
|
1316
|
+
},
|
|
1317
|
+
},
|
|
1318
|
+
"additionalProperties": False,
|
|
1319
|
+
},
|
|
1320
|
+
),
|
|
1321
|
+
Tool(
|
|
1322
|
+
name="create_surface",
|
|
1323
|
+
description=(
|
|
1324
|
+
"Create a CUSTOM DEVICE surface for the project (task 928), e.g. "
|
|
1325
|
+
"'watch', 'tv', 'kiosk'. Device surfaces are extensible; a11y surfaces "
|
|
1326
|
+
"are a FIXED semantic set — creating an a11y slug (e.g. aria_label) is "
|
|
1327
|
+
"rejected with 422. Returns the updated surface catalog. Builtins need "
|
|
1328
|
+
"no creation (they exist lazily)."
|
|
1329
|
+
),
|
|
1330
|
+
inputSchema={
|
|
1331
|
+
"type": "object",
|
|
1332
|
+
"properties": {
|
|
1333
|
+
"project_uuid": {
|
|
1334
|
+
"type": "string",
|
|
1335
|
+
"description": "Project UUID. Required when multiple projects are configured (SONENTA_PROJECTS); defaults to the single configured project otherwise.",
|
|
1336
|
+
},
|
|
1337
|
+
"slug": {
|
|
1338
|
+
"type": "string",
|
|
1339
|
+
"pattern": "^[a-z0-9_-]{1,40}$",
|
|
1340
|
+
"description": "Surface slug: lowercase letters, digits, '_' or '-', 1-40 chars (e.g. 'watch').",
|
|
1341
|
+
},
|
|
1342
|
+
"label": {
|
|
1343
|
+
"type": "string",
|
|
1344
|
+
"description": "Optional human-readable label (defaults from the slug).",
|
|
1345
|
+
},
|
|
1346
|
+
},
|
|
1347
|
+
"required": ["slug"],
|
|
1348
|
+
"additionalProperties": False,
|
|
1349
|
+
},
|
|
1350
|
+
),
|
|
1351
|
+
Tool(
|
|
1352
|
+
name="update_surface",
|
|
1353
|
+
description=(
|
|
1354
|
+
"Rename and/or toggle a surface (task 928): set its `label` and/or "
|
|
1355
|
+
"`active`. Deactivating is SOFT — existing variants are RETAINED but "
|
|
1356
|
+
"hidden and dropped from the CDN until reactivated (which republishes "
|
|
1357
|
+
"them); the response `affected_variants` reports how many are impacted. "
|
|
1358
|
+
"Builtins can be toggled/renamed but not deleted. Returns "
|
|
1359
|
+
"{surfaces, affected_variants}."
|
|
1360
|
+
),
|
|
1361
|
+
inputSchema={
|
|
1362
|
+
"type": "object",
|
|
1363
|
+
"properties": {
|
|
1364
|
+
"project_uuid": {
|
|
1365
|
+
"type": "string",
|
|
1366
|
+
"description": "Project UUID. Required when multiple projects are configured (SONENTA_PROJECTS); defaults to the single configured project otherwise.",
|
|
1367
|
+
},
|
|
1368
|
+
"slug": {
|
|
1369
|
+
"type": "string",
|
|
1370
|
+
"description": "Slug of the surface to update.",
|
|
1371
|
+
},
|
|
1372
|
+
"label": {
|
|
1373
|
+
"type": "string",
|
|
1374
|
+
"description": "New human-readable label (rename).",
|
|
1375
|
+
},
|
|
1376
|
+
"active": {
|
|
1377
|
+
"type": "boolean",
|
|
1378
|
+
"description": "Activate (true) or soft-deactivate (false) the surface.",
|
|
1379
|
+
},
|
|
1380
|
+
},
|
|
1381
|
+
"required": ["slug"],
|
|
1382
|
+
"additionalProperties": False,
|
|
1383
|
+
},
|
|
1384
|
+
),
|
|
1385
|
+
Tool(
|
|
1386
|
+
name="delete_surface",
|
|
1387
|
+
description=(
|
|
1388
|
+
"Delete a CUSTOM surface (task 928). Builtins cannot be deleted — "
|
|
1389
|
+
"deactivate them with update_surface(active=false) instead (a 422/409 "
|
|
1390
|
+
"is returned if you try to delete a builtin). Deleting a custom surface "
|
|
1391
|
+
"removes it from the catalog."
|
|
1392
|
+
),
|
|
1393
|
+
inputSchema={
|
|
1394
|
+
"type": "object",
|
|
1395
|
+
"properties": {
|
|
1396
|
+
"project_uuid": {
|
|
1397
|
+
"type": "string",
|
|
1398
|
+
"description": "Project UUID. Required when multiple projects are configured (SONENTA_PROJECTS); defaults to the single configured project otherwise.",
|
|
1399
|
+
},
|
|
1400
|
+
"slug": {
|
|
1401
|
+
"type": "string",
|
|
1402
|
+
"description": "Slug of the custom surface to delete.",
|
|
1403
|
+
},
|
|
1404
|
+
},
|
|
1405
|
+
"required": ["slug"],
|
|
1406
|
+
"additionalProperties": False,
|
|
1407
|
+
},
|
|
1408
|
+
),
|
|
1409
|
+
Tool(
|
|
1410
|
+
name="get_variants",
|
|
1411
|
+
description=(
|
|
1412
|
+
"Read the full VARIANT MATRIX for one key (task 928): every ACTIVE "
|
|
1413
|
+
"surface (device + a11y) x every project language, with each cell's "
|
|
1414
|
+
"{override, value, resolvedValue, status, drift, ...}. The response "
|
|
1415
|
+
"also lists `surfaces` (active) and `surfaceKinds` ({surface: "
|
|
1416
|
+
"'device'|'a11y'}). Address the key by key_uuid (from list_keys). "
|
|
1417
|
+
"Surfaced verbatim."
|
|
1418
|
+
),
|
|
1419
|
+
inputSchema={
|
|
1420
|
+
"type": "object",
|
|
1421
|
+
"properties": {
|
|
1422
|
+
"project_uuid": {
|
|
1423
|
+
"type": "string",
|
|
1424
|
+
"description": "Project UUID. Required when multiple projects are configured (SONENTA_PROJECTS); defaults to the single configured project otherwise.",
|
|
1425
|
+
},
|
|
1426
|
+
"key_uuid": {
|
|
1427
|
+
"type": "string",
|
|
1428
|
+
"description": "Key UUID (from list_keys).",
|
|
1429
|
+
},
|
|
1430
|
+
},
|
|
1431
|
+
"required": ["key_uuid"],
|
|
1432
|
+
"additionalProperties": False,
|
|
1433
|
+
},
|
|
1434
|
+
),
|
|
1435
|
+
Tool(
|
|
1436
|
+
name="set_variant",
|
|
1437
|
+
description=(
|
|
1438
|
+
"Upsert ONE variant override for (key, language, surface) for ANY "
|
|
1439
|
+
"surface active on the project (task 928) — device (desktop / mobile / "
|
|
1440
|
+
"tablet / custom like watch / tv) OR a11y (aria_label / alt_text / "
|
|
1441
|
+
"screen_reader / plain_language). Address by key_uuid + locale CODE + "
|
|
1442
|
+
"surface slug (the fields get_variants / list_keys already give you). "
|
|
1443
|
+
"Stored as a draft. 422 if the surface is not active for the project "
|
|
1444
|
+
"(see list_surfaces); 409 if the cell is already reviewed/approved "
|
|
1445
|
+
"(never overwritten). Returns {key_uuid, surface, language_code, "
|
|
1446
|
+
"value, status}. (For a11y specifically you can also use "
|
|
1447
|
+
"set_a11y_variant.)"
|
|
1448
|
+
),
|
|
1449
|
+
inputSchema={
|
|
1450
|
+
"type": "object",
|
|
1451
|
+
"properties": {
|
|
1452
|
+
"project_uuid": {
|
|
1453
|
+
"type": "string",
|
|
1454
|
+
"description": "Project UUID. Required when multiple projects are configured (SONENTA_PROJECTS); defaults to the single configured project otherwise.",
|
|
1455
|
+
},
|
|
1456
|
+
"key_uuid": {
|
|
1457
|
+
"type": "string",
|
|
1458
|
+
"description": "Key UUID (from list_keys / get_variants).",
|
|
1459
|
+
},
|
|
1460
|
+
"language_code": {
|
|
1461
|
+
"type": "string",
|
|
1462
|
+
"description": "Target locale CODE, e.g. 'fr'. Backend resolves it; 404 if unknown.",
|
|
1463
|
+
},
|
|
1464
|
+
"surface": {
|
|
1465
|
+
"type": "string",
|
|
1466
|
+
"description": "Surface slug — any surface ACTIVE for the project (device or a11y). See list_surfaces.",
|
|
1467
|
+
},
|
|
1468
|
+
"value": {
|
|
1469
|
+
"type": "string",
|
|
1470
|
+
"description": "The variant text value for this (key, language, surface).",
|
|
1471
|
+
},
|
|
1472
|
+
},
|
|
1473
|
+
"required": ["key_uuid", "language_code", "surface", "value"],
|
|
1474
|
+
"additionalProperties": False,
|
|
1475
|
+
},
|
|
1476
|
+
),
|
|
1477
|
+
Tool(
|
|
1478
|
+
name="delete_variant",
|
|
1479
|
+
description=(
|
|
1480
|
+
"Delete ONE variant override for (key, language, surface), for ANY "
|
|
1481
|
+
"surface (device or a11y) — task 928. The cell re-inherits the base "
|
|
1482
|
+
"value; a 404 means there was no override. Address by key_uuid + "
|
|
1483
|
+
"language_code + surface (same as set_variant)."
|
|
1484
|
+
),
|
|
1485
|
+
inputSchema={
|
|
1486
|
+
"type": "object",
|
|
1487
|
+
"properties": {
|
|
1488
|
+
"project_uuid": {
|
|
1489
|
+
"type": "string",
|
|
1490
|
+
"description": "Project UUID. Required when multiple projects are configured (SONENTA_PROJECTS); defaults to the single configured project otherwise.",
|
|
1491
|
+
},
|
|
1492
|
+
"key_uuid": {
|
|
1493
|
+
"type": "string",
|
|
1494
|
+
"description": "Key UUID (from list_keys / get_variants).",
|
|
1495
|
+
},
|
|
1496
|
+
"language_code": {
|
|
1497
|
+
"type": "string",
|
|
1498
|
+
"description": "Target locale CODE, e.g. 'fr'.",
|
|
1499
|
+
},
|
|
1500
|
+
"surface": {
|
|
1501
|
+
"type": "string",
|
|
1502
|
+
"description": "Surface slug (device or a11y) to clear.",
|
|
1503
|
+
},
|
|
1504
|
+
},
|
|
1505
|
+
"required": ["key_uuid", "language_code", "surface"],
|
|
1506
|
+
"additionalProperties": False,
|
|
1507
|
+
},
|
|
1508
|
+
),
|
|
1290
1509
|
]
|
|
1291
1510
|
|
|
1292
1511
|
@server.call_tool()
|
|
@@ -1726,11 +1945,13 @@ def register(server: Server, client: VerbumiaClient) -> tuple[Any, Any]:
|
|
|
1726
1945
|
return _err("key_uuid, language_code and surface are required")
|
|
1727
1946
|
if surface not in A11Y_SURFACES:
|
|
1728
1947
|
return _err(f"surface must be one of {', '.join(A11Y_SURFACES)}")
|
|
1729
|
-
# mcp:* code-addressed
|
|
1730
|
-
#
|
|
1948
|
+
# mcp:* code-addressed GENERIC variant route (covers a11y + device;
|
|
1949
|
+
# task 928). Backend resolves the locale code -> uuid and validates the
|
|
1950
|
+
# surface is active server-side. (The legacy /a11y-variants/ path still
|
|
1951
|
+
# works for back-compat, but /variants/ is canonical.)
|
|
1731
1952
|
path = (
|
|
1732
1953
|
f"/v1/mcp/projects/{project_uuid}/keys/{key_uuid}"
|
|
1733
|
-
f"/
|
|
1954
|
+
f"/variants/{language_code}/{surface}"
|
|
1734
1955
|
)
|
|
1735
1956
|
if name == "delete_a11y_variant":
|
|
1736
1957
|
await client.delete(path)
|
|
@@ -1746,6 +1967,79 @@ def register(server: Server, client: VerbumiaClient) -> tuple[Any, Any]:
|
|
|
1746
1967
|
return _err("value is required")
|
|
1747
1968
|
data = await client.put(path, json={"value": args["value"]})
|
|
1748
1969
|
return _text(data)
|
|
1970
|
+
if name == "list_surfaces":
|
|
1971
|
+
project_uuid = _project_uuid(args, client)
|
|
1972
|
+
data = await client.get(f"/v1/mcp/projects/{project_uuid}/surfaces")
|
|
1973
|
+
return _text(data)
|
|
1974
|
+
if name == "create_surface":
|
|
1975
|
+
project_uuid = _project_uuid(args, client)
|
|
1976
|
+
if not args.get("slug"):
|
|
1977
|
+
return _err("slug is required")
|
|
1978
|
+
body: dict[str, Any] = {"slug": args["slug"]}
|
|
1979
|
+
if "label" in args:
|
|
1980
|
+
body["label"] = args["label"]
|
|
1981
|
+
data = await client.post(
|
|
1982
|
+
f"/v1/mcp/projects/{project_uuid}/surfaces", json=body
|
|
1983
|
+
)
|
|
1984
|
+
return _text(data)
|
|
1985
|
+
if name == "update_surface":
|
|
1986
|
+
project_uuid = _project_uuid(args, client)
|
|
1987
|
+
slug = args.get("slug")
|
|
1988
|
+
if not slug:
|
|
1989
|
+
return _err("slug is required")
|
|
1990
|
+
body: dict[str, Any] = {}
|
|
1991
|
+
for opt in ("label", "active"):
|
|
1992
|
+
if opt in args:
|
|
1993
|
+
body[opt] = args[opt]
|
|
1994
|
+
if not body:
|
|
1995
|
+
return _err("nothing to update: pass label and/or active")
|
|
1996
|
+
data = await client.put(
|
|
1997
|
+
f"/v1/mcp/projects/{project_uuid}/surfaces/{slug}", json=body
|
|
1998
|
+
)
|
|
1999
|
+
return _text(data)
|
|
2000
|
+
if name == "delete_surface":
|
|
2001
|
+
project_uuid = _project_uuid(args, client)
|
|
2002
|
+
slug = args.get("slug")
|
|
2003
|
+
if not slug:
|
|
2004
|
+
return _err("slug is required")
|
|
2005
|
+
await client.delete(f"/v1/mcp/projects/{project_uuid}/surfaces/{slug}")
|
|
2006
|
+
return _text({"deleted": True, "slug": slug})
|
|
2007
|
+
if name == "get_variants":
|
|
2008
|
+
project_uuid = _project_uuid(args, client)
|
|
2009
|
+
key_uuid = args.get("key_uuid")
|
|
2010
|
+
if not key_uuid:
|
|
2011
|
+
return _err("key_uuid is required")
|
|
2012
|
+
data = await client.get(
|
|
2013
|
+
f"/v1/mcp/projects/{project_uuid}/keys/{key_uuid}/variants"
|
|
2014
|
+
)
|
|
2015
|
+
return _text(data)
|
|
2016
|
+
if name in ("set_variant", "delete_variant"):
|
|
2017
|
+
project_uuid = _project_uuid(args, client)
|
|
2018
|
+
key_uuid = args.get("key_uuid")
|
|
2019
|
+
language_code = args.get("language_code")
|
|
2020
|
+
surface = args.get("surface")
|
|
2021
|
+
if not key_uuid or not language_code or not surface:
|
|
2022
|
+
return _err("key_uuid, language_code and surface are required")
|
|
2023
|
+
# generic variant route: backend validates the surface is active (422)
|
|
2024
|
+
# and guards reviewed/approved cells (409).
|
|
2025
|
+
path = (
|
|
2026
|
+
f"/v1/mcp/projects/{project_uuid}/keys/{key_uuid}"
|
|
2027
|
+
f"/variants/{language_code}/{surface}"
|
|
2028
|
+
)
|
|
2029
|
+
if name == "delete_variant":
|
|
2030
|
+
await client.delete(path)
|
|
2031
|
+
return _text(
|
|
2032
|
+
{
|
|
2033
|
+
"deleted": True,
|
|
2034
|
+
"key_uuid": key_uuid,
|
|
2035
|
+
"language_code": language_code,
|
|
2036
|
+
"surface": surface,
|
|
2037
|
+
}
|
|
2038
|
+
)
|
|
2039
|
+
if "value" not in args:
|
|
2040
|
+
return _err("value is required")
|
|
2041
|
+
data = await client.put(path, json={"value": args["value"]})
|
|
2042
|
+
return _text(data)
|
|
1749
2043
|
return _err(f"unknown tool: {name}")
|
|
1750
2044
|
except VerbumiaApiError as exc:
|
|
1751
2045
|
return _err(f"API {exc.status}: {exc.body}")
|
|
Binary file
|