@thalovant/mcp-server 0.1.8 → 0.1.9

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/.env.example CHANGED
@@ -3,6 +3,9 @@ THALOVANT_PROFILE=prod
3
3
  THALOVANT_API_URL=https://api.thalovant.com
4
4
 
5
5
  # Use one control-plane auth option for private/admin tools.
6
+ # Recommended: a scoped, revocable API token (dashboard or device flow).
7
+ # Minimum scopes for the full tool surface: hubs:read, clients:write, memory:read, memory:write.
8
+ # THALOVANT_API_TOKEN=
6
9
  # THALOVANT_ACCESS_TOKEN=
7
10
  # THALOVANT_EMAIL=
8
11
  # THALOVANT_PASSWORD=
package/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.9
4
+
5
+ - Added first-class scoped API token auth for the control plane: set `THALOVANT_API_TOKEN` and the server authenticates with the token directly and never calls the login endpoint. Precedence is `THALOVANT_API_TOKEN`, then `THALOVANT_ACCESS_TOKEN`, then the `THALOVANT_EMAIL`/`THALOVANT_PASSWORD` login fallback.
6
+ - `thalovant_config_status` now reports the active control-plane auth mode (`controlPlaneAuthMode`: `api-token`, `access-token`, `email-password`, or `none`) and `hasApiToken`, without revealing token values.
7
+ - Documented API tokens as the recommended auth mode for AI and CI use, including the minimum token scopes for the full control-plane tool surface: `hubs:read`, `clients:write`, `memory:read`, `memory:write`.
8
+ - Clarified the unauthenticated-tool error to name `THALOVANT_API_TOKEN` as the recommended option.
9
+
3
10
  ## 0.1.8
4
11
 
5
12
  - Tightened memory tool input validation to match the control-plane API exactly: `title` max 160, `content` max 4096, `source` max 64, `consentScope` max 128, `consentVersion` max 64, `retentionPolicy` max 64 on create/update, and list `query` max 240, so invalid values fail with a clear client-side error instead of an opaque API 422.
package/README.md CHANGED
@@ -29,13 +29,43 @@ npm run build
29
29
 
30
30
  Node.js 20 or newer is required.
31
31
 
32
- ## Local Stdio
32
+ ## Control-Plane Auth
33
33
 
34
34
  Public hub discovery does not need Thalovant credentials. Private control-plane tools and runtime hub tools read credentials only from the MCP server environment or server-side principal credential files. Do not pass API tokens or passwords through chat or tool arguments.
35
35
 
36
+ The server selects control-plane auth in this order:
37
+
38
+ 1. `THALOVANT_API_TOKEN` — a scoped Thalovant API token. Recommended.
39
+ 2. `THALOVANT_ACCESS_TOKEN` — a pre-issued session access token.
40
+ 3. `THALOVANT_EMAIL` + `THALOVANT_PASSWORD` — interactive-account login fallback.
41
+
42
+ When a token is set, the server never calls the login endpoint. `thalovant_config_status` reports the active mode as `controlPlaneAuthMode` without revealing token values.
43
+
44
+ ### API Tokens (Recommended For AI Agents And CI)
45
+
46
+ Scoped API tokens are the right credential for AI and automation use: they are minted from the Thalovant dashboard (or through the device flow), carry only the scopes you grant, can be revoked individually, and never involve your account password or MFA. Tokens start with `tvpat_`.
47
+
48
+ ```bash
49
+ export THALOVANT_API_TOKEN="tvpat_..."
50
+ export THALOVANT_API_URL="https://api.thalovant.com"
51
+
52
+ npm start
53
+ ```
54
+
55
+ Minimum scopes for the full control-plane tool surface:
56
+
57
+ | Scope | Used by |
58
+ |-------|---------|
59
+ | `hubs:read` | `thalovant_list_hubs`, `thalovant_get_hub`, `thalovant_get_analytics_overview`, and the hub lookup inside `thalovant_create_client_identity` |
60
+ | `clients:write` | `thalovant_create_client_identity` (`POST /v1/clients`) |
61
+ | `memory:read` | `thalovant_list_memory_items`, `thalovant_get_memory_summary`, `thalovant_get_memory_item` |
62
+ | `memory:write` | `thalovant_create_memory_item`, `thalovant_update_memory_item`, `thalovant_delete_memory_item` |
63
+
64
+ Grant fewer scopes for narrower deployments: a read-only assistant needs only `hubs:read` and `memory:read`. `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.
65
+
66
+ ### Login Fallback
67
+
36
68
  ```bash
37
- export THALOVANT_ACCESS_TOKEN="..."
38
- # or
39
69
  export THALOVANT_EMAIL="you@example.com"
40
70
  export THALOVANT_PASSWORD="..."
41
71
 
@@ -45,6 +75,10 @@ export THALOVANT_API_URL="https://api.thalovant.com"
45
75
  npm start
46
76
  ```
47
77
 
78
+ If neither a token nor email/password is configured, authenticated control-plane tools fail with a clear error naming the supported options.
79
+
80
+ ## Local Stdio
81
+
48
82
  The server speaks MCP over stdio and does not write logs to stdout.
49
83
 
50
84
  Runtime hub tools load local identities in this order:
@@ -208,6 +242,8 @@ MCP_HTTP_TRUST_PROXY=false
208
242
 
209
243
  ## Claude Desktop
210
244
 
245
+ Recommended: authenticate with a scoped API token so the MCP config never contains your account password.
246
+
211
247
  ```json
