@sonenta/mcp 0.26.0 → 0.28.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.28.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.28.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"
|
|
@@ -1881,6 +1881,76 @@ def register(server: Server, client: VerbumiaClient) -> tuple[Any, Any]:
|
|
|
1881
1881
|
"additionalProperties": False,
|
|
1882
1882
|
},
|
|
1883
1883
|
),
|
|
1884
|
+
Tool(
|
|
1885
|
+
name="list_a11y_review_queue",
|
|
1886
|
+
description=(
|
|
1887
|
+
"Read the a11y REVIEW QUEUE — the per-(key, locale, surface) review "
|
|
1888
|
+
"items with their state. Each item: {key_uuid, key_name, "
|
|
1889
|
+
"namespace_slug, surface, surface_kind, locale, state (missing | draft "
|
|
1890
|
+
"| translated | reviewed | approved | rejected), value, is_bot, gap, "
|
|
1891
|
+
"base_value, screenshots[], drift, ignored, ignore_reason, "
|
|
1892
|
+
"reject_reason}; the envelope carries by_state / by_surface rollups. "
|
|
1893
|
+
"**Pass state='rejected' to drive the RECTIFICATION loop**: a reviewer "
|
|
1894
|
+
"rejected a suggestion and left a `reject_reason` — the retained "
|
|
1895
|
+
"`value` is the rejected text and `reject_reason` is the human's "
|
|
1896
|
+
"instruction. The agent regenerates a corrected value addressing the "
|
|
1897
|
+
"reason and re-proposes via set_a11y_variant (rejected is unprotected, "
|
|
1898
|
+
"so it returns to draft). Defaults to the production version. READ-ONLY."
|
|
1899
|
+
),
|
|
1900
|
+
inputSchema={
|
|
1901
|
+
"type": "object",
|
|
1902
|
+
"properties": {
|
|
1903
|
+
"project_uuid": {
|
|
1904
|
+
"type": "string",
|
|
1905
|
+
"description": "Project UUID. Required when multiple projects are configured (SONENTA_PROJECTS); defaults to the single configured project otherwise.",
|
|
1906
|
+
},
|
|
1907
|
+
"version_id": {
|
|
1908
|
+
"type": "string",
|
|
1909
|
+
"description": "Optional version UUID; defaults to the production version.",
|
|
1910
|
+
},
|
|
1911
|
+
"state": {
|
|
1912
|
+
"type": "string",
|
|
1913
|
+
"enum": [
|
|
1914
|
+
"missing",
|
|
1915
|
+
"draft",
|
|
1916
|
+
"translated",
|
|
1917
|
+
"reviewed",
|
|
1918
|
+
"approved",
|
|
1919
|
+
"rejected",
|
|
1920
|
+
],
|
|
1921
|
+
"description": "Filter to one review state. Use 'rejected' for the rectification loop (items carry reject_reason).",
|
|
1922
|
+
},
|
|
1923
|
+
"locale": {
|
|
1924
|
+
"type": "string",
|
|
1925
|
+
"description": "Filter to one locale code (e.g. 'fr'). Use 'source' for source-locale rows.",
|
|
1926
|
+
},
|
|
1927
|
+
"surface": {
|
|
1928
|
+
"type": "string",
|
|
1929
|
+
"enum": list(A11Y_SURFACES),
|
|
1930
|
+
"description": "Filter to one a11y surface.",
|
|
1931
|
+
},
|
|
1932
|
+
"namespace_uuid": {
|
|
1933
|
+
"type": "string",
|
|
1934
|
+
"description": "Restrict to one namespace by its UUID.",
|
|
1935
|
+
},
|
|
1936
|
+
"key_uuid": {
|
|
1937
|
+
"type": "string",
|
|
1938
|
+
"description": "Restrict to one key by its UUID.",
|
|
1939
|
+
},
|
|
1940
|
+
"include_ignored": {
|
|
1941
|
+
"type": "boolean",
|
|
1942
|
+
"description": "Include items suppressed by the remediation plan (ignored cells). Default false.",
|
|
1943
|
+
},
|
|
1944
|
+
"group_by_key": {
|
|
1945
|
+
"type": "boolean",
|
|
1946
|
+
"description": "Aggregate items by key (one entry per key with its surfaces/locales nested) instead of a flat list.",
|
|
1947
|
+
},
|
|
1948
|
+
"limit": {"type": "integer", "minimum": 1, "maximum": 500},
|
|
1949
|
+
"offset": {"type": "integer", "minimum": 0},
|
|
1950
|
+
},
|
|
1951
|
+
"additionalProperties": False,
|
|
1952
|
+
},
|
|
1953
|
+
),
|
|
1884
1954
|
Tool(
|
|
1885
1955
|
name="a11y_remediation_plan_get",
|
|
1886
1956
|
description=(
|
|
@@ -2093,6 +2163,101 @@ def register(server: Server, client: VerbumiaClient) -> tuple[Any, Any]:
|
|
|
2093
2163
|
"additionalProperties": False,
|
|
2094
2164
|
},
|
|
2095
2165
|
),
|
|
2166
|
+
# --- Source Health: agent-authored merge plan + per-cluster applied
|
|
2167
|
+
# marking (task 1363; backend PR #183 + cluster-applied route) ---
|
|
2168
|
+
Tool(
|
|
2169
|
+
name="set_source_duplicate_merge_plan",
|
|
2170
|
+
description=(
|
|
2171
|
+
"AUTHOR (or clear) the merge plan for one duplicate group, addressed "
|
|
2172
|
+
"by its shared source_value (Source Health duplicates). This is how "
|
|
2173
|
+
"the sonenta-source-health agent records the CONSOLIDATION it proposes "
|
|
2174
|
+
"and the dev accepted: which keys collapse onto which canonical, and "
|
|
2175
|
+
"what to do with whatever still shares the text. `merge_plan` = "
|
|
2176
|
+
"{clusters:[{canonical_key_uuid, redundant_key_uuids:[...]}], "
|
|
2177
|
+
"survivor_outcome:'allowed'|'differentiate'} — or null/omit to CLEAR "
|
|
2178
|
+
"the plan. Saving a plan sets the group's status to to_fix. After "
|
|
2179
|
+
"authoring, the agent repoints t() usages, trashes the redundant keys "
|
|
2180
|
+
"(delete_keys_bulk), marks each cluster applied (mark_cluster_applied), "
|
|
2181
|
+
"and finally set_duplicate_status(resolved). Author only a plan the "
|
|
2182
|
+
"dev accepted — never decide a merge silently."
|
|
2183
|
+
),
|
|
2184
|
+
inputSchema={
|
|
2185
|
+
"type": "object",
|
|
2186
|
+
"properties": {
|
|
2187
|
+
"project_uuid": {
|
|
2188
|
+
"type": "string",
|
|
2189
|
+
"description": "Project UUID. Required when multiple projects are configured (SONENTA_PROJECTS); defaults to the single configured project otherwise.",
|
|
2190
|
+
},
|
|
2191
|
+
"source_value": {
|
|
2192
|
+
"type": "string",
|
|
2193
|
+
"description": "The shared source-language value identifying the duplicate group (from list_source_duplicates).",
|
|
2194
|
+
},
|
|
2195
|
+
"merge_plan": {
|
|
2196
|
+
"type": ["object", "null"],
|
|
2197
|
+
"description": "The consolidation plan, or null to clear it.",
|
|
2198
|
+
"properties": {
|
|
2199
|
+
"clusters": {
|
|
2200
|
+
"type": "array",
|
|
2201
|
+
"items": {
|
|
2202
|
+
"type": "object",
|
|
2203
|
+
"properties": {
|
|
2204
|
+
"canonical_key_uuid": {"type": "string"},
|
|
2205
|
+
"redundant_key_uuids": {
|
|
2206
|
+
"type": "array",
|
|
2207
|
+
"items": {"type": "string"},
|
|
2208
|
+
},
|
|
2209
|
+
},
|
|
2210
|
+
"required": ["canonical_key_uuid", "redundant_key_uuids"],
|
|
2211
|
+
},
|
|
2212
|
+
},
|
|
2213
|
+
"survivor_outcome": {
|
|
2214
|
+
"type": "string",
|
|
2215
|
+
"enum": ["allowed", "differentiate"],
|
|
2216
|
+
"description": "What to do with survivors that still share the text: allowed (sanctioned duplicate) or differentiate (make distinct).",
|
|
2217
|
+
},
|
|
2218
|
+
},
|
|
2219
|
+
},
|
|
2220
|
+
},
|
|
2221
|
+
"required": ["source_value"],
|
|
2222
|
+
"additionalProperties": False,
|
|
2223
|
+
},
|
|
2224
|
+
),
|
|
2225
|
+
Tool(
|
|
2226
|
+
name="mark_cluster_applied",
|
|
2227
|
+
description=(
|
|
2228
|
+
"Mark ONE cluster of a duplicate group's merge plan as APPLIED — "
|
|
2229
|
+
"addressed by the group's source_value + the cluster's "
|
|
2230
|
+
"canonical_key_uuid. Call it after you have repointed the redundant "
|
|
2231
|
+
"keys' t() usages onto the canonical and trashed them "
|
|
2232
|
+
"(delete_keys_bulk), so the dashboard tracks per-cluster progress. "
|
|
2233
|
+
"Pass applied=false to UN-mark it. Once every cluster of the group is "
|
|
2234
|
+
"applied (and the survivor_outcome handled), set_duplicate_status("
|
|
2235
|
+
"resolved) closes the group."
|
|
2236
|
+
),
|
|
2237
|
+
inputSchema={
|
|
2238
|
+
"type": "object",
|
|
2239
|
+
"properties": {
|
|
2240
|
+
"project_uuid": {
|
|
2241
|
+
"type": "string",
|
|
2242
|
+
"description": "Project UUID. Required when multiple projects are configured (SONENTA_PROJECTS); defaults to the single configured project otherwise.",
|
|
2243
|
+
},
|
|
2244
|
+
"source_value": {
|
|
2245
|
+
"type": "string",
|
|
2246
|
+
"description": "The shared source-language value identifying the duplicate group.",
|
|
2247
|
+
},
|
|
2248
|
+
"canonical_key_uuid": {
|
|
2249
|
+
"type": "string",
|
|
2250
|
+
"description": "The surviving canonical key of the cluster to mark applied.",
|
|
2251
|
+
},
|
|
2252
|
+
"applied": {
|
|
2253
|
+
"type": "boolean",
|
|
2254
|
+
"description": "True to mark applied (default), false to un-mark.",
|
|
2255
|
+
},
|
|
2256
|
+
},
|
|
2257
|
+
"required": ["source_value", "canonical_key_uuid"],
|
|
2258
|
+
"additionalProperties": False,
|
|
2259
|
+
},
|
|
2260
|
+
),
|
|
2096
2261
|
]
|
|
2097
2262
|
|
|
2098
2263
|
@server.call_tool()
|
|
@@ -2716,6 +2881,29 @@ def register(server: Server, client: VerbumiaClient) -> tuple[Any, Any]:
|
|
|
2716
2881
|
f"/v1/mcp/projects/{project_uuid}/{segment}", params=params
|
|
2717
2882
|
)
|
|
2718
2883
|
return _text(data)
|
|
2884
|
+
if name == "list_a11y_review_queue":
|
|
2885
|
+
project_uuid = _project_uuid(args, client)
|
|
2886
|
+
params: dict[str, Any] = {}
|
|
2887
|
+
for opt in (
|
|
2888
|
+
"version_id",
|
|
2889
|
+
"state",
|
|
2890
|
+
"locale",
|
|
2891
|
+
"surface",
|
|
2892
|
+
"namespace_uuid",
|
|
2893
|
+
"key_uuid",
|
|
2894
|
+
"limit",
|
|
2895
|
+
"offset",
|
|
2896
|
+
):
|
|
2897
|
+
if args.get(opt) is not None:
|
|
2898
|
+
params[opt] = args[opt]
|
|
2899
|
+
if args.get("include_ignored"):
|
|
2900
|
+
params["include_ignored"] = "true"
|
|
2901
|
+
if args.get("group_by_key"):
|
|
2902
|
+
params["group_by_key"] = "true"
|
|
2903
|
+
data = await client.get(
|
|
2904
|
+
f"/v1/mcp/projects/{project_uuid}/a11y/review/queue", params=params
|
|
2905
|
+
)
|
|
2906
|
+
return _text(data)
|
|
2719
2907
|
if name == "a11y_remediation_plan_get":
|
|
2720
2908
|
project_uuid = _project_uuid(args, client)
|
|
2721
2909
|
params: dict[str, Any] = {}
|
|
@@ -2792,6 +2980,35 @@ def register(server: Server, client: VerbumiaClient) -> tuple[Any, Any]:
|
|
|
2792
2980
|
json=body,
|
|
2793
2981
|
)
|
|
2794
2982
|
return _text(data)
|
|
2983
|
+
if name == "set_source_duplicate_merge_plan":
|
|
2984
|
+
project_uuid = _project_uuid(args, client)
|
|
2985
|
+
if not args.get("source_value"):
|
|
2986
|
+
return _err("source_value is required")
|
|
2987
|
+
body = {"source_value": args["source_value"]}
|
|
2988
|
+
# merge_plan may be an object OR explicit null (to clear); send it
|
|
2989
|
+
# whenever the key is present at all.
|
|
2990
|
+
if "merge_plan" in args:
|
|
2991
|
+
body["merge_plan"] = args["merge_plan"]
|
|
2992
|
+
data = await client.put(
|
|
2993
|
+
f"/v1/mcp/projects/{project_uuid}/source-duplicates/merge-plan",
|
|
2994
|
+
json=body,
|
|
2995
|
+
)
|
|
2996
|
+
return _text(data)
|
|
2997
|
+
if name == "mark_cluster_applied":
|
|
2998
|
+
project_uuid = _project_uuid(args, client)
|
|
2999
|
+
if not args.get("source_value") or not args.get("canonical_key_uuid"):
|
|
3000
|
+
return _err("source_value and canonical_key_uuid are required")
|
|
3001
|
+
body = {
|
|
3002
|
+
"source_value": args["source_value"],
|
|
3003
|
+
"canonical_key_uuid": args["canonical_key_uuid"],
|
|
3004
|
+
}
|
|
3005
|
+
if "applied" in args:
|
|
3006
|
+
body["applied"] = bool(args["applied"])
|
|
3007
|
+
data = await client.put(
|
|
3008
|
+
f"/v1/mcp/projects/{project_uuid}/source-duplicates/cluster-applied",
|
|
3009
|
+
json=body,
|
|
3010
|
+
)
|
|
3011
|
+
return _text(data)
|
|
2795
3012
|
return _err(f"unknown tool: {name}")
|
|
2796
3013
|
except VerbumiaApiError as exc:
|
|
2797
3014
|
return _err(f"API {exc.status}: {exc.body}")
|
|
Binary file
|