portkey-admin-mcp 0.12.1 → 0.13.0

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/ENDPOINTS.md CHANGED
@@ -6,7 +6,7 @@ Route mappings were reviewed against the official Portkey OpenAPI on 2026-09-08.
6
6
  - Base URL: `https://api.portkey.ai/v1`
7
7
  - Authentication: `x-portkey-api-key`
8
8
  - Public catalog exception: `get_model_pricing` uses `https://api.portkey.ai` without authentication
9
- - Total: 181 tools across 20 domains
9
+ - Total: 184 tools across 20 domains
10
10
  - Enterprise-gated names and counts are maintained in `src/tools/index.ts` and verified against README by `npm run verify:readme-tools`
11
11
 
12
12
  The route lists are domain-level service routes. The tool tables are the complete
@@ -14,6 +14,9 @@ MCP catalog and preserve the actual selection guidance exposed through
14
14
  `tools/list`. A tool can perform a workflow across several listed routes rather
15
15
  than mapping one-to-one to one HTTP endpoint.
16
16
 
17
+ Routes marked "undocumented upstream" are called by this server but are not in
18
+ the public Portkey OpenAPI, so their contracts can change without a spec diff.
19
+
17
20
  ## Workflow-only and multi-request tools
18
21
 
19
22
  | Tool | Behavior |
@@ -50,6 +53,9 @@ than mapping one-to-one to one HTTP endpoint.
50
53
  | `get_analytics_group_models` | GET `/analytics/groups/ai-models` |
51
54
  | `get_analytics_group_metadata` | GET `/analytics/groups/metadata/{key}` |
52
55
  | `get_analytics_group_providers` | GET `/analytics/groups/provider` |
56
+ | `get_analytics_group_mcp` | GET `/analytics/groups/mcp` |
57
+ | `get_analytics_group_a2a` | GET `/analytics/groups/a2a` |
58
+ | `get_analytics_group_workspaces` | GET `/analytics/groups/workspaces` |
53
59
 
54
60
  <!-- tool-catalog:start -->
55
61
  ## users (10)
@@ -79,7 +85,7 @@ Routes:
79
85
 
80
86
  - GET/POST `/admin/workspaces`; GET/PUT/DELETE `/admin/workspaces/{workspaceId}`
81
87
  - GET/POST `/admin/workspaces/{workspaceId}/users`; GET/PUT/DELETE `/admin/workspaces/{workspaceId}/users/{userId}`
82
- - GET/POST `/scim/workspaces`; DELETE `/scim/workspaces/{mappingId}`; GET `/scim/groups`
88
+ - GET/POST `/scim/workspaces`; DELETE `/scim/workspaces/{mappingId}`; GET `/scim/groups` (undocumented upstream; served from the `/v2` base)
83
89
 
84
90
  | Tool | Selection guidance and result |
85
91
  |---|---|
@@ -118,6 +124,7 @@ Routes:
118
124
  Routes:
119
125
 
120
126
  - GET/POST `/deployments`; GET/PUT/DELETE `/deployments/{id}`. DELETE archives; deprecated `/ping` is intentionally omitted.
127
+ - Undocumented upstream: these tools call the `/v2` base (the `/v1` base with its suffix swapped to `/v2`), while the public OpenAPI lists `/deployments` under `/v1`.
121
128
 
122
129
  | Tool | Selection guidance and result |
123
130
  |---|---|
@@ -156,9 +163,9 @@ Routes:
156
163
 
157
164
  | Tool | Selection guidance and result |
158
165
  |---|---|
