@thalovant/mcp-server 0.7.0 → 0.7.1
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 +7 -2
- package/README.md +10 -3
- package/dist/index.js +11 -2
- package/package.json +1 -1
- package/server.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
|
-
Last Edit: Claude
|
|
1
|
+
Last Edit: Claude Fable 5.1 - 2026-11-06 - Motive: 0.7.1 hints for the store's licensing refusal and the memory limit; date the published 0.7.0.
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
-
## 0.7.
|
|
5
|
+
## 0.7.1 - Unreleased
|
|
6
|
+
|
|
7
|
+
- **Two refusals explained by their code.** A skill the store does not install for licensing reasons (YouTube, YouTube Music, Spotify, SoundCloud and Bandcamp; the API's 409 `skill_unavailable_licensing` with `reason: licensing`, declared with the launch data-protection change) got the generic 409 hint, which talks about a version already installed. It now says the service's terms do not allow a hosted assistant to play its content, that no plan, scope, version or retry changes that, that radio and aggregator skills install as usual, and that `thalovant_list_marketplace_skills` reports it per skill as `unavailable_reason` and `installable`. A memory create or update refused with 409 `memory_limit` (the plan's remembered items are used up; a Free plan keeps one) carried no hint at all, because the memory tools never went through the hint path; `thalovant_create_memory_item` and `thalovant_update_memory_item` now do, under a profile of their own that adds a hint for that code alone (the hub-centric scope and plan hints would misdescribe the memory routes), naming the `limit` and `upgrade_plan` fields, the delete tool that frees a slot, the update tool that changes the item that exists, and that granting a scope will not help. Two tests drive both through the fake control plane.
|
|
8
|
+
- `package.json`, `package-lock.json`, `server.json`, the OCI label, the README and this file move to 0.7.1 together.
|
|
9
|
+
|
|
10
|
+
## 0.7.0 - 2026-11-03
|
|
6
11
|
|
|
7
12
|
A hub can answer in a chat network through a chat app: Telegram and Discord, and Matrix, Mattermost and Twitch as beta once the API lists them. These tools let an agent read and look after the bridges a person connected in the console. Existing tool schemas are unchanged.
|
|
8
13
|
|
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Last Edit: Claude
|
|
1
|
+
Last Edit: Claude Fable 5.1 - 2026-11-06 - Motive: Say what the 409 skill_unavailable_licensing and memory_limit refusals get as hints (0.7.1).
|
|
2
2
|
|
|
3
3
|
# Thalovant MCP Server
|
|
4
4
|
|
|
@@ -103,7 +103,7 @@ Grant fewer scopes for narrower deployments: a read-only assistant needs only `h
|
|
|
103
103
|
|
|
104
104
|
`thalovant_list_hub_skills` returns the whole `GET /v1/hubs/{hub_id}/skills` envelope: `hub_id`, `runtime_group_id`, `observed_at`, `source`, the runtime's phase and message, and `data`, one row per skill (possibly empty) with `skill`, `title`, `marketplace_skill_id`, `package_name`, `source_type`, `install_source`, `version`, `version_pin`, `installed_version`, `observed_version`, `previous_version`, `latest_version`, `available_version`, `update_available`, `changelog`, `active`, `state`, the runtime's phase, message and last error, and `last_transition_at`. `state` is one of `pending`, `installed`, `failed`, `removing`, `drifted`, `quarantined`, or `unmanaged`; a change in progress shows as `pending`.
|
|
105
105
|
|
|
106
|
-
Each write answers `202` with `operation_id`, `hub_id`, `runtime_group_id`, `skill`, `version` (`null` for a removal), `previous_version`, and `state` (`installing`, `updating`, or `removing`); pass `wait: true` to poll that operation every 2 s until it converges (`installed`, or `removed` for a removal; a `failed` or `timed_out` operation raises an error carrying its `error_message`), with a 120 s default `timeoutMs`, or follow it yourself with `thalovant_get_operation`. Installing a skill that is already installed at another version performs an update; the same version fails `409` with code `skill_version_already_installed`. A hub with no runtime group fails `404` with code `hub_without_runtime_group` (a plain `404` means an unknown hub or a skill that is not installed), and an unresolvable `latest` or an invalid version fails `422`. Errors are RFC 7807 problem bodies; the tool error keeps the short `message`, which appends the root `code` in parentheses, for example `Thalovant API request failed with HTTP 409: Skill version already installed. (skill_version_already_installed)`, and then the code and the body's other fields (see [Tool Errors](#tool-errors)).
|
|
106
|
+
Each write answers `202` with `operation_id`, `hub_id`, `runtime_group_id`, `skill`, `version` (`null` for a removal), `previous_version`, and `state` (`installing`, `updating`, or `removing`); pass `wait: true` to poll that operation every 2 s until it converges (`installed`, or `removed` for a removal; a `failed` or `timed_out` operation raises an error carrying its `error_message`), with a 120 s default `timeoutMs`, or follow it yourself with `thalovant_get_operation`. Installing a skill that is already installed at another version performs an update; the same version fails `409` with code `skill_version_already_installed`. A hub with no runtime group fails `404` with code `hub_without_runtime_group` (a plain `404` means an unknown hub or a skill that is not installed), and an unresolvable `latest` or an invalid version fails `422`. Errors are RFC 7807 problem bodies; the tool error keeps the short `message`, which appends the root `code` in parentheses, for example `Thalovant API request failed with HTTP 409: Skill version already installed. (skill_version_already_installed)`, and then the code and the body's other fields (see [Tool Errors](#tool-errors)). A skill the store does not install for licensing reasons (YouTube, YouTube Music, Spotify, SoundCloud and Bandcamp: the service's terms do not allow a hosted assistant to play its content) fails `409` with code `skill_unavailable_licensing` and `reason: licensing`, which `thalovant_list_marketplace_skills` announces per skill as `unavailable_reason` and `installable`; no plan, scope or version changes that.
|
|
107
107
|
|
|
108
108
|
Listing needs `hubs:inspect` (implied by `hubs:read`); the writes need `hubs:write` and a paid plan, and because scope is checked before plan a free-plan token sees `403`, never `402`. Hub-restricted tokens (a `hub_ids` allowlist) are honoured on all four routes. The server uses the published Node SDK hub-skill methods and preserves MCP cancellation checks during polling. A failed status read retains the accepted operation ID; use `thalovant_get_operation` with that ID instead of submitting the write again. No new poll starts at or after the polling deadline. That deadline does not cancel an HTTP request already in flight.
|
|
109
109
|
|
|
@@ -517,6 +517,13 @@ fields: {"allowed_images":{"bus":[...],"core":[...]},"allowed_repositories":{"co
|
|
|
517
517
|
|
|
518
518
|
A hint may follow for statuses that need one. A `platform_image_required` or
|
|
519
519
|
`plan_limit` 403 gets its own hint rather than the general scope hint.
|
|
520
|
+
A 409 `skill_unavailable_licensing` says the store refuses the skill for its
|
|
521
|
+
licensing and where the catalog announces it, instead of the version hint. A
|
|
522
|
+
memory create or update refused with 409 `memory_limit` (the plan's remembered
|
|
523
|
+
items are used up; a Free plan keeps one, `limit` and `upgrade_plan` are in the
|
|
524
|
+
fields) names the delete tool that frees a slot, the update tool that changes
|
|
525
|
+
the item that exists, and the plan to move to; other memory refusals carry the
|
|
526
|
+
SDK's message alone.
|
|
520
527
|
|
|
521
528
|
## Request hints, embedded audio, and configuration merging
|
|
522
529
|
|
|
@@ -589,7 +596,7 @@ Runtime calls sharing the same hub client identity run sequentially within one
|
|
|
589
596
|
MCP process. Use a distinct client identity for each independently running MCP
|
|
590
597
|
server so the hub can keep their sessions separate.
|
|
591
598
|
|
|
592
|
-
Version 0.7.
|
|
599
|
+
Version 0.7.1 requires `@thalovant/sdk` `^0.10.0` (0.10.0 through versions below 0.11.0), which carries the chat app methods and `ThalovantApiError.fields`. Since 0.5.1 the server enforces
|
|
593
600
|
secure effective MQTT URLs and carries a single connection deadline through
|
|
594
601
|
MQTT setup and HTTP failure cleanup. Runtime tools support
|
|
595
602
|
HiveMind v3 Noise over WSS, HTTPS and MQTT over TLS. `thalovant_healthcheck`
|
package/dist/index.js
CHANGED
|
@@ -259,11 +259,18 @@ function releaseOptionsFrom(args) {
|
|
|
259
259
|
const SCOPE_HINT_403 = 'HTTP 403 "Insufficient scopes" — the token lacks the scope this route needs: hubs:write for provisioning, hubs:read for the marketplace catalog, hubs:inspect for runtime-group and hub runtime views (hubs:write implies hubs:read, which implies hubs:inspect and hubs:preview). The API checks scope BEFORE the paid-plan gate, so a 403 can mask a plan problem and granting the scope may surface a 402 next. Free-plan API tokens are capped at hubs:read, clients:read, and clients:write, so a free-tier API token fails provisioning with this 403 and never reaches the 402. A 403 here can also mean the caller does not own the resource ("Ownership required"), or a plan restriction such as HUB_AUTOSCALING_NOT_INCLUDED or a custom hub domain the plan does not allow.';
|
|
260
260
|
const PLATFORM_IMAGE_HINT_403 = 'HTTP 403 platform_image_required — only a platform administrator can run an image the platform does not release. This is not a scope problem: pick, for each key in refused_images, one of that key\'s allowed_images, or any tag or digest of its allowed_repositories entry (both are in the fields above), and retry.';
|
|
261
261
|
const PLAN_LIMIT_HINT_403 = 'HTTP 403 plan_limit — the plan\'s allowance for the named resource is used up (see resource, used and limit in the fields above). Granting a scope will not help: free one (delete or reuse an existing one) or move the workspace to a larger plan.';
|
|
262
|
+
const LICENSING_HINT_409 = "HTTP 409 skill_unavailable_licensing — the store does not install this skill on Thalovant: the service's terms do not allow a hosted assistant to play its content (YouTube, YouTube Music, Spotify, SoundCloud and Bandcamp; the problem's reason says licensing). No plan, scope or version changes that, and retrying will not either; radio and aggregator skills such as TuneIn, SomaFM and News install as usual. thalovant_list_marketplace_skills reports this per skill as unavailable_reason and installable (false), so check them before installing.";
|
|
263
|
+
const MEMORY_LIMIT_HINT_409 = "HTTP 409 memory_limit — the plan's remembered items are used up (see limit in the fields above; a Free plan keeps one). Free a slot with thalovant_delete_memory_item, change the item that exists with thalovant_update_memory_item, or move the workspace to the plan upgrade_plan names (Home); granting a scope will not help.";
|
|
262
264
|
const PLAN_HINT_402 = 'HTTP 402 "API access requires a paid plan." — the token is valid and correctly scoped but the tenant is on the free plan. Free-tier callers can browse the catalog (thalovant_list_marketplace_skills) and set hub ratings, but cannot create, update, release, or delete hubs and runtime groups, and cannot install skills.';
|
|
263
265
|
const MARKETPLACE_HINT_402 = 'HTTP 402 "This skill requires paid marketplace access for the tenant plan." — a DIFFERENT 402 from the plan gate: the plan is paid enough to provision, but this catalog entry has access_tier "paid" and the plan does not include paid marketplace skills. thalovant_list_runtime_group_marketplace reports this per skill as purchase_required, installable, and access_message; check it before installing.';
|
|
264
266
|
const HUB_SKILL_HINT_422 = 'HTTP 422 — the requested hub skill version is unusable: "latest" could not be resolved to a published version of that skill, or the version string is not a valid version. Check the skill name and its published versions with thalovant_list_marketplace_skills, or pass an explicit x.y.z.';
|
|
265
267
|
const ETAG_HINT_412 = 'HTTP 412 "ETag mismatch" — the If-Match etag was missing or stale and nothing changed. Re-fetch the hub with thalovant_get_hub, read the `etag` field from the response BODY (there is no ETag response header), and retry with that exact value. The comparison is exact string equality, so do not rewrite or weaken the value.';
|
|
266
268
|
function controlPlaneErrorHint(profile, status, body, code) {
|
|
269
|
+
if (profile === "memoryWrite") {
|
|
270
|
+
// The memory routes have their own scopes and refusals, which the hub-centric
|
|
271
|
+
// hints below would misdescribe; the one worth a hint is the plan's limit.
|
|
272
|
+
return status === 409 && code === "memory_limit" ? MEMORY_LIMIT_HINT_409 : undefined;
|
|
273
|
+
}
|
|
267
274
|
switch (status) {
|
|
268
275
|
case 402:
|
|
269
276
|
return (profile === "skillInstall" || profile === "hubSkillInstall") && /marketplace/i.test(body) ? MARKETPLACE_HINT_402 : PLAN_HINT_402;
|
|
@@ -280,6 +287,8 @@ function controlPlaneErrorHint(profile, status, body, code) {
|
|
|
280
287
|
? "HTTP 404 (hub_without_runtime_group) — the hub exists but has no runtime group attached yet, so it cannot hold skills; attach it to a runtime group (thalovant_update_hub) before managing its skills. A 404 without that code means the hub is unknown, or the named skill is not installed on it."
|
|
281
288
|
: undefined;
|
|
282
289
|
case 409:
|
|
290
|
+
if (code === "skill_unavailable_licensing")
|
|
291
|
+
return LICENSING_HINT_409;
|
|
283
292
|
if (profile === "hubWrite") {
|
|
284
293
|
return 'HTTP 409 — for a hub create this is either a duplicate ("Hub with name ... already exists for this owner" / "Hub slug ... already exists"), an autoscaling slot limit (AUTOSCALING_HUB_LIMIT_REACHED), or "Idempotency key re-used with different payload". Only hub create honors Idempotency-Key: retrying an identical create is safe and returns the original hub, but reusing a key with a changed body conflicts — use a new idempotencyKey for a genuinely different hub.';
|
|
285
294
|
}
|
|
@@ -1990,7 +1999,7 @@ export function createServer() {
|
|
|
1990
1999
|
const { loginScope, apiUrl, ...payload } = args;
|
|
1991
2000
|
const api = await createControlPlane({ loginScope, apiUrl });
|
|
1992
2001
|
ensureAuthenticated(api);
|
|
1993
|
-
return jsonContent(redactSecrets(await api.createMemoryItem(payload)));
|
|
2002
|
+
return jsonContent(redactSecrets(await callControlPlane("memoryWrite", () => api.createMemoryItem(payload))));
|
|
1994
2003
|
});
|
|
1995
2004
|
registerThalovantTool(server, "thalovant_update_memory_item", {
|
|
1996
2005
|
title: "Update Memory Item",
|
|
@@ -2019,7 +2028,7 @@ export function createServer() {
|
|
|
2019
2028
|
const { loginScope, apiUrl, memoryId, ...payload } = args;
|
|
2020
2029
|
const api = await createControlPlane({ loginScope, apiUrl });
|
|
2021
2030
|
ensureAuthenticated(api);
|
|
2022
|
-
return jsonContent(redactSecrets(await api.updateMemoryItem(memoryId, payload)));
|
|
2031
|
+
return jsonContent(redactSecrets(await callControlPlane("memoryWrite", () => api.updateMemoryItem(memoryId, payload))));
|
|
2023
2032
|
});
|
|
2024
2033
|
registerThalovantTool(server, "thalovant_delete_memory_item", {
|
|
2025
2034
|
title: "Delete Memory Item",
|
package/package.json
CHANGED
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.7.
|
|
10
|
+
"version": "0.7.1",
|
|
11
11
|
"packages": [
|
|
12
12
|
{
|
|
13
13
|
"registryType": "npm",
|
|
14
14
|
"identifier": "@thalovant/mcp-server",
|
|
15
|
-
"version": "0.7.
|
|
15
|
+
"version": "0.7.1",
|
|
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.7.
|
|
22
|
+
"identifier": "ghcr.io/thalovant/thalovant-mcp:0.7.1",
|
|
23
23
|
"transport": {
|
|
24
24
|
"type": "streamable-http",
|
|
25
25
|
"url": "http://127.0.0.1:3000/mcp"
|