@sonenta/mcp 0.21.3 → 0.23.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.23.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 = "sonenta-mcp"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.23.0"
|
|
4
4
|
description = "Model Context Protocol server for Sonenta — 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"
|
|
@@ -1535,6 +1535,79 @@ def register(server: Server, client: VerbumiaClient) -> tuple[Any, Any]:
|
|
|
1535
1535
|
"additionalProperties": False,
|
|
1536
1536
|
},
|
|
1537
1537
|
),
|
|
1538
|
+
Tool(
|
|
1539
|
+
name="recommend_surfaces",
|
|
1540
|
+
description=(
|
|
1541
|
+
"Read-only per-key A11Y SURFACE RECOMMENDATIONS (#2): for each key, "
|
|
1542
|
+
"the a11y surfaces implied by its semantic TYPE, derived from the "
|
|
1543
|
+
"backend's authoritative key.type -> treatment mapping "
|
|
1544
|
+
"(A11Y_TREATMENTS_BY_TYPE) — the single source of truth; do NOT "
|
|
1545
|
+
"reimplement the mapping in the client. Returns {project_uuid, "
|
|
1546
|
+
"version_uuid, active_a11y_surfaces[], keys_scanned, keys_with_gaps, "
|
|
1547
|
+
"gaps_by_surface{surface:int}, items:[{key_uuid, key_name, "
|
|
1548
|
+
"namespace_slug, type, base_role (visible_text|alt_text|"
|
|
1549
|
+
"accessible_name), recommended_surfaces:[{surface, active, "
|
|
1550
|
+
"present_in_source}], has_gap}]}. A recommended surface that is "
|
|
1551
|
+
"active && !present_in_source is a config-satisfied GAP to AUTHOR — "
|
|
1552
|
+
"hand the actual text off to sonenta-a11y (set_a11y_variant), this "
|
|
1553
|
+
"tool only tells you WHERE. DEVICE surfaces are not included here. "
|
|
1554
|
+
"Defaults to the production version."
|
|
1555
|
+
),
|
|
1556
|
+
inputSchema={
|
|
1557
|
+
"type": "object",
|
|
1558
|
+
"properties": {
|
|
1559
|
+
"project_uuid": {
|
|
1560
|
+
"type": "string",
|
|
1561
|
+
"description": "Project UUID. Required when multiple projects are configured (SONENTA_PROJECTS); defaults to the single configured project otherwise.",
|
|
1562
|
+
},
|
|
1563
|
+
"version_id": {
|
|
1564
|
+
"type": "string",
|
|
1565
|
+
"description": "Optional version UUID; defaults to the production version.",
|
|
1566
|
+
},
|
|
1567
|
+
"namespace_id": {
|
|
1568
|
+
"type": "string",
|
|
1569
|
+
"description": "Optional namespace UUID to scope the scan.",
|
|
1570
|
+
},
|
|
1571
|
+
"key_id": {
|
|
1572
|
+
"type": "string",
|
|
1573
|
+
"description": "Optional single key UUID to scope the scan.",
|
|
1574
|
+
},
|
|
1575
|
+
"only_gaps": {
|
|
1576
|
+
"type": "boolean",
|
|
1577
|
+
"description": "When true, return only keys that have a gap (has_gap=true).",
|
|
1578
|
+
},
|
|
1579
|
+
},
|
|
1580
|
+
"additionalProperties": False,
|
|
1581
|
+
},
|
|
1582
|
+
),
|
|
1583
|
+
Tool(
|
|
1584
|
+
name="surface_coverage",
|
|
1585
|
+
description=(
|
|
1586
|
+
"Read-only COVERAGE BY SURFACE (#3): per active surface, how complete "
|
|
1587
|
+
"it is. Returns {project_uuid, version_uuid, languages[], keys_total, "
|
|
1588
|
+
"surfaces:[{surface, label, kind, meaning, eligible_keys, "
|
|
1589
|
+
"eligible_cells, present_cells, pct, by_language:[{code, eligible, "
|
|
1590
|
+
"present, pct}]}]}. The `meaning` field tells you how to read `pct`: "
|
|
1591
|
+
"'a11y_completeness' for a11y surfaces (eligible = type-relevant keys; "
|
|
1592
|
+
"pct = real fill of NEEDED a11y gaps), 'override_density' for device "
|
|
1593
|
+
"surfaces (un-overridden cells fall back to the base value — that is "
|
|
1594
|
+
"NOT broken, just un-customized). Defaults to the production version."
|
|
1595
|
+
),
|
|
1596
|
+
inputSchema={
|
|
1597
|
+
"type": "object",
|
|
1598
|
+
"properties": {
|
|
1599
|
+
"project_uuid": {
|
|
1600
|
+
"type": "string",
|
|
1601
|
+
"description": "Project UUID. Required when multiple projects are configured (SONENTA_PROJECTS); defaults to the single configured project otherwise.",
|
|
1602
|
+
},
|
|
1603
|
+
"version_id": {
|
|
1604
|
+
"type": "string",
|
|
1605
|
+
"description": "Optional version UUID; defaults to the production version.",
|
|
1606
|
+
},
|
|
1607
|
+
},
|
|
1608
|
+
"additionalProperties": False,
|
|
1609
|
+
},
|
|
1610
|
+
),
|
|
1538
1611
|
Tool(
|
|
1539
1612
|
name="get_variants",
|
|
1540
1613
|
description=(
|
|
@@ -1750,6 +1823,154 @@ def register(server: Server, client: VerbumiaClient) -> tuple[Any, Any]:
|
|
|
1750
1823
|
"additionalProperties": False,
|
|
1751
1824
|
},
|
|
1752
1825
|
),
|
|
1826
|
+
# --- a11y conformance reports + remediation plan (sprint 111c4658, B5 MCP twins) ---
|
|
1827
|
+
Tool(
|
|
1828
|
+
name="wcag_report",
|
|
1829
|
+
description=(
|
|
1830
|
+
"Read-only WCAG 2.2 CONFORMANCE report for the content layer Sonenta "
|
|
1831
|
+
"governs (strings, alt text, accessible names, a11y variants, reading "
|
|
1832
|
+
"level), evaluated PER LOCALE with a level-AA score. Reports the "
|
|
1833
|
+
"success criteria decidable from content (1.1.1, 1.3.1, 2.4.4, 2.4.9, "
|
|
1834
|
+
"3.1.1, 3.1.2, 3.1.5, 4.1.2); SC requiring the rendered DOM (contrast, "
|
|
1835
|
+
"keyboard, focus) appear ONLY under scope.out_of_scope_sc and are NEVER "
|
|
1836
|
+
"counted as pass. AAA criteria (2.4.9, 3.1.5) are shown but EXCLUDED "
|
|
1837
|
+
"from the AA score. conformance.score_pct is the headline AA number "
|
|
1838
|
+
"(with per-locale breakdown). Read scope.content_layer_sc dynamically — "
|
|
1839
|
+
"do not hardcode the SC list. Defaults to the production version. "
|
|
1840
|
+
"0-credit, read-only."
|
|
1841
|
+
),
|
|
1842
|
+
inputSchema={
|
|
1843
|
+
"type": "object",
|
|
1844
|
+
"properties": {
|
|
1845
|
+
"project_uuid": {
|
|
1846
|
+
"type": "string",
|
|
1847
|
+
"description": "Project UUID. Required when multiple projects are configured (SONENTA_PROJECTS); defaults to the single configured project otherwise.",
|
|
1848
|
+
},
|
|
1849
|
+
"version_id": {
|
|
1850
|
+
"type": "string",
|
|
1851
|
+
"description": "Optional version UUID; defaults to the production version.",
|
|
1852
|
+
},
|
|
1853
|
+
},
|
|
1854
|
+
"additionalProperties": False,
|
|
1855
|
+
},
|
|
1856
|
+
),
|
|
1857
|
+
Tool(
|
|
1858
|
+
name="eaa_statement",
|
|
1859
|
+
description=(
|
|
1860
|
+
"Read-only EAA / EN 301 549 accessibility conformance STATEMENT for the "
|
|
1861
|
+
"content layer, per project x locale set (JSON). Maps each covered WCAG "
|
|
1862
|
+
"2.2 SC to its EN 301 549 clause (e.g. 1.1.1 -> 9.1.1.1) and reports "
|
|
1863
|
+
"{org, product, version, level:'AA', score_aa_percent, generated_at, "
|
|
1864
|
+
"standard, criteria_summary[], scope_statement:{attested[], "
|
|
1865
|
+
"out_of_scope[]}, contact}. Honest scope: attests alt-text / labels / "
|
|
1866
|
+
"language / plain-language per locale; the rendered-DOM audit is out of "
|
|
1867
|
+
"scope. Defaults to the production version. 0-credit, read-only."
|
|
1868
|
+
),
|
|
1869
|
+
inputSchema={
|
|
1870
|
+
"type": "object",
|
|
1871
|
+
"properties": {
|
|
1872
|
+
"project_uuid": {
|
|
1873
|
+
"type": "string",
|
|
1874
|
+
"description": "Project UUID. Required when multiple projects are configured (SONENTA_PROJECTS); defaults to the single configured project otherwise.",
|
|
1875
|
+
},
|
|
1876
|
+
"version_id": {
|
|
1877
|
+
"type": "string",
|
|
1878
|
+
"description": "Optional version UUID; defaults to the production version.",
|
|
1879
|
+
},
|
|
1880
|
+
},
|
|
1881
|
+
"additionalProperties": False,
|
|
1882
|
+
},
|
|
1883
|
+
),
|
|
1884
|
+
Tool(
|
|
1885
|
+
name="a11y_remediation_plan_get",
|
|
1886
|
+
description=(
|
|
1887
|
+
"Read the a11y REMEDIATION PLAN for the project (or null if none "
|
|
1888
|
+
"exists). The plan is authored/approved in the dashboard; this tool "
|
|
1889
|
+
"OBSERVES it. Shape: {version_uuid, status (draft|approved), "
|
|
1890
|
+
"approved_at, plan:{items:[{key_uuid, locale, surface, decision "
|
|
1891
|
+
"(apply|ignore), reason?, value?}]}}. The backend mutates nothing on "
|
|
1892
|
+
"PUT/approve — once status=approved, call a11y_remediation_plan_apply "
|
|
1893
|
+
"to bulk-execute it. Defaults to the production version. Read-only."
|
|
1894
|
+
),
|
|
1895
|
+
inputSchema={
|
|
1896
|
+
"type": "object",
|
|
1897
|
+
"properties": {
|
|
1898
|
+
"project_uuid": {
|
|
1899
|
+
"type": "string",
|
|
1900
|
+
"description": "Project UUID. Required when multiple projects are configured (SONENTA_PROJECTS); defaults to the single configured project otherwise.",
|
|
1901
|
+
},
|
|
1902
|
+
"version_id": {
|
|
1903
|
+
"type": "string",
|
|
1904
|
+
"description": "Optional version UUID; defaults to the production version.",
|
|
1905
|
+
},
|
|
1906
|
+
},
|
|
1907
|
+
"additionalProperties": False,
|
|
1908
|
+
},
|
|
1909
|
+
),
|
|
1910
|
+
Tool(
|
|
1911
|
+
name="a11y_remediation_plan_apply",
|
|
1912
|
+
description=(
|
|
1913
|
+
"EXECUTE the APPROVED a11y remediation plan — the agent's bulk-execute "
|
|
1914
|
+
"entrypoint. Only acts on a plan whose status=approved (poll "
|
|
1915
|
+
"a11y_remediation_plan_get first); a draft/absent plan is rejected. For "
|
|
1916
|
+
"each 'apply' item it writes the a11y variant (the item's value, else "
|
|
1917
|
+
"the current draft override) via the normal variant overlay — "
|
|
1918
|
+
"non-destructive and reversible (trashable/restorable). 'ignore' items "
|
|
1919
|
+
"persistently suppress that (key, locale, surface) cell. Returns the "
|
|
1920
|
+
"execution summary. Defaults to the production version."
|
|
1921
|
+
),
|
|
1922
|
+
inputSchema={
|
|
1923
|
+
"type": "object",
|
|
1924
|
+
"properties": {
|
|
1925
|
+
"project_uuid": {
|
|
1926
|
+
"type": "string",
|
|
1927
|
+
"description": "Project UUID. Required when multiple projects are configured (SONENTA_PROJECTS); defaults to the single configured project otherwise.",
|
|
1928
|
+
},
|
|
1929
|
+
"version_id": {
|
|
1930
|
+
"type": "string",
|
|
1931
|
+
"description": "Optional version UUID; defaults to the production version.",
|
|
1932
|
+
},
|
|
1933
|
+
},
|
|
1934
|
+
"additionalProperties": False,
|
|
1935
|
+
},
|
|
1936
|
+
),
|
|
1937
|
+
Tool(
|
|
1938
|
+
name="score_cognitive_local",
|
|
1939
|
+
description=(
|
|
1940
|
+
"Compute and persist cognitive-difficulty scores from a VALIDATED, "
|
|
1941
|
+
"deterministic READABILITY metric — the local-first, **0-credit**, "
|
|
1942
|
+
"no-AI path (SC 3.1.5). English uses Flesch-Kincaid; every other "
|
|
1943
|
+
"language uses LIX, both normalised to difficulty 0-100 (higher = "
|
|
1944
|
+
"harder) with a per-language threshold. Writes cognitive_score for the "
|
|
1945
|
+
"scoped keys; a key enters the reading_level_high queue once its score "
|
|
1946
|
+
">= the project threshold. Prefer this over analyze_cognitive (billed "
|
|
1947
|
+
"AI) for difficulty scoring. Scope with key_uuids and/or namespace_uuid "
|
|
1948
|
+
"(omit both = whole project). Returns the scoring summary."
|
|
1949
|
+
),
|
|
1950
|
+
inputSchema={
|
|
1951
|
+
"type": "object",
|
|
1952
|
+
"properties": {
|
|
1953
|
+
"project_uuid": {
|
|
1954
|
+
"type": "string",
|
|
1955
|
+
"description": "Project UUID. Required when multiple projects are configured (SONENTA_PROJECTS); defaults to the single configured project otherwise.",
|
|
1956
|
+
},
|
|
1957
|
+
"key_uuids": {
|
|
1958
|
+
"type": "array",
|
|
1959
|
+
"items": {"type": "string"},
|
|
1960
|
+
"description": "Restrict scoring to these keys. Omit to scope the whole project (or a namespace).",
|
|
1961
|
+
},
|
|
1962
|
+
"namespace_uuid": {
|
|
1963
|
+
"type": "string",
|
|
1964
|
+
"description": "Restrict scoring to one namespace by its UUID.",
|
|
1965
|
+
},
|
|
1966
|
+
"overwrite": {
|
|
1967
|
+
"type": "boolean",
|
|
1968
|
+
"description": "Re-score keys that already have a cognitive_score (default false = only score unscored keys).",
|
|
1969
|
+
},
|
|
1970
|
+
},
|
|
1971
|
+
"additionalProperties": False,
|
|
1972
|
+
},
|
|
1973
|
+
),
|
|
1753
1974
|
# --- Source Health: duplicate source strings (#1116; backend #1114, PR #147) ---
|
|
1754
1975
|
Tool(
|
|
1755
1976
|
name="list_source_duplicates",
|
|
@@ -2339,6 +2560,29 @@ def register(server: Server, client: VerbumiaClient) -> tuple[Any, Any]:
|
|
|
2339
2560
|
return _err("slug is required")
|
|
2340
2561
|
await client.delete(f"/v1/mcp/projects/{project_uuid}/surfaces/{slug}")
|
|
2341
2562
|
return _text({"deleted": True, "slug": slug})
|
|
2563
|
+
if name == "recommend_surfaces":
|
|
2564
|
+
project_uuid = _project_uuid(args, client)
|
|
2565
|
+
params: dict[str, Any] = {}
|
|
2566
|
+
for opt in ("version_id", "namespace_id", "key_id"):
|
|
2567
|
+
if args.get(opt):
|
|
2568
|
+
params[opt] = args[opt]
|
|
2569
|
+
if args.get("only_gaps"):
|
|
2570
|
+
params["only_gaps"] = "true"
|
|
2571
|
+
data = await client.get(
|
|
2572
|
+
f"/v1/mcp/projects/{project_uuid}/recommend-surfaces",
|
|
2573
|
+
params=params,
|
|
2574
|
+
)
|
|
2575
|
+
return _text(data)
|
|
2576
|
+
if name == "surface_coverage":
|
|
2577
|
+
project_uuid = _project_uuid(args, client)
|
|
2578
|
+
params: dict[str, Any] = {}
|
|
2579
|
+
if args.get("version_id"):
|
|
2580
|
+
params["version_id"] = args["version_id"]
|
|
2581
|
+
data = await client.get(
|
|
2582
|
+
f"/v1/mcp/projects/{project_uuid}/surface-coverage",
|
|
2583
|
+
params=params,
|
|
2584
|
+
)
|
|
2585
|
+
return _text(data)
|
|
2342
2586
|
if name == "get_variants":
|
|
2343
2587
|
project_uuid = _project_uuid(args, client)
|
|
2344
2588
|
key_uuid = args.get("key_uuid")
|
|
@@ -2419,6 +2663,48 @@ def register(server: Server, client: VerbumiaClient) -> tuple[Any, Any]:
|
|
|
2419
2663
|
f"/v1/mcp/projects/{project_uuid}/cognitive/analyze", json=body
|
|
2420
2664
|
)
|
|
2421
2665
|
return _text(data)
|
|
2666
|
+
# --- a11y conformance reports + remediation plan (sprint 111c4658, B5) ---
|
|
2667
|
+
if name in ("wcag_report", "eaa_statement"):
|
|
2668
|
+
project_uuid = _project_uuid(args, client)
|
|
2669
|
+
params: dict[str, Any] = {}
|
|
2670
|
+
if args.get("version_id"):
|
|
2671
|
+
params["version_id"] = args["version_id"]
|
|
2672
|
+
segment = "wcag-report" if name == "wcag_report" else "eaa-statement"
|
|
2673
|
+
data = await client.get(
|
|
2674
|
+
f"/v1/mcp/projects/{project_uuid}/{segment}", params=params
|
|
2675
|
+
)
|
|
2676
|
+
return _text(data)
|
|
2677
|
+
if name == "a11y_remediation_plan_get":
|
|
2678
|
+
project_uuid = _project_uuid(args, client)
|
|
2679
|
+
params: dict[str, Any] = {}
|
|
2680
|
+
if args.get("version_id"):
|
|
2681
|
+
params["version_id"] = args["version_id"]
|
|
2682
|
+
data = await client.get(
|
|
2683
|
+
f"/v1/mcp/projects/{project_uuid}/a11y/remediation-plan", params=params
|
|
2684
|
+
)
|
|
2685
|
+
return _text(data)
|
|
2686
|
+
if name == "a11y_remediation_plan_apply":
|
|
2687
|
+
project_uuid = _project_uuid(args, client)
|
|
2688
|
+
body: dict[str, Any] = {}
|
|
2689
|
+
if args.get("version_id"):
|
|
2690
|
+
body["version_id"] = args["version_id"]
|
|
2691
|
+
data = await client.post(
|
|
2692
|
+
f"/v1/mcp/projects/{project_uuid}/a11y/remediation-plan/apply",
|
|
2693
|
+
json=body,
|
|
2694
|
+
)
|
|
2695
|
+
return _text(data)
|
|
2696
|
+
if name == "score_cognitive_local":
|
|
2697
|
+
project_uuid = _project_uuid(args, client)
|
|
2698
|
+
body: dict[str, Any] = {}
|
|
2699
|
+
for opt in ("key_uuids", "namespace_uuid"):
|
|
2700
|
+
if args.get(opt):
|
|
2701
|
+
body[opt] = args[opt]
|
|
2702
|
+
if args.get("overwrite"):
|
|
2703
|
+
body["overwrite"] = True
|
|
2704
|
+
data = await client.post(
|
|
2705
|
+
f"/v1/mcp/projects/{project_uuid}/cognitive/score-local", json=body
|
|
2706
|
+
)
|
|
2707
|
+
return _text(data)
|
|
2422
2708
|
# --- Source Health: duplicates (#1116; backend #1114, PR #147) ---
|
|
2423
2709
|
if name == "list_source_duplicates":
|
|
2424
2710
|
project_uuid = _project_uuid(args, client)
|
|
Binary file
|