159
- | `list_collections` | List prompt collections in the workspace, optionally filtering by name or workspace. Returns ids, names, slugs, and timestamps so you can choose a collection_id before create_prompt, get_collection, or list_prompts. |
160
- | `create_collection` | Create a new prompt collection for organizing prompts by app. Use this when you need a new namespace before create_prompt; returns the collection id and slug, and does not move any prompts. |
161
- | `get_collection` | Fetch one collection by id or slug and return its name, slug, workspace, and timestamps. Use list_collections when browsing and get_collection when you already know the target. |
166
+ | `list_collections` | List prompt collections in the workspace, optionally filtering by name or workspace. Returns ids, names, slugs, parent collection ids, and timestamps so you can choose a collection_id before create_prompt, get_collection, or list_prompts. |
167
+ | `create_collection` | Create a new prompt collection for organizing prompts by app. Use this when you need a new namespace before create_prompt; set parent_collection_id to nest it under an existing collection. Returns the collection id and slug, and does not move any prompts. |
168
+ | `get_collection` | Fetch one collection by id or slug and return its name, slug, workspace, parent collection id, child collections with prompt counts, and timestamps. Use list_collections when browsing and get_collection when you already know the target. |
162
169
  | `update_collection` | Update a collection's name or description only. This does not move prompts or change membership, so use it for metadata changes rather than reorganization. |
163
170
  | `delete_collection` | Delete a prompt collection by ID. This cannot be undone; prompts stay in the workspace but lose their collection grouping, so reassign them first if organization matters. |
164
171
 
@@ -187,7 +194,7 @@ Routes:
187
194
  | `get_prompt_version` | Retrieve a specific prompt version by its version UUID. Use list_prompt_versions to find the id first; returns the template, parameters, and model config for that version. |
188
195
  | `update_prompt_version` | Update a specific prompt version's label assignment. This only assigns or removes a label, and null clears the label after you look up ids with list_prompt_labels. |
189
196
 
190
- ## analytics (22)
197
+ ## analytics (25)
191
198
 
192
199
  Routes:
193
200
 
@@ -209,6 +216,9 @@ Routes:
209
216
  | `get_analytics_group_models` | Get a paginated per-model breakdown with total_groups, group_count, and a models array containing request count, cost, and token usage. Use this to compare model cost, popularity, and efficiency; use get_token_analytics or get_cost_analytics for time-series trends instead. Enterprise-gated. Returns 403 on non-Enterprise Portkey plans. |
210
217
  | `get_analytics_group_providers` | Enterprise-gated. Get provider-grouped analytics for one workspace and time range with selectable metrics, ordering, pagination, and optional total count. Use this when comparing provider traffic or reliability; requested metric fields are preserved in each provider row. Enterprise-gated. Returns 403 on non-Enterprise Portkey plans. |
211
218
  | `get_analytics_group_metadata` | Get a paginated metadata breakdown with total_groups, group_count, and a metadata_groups array grouped by the required metadata_key. Use this for custom breakdowns like per-environment or per-feature analysis; pass metadata_key in addition to the time window. Enterprise-gated. Returns 403 on non-Enterprise Portkey plans. |
219
+ | `get_analytics_group_mcp` | Get a paginated per-MCP-server breakdown with total_groups, group_count, and an mcp_servers array containing each server name and its request count. Use this to see which MCP servers receive the most traffic; use get_analytics_group_a2a for A2A agents or get_analytics_group_users and get_analytics_group_models for other breakdowns. Enterprise-gated. Returns 403 on non-Enterprise Portkey plans. |
220
+ | `get_analytics_group_a2a` | Get a paginated per-agent breakdown with total_groups, group_count, and an agents array containing each A2A (agent-to-agent) agent name and its request count. Use this to see which agents receive the most traffic; use get_analytics_group_mcp for MCP servers instead. Enterprise-gated. Returns 403 on non-Enterprise Portkey plans. |
221
+ | `get_analytics_group_workspaces` | Get a paginated per-workspace breakdown with total_groups, group_count, is_quota_exceeded when reported, and a workspaces array containing each workspace_slug with request count and cost. Use this for org-wide chargeback or comparing workspaces; pass workspace_slug to other analytics tools to drill into one workspace. Enterprise-gated. Returns 403 on non-Enterprise Portkey plans. |
212
222
  | `get_error_stacks_analytics` | Get stacked error-series data grouped by HTTP status code over time, with summary and per-code series. Use this to see which error classes dominate; use get_error_status_codes_analytics for distinct-code distribution instead. Enterprise-gated. Returns 403 on non-Enterprise Portkey plans. |
