@sonenta/mcp 0.29.0 → 0.31.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.31.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.31.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,16 +89,20 @@ 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
|
|
93
|
-
# duplicate group —
|
|
94
|
-
#
|
|
95
|
-
#
|
|
92
|
+
# RS1 (task 1367) + FM1 (task 1390): audit trail of code edits an agent made while
|
|
93
|
+
# resolving a duplicate group — accepted on ALL FOUR resolution paths
|
|
94
|
+
# (set_source_duplicate_merge_plan, set_duplicate_status, apply_new_key_cluster,
|
|
95
|
+
# mark_cluster_applied), persisted + surfaced in resolved_duplicates[]. FM1 changed
|
|
96
|
+
# the semantics to UNION-MERGE (accumulate + dedup by tuple), not overwrite.
|
|
96
97
|
_FILES_MODIFIED_SCHEMA = {
|
|
97
98
|
"type": "array",
|
|
98
99
|
"description": (
|
|
99
100
|
"Optional audit trail of the code edits you made (e.g. t() repoints) while "
|
|
100
|
-
"resolving this group: each {path (required), line?, key_name?}.
|
|
101
|
-
"
|
|
101
|
+
"resolving this group: each {path (required), line?, key_name?}. Accepted on "
|
|
102
|
+
"every resolution path and MERGED (union + dedup by the full {path,line,"
|
|
103
|
+
"key_name} tuple) into the record — so record your edits at whatever step you "
|
|
104
|
+
"make them and they accumulate; omit to preserve the existing list. Always "
|
|
105
|
+
"pass the STRUCTURED field, never just a note."
|
|
102
106
|
),
|
|
103
107
|
"items": {
|
|
104
108
|
"type": "object",
|
|
@@ -2225,13 +2229,26 @@ def register(server: Server, client: VerbumiaClient) -> tuple[Any, Any]:
|
|
|
2225
2229
|
"items": {
|
|
2226
2230
|
"type": "object",
|
|
2227
2231
|
"properties": {
|
|
2228
|
-
"canonical_key_uuid": {
|
|
2232
|
+
"canonical_key_uuid": {
|
|
2233
|
+
"type": "string",
|
|
2234
|
+
"description": "An EXISTING key kept as the canonical survivor. Mutually exclusive with new_key.",
|
|
2235
|
+
},
|
|
2236
|
+
"new_key": {
|
|
2237
|
+
"type": "object",
|
|
2238
|
+
"description": "Create a BRAND-NEW canonical key instead of keeping an existing one (NK1). Mutually exclusive with canonical_key_uuid. For a new_key cluster, redundant_key_uuids = ALL the group's keys (none survives). After authoring, call apply_new_key_cluster — the backend creates the key + copies translations + trashes the old keys.",
|
|
2239
|
+
"properties": {
|
|
2240
|
+
"name": {"type": "string", "description": "New key name (must not collide with an active key)."},
|
|
2241
|
+
"namespace": {"type": "string", "description": "Namespace slug the new key lives in (must exist)."},
|
|
2242
|
+
},
|
|
2243
|
+
"required": ["name", "namespace"],
|
|
2244
|
+
},
|
|
2229
2245
|
"redundant_key_uuids": {
|
|
2230
2246
|
"type": "array",
|
|
2231
2247
|
"items": {"type": "string"},
|
|
2248
|
+
"description": "Keys folded into the canonical. For a new_key cluster, this is ALL the group's keys.",
|
|
2232
2249
|
},
|
|
2233
2250
|
},
|
|
2234
|
-
"required": ["
|
|
2251
|
+
"required": ["redundant_key_uuids"],
|
|
2235
2252
|
},
|
|
2236
2253
|
},
|
|
2237
2254
|
"survivor_outcome": {
|
|
@@ -2278,11 +2295,55 @@ def register(server: Server, client: VerbumiaClient) -> tuple[Any, Any]:
|
|
|
2278
2295
|
"type": "boolean",
|
|
2279
2296
|
"description": "True to mark applied (default), false to un-mark.",
|
|
2280
2297
|
},
|
|
2298
|
+
"files_modified": _FILES_MODIFIED_SCHEMA,
|
|
2281
2299
|
},
|
|
2282
2300
|
"required": ["source_value", "canonical_key_uuid"],
|
|
2283
2301
|
"additionalProperties": False,
|
|
2284
2302
|
},
|
|
2285
2303
|
),
|
|
2304
|
+
Tool(
|
|
2305
|
+
name="apply_new_key_cluster",
|
|
2306
|
+
description=(
|
|
2307
|
+
"Consolidate a duplicate group onto a BRAND-NEW canonical key (NK1) — "
|
|
2308
|
+
"the BACKEND does the atomic data transaction so no translation is "
|
|
2309
|
+
"lost: it creates the new key (type/description/context inherited from "
|
|
2310
|
+
"the group's most-complete key), COPIES every language value from that "
|
|
2311
|
+
"most-complete key, and TRASHES all the old keys. Address it by "
|
|
2312
|
+
"source_value + new_key {name, namespace} (the namespace must exist and "
|
|
2313
|
+
"the name must be free). Returns {new_key_uuid, name, namespace, "
|
|
2314
|
+
"copied_from_key_uuid, copied_languages, trashed_key_uuids}. YOUR job "
|
|
2315
|
+
"after this is the CODE only: repoint every t() usage of the trashed "
|
|
2316
|
+
"keys onto new_key_uuid, and record those edits in `files_modified` "
|
|
2317
|
+
"(accepted right here, union-merged). You do NOT create_key or "
|
|
2318
|
+
"delete_keys_bulk yourself — the backend owns that. Author the "
|
|
2319
|
+
"new_key cluster in the merge plan first (on the dev's acceptance)."
|
|
2320
|
+
),
|
|
2321
|
+
inputSchema={
|
|
2322
|
+
"type": "object",
|
|
2323
|
+
"properties": {
|
|
2324
|
+
"project_uuid": {
|
|
2325
|
+
"type": "string",
|
|
2326
|
+
"description": "Project UUID. Required when multiple projects are configured (SONENTA_PROJECTS); defaults to the single configured project otherwise.",
|
|
2327
|
+
},
|
|
2328
|
+
"source_value": {
|
|
2329
|
+
"type": "string",
|
|
2330
|
+
"description": "The shared source-language value identifying the duplicate group.",
|
|
2331
|
+
},
|
|
2332
|
+
"new_key": {
|
|
2333
|
+
"type": "object",
|
|
2334
|
+
"description": "The new canonical key to create and consolidate the group onto.",
|
|
2335
|
+
"properties": {
|
|
2336
|
+
"name": {"type": "string", "description": "New key name (must not collide with an active key)."},
|
|
2337
|
+
"namespace": {"type": "string", "description": "Namespace slug the new key lives in (must exist)."},
|
|
2338
|
+
},
|
|
2339
|
+
"required": ["name", "namespace"],
|
|
2340
|
+
},
|
|
2341
|
+
"files_modified": _FILES_MODIFIED_SCHEMA,
|
|
2342
|
+
},
|
|
2343
|
+
"required": ["source_value", "new_key"],
|
|
2344
|
+
"additionalProperties": False,
|
|
2345
|
+
},
|
|
2346
|
+
),
|
|
2286
2347
|
]
|
|
2287
2348
|
|
|
2288
2349
|
@server.call_tool()
|
|
@@ -3033,11 +3094,28 @@ def register(server: Server, client: VerbumiaClient) -> tuple[Any, Any]:
|
|
|
3033
3094
|
}
|
|
3034
3095
|
if "applied" in args:
|
|
3035
3096
|
body["applied"] = bool(args["applied"])
|
|
3097
|
+
if args.get("files_modified"):
|
|
3098
|
+
body["files_modified"] = args["files_modified"]
|
|
3036
3099
|
data = await client.put(
|
|
3037
3100
|
f"/v1/mcp/projects/{project_uuid}/source-duplicates/cluster-applied",
|
|
3038
3101
|
json=body,
|
|
3039
3102
|
)
|
|
3040
3103
|
return _text(data)
|
|
3104
|
+
if name == "apply_new_key_cluster":
|
|
3105
|
+
project_uuid = _project_uuid(args, client)
|
|
3106
|
+
new_key = args.get("new_key")
|
|
3107
|
+
if not args.get("source_value") or not isinstance(new_key, dict):
|
|
3108
|
+
return _err("source_value and new_key {name, namespace} are required")
|
|
3109
|
+
if not new_key.get("name") or not new_key.get("namespace"):
|
|
3110
|
+
return _err("new_key requires name and namespace")
|
|
3111
|
+
body = {"source_value": args["source_value"], "new_key": new_key}
|
|
3112
|
+
if args.get("files_modified"):
|
|
3113
|
+
body["files_modified"] = args["files_modified"]
|
|
3114
|
+
data = await client.post(
|
|
3115
|
+
f"/v1/mcp/projects/{project_uuid}/source-duplicates/apply-cluster",
|
|
3116
|
+
json=body,
|
|
3117
|
+
)
|
|
3118
|
+
return _text(data)
|
|
3041
3119
|
return _err(f"unknown tool: {name}")
|
|
3042
3120
|
except VerbumiaApiError as exc:
|
|
3043
3121
|
return _err(f"API {exc.status}: {exc.body}")
|
|
Binary file
|