@thalovant/mcp-server 0.7.1 → 0.7.2
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 +9 -2
- package/README.md +8 -4
- package/dist/index.js +10 -1
- package/package.json +1 -1
- package/server.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,10 +1,17 @@
|
|
|
1
|
-
Last Edit: Claude
|
|
1
|
+
Last Edit: Claude Opus 5.5 - 2026-11-07 - Motive: Version 0.7.2, dated for its tag: the skill_unavailable_unpublished hint (thalovant-api#495).
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
-
## 0.7.
|
|
5
|
+
## 0.7.2 - 2026-11-07
|
|
6
|
+
|
|
7
|
+
- **A skill with no published release is explained by its code.** thalovant-api#495 adds a second reason the store refuses a skill: `unpublished`, when no installable release of it exists. Installing one answers 409 `skill_unavailable_unpublished` with `reason: unpublished`, before any paid-plan 402, and it got the generic 409 hint, which talks about a version already installed. It now says the skill cannot be installed because no release has been published, that no plan, scope, version or retry changes that and there is nothing to buy, that a non-admin token does not see it in `thalovant_list_marketplace_skills`, and that `thalovant_list_runtime_group_marketplace` lists it only for a group that already has it, with `unavailable_reason` and `installable` and `purchase_required` false. Any other `skill_unavailable_*` code gets the store's refusal in general terms instead of the version hint. `thalovant_list_runtime_group_marketplace`'s description names the field. Three tests drive the hub and runtime-group installs and an unknown code through the fake control plane.
|
|
8
|
+
- The parity contract refreshes the evidence hashes of `src/index.ts` and `test/provisioning.test.ts`.
|
|
9
|
+
- `package.json`, `package-lock.json`, `server.json`, the OCI label, the README and this file move to 0.7.2 together.
|
|
10
|
+
|
|
11
|
+
## 0.7.1 - 2026-11-06
|
|
6
12
|
|
|
7
13
|
- **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.
|
|
14
|
+
- **The real-transport test gets a 90 s budget.** `test/runtime-noise.test.ts` opens eight HTTPS sessions against a local hub, each with its own Noise handshake over a polled connection, and takes about 22 s on a workstation; its 30 s budget ran out on a shared runner twice (`main`, 2026-11-03 and 2026-11-06), passing on the rerun both times. The budget is for the runner, not the calls: every call keeps its own `timeoutMs`, and no assertion changes.
|
|
8
15
|
- `package.json`, `package-lock.json`, `server.json`, the OCI label, the README and this file move to 0.7.1 together.
|
|
9
16
|
|
|
10
17
|
## 0.7.0 - 2026-11-03
|
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Last Edit: Claude
|
|
1
|
+
Last Edit: Claude Opus 5.5 - 2026-11-07 - Motive: Version 0.7.2, which carries the skill_unavailable_unpublished hint.
|
|
2
2
|
|
|
3
3
|
# Thalovant MCP Server
|
|
4
4
|
|
|
@@ -89,7 +89,7 @@ Scope is not the whole story for provisioning. Every hub and runtime-group write
|
|
|
89
89
|
- A correctly scoped token on a free plan fails `402 API access requires a paid plan.`
|
|
90
90
|
- `thalovant_install_runtime_group_skill` can fail with a **second, distinct** 402, `This skill requires paid marketplace access for the tenant plan.`, when the plan is paid but does not include `access_tier: paid` catalog entries.
|
|
91
91
|
|
|
92
|
-
Discovery is deliberately not paid-gated: **a free-tier token can browse the marketplace catalog and set hub ratings, but cannot install skills or provision hubs.** Use `thalovant_list_runtime_group_marketplace` before installing — it reports `installable`, `purchase_required`, and `access_message` per skill, which turns an opaque 402 into a decision you can make up front.
|
|
92
|
+
Discovery is deliberately not paid-gated: **a free-tier token can browse the marketplace catalog and set hub ratings, but cannot install skills or provision hubs.** Use `thalovant_list_runtime_group_marketplace` before installing — it reports `installable`, `purchase_required`, and `access_message` per skill, which turns an opaque 402 into a decision you can make up front. A skill the store does not install carries `unavailable_reason` (`licensing` or `unpublished`) with `installable` and `purchase_required` false, and is listed there only for a group that already has it.
|
|
93
93
|
|
|
94
94
|
Grant fewer scopes for narrower deployments: a read-only assistant needs only `hubs:read` and `memory:read`, and a discovery-only agent that browses skills but never provisions needs `hubs:read` alone. `thalovant_get_analytics_overview` with `admin: true` additionally requires an admin account with `admin:analytics`, which API tokens for regular use should not carry. Runtime hub tools (`thalovant_ask`, `thalovant_send_action`, and friends) use Thalovant client identities, not control-plane tokens.
|
|
95
95
|
|
|
@@ -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)). 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.
|
|
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. A skill with no published release fails `409` with code `skill_unavailable_unpublished` and `reason: unpublished`, before any paid-plan `402`: it cannot be installed or bought until a release is published. A non-admin token does not see such a skill in `thalovant_list_marketplace_skills` at all.
|
|
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
|
|
|
@@ -519,6 +519,10 @@ 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
520
|
A 409 `skill_unavailable_licensing` says the store refuses the skill for its
|
|
521
521
|
licensing and where the catalog announces it, instead of the version hint. A
|
|
522
|
+
409 `skill_unavailable_unpublished` says the skill cannot be installed because
|
|
523
|
+
no release of it has been published, that no plan, scope, version or retry
|
|
524
|
+
changes that and there is nothing to buy, and where the listings show it; any
|
|
525
|
+
other `skill_unavailable_*` code gets the store's refusal in general terms. A
|
|
522
526
|
memory create or update refused with 409 `memory_limit` (the plan's remembered
|
|
523
527
|
items are used up; a Free plan keeps one, `limit` and `upgrade_plan` are in the
|
|
524
528
|
fields) names the delete tool that frees a slot, the update tool that changes
|
|
@@ -596,7 +600,7 @@ Runtime calls sharing the same hub client identity run sequentially within one
|
|
|
596
600
|
MCP process. Use a distinct client identity for each independently running MCP
|
|
597
601
|
server so the hub can keep their sessions separate.
|
|
598
602
|
|
|
599
|
-
Version 0.7.
|
|
603
|
+
Version 0.7.2 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
|
|
600
604
|
secure effective MQTT URLs and carries a single connection deadline through
|
|
601
605
|
MQTT setup and HTTP failure cleanup. Runtime tools support
|
|
602
606
|
HiveMind v3 Noise over WSS, HTTPS and MQTT over TLS. `thalovant_healthcheck`
|
package/dist/index.js
CHANGED
|
@@ -260,6 +260,9 @@ const SCOPE_HINT_403 = 'HTTP 403 "Insufficient scopes" — the token lacks the s
|
|
|
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
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 UNPUBLISHED_HINT_409 = 'HTTP 409 skill_unavailable_unpublished — this skill cannot be installed: no release of it has been published yet, so there is nothing a runtime could install (the problem\'s reason says unpublished). No plan, scope, version or retry changes that, and it cannot be bought either; it becomes installable only once a release is published. A non-admin token does not see it in thalovant_list_marketplace_skills at all (an admin\'s lists it with unavailable_reason "unpublished" and installable false), and thalovant_list_runtime_group_marketplace lists it only for a group that already has it, with unavailable_reason, installable false and purchase_required false.';
|
|
264
|
+
/** Any other `skill_unavailable_*` refusal: a reason the API may add later. */
|
|
265
|
+
const SKILL_UNAVAILABLE_HINT_409 = "HTTP 409 skill_unavailable — the store does not install this skill on Thalovant; the problem's reason and sentence say why. No plan, scope, version or retry changes that, and there is nothing to buy. thalovant_list_runtime_group_marketplace reports such a skill with unavailable_reason, and installable false, for a group that already has it.";
|
|
263
266
|
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.";
|
|
264
267
|
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.';
|
|
265
268
|
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.';
|
|
@@ -287,8 +290,14 @@ function controlPlaneErrorHint(profile, status, body, code) {
|
|
|
287
290
|
? "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."
|
|
288
291
|
: undefined;
|
|
289
292
|
case 409:
|
|
293
|
+
// A skill the store refuses answers 409 before any paid-plan 402, and is
|
|
294
|
+
// never the version clash the generic hint below describes.
|
|
290
295
|
if (code === "skill_unavailable_licensing")
|
|
291
296
|
return LICENSING_HINT_409;
|
|
297
|
+
if (code === "skill_unavailable_unpublished")
|
|
298
|
+
return UNPUBLISHED_HINT_409;
|
|
299
|
+
if (code?.startsWith("skill_unavailable_"))
|
|
300
|
+
return SKILL_UNAVAILABLE_HINT_409;
|
|
292
301
|
if (profile === "hubWrite") {
|
|
293
302
|
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.';
|
|
294
303
|
}
|
|
@@ -2079,7 +2088,7 @@ export function createServer() {
|
|
|
2079
2088
|
});
|
|
2080
2089
|
registerThalovantTool(server, "thalovant_list_runtime_group_marketplace", {
|
|
2081
2090
|
title: "List Runtime Group Marketplace",
|
|
2082
|
-
description: "List the marketplace catalog resolved against one runtime group. This is the view to read immediately before installing: every catalog entry comes back with the group's own state folded in — whether the skill is desired (active, version_pin, source_type), whether it was observed running (observed_source, observed_at, intent counts), operator status, and the plan verdict (purchase_required, installable, access_message). Check installable and purchase_required here to avoid a 402 at install time. Requires the hubs:inspect scope; browsing needs no paid plan. Answers 404 for an unknown group and 403 when the caller does not own it.",
|
|
2091
|
+
description: "List the marketplace catalog resolved against one runtime group. This is the view to read immediately before installing: every catalog entry comes back with the group's own state folded in — whether the skill is desired (active, version_pin, source_type), whether it was observed running (observed_source, observed_at, intent counts), operator status, and the plan verdict (purchase_required, installable, access_message). Check installable and purchase_required here to avoid a 402 at install time. A skill the store does not install carries unavailable_reason (licensing or unpublished) with installable and purchase_required false, and is listed only when the group already has it. Requires the hubs:inspect scope; browsing needs no paid plan. Answers 404 for an unknown group and 403 when the caller does not own it.",
|
|
2083
2092
|
inputSchema: {
|
|
2084
2093
|
...controlPlaneSchema,
|
|
2085
2094
|
runtimeGroupId: z.string().min(1).describe("Runtime group UUID."),
|
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.2",
|
|
11
11
|
"packages": [
|
|
12
12
|
{
|
|
13
13
|
"registryType": "npm",
|
|
14
14
|
"identifier": "@thalovant/mcp-server",
|
|
15
|
-
"version": "0.7.
|
|
15
|
+
"version": "0.7.2",
|
|
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.2",
|
|
23
23
|
"transport": {
|
|
24
24
|
"type": "streamable-http",
|
|
25
25
|
"url": "http://127.0.0.1:3000/mcp"
|