213
223
  | `get_error_status_codes_analytics` | Get HTTP error-code distribution time-series data with summary and per-code series. Use this to see which codes occur most often; use get_error_stacks_analytics for stacked or cumulative breakdowns. Enterprise-gated. Returns 403 on non-Enterprise Portkey plans. |
214
224
  | `get_user_requests_analytics` | Get per-user request-count time-series data with counts grouped by user. Use this to find heavy users and traffic concentration; use get_users_analytics for aggregate active and new user trends instead. Enterprise-gated. Returns 403 on non-Enterprise Portkey plans. |
@@ -222,8 +232,8 @@ Routes:
222
232
 
223
233
  Routes:
224
234
 
225
- - GET/PUT `/admin/organisation/defaults`
226
- - GET/PUT `/workspace-exclusions/{input-guardrails|output-guardrails}`
235
+ - GET/PUT `/admin/organisation/defaults` (undocumented upstream)
236
+ - GET/PUT `/workspace-exclusions/{input-guardrails|output-guardrails}` (undocumented upstream)
227
237
  - GET/POST `/guardrails`; GET/PUT/DELETE `/guardrails/{guardrailId}`
228
238
  - GET/PUT `/guardrails/{guardrailId}/mcp-servers`; PUT `/guardrails/{guardrailId}/mcp-servers/{mcpServerId}`
229
239
 
@@ -238,9 +248,9 @@ Routes:
238
248
  | `list_guardrails` | List guardrails in the org with id, slug, status, ownership, and optional workspace/org filters. Use this to find IDs and slugs before get_guardrail, update_guardrail, or delete_guardrail. |
239
249
  | `get_guardrail` | Fetch one guardrail by id or slug with its full checks and actions; use list_guardrails to discover ids first. Use before update_guardrail or delete_guardrail when you need the exact enforcement policy, and returns the full check and action configuration alongside status and ownership. |
240
250
  | `create_guardrail` | Create an LLM or MCP-tool guardrail. LLM guardrails require checks and actions; MCP-tool guardrails can be created first and mapped to servers afterward. The new version becomes the policy anchor for downstream use. |
241
- | `list_guardrail_mcp_servers` | List every MCP-server mapping for one guardrail, including the input/output phases and mapped capability IDs. Use this before replace_guardrail_mcp_servers because replacement removes every mapping omitted from its request. |
242
- | `replace_guardrail_mcp_servers` | Replace the complete MCP-server mapping set for one guardrail. Any existing server omitted from mcp_servers is removed, and an empty object clears all mappings. Read list_guardrail_mcp_servers first. Repeating the same complete map is safe. |
243
- | `upsert_guardrail_mcp_server` | Create or replace one guardrail mapping for one MCP server without changing mappings for other servers. run_on defaults to both input and output. Use list_guardrail_mcp_servers to inspect the current mapping set first. Repeating the same mapping is safe. |
251
+ | `list_guardrail_mcp_servers` | List every MCP-server mapping for one guardrail, including the input/output phases and mapped capability IDs. Requires a guardrail with target mcp_tools. Use this before replace_guardrail_mcp_servers because replacement removes every mapping omitted from its request. |
252
+ | `replace_guardrail_mcp_servers` | Replace the complete MCP-server mapping set for one guardrail. Requires a guardrail with target mcp_tools. Any existing server omitted from mcp_servers is removed, and an empty object clears all mappings. Read list_guardrail_mcp_servers first. Repeating the same complete map is safe. |
253
+ | `upsert_guardrail_mcp_server` | Create or replace one guardrail mapping for one MCP server without changing mappings for other servers. Requires a guardrail with target mcp_tools. run_on defaults to both input and output. Use list_guardrail_mcp_servers to inspect the current mapping set first. Repeating the same mapping is safe. |
244
254
  | `update_guardrail` | Update a guardrail's name, checks, or actions, unlike create_guardrail which registers a new one or delete_guardrail which removes it. This creates a new version that takes effect immediately for dependent configs, so review list_guardrails first; returns the updated id, slug, and version_id. |
