@sonenta/mcp 0.27.0 → 0.29.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.29.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.29.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"
|
|
@@ -89,6 +89,29 @@ from .client import VerbumiaApiError, VerbumiaClient
|
|
|
89
89
|
# visible text. `surfaceKinds` in the variants matrix tags each as a11y.
|
|
90
90
|
A11Y_SURFACES = ("aria_label", "alt_text", "screen_reader", "plain_language")
|
|
91
91
|
|
|
92
|
+
# RS1 (task 1367): audit trail of code edits an agent made while resolving a
|
|
93
|
+
# duplicate group — passed on set_source_duplicate_merge_plan / set_duplicate_status,
|
|
94
|
+
# persisted + surfaced in resolved_duplicates[]. Supplying it overwrites; omitting
|
|
95
|
+
# preserves the prior value.
|
|
96
|
+
_FILES_MODIFIED_SCHEMA = {
|
|
97
|
+
"type": "array",
|
|
98
|
+
"description": (
|
|
99
|
+
"Optional audit trail of the code edits you made (e.g. t() repoints) while "
|
|
100
|
+
"resolving this group: each {path (required), line?, key_name?}. Supplying it "
|
|
101
|
+
"overwrites the stored record; omit to preserve the prior value."
|
|
102
|
+
),
|
|
103
|
+
"items": {
|
|
104
|
+
"type": "object",
|
|
105
|
+
"properties": {
|
|
106
|
+
"path": {"type": "string", "description": "Repo-relative file path that was edited."},
|
|
107
|
+
"line": {"type": "integer", "description": "Optional 1-based line number of the edit."},
|
|
108
|
+
"key_name": {"type": "string", "description": "Optional key (namespace::name or name) the edit concerns."},
|
|
109
|
+
},
|
|
110
|
+
"required": ["path"],
|
|
111
|
+
"additionalProperties": False,
|
|
112
|
+
},
|
|
113
|
+
}
|
|
114
|
+
|
|
92
115
|
# Key semantic types (a11y key.type pivot). Default "text". The type decides
|
|
93
116
|
# which a11y treatments a key offers (e.g. an `image` key's base value IS its
|
|
94
117
|
# alt text; a `button` offers aria_label) — the engine gates variant/a11y tools
|
|
@@ -2158,11 +2181,108 @@ def register(server: Server, client: VerbumiaClient) -> tuple[Any, Any]:
|
|
|
2158
2181
|
"type": "string",
|
|
2159
2182
|
"description": "Optional human/agent note recording why the status was set (audit trail).",
|
|
2160
2183
|
},
|
|
2184
|
+
"files_modified": _FILES_MODIFIED_SCHEMA,
|
|
2161
2185
|
},
|
|
2162
2186
|
"required": ["source_value", "status"],
|
|
2163
2187
|
"additionalProperties": False,
|
|
2164
2188
|
},
|
|
2165
2189
|
),
|
|
2190
|
+
# --- Source Health: agent-authored merge plan + per-cluster applied
|
|
2191
|
+
# marking (task 1363; backend PR #183 + cluster-applied route) ---
|
|
2192
|
+
Tool(
|
|
2193
|
+
name="set_source_duplicate_merge_plan",
|
|
2194
|
+
description=(
|
|
2195
|
+
"AUTHOR (or clear) the merge plan for one duplicate group, addressed "
|
|
2196
|
+
"by its shared source_value (Source Health duplicates). This is how "
|
|
2197
|
+
"the sonenta-source-health agent records the CONSOLIDATION it proposes "
|
|
2198
|
+
"and the dev accepted: which keys collapse onto which canonical, and "
|
|
2199
|
+
"what to do with whatever still shares the text. `merge_plan` = "
|
|
2200
|
+
"{clusters:[{canonical_key_uuid, redundant_key_uuids:[...]}], "
|
|
2201
|
+
"survivor_outcome:'allowed'|'differentiate'} — or null/omit to CLEAR "
|
|
2202
|
+
"the plan. Saving a plan sets the group's status to to_fix. After "
|
|
2203
|
+
"authoring, the agent repoints t() usages, trashes the redundant keys "
|
|
2204
|
+
"(delete_keys_bulk), marks each cluster applied (mark_cluster_applied), "
|
|
2205
|
+
"and finally set_duplicate_status(resolved). Author only a plan the "
|
|
2206
|
+
"dev accepted — never decide a merge silently."
|
|
2207
|
+
),
|
|
2208
|
+
inputSchema={
|
|
2209
|
+
"type": "object",
|
|
2210
|
+
"properties": {
|
|
2211
|
+
"project_uuid": {
|
|
2212
|
+
"type": "string",
|
|
2213
|
+
"description": "Project UUID. Required when multiple projects are configured (SONENTA_PROJECTS); defaults to the single configured project otherwise.",
|
|
2214
|
+
},
|
|
2215
|
+
"source_value": {
|
|
2216
|
+
"type": "string",
|
|
2217
|
+
"description": "The shared source-language value identifying the duplicate group (from list_source_duplicates).",
|
|
2218
|
+
},
|
|
2219
|
+
"merge_plan": {
|
|
2220
|
+
"type": ["object", "null"],
|
|
2221
|
+
"description": "The consolidation plan, or null to clear it.",
|
|
2222
|
+
"properties": {
|
|
2223
|
+
"clusters": {
|
|
2224
|
+
"type": "array",
|
|
2225
|
+
"items": {
|
|
2226
|
+
"type": "object",
|
|
2227
|
+
"properties": {
|
|
2228
|
+
"canonical_key_uuid": {"type": "string"},
|
|
2229
|
+
"redundant_key_uuids": {
|
|
2230
|
+
"type": "array",
|
|
2231
|
+
"items": {"type": "string"},
|
|
2232
|
+
},
|
|
2233
|
+
},
|
|
2234
|
+
"required": ["canonical_key_uuid", "redundant_key_uuids"],
|
|
2235
|
+
},
|
|
2236
|
+
},
|
|
2237
|
+
"survivor_outcome": {
|
|
2238
|
+
"type": "string",
|
|
2239
|
+
"enum": ["allowed", "differentiate"],
|
|
2240
|
+
"description": "What to do with survivors that still share the text: allowed (sanctioned duplicate) or differentiate (make distinct).",
|
|
2241
|
+
},
|
|
2242
|
+
},
|
|
2243
|
+
},
|
|
2244
|
+
"files_modified": _FILES_MODIFIED_SCHEMA,
|
|
2245
|
+
},
|
|
2246
|
+
"required": ["source_value"],
|
|
2247
|
+
"additionalProperties": False,
|
|
2248
|
+
},
|
|
2249
|
+
),
|
|
2250
|
+
Tool(
|
|
2251
|
+
name="mark_cluster_applied",
|
|
2252
|
+
description=(
|
|
2253
|
+
"Mark ONE cluster of a duplicate group's merge plan as APPLIED — "
|
|
2254
|
+
"addressed by the group's source_value + the cluster's "
|
|
2255
|
+
"canonical_key_uuid. Call it after you have repointed the redundant "
|
|
2256
|
+
"keys' t() usages onto the canonical and trashed them "
|
|
2257
|
+
"(delete_keys_bulk), so the dashboard tracks per-cluster progress. "
|
|
2258
|
+
"Pass applied=false to UN-mark it. Once every cluster of the group is "
|
|
2259
|
+
"applied (and the survivor_outcome handled), set_duplicate_status("
|
|
2260
|
+
"resolved) closes the group."
|
|
2261
|
+
),
|
|
2262
|
+
inputSchema={
|
|
2263
|
+
"type": "object",
|
|
2264
|
+
"properties": {
|
|
2265
|
+
"project_uuid": {
|
|
2266
|
+
"type": "string",
|
|
2267
|
+
"description": "Project UUID. Required when multiple projects are configured (SONENTA_PROJECTS); defaults to the single configured project otherwise.",
|
|
2268
|
+
},
|
|
2269
|
+
"source_value": {
|
|
2270
|
+
"type": "string",
|
|
2271
|
+
"description": "The shared source-language value identifying the duplicate group.",
|
|
2272
|
+
},
|
|
2273
|
+
"canonical_key_uuid": {
|
|
2274
|
+
"type": "string",
|
|
2275
|
+
"description": "The surviving canonical key of the cluster to mark applied.",
|
|
2276
|
+
},
|
|
2277
|
+
"applied": {
|
|
2278
|
+
"type": "boolean",
|
|
2279
|
+
"description": "True to mark applied (default), false to un-mark.",
|
|
2280
|
+
},
|
|
2281
|
+
},
|
|
2282
|
+
"required": ["source_value", "canonical_key_uuid"],
|
|
2283
|
+
"additionalProperties": False,
|
|
2284
|
+
},
|
|
2285
|
+
),
|
|
2166
2286
|
]
|
|
2167
2287
|
|
|
2168
2288
|
@server.call_tool()
|
|
@@ -2880,11 +3000,44 @@ def register(server: Server, client: VerbumiaClient) -> tuple[Any, Any]:
|
|
|
2880
3000
|
}
|
|
2881
3001
|
if args.get("note"):
|
|
2882
3002
|
body["note"] = args["note"]
|
|
3003
|
+
if args.get("files_modified"):
|
|
3004
|
+
body["files_modified"] = args["files_modified"]
|
|
2883
3005
|
data = await client.put(
|
|
2884
3006
|
f"/v1/mcp/projects/{project_uuid}/source-duplicates/status",
|
|
2885
3007
|
json=body,
|
|
2886
3008
|
)
|
|
2887
3009
|
return _text(data)
|
|
3010
|
+
if name == "set_source_duplicate_merge_plan":
|
|
3011
|
+
project_uuid = _project_uuid(args, client)
|
|
3012
|
+
if not args.get("source_value"):
|
|
3013
|
+
return _err("source_value is required")
|
|
3014
|
+
body = {"source_value": args["source_value"]}
|
|
3015
|
+
# merge_plan may be an object OR explicit null (to clear); send it
|
|
3016
|
+
# whenever the key is present at all.
|
|
3017
|
+
if "merge_plan" in args:
|
|
3018
|
+
body["merge_plan"] = args["merge_plan"]
|
|
3019
|
+
if args.get("files_modified"):
|
|
3020
|
+
body["files_modified"] = args["files_modified"]
|
|
3021
|
+
data = await client.put(
|
|
3022
|
+
f"/v1/mcp/projects/{project_uuid}/source-duplicates/merge-plan",
|
|
3023
|
+
json=body,
|
|
3024
|
+
)
|
|
3025
|
+
return _text(data)
|
|
3026
|
+
if name == "mark_cluster_applied":
|
|
3027
|
+
project_uuid = _project_uuid(args, client)
|
|
3028
|
+
if not args.get("source_value") or not args.get("canonical_key_uuid"):
|
|
3029
|
+
return _err("source_value and canonical_key_uuid are required")
|
|
3030
|
+
body = {
|
|
3031
|
+
"source_value": args["source_value"],
|
|
3032
|
+
"canonical_key_uuid": args["canonical_key_uuid"],
|
|
3033
|
+
}
|
|
3034
|
+
if "applied" in args:
|
|
3035
|
+
body["applied"] = bool(args["applied"])
|
|
3036
|
+
data = await client.put(
|
|
3037
|
+
f"/v1/mcp/projects/{project_uuid}/source-duplicates/cluster-applied",
|
|
3038
|
+
json=body,
|
|
3039
|
+
)
|
|
3040
|
+
return _text(data)
|
|
2888
3041
|
return _err(f"unknown tool: {name}")
|
|
2889
3042
|
except VerbumiaApiError as exc:
|
|
2890
3043
|
return _err(f"API {exc.status}: {exc.body}")
|
|
Binary file
|