212
248
  {
213
249
  "mcpServers": {
@@ -215,6 +251,7 @@ MCP_HTTP_TRUST_PROXY=false
215
251
  "command": "node",
216
252
  "args": ["/home/goldyfruit/Development/Thalovant/mcp/dist/index.js"],
217
253
  "env": {
254
+ "THALOVANT_API_TOKEN": "tvpat_...",
218
255
  "THALOVANT_PROFILE": "prod"
219
256
  }
220
257
  }
@@ -233,6 +270,7 @@ Use the same stdio command in your MCP client config:
233
270
  "command": "node",
234
271
  "args": ["/home/goldyfruit/Development/Thalovant/mcp/dist/index.js"],
235
272
  "env": {
273
+ "THALOVANT_API_TOKEN": "tvpat_...",
236
274
  "THALOVANT_PROFILE": "prod"
237
275
  }
238
276
  }
package/dist/index.js CHANGED
@@ -14,7 +14,7 @@ import { mkdir } from "node:fs/promises";
14
14
  import { fileURLToPath, pathToFileURL } from "node:url";
15
15
  import { createRemoteJWKSet, jwtVerify } from "jose";
16
16
  import { z } from "zod";
17
- const VERSION = "0.1.8";
17
+ const VERSION = "0.1.9";
18
18
  const DEFAULT_TIMEOUT_MS = 30_000;
19
19
  const MAX_TIMEOUT_MS = 300_000;
20
20
  const MAX_LIMIT = 100;
@@ -423,7 +423,8 @@ async function createControlPlane(options) {
423
423
  const credential = await credentialForPrincipal(principal);
424
424
  const canUseShared = allowSharedThalovantCredentials(principal);
425
425
  const apiUrl = options.apiUrl ?? credential?.control?.apiUrl ?? (canUseShared ? process.env.THALOVANT_API_URL : undefined) ?? DEFAULT_CONTROL_API_URL;
426
- const accessToken = credential?.control?.accessToken ?? (canUseShared ? process.env.THALOVANT_ACCESS_TOKEN : undefined);
426
+ const accessToken = credential?.control?.accessToken ??
427
+ (canUseShared ? process.env.THALOVANT_API_TOKEN ?? process.env.THALOVANT_ACCESS_TOKEN : undefined);
427
428
  const api = new ThalovantControlPlane(apiUrl, {
428
429
  accessToken,
429
430
  userAgent: `thalovant-mcp/${VERSION}`,
@@ -439,9 +440,18 @@ async function createControlPlane(options) {
439
440
  }
440
441
  function ensureAuthenticated(api) {
441
442
  if (!api.accessToken) {
442
- throw new Error("This tool requires Thalovant API auth. Configure THALOVANT_ACCESS_TOKEN, THALOVANT_EMAIL/THALOVANT_PASSWORD, or per-principal Thalovant credentials for this MCP principal.");
443
+ throw new Error("This tool requires Thalovant API auth. Configure THALOVANT_API_TOKEN (recommended: a scoped, revocable API token), THALOVANT_ACCESS_TOKEN, THALOVANT_EMAIL/THALOVANT_PASSWORD, or per-principal Thalovant credentials for this MCP principal.");
443
444
  }
444
445
  }
446
+ function controlPlaneAuthModeFromEnv() {
447
+ if (process.env.THALOVANT_API_TOKEN)
448
+ return "api-token";
449
+ if (process.env.THALOVANT_ACCESS_TOKEN)
450
+ return "access-token";
451
+ if (process.env.THALOVANT_EMAIL && process.env.THALOVANT_PASSWORD)
452
+ return "email-password";
453
+ return "none";
454
+ }
445
455
  async function createRuntimeClient(options) {
446
456
  const protocol = options.protocol ?? "wss";
447
457
  const principal = currentPrincipal();
@@ -896,6 +906,8 @@ export function createServer() {
896
906
  },
897
907
  }, async () => jsonContent({
898
908
  apiUrl: process.env.THALOVANT_API_URL ?? DEFAULT_CONTROL_API_URL,
909
+ controlPlaneAuthMode: controlPlaneAuthModeFromEnv(),
910
+ hasApiToken: Boolean(process.env.THALOVANT_API_TOKEN),
899
911
  hasAccessToken: Boolean(process.env.THALOVANT_ACCESS_TOKEN),
900
912
  hasEmailPassword: Boolean(process.env.THALOVANT_EMAIL && process.env.THALOVANT_PASSWORD),
901
913
  profile: process.env.THALOVANT_PROFILE,
@@ -4,6 +4,7 @@
4
4
  "command": "node",
5
5
  "args": ["/absolute/path/to/thalovant-mcp/dist/index.js"],
6
6
  "env": {
7
+ "THALOVANT_API_TOKEN": "tvpat_...",
7
8
  "THALOVANT_PROFILE": "prod"
8
9
  }
9
10
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thalovant/mcp-server",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
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",
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.1.8",
10
+ "version": "0.1.9",
11
11
  "packages": [
12
12
  {
13
13
  "registryType": "npm",
14
14
  "identifier": "@thalovant/mcp-server",
15
- "version": "0.1.8",
15
+ "version": "0.1.9",
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.1.8",
22
+ "identifier": "ghcr.io/thalovant/thalovant-mcp:0.1.9",
23
23
  "transport": {
24
24
  "type": "streamable-http",
25
25
  "url": "http://127.0.0.1:3000/mcp"