245
255
  | `delete_guardrail` | Delete a guardrail by id or slug. This is irreversible and removes the check from any configs that reference it, so review dependent configs first. |
246
256
 
@@ -275,7 +285,7 @@ Routes:
275
285
 
276
286
  | Tool | Selection guidance and result |
277
287
  |---|---|
278
- | `list_audit_logs` | List audit log events for a Portkey workspace or organization. Returns paginated action-level records with actor, resource, metadata, and timestamps for compliance or incident review; use this instead of analytics when you need individual events, not aggregates. Enterprise-gated. Returns 403 on non-Enterprise Portkey plans. |
288
+ | `list_audit_logs` | List audit log records for a Portkey organization within a time range (Enterprise plan only; other plans get a permissions error). Each record is a state-changing API request (POST, PUT, or DELETE) with timestamp, method, uri, request_id, user_id, user_type (user or api_key), organisation_id, workspace_id, response_status_code, resource_type, action, client_ip, country, plus request_body, query_params, and request_headers as JSON strings. Use it for compliance or incident review of individual events; use analytics instead for aggregates. Enterprise-gated. Returns 403 on non-Enterprise Portkey plans. |
279
289
 
280
290
  ## labels (5)
281
291
 
@@ -324,7 +334,7 @@ Routes:
324
334
  Routes:
325
335
 
326
336
  - POST `/logs`; GET `/logs/{logId}`
327
- - GET `/logs/exports/field-restrictions`; GET/POST `/logs/exports`; GET/PUT `/logs/exports/{exportId}`
337
+ - GET `/logs/exports/field-restrictions` (undocumented upstream); GET/POST `/logs/exports`; GET/PUT `/logs/exports/{exportId}`
328
338
  - POST `/logs/exports/{exportId}/{start|cancel}`; GET `/logs/exports/{exportId}/download`
329
339
 
330
340
  | Tool | Selection guidance and result |
@@ -379,10 +389,10 @@ Routes:
379
389
  | Tool | Selection guidance and result |
380
390
  |---|---|
381
391
  | `get_model_pricing` | Get Portkey's current public pricing configuration for one exact provider/model pair. Prices are returned in USD cents per token or provider-specific unit and may include cache, audio, image, fine-tuning, and calculation metadata. Use this read-only catalog lookup before setting integration pricing_adjustments or custom-model pricing; it does not return your negotiated integration multiplier or require Portkey authentication. |
382
- | `list_integrations` | List org-level AI provider connections with optional workspace or type filters. Use this to find integration slugs before model or workspace updates. Returns total plus id, name, slug, provider, status, description, workspace counts, and config summary. |
383
- | `create_integration` | Create an AI-provider integration that becomes the source for workspace providers. ai_provider_id identifies the backend; provider-specific fields configure Azure, Bedrock, Vertex, or custom hosts. For workspace-scoped integrations, create_default_provider controls automatic provider creation. key is write-only, but secret_mappings can resolve it or configuration fields from Secret References at runtime. pricing_adjustments apply negotiated discounts or markups to cost accounting. Use update_integration_models and update_integration_workspaces after creation; returns the new integration id and slug. |
392
+ | `list_integrations` | List org-level AI provider connections with optional workspace, type, or tag filters. Use this to find integration slugs before model or workspace updates. Returns total plus id, name, slug, provider, status, description, workspace counts, and config summary. |
393
+ | `create_integration` | Create an AI-provider integration that becomes the source for workspace providers. ai_provider_id identifies the backend; provider-specific fields configure Azure, Bedrock, Vertex, or custom hosts. For workspace-scoped integrations, create_default_provider controls automatic provider creation. key is write-only, but secret_mappings can resolve it or configuration fields from Secret References at runtime. pricing_adjustments apply negotiated discounts or markups to cost accounting; tags attach key-value labels that list_integrations can filter on. Use update_integration_models and update_integration_workspaces after creation; returns the new integration id and slug. |
384
394
  | `get_integration` | Fetch one integration by slug, including masked key, workspace access, allowed models, and configuration metadata. Use this before editing provider-specific settings or auditing access. Enterprise-gated. Returns 403 on non-Enterprise Portkey plans. |
