@sonenta/mcp 0.18.0 → 0.20.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.20.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.20.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"
|
|
@@ -9,9 +9,9 @@ Tools (V1 MCP surface; glossary_* added 2026-05-24; reports + trash added 2026-0
|
|
|
9
9
|
- missing_keys_stats — count-only summary of missing events (drives pagination)
|
|
10
10
|
- acknowledge_missing_keys— batch-resolve missing events (cleanup the dashboard)
|
|
11
11
|
- create_namespace — idempotent namespace creation (slug validated, slug_invalid on bad input)
|
|
12
|
-
- create_key — idempotent key creation
|
|
12
|
+
- create_key — idempotent key creation; optionally seeds source value + sets semantic `type`
|
|
13
13
|
- create_keys_bulk — batch create_key (up to 500/call, per-item results)
|
|
14
|
-
- update_key — edit a key's SOURCE value in place (PATCH); demotes reviewed/approved targets to needs-review
|
|
14
|
+
- update_key — edit a key's SOURCE value / `type` / description in place (PATCH); demotes reviewed/approved targets to needs-review
|
|
15
15
|
- update_keys_bulk — batch update_key (up to 500/call, per-item results)
|
|
16
16
|
- propose_translation — submit a translation value (auto-creates the key if missing)
|
|
17
17
|
- propose_translations_bulk— batch propose_translation (up to 500/call, per-item results)
|
|
@@ -42,6 +42,9 @@ Tools (V1 MCP surface; glossary_* added 2026-05-24; reports + trash added 2026-0
|
|
|
42
42
|
- get_variants — full variant matrix for one key (every active surface x language; #928)
|
|
43
43
|
- set_variant — upsert one variant override for ANY active surface (device or a11y)
|
|
44
44
|
- delete_variant — delete one variant override for any surface (cell re-inherits base)
|
|
45
|
+
- list_cognitive_candidates — text keys eligible for plain-language (cognitive) scoring
|
|
46
|
+
- set_cognitive_score — record a key's cognitive score (0-100) + plain-language suggestion (0 credit)
|
|
47
|
+
- analyze_cognitive — server AI cognitive analysis (billed; opt-in fallback to local scoring)
|
|
45
48
|
|
|
46
49
|
A11y (accessibility) tools (a11y V1) extend the variant engine with four SEMANTIC
|
|
47
50
|
surfaces — aria_label / alt_text / screen_reader / plain_language — orthogonal to
|
|
@@ -84,6 +87,30 @@ from .client import VerbumiaApiError, VerbumiaClient
|
|
|
84
87
|
# visible text. `surfaceKinds` in the variants matrix tags each as a11y.
|
|
85
88
|
A11Y_SURFACES = ("aria_label", "alt_text", "screen_reader", "plain_language")
|
|
86
89
|
|
|
90
|
+
# Key semantic types (a11y key.type pivot). Default "text". The type decides
|
|
91
|
+
# which a11y treatments a key offers (e.g. an `image` key's base value IS its
|
|
92
|
+
# alt text; a `button` offers aria_label) — the engine gates variant/a11y tools
|
|
93
|
+
# by type server-side, so listing these here is just for create/update_key.
|
|
94
|
+
KEY_TYPES = (
|
|
95
|
+
"text",
|
|
96
|
+
"heading",
|
|
97
|
+
"label",
|
|
98
|
+
"caption",
|
|
99
|
+
"badge",
|
|
100
|
+
"tooltip",
|
|
101
|
+
"error_message",
|
|
102
|
+
"toast",
|
|
103
|
+
"button",
|
|
104
|
+
"link",
|
|
105
|
+
"menu_item",
|
|
106
|
+
"input_placeholder",
|
|
107
|
+
"input_label",
|
|
108
|
+
"image",
|
|
109
|
+
"icon",
|
|
110
|
+
"meta_title",
|
|
111
|
+
"meta_description",
|
|
112
|
+
)
|
|
113
|
+
|
|
87
114
|
|
|
88
115
|
def _project_uuid(arguments: dict | None, client: VerbumiaClient) -> str:
|
|
89
116
|
"""Resolve project_uuid from per-call args or the configured env scope.
|
|
@@ -371,7 +398,8 @@ def register(server: Server, client: VerbumiaClient) -> tuple[Any, Any]:
|
|
|
371
398
|
"Returns created=false if the key already exists. When "
|
|
372
399
|
"source_value is supplied AND the project has a source "
|
|
373
400
|
"language, the value is also written as a source-language "
|
|
374
|
-
"translation in the same call."
|
|
401
|
+
"translation in the same call. Pass `type` (default 'text') to "
|
|
402
|
+
"set the key's semantic type, which decides its a11y treatments."
|
|
375
403
|
),
|
|
376
404
|
inputSchema={
|
|
377
405
|
"type": "object",
|
|
@@ -395,6 +423,12 @@ def register(server: Server, client: VerbumiaClient) -> tuple[Any, Any]:
|
|
|
395
423
|
"description": {"type": "string"},
|
|
396
424
|
"plurals": {"type": "boolean", "default": False},
|
|
397
425
|
"max_length": {"type": "integer", "minimum": 1},
|
|
426
|
+
"type": {
|
|
427
|
+
"type": "string",
|
|
428
|
+
"enum": list(KEY_TYPES),
|
|
429
|
+
"default": "text",
|
|
430
|
+
"description": "Semantic key type (default 'text'). Decides which a11y treatments apply — e.g. 'image' (base value is the alt text), 'icon' (base is the accessible name), 'button'/'link' (offer aria_label), 'heading'/'label' (plain_language/screen_reader).",
|
|
431
|
+
},
|
|
398
432
|
},
|
|
399
433
|
"required": ["namespace", "name"],
|
|
400
434
|
"additionalProperties": False,
|
|
@@ -465,6 +499,7 @@ def register(server: Server, client: VerbumiaClient) -> tuple[Any, Any]:
|
|
|
465
499
|
"description": {"type": "string"},
|
|
466
500
|
"plurals": {"type": "boolean", "default": False},
|
|
467
501
|
"max_length": {"type": "integer", "minimum": 1},
|
|
502
|
+
"type": {"type": "string", "enum": list(KEY_TYPES), "default": "text", "description": "Semantic key type (default 'text'); see create_key."},
|
|
468
503
|
},
|
|
469
504
|
"required": ["namespace", "name"],
|
|
470
505
|
"additionalProperties": False,
|
|
@@ -478,7 +513,8 @@ def register(server: Server, client: VerbumiaClient) -> tuple[Any, Any]:
|
|
|
478
513
|
Tool(
|
|
479
514
|
name="update_key",
|
|
480
515
|
description=(
|
|
481
|
-
"Edit a key
|
|
516
|
+
"Edit a key in place — its SOURCE-language value, its `type`, "
|
|
517
|
+
"and/or its description (pass at least one). Preserves the "
|
|
482
518
|
"key and its history (version bump + history revision + audit). "
|
|
483
519
|
"Address the key by EITHER key_uuid (preferred; from list_keys) "
|
|
484
520
|
"OR namespace + name — exactly one of the two. When the source "
|
|
@@ -516,8 +552,13 @@ def register(server: Server, client: VerbumiaClient) -> tuple[Any, Any]:
|
|
|
516
552
|
"type": "string",
|
|
517
553
|
"description": "Optional: also update the key's description.",
|
|
518
554
|
},
|
|
555
|
+
"type": {
|
|
556
|
+
"type": "string",
|
|
557
|
+
"enum": list(KEY_TYPES),
|
|
558
|
+
"description": "Optional: reclassify the key's semantic type (see create_key). Changing the type re-gates which a11y treatments the key offers.",
|
|
559
|
+
},
|
|
519
560
|
},
|
|
520
|
-
"required": [
|
|
561
|
+
"required": [],
|
|
521
562
|
"additionalProperties": False,
|
|
522
563
|
},
|
|
523
564
|
),
|
|
@@ -552,8 +593,9 @@ def register(server: Server, client: VerbumiaClient) -> tuple[Any, Any]:
|
|
|
552
593
|
"name": {"type": "string", "description": "Dot-notation key name (use with namespace)."},
|
|
553
594
|
"source_value": {"type": "string", "description": "New source-language value to write."},
|
|
554
595
|
"description": {"type": "string", "description": "Optional: also update the key's description."},
|
|
596
|
+
"type": {"type": "string", "enum": list(KEY_TYPES), "description": "Optional: reclassify the key's semantic type (see create_key)."},
|
|
555
597
|
},
|
|
556
|
-
"required": [
|
|
598
|
+
"required": [],
|
|
557
599
|
"additionalProperties": False,
|
|
558
600
|
},
|
|
559
601
|
},
|
|
@@ -1135,6 +1177,9 @@ def register(server: Server, client: VerbumiaClient) -> tuple[Any, Any]:
|
|
|
1135
1177
|
"locale lacks it), alt_missing (image key with no source alt_text), "
|
|
1136
1178
|
"reading_level_high (hard source text + no plain_language), "
|
|
1137
1179
|
"a11y_variant_absent (a require_surface is missing in the source). "
|
|
1180
|
+
"Gaps are TYPE-AWARE: only treatments relevant to each key's type are "
|
|
1181
|
+
"reported (e.g. alt_missing only on image keys, aria gaps only on "
|
|
1182
|
+
"buttons/links/inputs), so a text key is never flagged for aria/alt. "
|
|
1138
1183
|
"Defaults to the production version. Surfaced verbatim — use "
|
|
1139
1184
|
"list_a11y_gaps for just the actionable item list."
|
|
1140
1185
|
),
|
|
@@ -1409,12 +1454,15 @@ def register(server: Server, client: VerbumiaClient) -> tuple[Any, Any]:
|
|
|
1409
1454
|
Tool(
|
|
1410
1455
|
name="get_variants",
|
|
1411
1456
|
description=(
|
|
1412
|
-
"Read the full VARIANT MATRIX for one key (task 928): every
|
|
1413
|
-
"
|
|
1457
|
+
"Read the full VARIANT MATRIX for one key (task 928): every surface "
|
|
1458
|
+
"OFFERED for the key x every project language, with each cell's "
|
|
1414
1459
|
"{override, value, resolvedValue, status, drift, ...}. The response "
|
|
1415
|
-
"
|
|
1416
|
-
"
|
|
1417
|
-
"
|
|
1460
|
+
"lists `surfaces` and `surfaceKinds` ({surface: 'device'|'a11y'}) — "
|
|
1461
|
+
"these are the key's offered surfaces only: the project's active "
|
|
1462
|
+
"device surfaces plus the a11y treatments relevant to the key's TYPE "
|
|
1463
|
+
"(e.g. a text key shows no aria/alt). This is the source of truth for "
|
|
1464
|
+
"which surfaces set_variant will accept. Address by key_uuid (from "
|
|
1465
|
+
"list_keys). Surfaced verbatim."
|
|
1418
1466
|
),
|
|
1419
1467
|
inputSchema={
|
|
1420
1468
|
"type": "object",
|
|
@@ -1440,11 +1488,13 @@ def register(server: Server, client: VerbumiaClient) -> tuple[Any, Any]:
|
|
|
1440
1488
|
"tablet / custom like watch / tv) OR a11y (aria_label / alt_text / "
|
|
1441
1489
|
"screen_reader / plain_language). Address by key_uuid + locale CODE + "
|
|
1442
1490
|
"surface slug (the fields get_variants / list_keys already give you). "
|
|
1443
|
-
"Stored as a draft. 422
|
|
1444
|
-
"(see list_surfaces)
|
|
1445
|
-
"(
|
|
1446
|
-
"
|
|
1447
|
-
"
|
|
1491
|
+
"Stored as a draft. 422 unless the surface is OFFERED for this key — "
|
|
1492
|
+
"an active device surface (see list_surfaces) OR an a11y treatment "
|
|
1493
|
+
"relevant to the key's TYPE (e.g. no aria_label on a text key; see "
|
|
1494
|
+
"get_variants for the key's offered surfaces); 409 if the cell is "
|
|
1495
|
+
"already reviewed/approved (never overwritten). Returns {key_uuid, "
|
|
1496
|
+
"surface, language_code, value, status}. (For a11y specifically you "
|
|
1497
|
+
"can also use set_a11y_variant.)"
|
|
1448
1498
|
),
|
|
1449
1499
|
inputSchema={
|
|
1450
1500
|
"type": "object",
|
|
@@ -1506,6 +1556,116 @@ def register(server: Server, client: VerbumiaClient) -> tuple[Any, Any]:
|
|
|
1506
1556
|
"additionalProperties": False,
|
|
1507
1557
|
},
|
|
1508
1558
|
),
|
|
1559
|
+
Tool(
|
|
1560
|
+
name="list_cognitive_candidates",
|
|
1561
|
+
description=(
|
|
1562
|
+
"List keys that are CANDIDATES for plain-language (cognitive) scoring: "
|
|
1563
|
+
"text-relevant keys (a type that offers plain_language — text / heading "
|
|
1564
|
+
"/ label / caption) whose source value clears a small word floor. This "
|
|
1565
|
+
"is a scope filter, NOT a difficulty judgement — score them to find the "
|
|
1566
|
+
"hard ones. Pass only_unanalyzed=true to skip keys already scored. Each "
|
|
1567
|
+
"item carries key_uuid + source_value so you can score it locally with "
|
|
1568
|
+
"set_cognitive_score."
|
|
1569
|
+
),
|
|
1570
|
+
inputSchema={
|
|
1571
|
+
"type": "object",
|
|
1572
|
+
"properties": {
|
|
1573
|
+
"project_uuid": {
|
|
1574
|
+
"type": "string",
|
|
1575
|
+
"description": "Project UUID. Required when multiple projects are configured (SONENTA_PROJECTS); defaults to the single configured project otherwise.",
|
|
1576
|
+
},
|
|
1577
|
+
"only_unanalyzed": {
|
|
1578
|
+
"type": "boolean",
|
|
1579
|
+
"description": "Only return keys with no cognitive_score yet (not analyzed).",
|
|
1580
|
+
},
|
|
1581
|
+
"namespace_uuid": {
|
|
1582
|
+
"type": "string",
|
|
1583
|
+
"description": "Restrict to one namespace by its UUID.",
|
|
1584
|
+
},
|
|
1585
|
+
"limit": {"type": "integer", "minimum": 1, "maximum": 500, "default": 100},
|
|
1586
|
+
"offset": {"type": "integer", "minimum": 0, "default": 0},
|
|
1587
|
+
},
|
|
1588
|
+
"additionalProperties": False,
|
|
1589
|
+
},
|
|
1590
|
+
),
|
|
1591
|
+
Tool(
|
|
1592
|
+
name="set_cognitive_score",
|
|
1593
|
+
description=(
|
|
1594
|
+
"Record a key's cognitive-difficulty SCORE (0-100, higher = harder to "
|
|
1595
|
+
"read) and an optional plain-language SUGGESTION — the local-first, "
|
|
1596
|
+
"**0-credit** path. Use this after scoring a candidate YOURSELF: you "
|
|
1597
|
+
"(the agent) judge the difficulty and write a clearer rewrite, then "
|
|
1598
|
+
"persist both here (marked by_bot). A key only enters the review queue "
|
|
1599
|
+
"(reading_level_high) once its score is >= the project threshold "
|
|
1600
|
+
"(default 60). The suggestion is a draft for a human to apply/approve."
|
|
1601
|
+
),
|
|
1602
|
+
inputSchema={
|
|
1603
|
+
"type": "object",
|
|
1604
|
+
"properties": {
|
|
1605
|
+
"project_uuid": {
|
|
1606
|
+
"type": "string",
|
|
1607
|
+
"description": "Project UUID. Required when multiple projects are configured (SONENTA_PROJECTS); defaults to the single configured project otherwise.",
|
|
1608
|
+
},
|
|
1609
|
+
"key_uuid": {
|
|
1610
|
+
"type": "string",
|
|
1611
|
+
"description": "Key UUID (from list_cognitive_candidates / list_keys).",
|
|
1612
|
+
},
|
|
1613
|
+
"score": {
|
|
1614
|
+
"type": "number",
|
|
1615
|
+
"minimum": 0,
|
|
1616
|
+
"maximum": 100,
|
|
1617
|
+
"description": "Cognitive difficulty score, 0 (easy) to 100 (hard).",
|
|
1618
|
+
},
|
|
1619
|
+
"suggestion": {
|
|
1620
|
+
"type": "string",
|
|
1621
|
+
"description": "Optional plain-language rewrite of the source value (draft).",
|
|
1622
|
+
},
|
|
1623
|
+
},
|
|
1624
|
+
"required": ["key_uuid", "score"],
|
|
1625
|
+
"additionalProperties": False,
|
|
1626
|
+
},
|
|
1627
|
+
),
|
|
1628
|
+
Tool(
|
|
1629
|
+
name="analyze_cognitive",
|
|
1630
|
+
description=(
|
|
1631
|
+
"Server-side AI cognitive analysis — the BILLED, opt-in FALLBACK to "
|
|
1632
|
+
"local scoring. Rates the cognitive difficulty of candidate keys and "
|
|
1633
|
+
"suggests plain-language rewrites server-side. Prefer scoring locally "
|
|
1634
|
+
"with set_cognitive_score (0 credits); use this only for very large "
|
|
1635
|
+
"volumes or on explicit request. Bills credits (standard=1, premium=4 "
|
|
1636
|
+
"per key; 402 if insufficient, 503 if AI unavailable). Returns "
|
|
1637
|
+
"{requested, analyzed, credits_charged, credits_refunded}."
|
|
1638
|
+
),
|
|
1639
|
+
inputSchema={
|
|
1640
|
+
"type": "object",
|
|
1641
|
+
"properties": {
|
|
1642
|
+
"project_uuid": {
|
|
1643
|
+
"type": "string",
|
|
1644
|
+
"description": "Project UUID. Required when multiple projects are configured (SONENTA_PROJECTS); defaults to the single configured project otherwise.",
|
|
1645
|
+
},
|
|
1646
|
+
"tier": {
|
|
1647
|
+
"type": "string",
|
|
1648
|
+
"enum": ["standard", "premium"],
|
|
1649
|
+
"default": "standard",
|
|
1650
|
+
"description": "Quality tier (credit_cost per key: standard=1, premium=4).",
|
|
1651
|
+
},
|
|
1652
|
+
"key_uuids": {
|
|
1653
|
+
"type": "array",
|
|
1654
|
+
"items": {"type": "string"},
|
|
1655
|
+
"description": "Restrict to these keys (from list_cognitive_candidates). Omit to scope the whole project (or a namespace).",
|
|
1656
|
+
},
|
|
1657
|
+
"namespace_uuid": {
|
|
1658
|
+
"type": "string",
|
|
1659
|
+
"description": "Restrict to one namespace by its UUID.",
|
|
1660
|
+
},
|
|
1661
|
+
"idempotency_key": {
|
|
1662
|
+
"type": "string",
|
|
1663
|
+
"description": "Stable token making this billable call safe to retry: reuse the SAME value to avoid a double-charge. A random one is generated if omitted.",
|
|
1664
|
+
},
|
|
1665
|
+
},
|
|
1666
|
+
"additionalProperties": False,
|
|
1667
|
+
},
|
|
1668
|
+
),
|
|
1509
1669
|
]
|
|
1510
1670
|
|
|
1511
1671
|
@server.call_tool()
|
|
@@ -1627,7 +1787,7 @@ def register(server: Server, client: VerbumiaClient) -> tuple[Any, Any]:
|
|
|
1627
1787
|
"namespace": args["namespace"],
|
|
1628
1788
|
"name": args["name"],
|
|
1629
1789
|
}
|
|
1630
|
-
for opt in ("source_value", "description", "plurals", "max_length"):
|
|
1790
|
+
for opt in ("source_value", "description", "plurals", "max_length", "type"):
|
|
1631
1791
|
if opt in args:
|
|
1632
1792
|
body[opt] = args[opt]
|
|
1633
1793
|
data = await client.post(
|
|
@@ -1659,16 +1819,18 @@ def register(server: Server, client: VerbumiaClient) -> tuple[Any, Any]:
|
|
|
1659
1819
|
return _text(data)
|
|
1660
1820
|
if name == "update_key":
|
|
1661
1821
|
project_uuid = _project_uuid(args, client)
|
|
1662
|
-
if "source_value"
|
|
1663
|
-
return _err(
|
|
1822
|
+
if not any(k in args for k in ("source_value", "type", "description")):
|
|
1823
|
+
return _err(
|
|
1824
|
+
"nothing to update: pass at least one of source_value, type, description"
|
|
1825
|
+
)
|
|
1664
1826
|
has_uuid = bool(args.get("key_uuid"))
|
|
1665
1827
|
has_name = bool(args.get("namespace")) and bool(args.get("name"))
|
|
1666
1828
|
if has_uuid == has_name:
|
|
1667
1829
|
return _err(
|
|
1668
1830
|
"address the key by exactly one of key_uuid OR (namespace + name)"
|
|
1669
1831
|
)
|
|
1670
|
-
body: dict[str, Any] = {
|
|
1671
|
-
for opt in ("key_uuid", "namespace", "name", "description"):
|
|
1832
|
+
body: dict[str, Any] = {}
|
|
1833
|
+
for opt in ("source_value", "key_uuid", "namespace", "name", "description", "type"):
|
|
1672
1834
|
if opt in args:
|
|
1673
1835
|
body[opt] = args[opt]
|
|
1674
1836
|
data = await client.patch(
|
|
@@ -2040,6 +2202,50 @@ def register(server: Server, client: VerbumiaClient) -> tuple[Any, Any]:
|
|
|
2040
2202
|
return _err("value is required")
|
|
2041
2203
|
data = await client.put(path, json={"value": args["value"]})
|
|
2042
2204
|
return _text(data)
|
|
2205
|
+
if name == "list_cognitive_candidates":
|
|
2206
|
+
project_uuid = _project_uuid(args, client)
|
|
2207
|
+
params = {
|
|
2208
|
+
k: v
|
|
2209
|
+
for k, v in {
|
|
2210
|
+
"only_unanalyzed": ("true" if args.get("only_unanalyzed") else None),
|
|
2211
|
+
"namespace_uuid": args.get("namespace_uuid"),
|
|
2212
|
+
"limit": args.get("limit", 100),
|
|
2213
|
+
"offset": args.get("offset", 0),
|
|
2214
|
+
}.items()
|
|
2215
|
+
if v is not None
|
|
2216
|
+
}
|
|
2217
|
+
data = await client.get(
|
|
2218
|
+
f"/v1/mcp/projects/{project_uuid}/cognitive/candidates", params=params
|
|
2219
|
+
)
|
|
2220
|
+
return _text(data)
|
|
2221
|
+
if name == "set_cognitive_score":
|
|
2222
|
+
project_uuid = _project_uuid(args, client)
|
|
2223
|
+
key_uuid = args.get("key_uuid")
|
|
2224
|
+
if not key_uuid:
|
|
2225
|
+
return _err("key_uuid is required")
|
|
2226
|
+
if "score" not in args:
|
|
2227
|
+
return _err("score is required")
|
|
2228
|
+
body: dict[str, Any] = {"score": args["score"]}
|
|
2229
|
+
if "suggestion" in args:
|
|
2230
|
+
body["suggestion"] = args["suggestion"]
|
|
2231
|
+
data = await client.put(
|
|
2232
|
+
f"/v1/mcp/projects/{project_uuid}/keys/{key_uuid}/cognitive-score",
|
|
2233
|
+
json=body,
|
|
2234
|
+
)
|
|
2235
|
+
return _text(data)
|
|
2236
|
+
if name == "analyze_cognitive":
|
|
2237
|
+
project_uuid = _project_uuid(args, client)
|
|
2238
|
+
body: dict[str, Any] = {
|
|
2239
|
+
"tier": args.get("tier", "standard"),
|
|
2240
|
+
"idempotency_key": args.get("idempotency_key") or str(uuid.uuid4()),
|
|
2241
|
+
}
|
|
2242
|
+
for opt in ("key_uuids", "namespace_uuid"):
|
|
2243
|
+
if args.get(opt):
|
|
2244
|
+
body[opt] = args[opt]
|
|
2245
|
+
data = await client.post(
|
|
2246
|
+
f"/v1/mcp/projects/{project_uuid}/cognitive/analyze", json=body
|
|
2247
|
+
)
|
|
2248
|
+
return _text(data)
|
|
2043
2249
|
return _err(f"unknown tool: {name}")
|
|
2044
2250
|
except VerbumiaApiError as exc:
|
|
2045
2251
|
return _err(f"API {exc.status}: {exc.body}")
|
|
Binary file
|