@thalovant/mcp-server 0.6.2 → 0.6.4
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/CHANGELOG.md +13 -0
- package/README.md +18 -9
- package/dist/index.js +15 -11
- package/dist/inventory-output.js +6 -0
- package/package.json +2 -2
- package/server.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.6.4 — 2026-10-19
|
|
4
|
+
|
|
5
|
+
- **Descriptions that say what a runtime tool changes.** `thalovant_send_action`, `thalovant_send_code` and `thalovant_wait_for_event` had one-line descriptions that didn't say whether the tool changes anything. A scanner that reads only names and descriptions rated all three as high-risk tools that execute, `thalovant_wait_for_event` included, though it was already annotated `readOnlyHint: true`. `thalovant_send_action` now says the hub routes its payload like a spoken request, so a skill may act on it. `thalovant_send_code` says the hub receives its value as an exact utterance, and both say they return without waiting for a reply and that `THALOVANT_MCP_READONLY` leaves them out. `thalovant_wait_for_event` says it only listens and sends the hub nothing, and that `sessionId`, `requestId` and `context` filter which events count. `payload`, `title`, `value`, `kind`, `label` and `eventName` now have their own descriptions. Schemas, annotations and behaviour are unchanged.
|
|
6
|
+
- The Claude Desktop and Codex examples start the published package with `npx -y @thalovant/mcp-server`. They used to point at a path on one developer's machine.
|
|
7
|
+
- `package.json`, `server.json`, the OCI label, the README and this file move to 0.6.4 together.
|
|
8
|
+
|
|
9
|
+
## 0.6.3 — 2026-10-11
|
|
10
|
+
|
|
11
|
+
- **Sentences in the language the hub answers in.** `thalovant_intent_inventory` takes `@thalovant/sdk` 0.9.9, which lists a language the hub never loaded in one of the hub's own languages: the same language in another region first, then the hub's own language, then the one with the most sentences. A hub loads its `lang` and `secondary_langs` and lists nothing under any other tag, so on 2026-10-11 a ja-JP, es-ES or de-DE request came back empty on every public hub, even though the hub answers those people. The output's `listed_in` names the language each requested language was listed in. `examples` are now rendered from that language (they used to be rendered from the requested tag and came back empty). `presentation.notes` says when the sentences are in another language, so an agent can tell the user.
|
|
12
|
+
- **Fallback skills that exist.** The SDK reads fallbacks from `ovos.skills.list` and no longer asks `ovos.skills.fallback.list`, which ovos-core reverted the day it landed. Skills with no intents, such as Daily Desk's memory skill, now appear. `priority` is `null`: the hub does not say in which order it tries fallbacks, and the list is in skill id order. The tool description and README say so. A connection needs `ovos.skills.list` on its allow-list; until then fallbacks stay unknown, as before.
|
|
13
|
+
- Takes `@thalovant/sdk` ^0.9.9, and the lock resolves the published 0.9.9. The parity contract acknowledges reference digest `5b973a65ab58` (see thalovant/thalovant-python-sdk#105).
|
|
14
|
+
- `package.json`, `server.json`, the OCI label, the README and this file move to 0.6.3 together.
|
|
15
|
+
|
|
3
16
|
## 0.6.2 — 2026-10-02
|
|
4
17
|
|
|
5
18
|
- Takes `@thalovant/sdk` ^0.9.3, which the lock resolves. Its `reply.claimed` now recognizes a skill's own confident fallback-tier answer; the earlier range silently swallowed a genuinely successful Home Assistant reply (a `claimed` answer from the home skill's fallback tier read as "nothing answered"). No code change in this package: the logic is the SDK's `replyClaimMetadata`, which `src/reply-output.ts` delegates to.
|
package/README.md
CHANGED
|
@@ -24,6 +24,8 @@ Thalovant publishes SDKs for Python, Node.js, Go, and Rust. This server uses Nod
|
|
|
24
24
|
|
|
25
25
|
## Install
|
|
26
26
|
|
|
27
|
+
Run the published package with `npx -y @thalovant/mcp-server`, or build it from a checkout:
|
|
28
|
+
|
|
27
29
|
```bash
|
|
28
30
|
npm install
|
|
29
31
|
npm run build
|
|
@@ -308,8 +310,8 @@ Recommended: authenticate with a scoped API token so the MCP config never contai
|
|
|
308
310
|
{
|
|
309
311
|
"mcpServers": {
|
|
310
312
|
"thalovant": {
|
|
311
|
-
"command": "
|
|
312
|
-
"args": ["/
|
|
313
|
+
"command": "npx",
|
|
314
|
+
"args": ["-y", "@thalovant/mcp-server"],
|
|
313
315
|
"env": {
|
|
314
316
|
"THALOVANT_API_TOKEN": "tvpat_...",
|
|
315
317
|
"THALOVANT_PROFILE": "prod"
|
|
@@ -327,8 +329,8 @@ Use the same stdio command in your MCP client config:
|
|
|
327
329
|
{
|
|
328
330
|
"mcpServers": {
|
|
329
331
|
"thalovant": {
|
|
330
|
-
"command": "
|
|
331
|
-
"args": ["/
|
|
332
|
+
"command": "npx",
|
|
333
|
+
"args": ["-y", "@thalovant/mcp-server"],
|
|
332
334
|
"env": {
|
|
333
335
|
"THALOVANT_API_TOKEN": "tvpat_...",
|
|
334
336
|
"THALOVANT_PROFILE": "prod"
|
|
@@ -418,10 +420,17 @@ Tool outputs redact credential-shaped fields. `thalovant_create_client_identity`
|
|
|
418
420
|
|
|
419
421
|
`thalovant_intent_inventory` uses the runtime identity and accepts `languages`,
|
|
420
422
|
`describe`, `fallback`, `speakable`, `sentence`, `slots`, `exampleLimit`, and a per-query/batch `timeoutMs`. It returns registered
|
|
421
|
-
intents and examples, fallback skills, `fallbacks_known`,
|
|
422
|
-
requested language.
|
|
423
|
-
|
|
424
|
-
|
|
423
|
+
intents and examples, fallback skills, `fallbacks_known`, `listed_in`, and
|
|
424
|
+
`may_answer` by requested language. `listed_in` names the hub language each
|
|
425
|
+
requested language was listed in. A hub lists nothing under a language it did
|
|
426
|
+
not load, so a language with no sentences is listed in its usual form (`en-CA`
|
|
427
|
+
in `en-US`) or in the closest language the hub loaded, and `examples` are
|
|
428
|
+
rendered in that language. When `listed_in` differs from what was asked, the
|
|
429
|
+
sentences are in another language, and `presentation.notes` says so. Fallback
|
|
430
|
+
skills come from `ovos.skills.list`, in skill id order, with `priority: null`:
|
|
431
|
+
the hub does not say in which order it tries them. A missing or denied
|
|
432
|
+
fallback-skill query remains unknown, rather than being reported as a known
|
|
433
|
+
empty list. The optional probe adds at most 1500ms. A silent listing can use engine manifests; disable this with
|
|
425
434
|
`fallback: false`. Both new tools are available in read-only mode and respect
|
|
426
435
|
per-principal policy. `thalovant_get_operation` reads an operation ID returned by
|
|
427
436
|
provisioning without replaying the write.
|
|
@@ -531,7 +540,7 @@ Runtime calls sharing the same hub client identity run sequentially within one
|
|
|
531
540
|
MCP process. Use a distinct client identity for each independently running MCP
|
|
532
541
|
server so the hub can keep their sessions separate.
|
|
533
542
|
|
|
534
|
-
Version 0.6.
|
|
543
|
+
Version 0.6.4 requires `@thalovant/sdk` `^0.9.9` (0.9.9 through versions below 0.10.0). Since 0.5.1 the server enforces
|
|
535
544
|
secure effective MQTT URLs and carries a single connection deadline through
|
|
536
545
|
MQTT setup and HTTP failure cleanup. Runtime tools support
|
|
537
546
|
HiveMind v3 Noise over WSS, HTTPS and MQTT over TLS. `thalovant_healthcheck`
|
package/dist/index.js
CHANGED
|
@@ -1614,7 +1614,7 @@ export function createServer() {
|
|
|
1614
1614
|
});
|
|
1615
1615
|
registerThalovantTool(server, "thalovant_intent_inventory", {
|
|
1616
1616
|
title: "Runtime Intent Inventory",
|
|
1617
|
-
description: "Discover a hub's registered intents, language examples and fallback skills using its runtime identity. Unknown fallback support remains distinct from a known empty list; answerability is a conservative hint.",
|
|
1617
|
+
description: "Discover a hub's registered intents, language examples and fallback skills using its runtime identity. listed_in names, per requested language, the hub language the sentences were listed in: a hub lists nothing under a language it did not load, so a language with no sentences is listed in its usual form or the closest language the hub loaded. When listed_in differs from the language asked, tell the user which language the sentences are in. Fallback skills come from ovos.skills.list in skill id order; the hub does not say in which order they are tried, so priority is null. Unknown fallback support remains distinct from a known empty list; answerability is a conservative hint.",
|
|
1618
1618
|
inputSchema: {
|
|
1619
1619
|
...runtimeAuthSchema,
|
|
1620
1620
|
languages: z.array(z.string().trim().min(1).max(100)).min(1).max(20).default(["en-us"]),
|
|
@@ -1634,8 +1634,12 @@ export function createServer() {
|
|
|
1634
1634
|
return jsonContent(redactSecrets({
|
|
1635
1635
|
...inventory.asObject(),
|
|
1636
1636
|
presentation: inventoryPresentation(inventory),
|
|
1637
|
+
// Keyed by the language asked, rendered from the tag that answered:
|
|
1638
|
+
// a Spanish phone on an English hub gets the English sentences, and
|
|
1639
|
+
// listed_in says so.
|
|
1637
1640
|
examples: inventory.intents.map(intent => ({ id: intent.id,
|
|
1638
|
-
languages: Object.fromEntries(inventory.languages.map(lang => [lang,
|
|
1641
|
+
languages: Object.fromEntries(inventory.languages.map((lang, index) => [lang,
|
|
1642
|
+
intent.examples(inventory.listedIn[index] ?? lang, exampleLimit, { speakable, sentence, slots })])),
|
|
1639
1643
|
})),
|
|
1640
1644
|
may_answer: Object.fromEntries(inventory.languages.map(lang => [lang, inventory.mayAnswer(lang)])),
|
|
1641
1645
|
}));
|
|
@@ -1713,11 +1717,11 @@ export function createServer() {
|
|
|
1713
1717
|
});
|
|
1714
1718
|
registerThalovantTool(server, "thalovant_send_action", {
|
|
1715
1719
|
title: "Send Action",
|
|
1716
|
-
description: "Send
|
|
1720
|
+
description: "Send one action to a Thalovant hub using a saved identity, the way a button or a shortcut would. The hub routes payload like a spoken request, so the skill that takes it can change things: switch a light, start a timer, play music. Returns once the action is sent, without waiting for the reply; use thalovant_ask to read the answer. THALOVANT_MCP_READONLY leaves this tool out.",
|
|
1717
1721
|
inputSchema: {
|
|
1718
1722
|
...runtimeAuthSchema,
|
|
1719
|
-
payload: z.string().min(1).max(20_000),
|
|
1720
|
-
title: z.string().min(1).max(512).optional(),
|
|
1723
|
+
payload: z.string().min(1).max(20_000).describe("The request the hub routes, in words, such as \"turn on the kitchen light\"."),
|
|
1724
|
+
title: z.string().min(1).max(512).optional().describe("A label carried with the action in its context (input.title)."),
|
|
1721
1725
|
lang: z.string().min(1).optional(),
|
|
1722
1726
|
sessionId: z.string().min(1).optional(),
|
|
1723
1727
|
requestId: z.string().min(1).optional(),
|
|
@@ -1745,12 +1749,12 @@ export function createServer() {
|
|
|
1745
1749
|
});
|
|
1746
1750
|
registerThalovantTool(server, "thalovant_send_code", {
|
|
1747
1751
|
title: "Send Code",
|
|
1748
|
-
description: "Send
|
|
1752
|
+
description: "Send one exact value to a Thalovant hub using a saved identity: something typed, scanned, a barcode, a QR code or a serial number. The hub receives it as an utterance whose input is marked exact, and a skill that recognizes the value may act on it. Returns once the value is sent, without waiting for a reply. THALOVANT_MCP_READONLY leaves this tool out.",
|
|
1749
1753
|
inputSchema: {
|
|
1750
1754
|
...runtimeAuthSchema,
|
|
1751
|
-
value: z.string().min(1).max(20_000),
|
|
1752
|
-
kind: z.string().min(1).max(64).optional(),
|
|
1753
|
-
label: z.string().min(1).max(128).optional(),
|
|
1755
|
+
value: z.string().min(1).max(20_000).describe("The value exactly as read; only leading and trailing spaces are trimmed."),
|
|
1756
|
+
kind: z.string().min(1).max(64).optional().describe("What the value is, such as barcode, qr or serial. Defaults to code."),
|
|
1757
|
+
label: z.string().min(1).max(128).optional().describe("A label carried with the value in its context (input.label)."),
|
|
1754
1758
|
lang: z.string().min(1).optional(),
|
|
1755
1759
|
sessionId: z.string().min(1).optional(),
|
|
1756
1760
|
requestId: z.string().min(1).optional(),
|
|
@@ -1802,10 +1806,10 @@ export function createServer() {
|
|
|
1802
1806
|
});
|
|
1803
1807
|
registerThalovantTool(server, "thalovant_wait_for_event", {
|
|
1804
1808
|
title: "Wait For Event",
|
|
1805
|
-
description: "Wait for one named hub event using a saved identity.",
|
|
1809
|
+
description: "Wait for one named hub event using a saved identity and return it: the first eventName the hub sends once the connection is made, or a timeout error after timeoutMs. sessionId, requestId and context narrow it to events carrying the same values. Listens only: it opens the connection and sends the hub no message, so it changes nothing.",
|
|
1806
1810
|
inputSchema: {
|
|
1807
1811
|
...runtimeAuthSchema,
|
|
1808
|
-
eventName: z.string().min(1).max(256),
|
|
1812
|
+
eventName: z.string().min(1).max(256).describe("The bus message type to wait for, such as speak or recognizer_loop:utterance."),
|
|
1809
1813
|
timeoutMs: z.number().int().min(1_000).max(MAX_TIMEOUT_MS).default(DEFAULT_TIMEOUT_MS),
|
|
1810
1814
|
sessionId: z.string().min(1).optional(),
|
|
1811
1815
|
requestId: z.string().min(1).optional(),
|
package/dist/inventory-output.js
CHANGED
|
@@ -6,6 +6,12 @@ export function inventoryPresentation(runtime, generatedAt = new Date().toISOStr
|
|
|
6
6
|
`Runtime discovery source: ${runtime.source}.`,
|
|
7
7
|
...runtime.denied.map(query => `Query refused or unanswered: ${query}.`),
|
|
8
8
|
...(!runtime.fallbacksKnown ? ["Fallback skill support is unknown."] : []),
|
|
9
|
+
...(runtime.fallbacks.length > 0 ? ["Fallback skills are in skill id order; the hub does not say in which order it tries them."] : []),
|
|
10
|
+
...runtime.languages.flatMap((lang, index) => {
|
|
11
|
+
const listed = runtime.listedIn[index];
|
|
12
|
+
return listed && listed.toLowerCase().replaceAll("_", "-") !== lang.toLowerCase().replaceAll("_", "-")
|
|
13
|
+
? [`Sentences for ${lang} are listed in ${listed}: the hub has none under ${lang}.`] : [];
|
|
14
|
+
}),
|
|
9
15
|
];
|
|
10
16
|
const inventory = new Inventory("", "", "hub", generatedAt, runtime.skills.map(skill => new Skill(skill.skillId, friendlyTitle(skill.skillId), [], skill.intents.map(intent => new Intent(intent.id, intent.name, intent.skillId, intent.engine, intent.phrases, intent.languages)))), notes);
|
|
11
17
|
return { ...inventory.asObject(), languages_present: languagesPresent(inventory) };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thalovant/mcp-server",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.4",
|
|
4
4
|
"description": "Stdio and Streamable HTTP MCP server for Thalovant control-plane and hub runtime APIs.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
},
|
|
65
65
|
"dependencies": {
|
|
66
66
|
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
67
|
-
"@thalovant/sdk": "^0.9.
|
|
67
|
+
"@thalovant/sdk": "^0.9.9",
|
|
68
68
|
"jose": "^6.2.8",
|
|
69
69
|
"zod": "^3.25.76"
|
|
70
70
|
},
|
package/server.json
CHANGED
|
@@ -7,19 +7,19 @@
|
|
|
7
7
|
"url": "https://github.com/thalovant/thalovant-mcp",
|
|
8
8
|
"source": "github"
|
|
9
9
|
},
|
|
10
|
-
"version": "0.6.
|
|
10
|
+
"version": "0.6.4",
|
|
11
11
|
"packages": [
|
|
12
12
|
{
|
|
13
13
|
"registryType": "npm",
|
|
14
14
|
"identifier": "@thalovant/mcp-server",
|
|
15
|
-
"version": "0.6.
|
|
15
|
+
"version": "0.6.4",
|
|
16
16
|
"transport": {
|
|
17
17
|
"type": "stdio"
|
|
18
18
|
}
|
|
19
19
|
},
|
|
20
20
|
{
|
|
21
21
|
"registryType": "oci",
|
|
22
|
-
"identifier": "ghcr.io/thalovant/thalovant-mcp:0.6.
|
|
22
|
+
"identifier": "ghcr.io/thalovant/thalovant-mcp:0.6.4",
|
|
23
23
|
"transport": {
|
|
24
24
|
"type": "streamable-http",
|
|
25
25
|
"url": "http://127.0.0.1:3000/mcp"
|