385
- | `update_integration` | Update an integration's name, description, API key, provider config, Secret Reference mappings, or pricing adjustments by slug. Only provided fields change; key, secret mapping, and config changes take effect immediately and can disrupt dependent providers or live requests, while pricing multipliers change cost analytics and budget accounting. Review get_integration first. Model availability and workspace access remain separate in update_integration_models and update_integration_workspaces. |
395
+ | `update_integration` | Update an integration's name, description, API key, provider config, Secret Reference mappings, pricing adjustments, or tags by slug. Only provided fields change; tags replaces the whole map and null clears it; key, secret mapping, and config changes take effect immediately and can disrupt dependent providers or live requests, while pricing multipliers change cost analytics and budget accounting. Review get_integration first. Model availability and workspace access remain separate in update_integration_models and update_integration_workspaces. |
386
396
  | `delete_integration` | Delete an integration by slug. This is irreversible and stops the org-level connection, which will break dependent virtual keys, providers, and workspace access. |
387
397
  | `list_integration_models` | List models enabled on an integration. Use this to verify model availability before creating prompts or configs. Returns total plus model ids, display names, enabled state, and custom-model markers. Enterprise-gated. Returns 403 on non-Enterprise Portkey plans. |
388
398
  | `update_integration_models` | Bulk enable or disable integration models, register custom or fine-tuned models, set per-model hosts and headers, and attach static token pricing. allow_all_models controls whether future provider models start enabled. These changes affect every workspace using the integration; inspect list_integration_models first and use get_model_pricing when deriving custom rates. Returns success and the number of models updated. |
package/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  <h1>Portkey Admin MCP Server</h1>
6
6
 
