# MCP Server

> Connect Claude, Codex, Cursor, and other MCP clients to Thalovant hubs through the published Thalovant MCP server.

Source: https://docs.thalovant.com/developers/mcp/

---
{/* Last Edit: Codex (model identifier unavailable) - 2026-10-26 - Motive: Align install guidance with the verified MCP 0.6.6 release. */}

Use the Thalovant MCP server when an MCP client should discover hubs, provision hubs and runtime groups, create client identities, ask a hub, read analytics, or work with memory through Thalovant.

MCP means Model Context Protocol. It gives local agents and remote agent gateways a standard way to call Thalovant tools.

## At A Glance

| Item | Value |
| --- | --- |
| MCP registry name | `io.github.thalovant/thalovant-mcp` |
| npm package | `@thalovant/mcp-server` |
| current version | `0.6.6` |
| container image | `ghcr.io/thalovant/thalovant-mcp:0.6.6` |
| transports | stdio and Streamable HTTP |
| tool count | 50 by default; 53 with destructive tools enabled; 24 in read-only mode |
| local path | best for Claude Desktop, Codex, Cursor, and desktop agents |
| remote path | best for hosted agent gateways and shared agent platforms |
| license | MIT |

  
  
  
  

## Choose A Transport

| Transport | Use it when | Start command |
| --- | --- | --- |
| stdio | The MCP client runs on the same machine as the server process. | `npx --yes @thalovant/mcp-server@0.6.6 --stdio` |
| Streamable HTTP | Remote MCP clients connect over HTTP to `/mcp`. | `docker run ghcr.io/thalovant/thalovant-mcp:0.6.6` |

Start with stdio for a personal agent. Use Streamable HTTP when the server is deployed behind your own auth, logs, and network controls.

## Hub Runtime Connections

Hub runtime tools go through the Node SDK over WSS, HTTPS, or MQTT over TLS; every connection is encrypted and authenticated before anything is sent. MCP stdio and Streamable HTTP describe the agent-to-MCP connection; they don't select the hub protocol.