7
- **The [Portkey](https://portkey.ai/) Admin API as an MCP server — 181 tools across prompts, configs, keys, analytics, governance, deployments, and more.**
7
+ **The [Portkey](https://portkey.ai/) Admin API as an MCP server — 184 tools across prompts, configs, keys, analytics, governance, deployments, and more.**
8
8
 
9
9
  </div>
10
10
 
@@ -96,7 +96,7 @@ npx -y portkey-admin-mcp
96
96
  ```
97
97
 
98
98
  Scoping domains is also the biggest lever on context cost, not just access. `tools/list`
99
- is paginated, and the complete 181-tool catalog is roughly 400 KB once a
99
+ is paginated, and the complete 184-tool catalog is roughly 400 KB once a
100
100
  client follows `nextCursor` through every page. Narrowing to the domains a client
101
101
  actually needs cuts that roughly proportionally.
102
102
 
@@ -148,13 +148,13 @@ Then use this config:
148
148
  | **Guardrails** | 14 | LLM and MCP-tool policies, server mappings, organisation defaults, workspace exclusions |
149
149
  | **Usage Limits** | 7 | Cost and token consumption limits |
150
150
  | **Rate Limits** | 5 | Request frequency controls |
151
- | **Analytics** | 22 | Cost, latency, errors, tokens, cache, feedback, provider groups |
151
+ | **Analytics** | 25 | Cost, latency, errors, tokens, cache, feedback, provider, MCP, A2A, and workspace groups |
152
152
  | **Logging** | 10 | Log retrieval, ingestion, export, and field restrictions |
153
153
  | **Tracing** | 2 | Feedback creation and updates on traces |
154
154
  | **Users & Workspaces** | 24 | User management, invites, workspace members, SCIM group mappings |
155
155
  | **Audit** | 1 | Audit log access |
156
156
 
157
- **181 tools total across 20 tool domains.** See [ENDPOINTS.md](./ENDPOINTS.md) for the full list with descriptions.
157
+ **184 tools total across 20 tool domains.** See [ENDPOINTS.md](./ENDPOINTS.md) for the full list with descriptions.
158
158
 
159
159
  Portkey's newer product language increasingly presents provider credentials as
160
160
  Providers, while the current Admin API still exposes both `/virtual-keys` and
@@ -172,13 +172,13 @@ If a tool returns a `403` with Portkey error `AB03`, it means missing scopes —
172
172
  <details>
173
173
  <summary><strong>Enterprise-gated tools and other scope requirements</strong></summary>
174
174
 
175
- ### Enterprise-gated tools (53)
175
+ ### Enterprise-gated tools (56)
176
176
 
177
177
  The following tools require an **organisation-level scope that is only available on Portkey Enterprise plans**. They return `403 You do not have enough permissions to execute this request` on workspace plans. Their descriptions include an `Enterprise-gated. Returns 403 on non-Enterprise Portkey plans.` suffix so MCP clients know upfront.
178
178
 
179
179
  | Area | Tools | Required scope |
180
180
  |---|---|---|
181
- | Analytics (22) | `get_cost_analytics`, `get_request_analytics`, `get_token_analytics`, `get_latency_analytics`, `get_error_analytics`, `get_error_rate_analytics`, `get_cache_hit_latency`, `get_cache_hit_rate`, `get_cache_summary`, `get_users_analytics`, `get_error_stacks_analytics`, `get_error_status_codes_analytics`, `get_user_requests_analytics`, `get_rescued_requests_analytics`, `get_feedback_analytics`, `get_feedback_models_analytics`, `get_feedback_scores_analytics`, `get_feedback_weighted_analytics`, `get_analytics_group_users`, `get_analytics_group_models`, `get_analytics_group_metadata`, `get_analytics_group_providers` | org-level `analytics.view` |
181
+ | Analytics (25) | `get_cost_analytics`, `get_request_analytics`, `get_token_analytics`, `get_latency_analytics`, `get_error_analytics`, `get_error_rate_analytics`, `get_cache_hit_latency`, `get_cache_hit_rate`, `get_cache_summary`, `get_users_analytics`, `get_error_stacks_analytics`, `get_error_status_codes_analytics`, `get_user_requests_analytics`, `get_rescued_requests_analytics`, `get_feedback_analytics`, `get_feedback_models_analytics`, `get_feedback_scores_analytics`, `get_feedback_weighted_analytics`, `get_analytics_group_users`, `get_analytics_group_models`, `get_analytics_group_metadata`, `get_analytics_group_providers`, `get_analytics_group_mcp`, `get_analytics_group_a2a`, `get_analytics_group_workspaces` | org-level `analytics.view` |
182
182
  | Deployments (5) | `list_deployments`, `register_deployment`, `get_deployment`, `update_deployment`, `archive_deployment` | Enterprise deployment administration |
183
183
  | Audit | `list_audit_logs` | `audit_logs.list` |
184
184
  | Org-level integrations | `get_integration`, `list_integration_models`, `list_integration_workspaces` | `organisation_integrations.read` |
@@ -238,17 +238,22 @@ For local-only HTTP use, leave `MCP_HOST` at its default `127.0.0.1`. Set `MCP_H
238
238
  | `PORTKEY_ALLOW_PRIVATE_BASE_URL` | — | Set to `true` to allow a literal loopback/private `PORTKEY_BASE_URL` |
239
239
  | `PORTKEY_ALLOW_INSECURE_HTTP` | — | Separately set to `true` only when a trusted self-hosted gateway cannot use HTTPS |
240
240
  | `PORTKEY_TOOL_DOMAINS` | — | Server-side allowlist of the 20 domains: `users`, `workspaces`, `configs`, `deployments`, `keys`, `collections`, `prompts`, `analytics`, `guardrails`, `limits`, `audit`, `labels`, `partials`, `tracing`, `logging`, `providers`, `secret-references`, `integrations`, `mcp-integrations`, `mcp-servers`. HTTP `?tools=` may narrow it but cannot expand it |
241
+ | `MCP_TOOL_DOMAINS` | — | Fallback for `PORTKEY_TOOL_DOMAINS`, used only when that is unset |
242
+ | `MCP_TRANSPORT` | `stdio` | `stdio` or `http`; the Docker image picks its entrypoint from this (set `http` for the HTTP server) |
241
243
  | `MCP_HOST` | `127.0.0.1` | Bind address |
242
244
  | `MCP_PORT` | `3000` | Port |
245
+ | `PORT` | — | Port override; takes precedence over `MCP_PORT` when set |
243
246
  | `MCP_PUBLIC_BASE_URL` | — | Public absolute base URL to advertise from `/auth/info` and the status page; recommended for hosted deployments |
244
247
  | `MCP_AUTH_MODE` | `none` | `none`, `bearer`, or `clerk` (`none` is blocked for HTTP unless explicitly overridden) |
245
248
  | `MCP_AUTH_TOKEN` | — | Secret for bearer auth |
246
249
  | `CLERK_ISSUER` / `CLERK_AUDIENCE` | — | Required issuer and audience when `MCP_AUTH_MODE=clerk` |
250
+ | `CLERK_JWKS_URL` | `<CLERK_ISSUER>/.well-known/jwks.json` | JWKS endpoint for Clerk JWT verification; must be HTTPS. Set it only when the JWKS isn't at the default path |
247
251
  | `CLERK_ALLOWED_SUBJECTS` | — | Optional CSV subject allowlist for Clerk; at least one Clerk authorization policy is required |
248
252
  | `CLERK_ALLOWED_ORGANIZATION_IDS` / `CLERK_ALLOWED_ROLES` | — | Optional CSV organization and role constraints; every configured constraint must match |
249
253
  | `CLERK_REQUIRED_PERMISSIONS` | — | Optional CSV permissions that must all be present in the verified Clerk JWT |
250
254
  | `MCP_ALLOW_UNAUTHENTICATED_HTTP` | — | Set to `true` only for intentional local unauthenticated HTTP debugging |
251
255
  | `MCP_SESSION_MODE` | `stateful` | `stateful` or `stateless` |
256
+ | `MCP_SESSION_TIMEOUT` | `3600000` | Idle timeout for stateful sessions, in milliseconds; `0` or more |
252
257
  | `MCP_MAX_SESSIONS` | `100` | Maximum concurrent stateful sessions or active stateless request handlers |
253
258
  | `MCP_EVENT_STORE` | `off` | `off`, `memory`, or `redis`; stateless `GET /mcp` replay requires `memory` or `redis` |
254
259
  | `MCP_EVENT_TTL_SECONDS` | `300` | Replay retention in seconds |
@@ -260,11 +265,22 @@ For local-only HTTP use, leave `MCP_HOST` at its default `127.0.0.1`. Set `MCP_H
260
265
  | `MCP_REDIS_KEY_PREFIX` | `mcp:event-store` | Dedicated Redis namespace for replay data |
261
266
  | `MCP_TLS_KEY_PATH` | — | TLS key for native HTTPS |
262
267
  | `MCP_TLS_CERT_PATH` | — | TLS cert for native HTTPS |
268
+ | `MCP_TLS_CA_PATH` | — | Optional CA bundle for native HTTPS; only used when the TLS key and cert are set |
269
+ | `MCP_SHUTDOWN_TIMEOUT_MS` | `10000` | How long graceful shutdown waits before the process is forced to exit, in milliseconds; must be positive |
270
+ | `MCP_MAX_REQUEST_SIZE` | `1mb` | Maximum HTTP request body size |
271
+ | `MCP_READY_CHECK_MODE` | `local` | `local` or `portkey`; `portkey` makes `/ready` also check Portkey connectivity |
272
+ | `LOG_LEVEL` | `info` | `debug`, `info`, `warn`, or `error` |
263
273
  | `ALLOWED_ORIGINS` | — | CORS allow-list; also used to validate the `Host` header (DNS-rebinding protection) when `MCP_AUTH_MODE=none` |
274
+ | `CORS_ORIGIN` | — | Legacy fallback for `ALLOWED_ORIGINS`, used only when that is unset |
264
275
  | `MCP_TRUST_PROXY` | `loopback` | Express trust-proxy policy. Use an exact nonnegative hop count or trusted proxy subnet; `true` is rejected because it trusts forwarding headers from every peer |
265
276
  | `RATE_LIMIT_STORE` | `memory` | `redis` for multi-instance/serverless deployments; production memory mode requires `RATE_LIMIT_SINGLE_PROCESS=true` |
277
+ | `RATE_LIMIT_ENABLED` | `true` | Set to `false` to turn the pre-authentication rate limiter off |
278
+ | `RATE_LIMIT_SINGLE_PROCESS` | — | Set to `true` to acknowledge a single-process deployment when using in-memory limiting in production |
266
279
  | `RATE_LIMIT_REDIS_URL` | — | Shared limiter Redis URL, falling back to `MCP_REDIS_URL`/`REDIS_URL`; production requires `rediss://` |
267
280
  | `RATE_LIMIT_REDIS_KEY_PREFIX` | `mcp:rate-limit` | Redis namespace for atomic pre-authentication IP and principal-plus-IP token buckets |
281
+ | `RATE_LIMIT_MAX` | `60` | Maximum tokens in each pre-authentication IP and principal-plus-IP bucket |
282
+ | `RATE_LIMIT_WINDOW_MS` | `60000` | Rate-limit window in milliseconds |
283
+ | `RATE_LIMIT_REFILL` | `60` | Tokens refilled each window |
268
284
  | `RATE_LIMIT_MAX_BUCKETS` | `10000` | Maximum local buckets in explicit memory mode before new clients share overflow capacity |
269
285
 
270
286
  Production containers must choose their rate-limit topology explicitly: set
@@ -332,6 +348,9 @@ The live smoke suite reports expected credential-scope denials and the explicitl
332
348
  tracked hosted control-plane route gaps as skips. Unexpected HTTP responses,
333
349
  network errors, and response-contract failures still fail the run.
334
350
 
351
+ `list_audit_logs` is Enterprise-only, so the smoke suite skips its check unless
352
+ `PORTKEY_ORGANISATION_ID` is set. Set it to your organisation ID to exercise that route.
353
+
335
354
  The required CI and release gates measure every TypeScript source file and fail
336
355
  below 80% line coverage. The current full report is 98.19% lines, 91.92%
337
356
  branches, and 98.58% functions.
@@ -361,7 +380,7 @@ tool catalog in this repository as authoritative when a third-party index lags.
361
380
  ### Built With
362
381
 
363
382
  [![TypeScript](https://img.shields.io/badge/TypeScript_7.0-3178C6?logo=typescript&logoColor=fff)](https://www.typescriptlang.org/)
364
- [![MCP SDK](https://img.shields.io/badge/MCP_SDK_1.30-000?logo=modelcontextprotocol&logoColor=fff)](https://github.com/modelcontextprotocol/typescript-sdk)
383
+ [![MCP SDK](https://img.shields.io/badge/MCP_SDK_1.31-000?logo=modelcontextprotocol&logoColor=fff)](https://github.com/modelcontextprotocol/typescript-sdk)
365
384
  [![Zod 4](https://img.shields.io/badge/Zod_4-3E67B1?logo=zod&logoColor=fff)](https://zod.dev/)
366
385
  [![Biome](https://img.shields.io/badge/Biome_2.5-60a5fa?logo=biome&logoColor=fff)](https://biomejs.dev/)
367
386
  [![Node 24](https://img.shields.io/badge/Node_24-339933?logo=nodedotjs&logoColor=fff)](https://nodejs.org/)