Preserve the Node SDK's private configuration directory between MCP process or container restarts so its saved keys survive. By default this is `~/.config/thalovant` on Linux and macOS, `$XDG_CONFIG_HOME/thalovant` when that variable is set, or `%APPDATA%\Thalovant` on Windows. A custom identity file or `configPath` doesn't move it. See [Saved Keys](/developers/identity-files/#saved-keys).

Runtime calls using the same hub endpoint and access key are serialized within a single MCP process, and actual connection cleanup must finish before the next starts. Waiting for the identity lease is bounded at six seconds; a timed-out or cancelled queued call never runs later. If cleanup fails, that identity remains unavailable in the process so a new tool can't reuse uncertain session state. Use `thalovant_ask` or `thalovant_query` when a request needs its reply: separate send and wait tool calls don't share a persistent connection, and a waiter using the same identity can hold up a later send. Identity inspection alone doesn't open or disconnect a hub session. Use distinct runtime identities for separate MCP processes, or coordinate their identity use externally.

MCP request cancellation is forwarded to runtime connection setup, Ask, Query, and event waits. Cancelling stops the caller's wait. An action, code input, event emission, or inventory operation that has already started may still finish; its identity stays occupied through the operation and connection cleanup. Cancellation doesn't undo or automatically replay a published request.

Use a dedicated identity for each independently running MCP process or other client. In particular, don't reuse an identity already serving another app's HTTP session: the new client would wait for a session the other one owns. Keep the saved hub identity, and confirm any change with the hub owner before accepting it.

## Local Agent Setup

Public hub discovery works without Thalovant credentials. Private workspace tools and runtime tools need server-side Thalovant credentials.

Since version `0.1.9`, a scoped API token in `THALOVANT_API_TOKEN` is the recommended way to authenticate the server, so the config never contains your account password. Create the token on the dashboard's [API Tokens page](/account/api-tokens/) with these scopes for the full tool surface:

| Scope | Tools that need it |
| --- | --- |
| `hubs:read` | Hub discovery, hub detail, the marketplace catalog, and runtime group reads. |
| `hubs:inspect` | Runtime group inventory, the group marketplace view, hub runtime capabilities, `thalovant_list_hub_skills`, and `thalovant_list_hub_skill_history`. Granted automatically by `hubs:read`. |
| `hubs:write` | Hub and runtime group provisioning tools, plus `thalovant_install_hub_skill`, `thalovant_update_hub_skill`, and `thalovant_remove_hub_skill`. Paid plans. |
| `clients:write` | `thalovant_create_client_identity`. |
| `memory:read` | Memory list, summary, and item reads. Every plan. |
| `memory:write` | Memory create, update, and delete. Every plan; Free keeps one memory item. |

A read-only assistant needs only `hubs:read` and `memory:read`. Tokens are scoped, revocable, and show their last use on the API Tokens page.

The hub scopes imply one another. `hubs:write` grants `hubs:read`, which grants `hubs:inspect`, so a token minted with `hubs:read` already covers every discovery tool.

Your plan decides which of these scopes you can grant. The Free plan covers `hubs:read`, the client scopes, and the memory scopes, so an agent on it can run the Discovery tools, browse the marketplace catalog, call `thalovant_create_client_identity`, and use the Memory tools. Free keeps one memory item, so a second `thalovant_create_memory_item` fails with HTTP 409 and the code `memory_limit`. The Free plan also allows one active token at a time.

A Free-plan API token can't carry `hubs:write` at all. The API checks the plan first, so on Free the Provisioning tools fail with HTTP 402 and the upgrade message rather than a scope error. See [Provision Hubs](/developers/provisioning/#read-402-before-403).

The server's Thalovant API calls count against your plan's token rate limit and call quotas, so a busy agent can reach them. Over the limit, calls return HTTP 429 with a `Retry-After` header. The [API Tokens page](/account/api-tokens/) has the per-plan table and the matching error codes.

For stdio MCP hosts that use JSON server configuration, such as Claude Desktop or Cursor:

```json
{
  "mcpServers": {
    "thalovant": {
      "command": "npx",
      "args": ["--yes", "@thalovant/mcp-server@0.6.6", "--stdio"],
      "env": {
        "THALOVANT_API_TOKEN": "tvpat_...",
        "THALOVANT_PROFILE": "prod",
        "THALOVANT_API_URL": "https://api.thalovant.com"
      }
    }
  }
}
```

For control-plane authentication, the server tries `THALOVANT_API_TOKEN` first, then `THALOVANT_ACCESS_TOKEN`, then a `THALOVANT_EMAIL` and `THALOVANT_PASSWORD` login. With a token set, the server never calls the login endpoint. A matching per-principal control token takes precedence over these shared credentials.

The `thalovant_config_status` tool reports which mode the environment declares in its `controlPlaneAuthMode` field: `api-token`, `access-token`, `email-password`, or `none`. Token values never appear in its output.

  Don't paste Thalovant tokens, passwords, identity files, or setup links into chat. Configure them in the MCP server environment or in protected files.

### Configure A Hub Identity

An API token lets MCP call the Thalovant API. Runtime tools also need a client identity containing that hub's access key, password, and endpoints. For local stdio, use one of these sources:

| Source | Runtime tool arguments |
| --- | --- |
| Downloaded, protected JSON identity | `identityFile` with the path on the MCP server's machine |
| SDK YAML profile | `configPath` and/or `profile`; otherwise the default config and `THALOVANT_PROFILE` apply |
| SDK environment identity | `fromEnv: true`, with the SDK's identity variables configured in the server environment |

The server can also create an identity with `thalovant_create_client_identity`: provide the hub UUID and a filename such as `agent.json` in `savePath`, then use its `savedIdentityPath` in runtime calls. The server writes the full identity to the protected directory and returns a redacted summary.

For example, call `thalovant_ask` with tool arguments like these after placing the identity at that path:

```json
{
  "identityFile": "/path/to/private/agent.json",
  "protocol": "https",
  "text": "What time is it?",
  "timeoutMs": 30000
}
```

The default protocol is `wss`. Explicit `https` and `mqtt` require that transport to be enabled in the identity and on the hub. `thalovant_identity_status` checks the loaded identity without connecting; `thalovant_healthcheck` connects and authenticates before reporting runtime health.

## API Destination Restrictions

Configured API tokens and password credentials are bound to their configured API origin. An authenticated tool's `apiUrl` can't select another origin; the server rejects the override before contacting it. For a self-hosted API, configure its URL alongside matching credentials, either server-wide or on the authenticated principal. Equivalent normalized origins are accepted. Anonymous public discovery can use a custom URL when no API credentials are configured for that caller.

Control-plane requests refuse redirects, including redirects that would resend a login body. Authenticated requests and request bodies require HTTPS, with HTTP allowed only for explicit `localhost`, `127.0.0.1`, or `[::1]` development endpoints. API URLs can't contain embedded credentials. Set the final API URL directly when an old endpoint redirects.

## Remote HTTP Setup

The container runs Streamable HTTP on port `3000` and serves MCP at `/mcp`.

```bash
export MCP_HTTP_AUTH_TOKEN="$(openssl rand -hex 32)"
docker run --rm \
  -p 127.0.0.1:3000:3000 \
  -e MCP_HTTP_AUTH_TOKEN \
  -e MCP_HTTP_ALLOWED_HOSTS="127.0.0.1:3000,localhost:3000" \
  ghcr.io/thalovant/thalovant-mcp:0.6.6
```

Clients connect to:

```text
http://127.0.0.1:3000/mcp
Authorization: Bearer <token>
```

Health checks are available at `/healthz` and `/readyz`.

Configure the client with the same token stored in `MCP_HTTP_AUTH_TOKEN`. This example enables access to MCP; add per-principal Thalovant credentials below before using private or runtime tools. The HTTP health routes describe the MCP process, while `thalovant_healthcheck` verifies a hub connection.

For runtime calls in a container, mount a private, persistent directory for the SDK's saved keys at `/home/thalovant/.config/thalovant`, or set `XDG_CONFIG_HOME` to a mounted configuration root. The directory must be writable by the container's `thalovant` user; protect mounted identity files with owner-only permissions.

For a public endpoint, set exact public URL, host, and origin values:

```bash
export MCP_PUBLIC_URL="https://mcp.example.com"
export MCP_HTTP_ALLOWED_HOSTS="mcp.example.com"
export MCP_HTTP_ALLOWED_ORIGINS="https://agent.example.com"
```

## Auth And Credentials

1. **Keep bearer auth on.** HTTP mode requires `MCP_HTTP_AUTH_TOKEN` or `MCP_HTTP_AUTH_TOKENS` by default.
2. **Use OAuth validation for shared remote servers.** Set `MCP_HTTP_AUTH_MODE=jwt` with JWKS, or use `MCP_HTTP_AUTH_MODE=introspection` for opaque tokens.
3. **Map users to Thalovant credentials.** Use `THALOVANT_PRINCIPAL_CREDENTIALS_FILE` or `THALOVANT_PRINCIPAL_CREDENTIALS_DIR`.
4. **Disable shared credentials for multi-user servers.** Keep `THALOVANT_ALLOW_SHARED_CREDENTIALS=false`.
5. **Set tool policy.** Use `MCP_TOOL_ALLOWLIST` and `MCP_TOOL_DENYLIST` for server-wide controls.
6. **Send audit logs somewhere durable.** Set `MCP_AUDIT_LOG=stderr`, or set `MCP_AUDIT_LOG=file` with `MCP_AUDIT_LOG_FILE`. Use `MCP_AUDIT_LOG=both` with a file path for both destinations. A file path alone leaves logging off.

Remote callers' `identityFile`, `configPath`, `profile`, and `fromEnv` arguments are disabled by default. Configure the identity on the server for each authenticated principal using the [credential file format](https://github.com/thalovant/thalovant-mcp/blob/v0.2.0/examples/principal-credentials.sample.json). Directory-mode files are named `<sha256(principal-id)>.json`; a matching directory entry takes precedence over the shared credential file. `MCP_HTTP_ALLOW_CLIENT_CREDENTIAL_PATHS=true` permits caller-selected paths and should be limited to trusted private deployments.

The server publishes OAuth protected resource metadata at:

```text
https://mcp.example.com/.well-known/oauth-protected-resource
```

## Tool Groups

  
    `thalovant_config_status`, `thalovant_list_public_hubs`, `thalovant_get_public_hub`, `thalovant_list_hubs`, and `thalovant_get_hub`.
  
  
    `thalovant_identity_status`, `thalovant_healthcheck`, `thalovant_intent_inventory`, `thalovant_ask`, `thalovant_query`, `thalovant_send_action`, `thalovant_send_code`, `thalovant_emit_event`, and `thalovant_wait_for_event`.
  
  
    `thalovant_list_memory_items`, `thalovant_get_memory_summary`, `thalovant_get_memory_item`, `thalovant_create_memory_item`, `thalovant_update_memory_item`, and `thalovant_delete_memory_item`.
  
  
    `thalovant_create_client_identity`, `thalovant_get_operation`, and `thalovant_get_analytics_overview`.
  
  
    `thalovant_list_marketplace_skills`, `thalovant_list_runtime_group_marketplace`, `thalovant_list_runtime_group_inventory`, `thalovant_list_runtime_groups`, `thalovant_get_runtime_group`, `thalovant_get_runtime_group_config`, and `thalovant_get_hub_runtime_capabilities`.
  
  
    `thalovant_create_hub`, `thalovant_update_hub`, `thalovant_release_hub`, `thalovant_create_runtime_group`, `thalovant_update_runtime_group`, `thalovant_update_runtime_group_config`, `thalovant_release_runtime_group`, `thalovant_install_runtime_group_skill`, and `thalovant_uninstall_runtime_group_skill`.
  
  
    `thalovant_set_hub_rating` and `thalovant_clear_hub_rating`. These need `hubs:write`, which a Free-plan token cannot carry, so rate hubs in the dashboard on Free or use a token from a Home or higher plan.
  
  
    `thalovant_list_hub_skills`, `thalovant_list_hub_skill_history`, `thalovant_install_hub_skill`, `thalovant_update_hub_skill`, and `thalovant_remove_hub_skill`. History is available from `0.2.0`; the other tools from `0.1.23`.
  

`thalovant_create_client_identity` doesn't return secret identity material in chat output. Use `savePath` when you want the full identity written to a local file with mode `0600`. The path is resolved inside `THALOVANT_MCP_IDENTITY_DIR` (a safe config directory by default); a `savePath` that's absolute outside that base, or uses `..` to escape it, is rejected before any credential is created.

The Skill discovery and Provisioning groups, and the two opt-in delete tools below, are available. Discovery is read-only and works on any plan. Provisioning needs `hubs:write` and a paid plan. For the full flow, the etag rule, and the error table, see [Provision Hubs](/developers/provisioning/).

`thalovant_update_hub` requires the hub's current `etag` as an input and doesn't accept `name`, `namespace`, or `domain`, because those are fixed at creation. Call `thalovant_get_hub` first and pass the `etag` field from its response body.

The Hub skills group manages skills on the runtime group a hub selects, which affects every hub sharing that group. Each tool takes the hub UUID as `hubId`; the three write tools also take the skill id as `skill`. `thalovant_install_hub_skill` accepts an optional `version` (default `latest`), `thalovant_update_hub_skill` requires one, and `thalovant_remove_hub_skill` accepts no `version`. The three write tools return the accepted operation; pass `wait: true` to poll it with `thalovant_get_operation` semantics every 2 seconds, with a 120,000 ms polling budget unless `timeoutMs` says otherwise. `thalovant_list_hub_skills` returns the route's envelope with the rows under `data`, and it and the new history tool are visible in read-only mode. The app path, the routes, and the error table are on [Add a Skill to a Hub](/manage/add-a-skill-to-a-hub/).

Hub-skill requests and polling go through the published Node SDK. MCP cancellation checks still apply, and no new status read starts after the polling deadline. The polling deadline doesn't cancel an HTTP request already in flight. If a status read fails after a write was accepted, the tool error retains the operation ID; follow it with `thalovant_get_operation` instead of submitting the write again.

## Runtime Discovery And Routed Queries

`thalovant_intent_inventory` reads the hub through its configured runtime identity. Supply one to 20 language tags and an optional per-query `timeoutMs`; its response includes fallback handlers, `fallbacks_known`, and a `may_answer` map. Connection setup is cancellable; inventory then uses per-query or batch budgets and a separate optional fallback probe of at most 1.5 seconds. There's no single total inventory deadline. Unknown discovery doesn't mean the hub can't answer. See [intent discovery](/concepts/hub-intents/).

`thalovant_query` sends a routed query and collects matching cascade replies until completion or its deadline. It returns the same normalized reply fields as Ask and ignores another query's replies. Like Ask, it can trigger hub actions and is hidden in read-only mode. Reuse a `sessionId` across calls for conversation context; each tool call still owns a separate connection and cleanup. Leave `requestId` and `queryId` to the generated defaults or supply fresh values for every logical operation, including after cancellation. These IDs correlate replies and don't make repeated actions idempotent. `thalovant_wait_for_event` supplies a bounded event wait, rather than a persistent SDK event stream.

`thalovant_get_operation` reads an operation returned by provisioning. Check its typed status before treating the resource as ready; `requested`, `committed`, and `applied` are intermediate states. `failed` and `timed_out` report unsuccessful completion.

## Destructive Tools

`thalovant_delete_hub` and `thalovant_delete_runtime_group` are disabled by default. They aren't merely blocked when called: they are never registered, so they never appear in the tool list and a model can't see or attempt them.

Deleting a hub also deletes its dependent clients and ACLs, and none of it is reversible. A long-lived control-plane token paired with an always-visible delete tool is a different class of risk from a read or update tool, so these two are opt-in.

To turn them on, set the environment variable before the server starts:

```bash
export THALOVANT_ENABLE_DESTRUCTIVE_TOOLS="true"
```

| Rule | Value |
| --- | --- |
| Accepted true values | `1`, `true`, `yes`, and `on`, in any letter case. |
| Anything else | Leaves the tools off, including unset, empty, `0`, and `false`. |
| When it is read | At server construction. Restart the server process with the updated environment after changing it. |
| How to confirm | `thalovant_config_status` reports `destructiveToolsEnabled` and lists the tools the flag controls. |

This is deliberately separate from `MCP_TOOL_ALLOWLIST` and `MCP_TOOL_DENYLIST`. Those are call-time filters where an empty allowlist means "allow everything", so they can't express a tool that stays off until someone turns it on, and they can't hide a tool from the tool list. Once the flag is set, the delete tools become ordinary tools again and the policy still applies, so the two layers compose:

```bash
# Register delete tools, then deny their use to every principal.
export THALOVANT_ENABLE_DESTRUCTIVE_TOOLS="true"
export MCP_TOOL_DENYLIST="thalovant_delete_hub,thalovant_delete_runtime_group"
```

A global deny applies to every principal; a principal's `allowedTools` can't override it. To deny a tool only to selected principals, use their `deniedTools` entries and omit that tool from the global denylist.

Deleting a hub needs a nonempty current etag; a stale value fails with HTTP 412. Deleting a runtime group fails with HTTP 409 while it's the workspace default or still has hubs attached.

  Leave these tools off unless an agent has a real reason to delete Thalovant resources. Deleting a hub can't be undone.

## Restricting Sources And Tools

Since version `0.1.11`, three more environment variables narrow what the server will do, on top of the destructive-tool gate above. Like that gate, each is read at server start and reported by `thalovant_config_status`.

**Non-catalog skill sources are off by default.** `thalovant_install_runtime_group_skill` installs from the reviewed marketplace catalog. A `git` or URL source runs code the catalog never reviewed, so those sources are rejected unless you opt in:

```bash
export THALOVANT_ENABLE_GIT_SKILL_SOURCES="true"
```

With the flag unset, a non-catalog `sourceType` fails with a clear client-side error that names the variable, and no control-plane call is made. `thalovant_config_status` reports `gitSkillSourcesEnabled`.

**Identity files stay inside one directory.** When `thalovant_create_client_identity` writes to `savePath`, the path is confined to `THALOVANT_MCP_IDENTITY_DIR`, so an agent can't drop a credential file into an arbitrary location such as a synced folder or a git working tree. `thalovant_config_status` reports `identityDir`.

**Read-only mode hides every write tool.** Set `THALOVANT_MCP_READONLY="true"` to register only the tools marked read-only, including discovery, memory reads, analytics, identity status, health checks, and event waits. It also hides `thalovant_ask`, `thalovant_query`, action, code, and event-emission tools because a hub request can trigger actions. `thalovant_config_status` reports `readOnly`.

## Tool Errors

When the Thalovant API refuses a control-plane call, the tool error starts with the SDK's one-line message, which names the HTTP status and can be cut short. The lines after it say what the API said in full:

| Line | What it holds |
| --- | --- |
| `code:` | The API's machine-readable code, such as `platform_image_required` or `plan_limit`. |
| `detail:` | The whole sentence. It appears only when the first line had to shorten it. |
| `fields:` | Every other member of the error body as compact JSON, with the same secret redaction as other tool output. For `platform_image_required` that is `allowed_images`, `allowed_repositories`, and `refused_images`. |

A `platform_image_required` or `plan_limit` refusal gets a hint that fits it, not the general scope hint, because granting a scope changes neither. This arrived in `0.5.3`.

## Tool Input Rules

Since version `0.1.8`, the server validates tool inputs against the same bounds the Thalovant API enforces, so bad values fail with a clear client-side error instead of an opaque API 422.

| Rule | Value |
| --- | --- |
| `thalovant_list_public_hubs` page size | Capped at 48, matching the public hubs endpoint. Authenticated `thalovant_list_hubs` keeps its limit of 100. |
| Hub references on authenticated tools | `thalovant_get_hub` and `thalovant_create_client_identity` require the hub UUID. Slugs are only accepted by the public hub tools, such as `thalovant_get_public_hub`. |
| Memory `title` | 160 characters or fewer. |
| Memory `content` | 4096 characters or fewer. |
| Memory `source` | 64 characters or fewer. |
| Memory `consentScope` | 128 characters or fewer. |
| Memory `consentVersion` | 64 characters or fewer. |
| Memory `retentionPolicy` | 64 characters or fewer. |
| Memory list `query` | 240 characters or fewer. |
| Runtime `protocol` | `wss` (default), `https`, or `mqtt`. |
| Ask `text`, action `payload`, code `value` | Non-empty strings, up to 20,000 characters. Action `payload` is one string, not a separate command and object. |
| Runtime `timeoutMs` | 1,000–300,000 ms where offered; ask and event waits default to 30,000 ms, health checks to 10,000 ms. |

`thalovant_ask` returns `text`, `displayText`, `utterances`, `handled`, `ok`, `sessionId`, `requestId`, `displayItems`, `events`, and any `failureEvent`. Action, code, and event-emission tools confirm that the event was sent; they don't wait for a hub answer.

## Common Issues

| Symptom | Check first |
| --- | --- |
| Claude or Codex cannot start the server | Confirm Node.js 20 or newer is installed and the command uses `npx --yes @thalovant/mcp-server@0.6.6 --stdio`. |
| Public hub tools work but private API tools fail | Configure `THALOVANT_API_TOKEN` or a matching per-principal control token, then check `thalovant_config_status`. |
| API tools work but runtime tools fail | Configure a separate hub identity with its password and endpoints; an API token alone is insufficient. |
| Previous runtime session cleanup failed | This process blocks the identity. Finish and verify the previous hub session's cleanup before reusing that identity; restarting MCP alone does not prove it is closed. |
| The connection opens but authentication times out | Verify that another client is not using the same identity, and close the client that owns the existing session before retrying. |
| Runtime access fails after a process or container restart | Restore the original saved keys and check identity credentials. Do not delete saved hub identities as a retry step. |
| A tool fails with a scope error | Recreate the token on the API Tokens page with the scopes the tool group needs. |
| Memory create fails with HTTP 409 `memory_limit` on the Free plan | Free keeps one memory item. Delete the existing item, or upgrade to Home for unlimited memory. |
| Provisioning tools fail with HTTP 402 on the Free plan | The API checks the plan before the scopes. Upgrade, then mint a token with `hubs:write`. |
| Rating tools fail with HTTP 403 on the Free plan | Rating needs `hubs:write`, which a Free-plan token cannot carry. Rate the hub in the dashboard, or use a token from a Home or higher plan. |
| `thalovant_install_runtime_group_skill` returns HTTP 402 on a paid plan | The skill is a paid catalog entry the plan does not cover. Call `thalovant_list_runtime_group_marketplace` first and check `installable` and `purchase_required`. |
| `thalovant_update_hub` returns HTTP 412 | The `etag` is missing or stale. Call `thalovant_get_hub` again and pass the `etag` from its response body. |
| `thalovant_install_hub_skill` returns HTTP 409 or 404 | 409 (`skill_version_already_installed`) means the hub already has that skill at that version; post another version to update instead. 404 with the code `hub_without_runtime_group` means the hub is not in a runtime group yet; a 404 without a code means `hubId` is unknown, often a slug rather than the UUID. |
| The delete tools are missing from the tool list | They are opt-in. Set `THALOVANT_ENABLE_DESTRUCTIVE_TOOLS` and restart the server. See [Destructive Tools](#destructive-tools). |
| Calls return HTTP 429 | The token reached its plan's rate limit or call quota. Wait for the `Retry-After` interval, then retry. |
| HTTP returns 401 | Send `Authorization: Bearer <token>` and confirm the token matches the server config. |
| HTTP returns 403 for a browser client | Add the exact origin to `MCP_HTTP_ALLOWED_ORIGINS`. |
| Remote users see the same Thalovant data | Configure per-principal credentials and keep shared credentials disabled. |
| A risky tool should not be available | Add it to `MCP_TOOL_DENYLIST`, or use a per-principal `deniedTools` policy. |

## Next

Use [SDK Functions](/developers/sdk-functions/) when you want the underlying Thalovant SDK method names. Use [Provision Hubs](/developers/provisioning/) when an agent should create hubs and runtime groups. Use [Identity Files](/developers/identity-files/) when runtime tools need saved hub credentials.

## Shared-Runtime Skill History

`thalovant_list_hub_skill_history` accepts `hubId` and an optional integer `limit`
from 1 to 200 (default 50). It returns the newest skill events and operations,
including versions, timestamps, actors and outcome fields. The tool is read-only
and remains available when `THALOVANT_MCP_READONLY` is enabled.

The hub skill tools select the runtime group attached to the hub. **Every hub
sharing that group sees the same skill changes and history.** A restricted token
must cover all served hubs; `hubs:inspect` is sufficient for history. Use
`thalovant_get_operation` to inspect an accepted write rather than repeating it
when waiting fails.

## Request Hints, Audio, And Configuration Updates

`thalovant_ask` accepts `sttLang`, an ordered `pipeline`, and `location`
(`city` is required; `region`, `country`, `timezone`, `latitude`, and `longitude`
are optional). These hints apply to that request without changing stored runtime
configuration. Omit unused hints; an empty pipeline is ignored, and blank
language or city strings are rejected.

Ask and Query return language, audio metadata, and `droppedMedia`. Embedded
hexadecimal audio stays out of text output. Set `includeAudio: true` to receive
separate MCP audio blocks for recognized formats, or embedded binary resource
blocks for unknown formats. The SDK bounds clips at 4 MiB each and 16 MiB per
reply before collection. The client owns playback; the server never fetches
skill-supplied audio paths or URLs.

`thalovant_intent_inventory` accepts `speakable`, `sentence`, `slots`, and `exampleLimit`.
The example limit is 1–20 per language, with a default of 2.
Raw patterns stay available; rendered examples remove optional wording and
retain the original complete-phrase ranking.

`thalovant_update_runtime_group_config` defaults to `merge: true`, using a
revision precondition and retrying only HTTP 412 up to three total attempts.
It needs the `hubs:read` and `hubs:write` scopes and a paid plan. Pass `merge: false` only for an
intentional unconditional replacement, which requires the `hubs:write` scope, a paid plan, and
coordination with other writers. Older APIs without revision support fail
before a merge write. See [configuration updates](/developers/provisioning/).

The underlying Node SDK rejects guarded merges containing integers outside
JavaScript’s safe range before writing, including supplied personas. It also
rejects non-finite values and stored numeric exponents that overflow JavaScript
numbers, preventing conversion to `null`. Use string identifiers or a client
with lossless integer support for such configuration values.

Set `sentence: true` to render inventory examples with locale sample slots,
capitalization and punctuation. It implies speakable rendering. Explicit `slots`
override locale samples, regional selection follows OVOS matching, and the limit
counts unique nonempty rendered examples. Unknown locales retain bare text.
Raw patterns remain in the inventory response.

The server handles SIGTERM and SIGINT by closing its MCP sessions and HTTP
connections, including in the published container. Shutdown has a ten-second
failure deadline if cleanup stalls.

## Presentable Inventory Output

`thalovant_intent_inventory` adds a `presentation` object alongside its existing
native discovery fields, examples, and answerability hints. It groups intents
under readable skill titles and includes `languages_present` and explicit
intent language order. Titles are derived from IDs; catalogue locales remain
empty and hub metadata remains unknown when the runtime can't provide them.
Observed phrases don't prove catalogue locale support. Notes retain refused or
unanswered queries and unknown fallback support.

The server doesn't share an inventory disk cache or a managed session across
callers. Each tool call keeps its existing identity lease and cleanup lifecycle.

## Reply Claims

Runtime reply summaries include `pipelineIds`, `skillIds` and `claimed`, computed by Node SDK 0.7.1.

Pipeline and skill IDs are nonempty strings in first-seen order, with duplicates removed. A successful reply with only pipeline IDs containing the case-sensitive text `fallback` reports an unclaimed reply. Any non-fallback stage makes a successful reply claimed. Successful replies from older hubs without stage stamps remain claimed. Failed or unhandled replies are never claimed. Malformed non-string stamps are ignored.

Use this as a hint when deciding whether to continue a conversation. Fallback text and the existing success status are retained. These stamps aren't verified peer identity and must not authorize actions.
