portkey-admin-mcp 0.4.1 → 0.5.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.
Files changed (4) hide show
  1. package/README.md +68 -28
  2. package/build/index.js +1213 -633
  3. package/build/server.js +1597 -683
  4. package/package.json +16 -13
package/build/server.js CHANGED
@@ -4,7 +4,7 @@
4
4
  import { pathToFileURL } from "node:url";
5
5
 
6
6
  // src/lib/http-app.ts
7
- import { randomUUID } from "node:crypto";
7
+ import { randomUUID as randomUUID2 } from "node:crypto";
8
8
  import { readFileSync as readFileSync2 } from "node:fs";
9
9
  import {
10
10
  createServer as createHttpServer
@@ -12,7 +12,9 @@ import {
12
12
  import {
13
13
  createServer as createHttpsServer
14
14
  } from "node:https";
15
- import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
15
+ import {
16
+ StreamableHTTPServerTransport
17
+ } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
16
18
  import {
17
19
  isInitializeRequest,
18
20
  LATEST_PROTOCOL_VERSION,
@@ -212,11 +214,11 @@ var BaseService = class {
212
214
  }
213
215
  this.apiKey = apiKey;
214
216
  if (baseUrlOverride !== void 0) {
215
- this.baseUrl = baseUrlOverride;
217
+ this.baseUrl = baseUrlOverride.replace(/\/+$/, "");
216
218
  } else {
217
219
  const baseUrl = process.env.PORTKEY_BASE_URL ?? DEFAULT_BASE_URL;
218
220
  validateUrl(baseUrl);
219
- this.baseUrl = baseUrl;
221
+ this.baseUrl = baseUrl.replace(/\/+$/, "");
220
222
  }
221
223
  }
222
224
  encodePathSegment(value) {
@@ -781,6 +783,12 @@ var KeysService = class extends BaseService {
781
783
  await this.put(`/api-keys/${this.encodePathSegment(id)}`, data);
782
784
  return { success: true };
783
785
  }
786
+ async rotateApiKey(id, data = {}) {
787
+ return this.post(
788
+ `/api-keys/${this.encodePathSegment(id)}/rotate`,
789
+ data
790
+ );
791
+ }
784
792
  async deleteApiKey(id) {
785
793
  await this.delete(`/api-keys/${this.encodePathSegment(id)}`);
786
794
  return { success: true };
@@ -1490,6 +1498,31 @@ var ProvidersService = class extends BaseService {
1490
1498
  }
1491
1499
  };
1492
1500
 
1501
+ // src/services/secret-references.service.ts
1502
+ var SecretReferencesService = class extends BaseService {
1503
+ async createSecretReference(data) {
1504
+ return this.post("/secret-references", data);
1505
+ }
1506
+ async listSecretReferences(params) {
1507
+ return this.get("/secret-references", params);
1508
+ }
1509
+ async getSecretReference(id) {
1510
+ return this.get(
1511
+ `/secret-references/${this.encodePathSegment(id)}`
1512
+ );
1513
+ }
1514
+ async updateSecretReference(id, data) {
1515
+ return this.put(
1516
+ `/secret-references/${this.encodePathSegment(id)}`,
1517
+ data
1518
+ );
1519
+ }
1520
+ async deleteSecretReference(id) {
1521
+ await this.delete(`/secret-references/${this.encodePathSegment(id)}`);
1522
+ return { success: true };
1523
+ }
1524
+ };
1525
+
1493
1526
  // src/services/tracing.service.ts
1494
1527
  var TracingService = class extends BaseService {
1495
1528
  // Feedback endpoints
@@ -1640,8 +1673,9 @@ var WorkspacesService = class extends BaseService {
1640
1673
  };
1641
1674
 
1642
1675
  // src/services/index.ts
1643
- import crypto2 from "node:crypto";
1676
+ import { createHmac, randomBytes } from "node:crypto";
1644
1677
  var MISSING_API_KEY_PLACEHOLDER = "__PORTKEY_API_KEY_NOT_CONFIGURED__";
1678
+ var SERVICE_CACHE_HMAC_KEY = randomBytes(32);
1645
1679
  function resolvePortkeyApiKey(apiKey) {
1646
1680
  const resolvedApiKey = apiKey ?? process.env.PORTKEY_API_KEY;
1647
1681
  if (!resolvedApiKey) {
@@ -1655,7 +1689,7 @@ function resolveSharedPortkeyApiKey(apiKey) {
1655
1689
  return apiKey ?? process.env.PORTKEY_API_KEY ?? MISSING_API_KEY_PLACEHOLDER;
1656
1690
  }
1657
1691
  function getSharedServiceCacheKey(apiKey) {
1658
- const keyDigest = crypto2.createHash("sha256").update(apiKey).digest("hex");
1692
+ const keyDigest = createHmac("sha256", SERVICE_CACHE_HMAC_KEY).update(apiKey).digest("hex");
1659
1693
  return JSON.stringify({
1660
1694
  apiKey: keyDigest,
1661
1695
  baseUrl: process.env.PORTKEY_BASE_URL?.trim() || ""
@@ -1679,6 +1713,7 @@ var PortkeyService = class {
1679
1713
  tracing;
1680
1714
  logging;
1681
1715
  providers;
1716
+ secretReferences;
1682
1717
  mcpIntegrations;
1683
1718
  mcpServers;
1684
1719
  health;
@@ -1705,6 +1740,10 @@ var PortkeyService = class {
1705
1740
  this.tracing = new TracingService(resolvedApiKey, resolvedBaseUrl);
1706
1741
  this.logging = new LoggingService(resolvedApiKey, resolvedBaseUrl);
1707
1742
  this.providers = new ProvidersService(resolvedApiKey, resolvedBaseUrl);
1743
+ this.secretReferences = new SecretReferencesService(
1744
+ resolvedApiKey,
1745
+ resolvedBaseUrl
1746
+ );
1708
1747
  this.mcpIntegrations = new McpIntegrationsService(
1709
1748
  resolvedApiKey,
1710
1749
  resolvedBaseUrl
@@ -1726,52 +1765,92 @@ function getSharedPortkeyService(apiKey) {
1726
1765
  }
1727
1766
 
1728
1767
  // src/tools/index.ts
1729
- import { z as z20 } from "zod";
1768
+ import { z as z22 } from "zod";
1730
1769
 
1731
1770
  // src/lib/type-guards.ts
1732
1771
  function isRecord(value) {
1733
1772
  return typeof value === "object" && value !== null;
1734
1773
  }
1735
1774
 
1736
- // src/tools/analytics.tools.ts
1775
+ // src/schemas/contracts/secret-references.contract.ts
1737
1776
  import { z } from "zod";
1777
+ var SecretManagerTypeSchema = z.enum([
1778
+ "aws_sm",
1779
+ "azure_kv",
1780
+ "hashicorp_vault"
1781
+ ]);
1782
+ var SecretReferenceListItemSchema = z.object({
1783
+ id: z.string().uuid(),
1784
+ name: z.string(),
1785
+ slug: z.string(),
1786
+ manager_type: SecretManagerTypeSchema,
1787
+ status: z.literal("ACTIVE"),
1788
+ created_at: z.iso.datetime(),
1789
+ last_updated_at: z.iso.datetime(),
1790
+ object: z.literal("secret-reference")
1791
+ });
1792
+ var ListSecretReferencesResponseSchema = z.object({
1793
+ object: z.literal("list"),
1794
+ total: z.number().int().nonnegative(),
1795
+ data: z.array(SecretReferenceListItemSchema)
1796
+ });
1797
+ var SecretReferenceDetailSchema = SecretReferenceListItemSchema.extend(
1798
+ {
1799
+ organisation_id: z.string().uuid(),
1800
+ description: z.string().nullable(),
1801
+ secret_path: z.string(),
1802
+ secret_key: z.string().nullable(),
1803
+ allow_all_workspaces: z.boolean(),
1804
+ tags: z.record(z.string(), z.string()).nullable(),
1805
+ created_by: z.string(),
1806
+ auth_config: z.record(z.string(), z.unknown())
1807
+ }
1808
+ );
1809
+ var CreateSecretReferenceResponseSchema = z.object({
1810
+ id: z.string().uuid(),
1811
+ slug: z.string(),
1812
+ object: z.literal("secret-reference")
1813
+ });
1814
+
1815
+ // src/tools/analytics.tools.ts
1816
+ import { z as z2 } from "zod";
1738
1817
  var baseAnalyticsSchema = {
1739
- time_of_generation_min: z.string().describe(
1818
+ time_of_generation_min: z2.string().describe(
1740
1819
  "Start time for the analytics period (ISO8601 format, e.g., '2024-01-01T00:00:00Z')"
1741
1820
  ),
1742
- time_of_generation_max: z.string().describe(
1821
+ time_of_generation_max: z2.string().describe(
1743
1822
  "End time for the analytics period (ISO8601 format, e.g., '2024-02-01T00:00:00Z')"
1744
1823
  ),
1745
- total_units_min: z.coerce.number().positive().optional().describe("Minimum number of total tokens to filter by"),
1746
- total_units_max: z.coerce.number().positive().optional().describe("Maximum number of total tokens to filter by"),
1747
- cost_min: z.coerce.number().positive().optional().describe("Minimum cost in cents to filter by"),
1748
- cost_max: z.coerce.number().positive().optional().describe("Maximum cost in cents to filter by"),
1749
- prompt_token_min: z.coerce.number().positive().optional().describe("Minimum number of prompt tokens"),
1750
- prompt_token_max: z.coerce.number().positive().optional().describe("Maximum number of prompt tokens"),
1751
- completion_token_min: z.coerce.number().positive().optional().describe("Minimum number of completion tokens"),
1752
- completion_token_max: z.coerce.number().positive().optional().describe("Maximum number of completion tokens"),
1753
- status_code: z.string().optional().describe(
1824
+ total_units_min: z2.coerce.number().positive().optional().describe("Minimum number of total tokens to filter by"),
1825
+ total_units_max: z2.coerce.number().positive().optional().describe("Maximum number of total tokens to filter by"),
1826
+ cost_min: z2.coerce.number().positive().optional().describe("Minimum cost in cents to filter by"),
1827
+ cost_max: z2.coerce.number().positive().optional().describe("Maximum cost in cents to filter by"),
1828
+ prompt_token_min: z2.coerce.number().positive().optional().describe("Minimum number of prompt tokens"),
1829
+ prompt_token_max: z2.coerce.number().positive().optional().describe("Maximum number of prompt tokens"),
1830
+ completion_token_min: z2.coerce.number().positive().optional().describe("Minimum number of completion tokens"),
1831
+ completion_token_max: z2.coerce.number().positive().optional().describe("Maximum number of completion tokens"),
1832
+ status_code: z2.string().optional().describe(
1754
1833
  "Legacy Portkey query param for HTTP status codes. Comma-separated string; prefer status_codes for structured inputs."
1755
1834
  ),
1756
- weighted_feedback_min: z.coerce.number().min(-10).max(10).optional().describe("Minimum weighted feedback score (-10 to 10)"),
1757
- weighted_feedback_max: z.coerce.number().min(-10).max(10).optional().describe("Maximum weighted feedback score (-10 to 10)"),
1758
- virtual_keys: z.string().optional().describe(
1835
+ weighted_feedback_min: z2.coerce.number().min(-10).max(10).optional().describe("Minimum weighted feedback score (-10 to 10)"),
1836
+ weighted_feedback_max: z2.coerce.number().min(-10).max(10).optional().describe("Maximum weighted feedback score (-10 to 10)"),
1837
+ virtual_keys: z2.string().optional().describe(
1759
1838
  "Legacy Portkey query param for virtual key slugs. Comma-separated string; prefer virtual_key_slugs for structured inputs."
1760
1839
  ),
1761
- configs: z.string().optional().describe(
1840
+ configs: z2.string().optional().describe(
1762
1841
  "Legacy Portkey query param for config slugs. Comma-separated string; prefer config_slugs for structured inputs."
1763
1842
  ),
1764
- status_codes: z.array(z.string()).optional().describe(
1843
+ status_codes: z2.array(z2.string()).optional().describe(
1765
1844
  "Structured alias for status_code. Use an array of HTTP status codes; normalized to the legacy comma-separated Portkey query param."
1766
1845
  ),
1767
- virtual_key_slugs: z.array(z.string()).optional().describe(
1846
+ virtual_key_slugs: z2.array(z2.string()).optional().describe(
1768
1847
  "Structured alias for virtual_keys. Use an array of virtual key slugs; normalized to the legacy comma-separated Portkey query param."
1769
1848
  ),
1770
- config_slugs: z.array(z.string()).optional().describe(
1849
+ config_slugs: z2.array(z2.string()).optional().describe(
1771
1850
  "Structured alias for configs. Use an array of config slugs; normalized to the legacy comma-separated Portkey query param."
1772
1851
  ),
1773
- workspace_slug: z.string().optional().describe("Filter by specific workspace"),
1774
- api_key_ids: z.preprocess((value) => {
1852
+ workspace_slug: z2.string().optional().describe("Filter by specific workspace"),
1853
+ api_key_ids: z2.preprocess((value) => {
1775
1854
  if (value == null) {
1776
1855
  return value;
1777
1856
  }
@@ -1779,43 +1858,43 @@ var baseAnalyticsSchema = {
1779
1858
  return value.map((item) => String(item)).join(",");
1780
1859
  }
1781
1860
  return value;
1782
- }, z.string().optional()).describe(
1861
+ }, z2.string().optional()).describe(
1783
1862
  "Legacy Portkey query param for API key UUIDs. Comma-separated string; request_analytics also accepts an array and normalizes it to this form."
1784
1863
  ),
1785
- metadata: z.string().optional().describe(
1864
+ metadata: z2.string().optional().describe(
1786
1865
  `Legacy Portkey query param for metadata filtering. Stringified JSON object, e.g. '{"env":"prod","app":"myapp"}'; prefer metadata_filter for structured inputs.`
1787
1866
  ),
1788
- ai_org_model: z.string().optional().describe(
1867
+ ai_org_model: z2.string().optional().describe(
1789
1868
  "Legacy Portkey query param for provider/model pairs. Format: 'provider__model' with double underscore, e.g. 'openai__gpt-4' or 'anthropic__claude-3-opus'. Comma-separated string; prefer provider_models for structured inputs."
1790
1869
  ),
1791
- provider_models: z.array(z.string()).optional().describe(
1870
+ provider_models: z2.array(z2.string()).optional().describe(
1792
1871
  "Structured alias for ai_org_model. Use provider__model strings in an array; normalized to the legacy comma-separated Portkey query param."
1793
1872
  ),
1794
- trace_id: z.string().optional().describe(
1873
+ trace_id: z2.string().optional().describe(
1795
1874
  "Legacy Portkey query param for trace IDs. Comma-separated string; prefer trace_ids for structured inputs."
1796
1875
  ),
1797
- trace_ids: z.array(z.string()).optional().describe(
1876
+ trace_ids: z2.array(z2.string()).optional().describe(
1798
1877
  "Structured alias for trace_id. Use an array of trace IDs; normalized to the legacy comma-separated Portkey query param."
1799
1878
  ),
1800
- span_id: z.string().optional().describe(
1879
+ span_id: z2.string().optional().describe(
1801
1880
  "Legacy Portkey query param for span IDs. Comma-separated string; prefer span_ids for structured inputs."
1802
1881
  ),
1803
- span_ids: z.array(z.string()).optional().describe(
1882
+ span_ids: z2.array(z2.string()).optional().describe(
1804
1883
  "Structured alias for span_id. Use an array of span IDs; normalized to the legacy comma-separated Portkey query param."
1805
1884
  ),
1806
- metadata_filter: z.record(z.string(), z.unknown()).optional().describe(
1885
+ metadata_filter: z2.record(z2.string(), z2.unknown()).optional().describe(
1807
1886
  "Structured alias for metadata. Use an object such as { env: 'prod' }; normalized to a JSON string before the request is sent."
1808
1887
  ),
1809
- prompt_slug: z.string().optional().describe("Filter by prompt slug")
1888
+ prompt_slug: z2.string().optional().describe("Filter by prompt slug")
1810
1889
  };
1811
1890
  var paginatedAnalyticsSchema = {
1812
1891
  ...baseAnalyticsSchema,
1813
- current_page: z.coerce.number().positive().optional().describe("Page number for pagination"),
1814
- page_size: z.coerce.number().int().positive().max(100).optional().describe("Results per page (max 100)")
1892
+ current_page: z2.coerce.number().int().positive().optional().describe("Page number for pagination"),
1893
+ page_size: z2.coerce.number().int().positive().max(100).optional().describe("Results per page (max 100)")
1815
1894
  };
1816
1895
  var analyticsGroupMetadataSchema = {
1817
1896
  ...paginatedAnalyticsSchema,
1818
- metadata_key: z.string().describe("The metadata key to group by (e.g., 'env', 'app', 'client_id')")
1897
+ metadata_key: z2.string().describe("The metadata key to group by (e.g., 'env', 'app', 'client_id')")
1819
1898
  };
1820
1899
  function formatGraphAnalytics(summary, dataPoints) {
1821
1900
  return {
@@ -2398,26 +2477,26 @@ function registerAnalyticsTools(server, service) {
2398
2477
  }
2399
2478
 
2400
2479
  // src/tools/audit.tools.ts
2401
- import { z as z2 } from "zod";
2480
+ import { z as z3 } from "zod";
2402
2481
  var AUDIT_TOOL_SCHEMAS = {
2403
2482
  listAuditLogs: {
2404
- workspace_id: z2.string().optional().describe("Filter audit logs by workspace ID"),
2405
- actor_id: z2.string().optional().describe("Filter by the user ID who performed the action"),
2406
- action: z2.string().optional().describe(
2483
+ workspace_id: z3.string().optional().describe("Filter audit logs by workspace ID"),
2484
+ actor_id: z3.string().optional().describe("Filter by the user ID who performed the action"),
2485
+ action: z3.string().optional().describe(
2407
2486
  "Filter by action type (e.g., 'create', 'update', 'delete', 'login')"
2408
2487
  ),
2409
- resource_type: z2.string().optional().describe(
2488
+ resource_type: z3.string().optional().describe(
2410
2489
  "Filter by resource type (e.g., 'user', 'workspace', 'config', 'virtual_key')"
2411
2490
  ),
2412
- resource_id: z2.string().optional().describe("Filter by specific resource ID"),
2413
- start_time: z2.string().optional().describe(
2491
+ resource_id: z3.string().optional().describe("Filter by specific resource ID"),
2492
+ start_time: z3.string().optional().describe(
2414
2493
  "Start of time range filter (ISO 8601 format, e.g., '2024-01-01T00:00:00Z')"
2415
2494
  ),
2416
- end_time: z2.string().optional().describe(
2495
+ end_time: z3.string().optional().describe(
2417
2496
  "End of time range filter (ISO 8601 format, e.g., '2024-01-31T23:59:59Z')"
2418
2497
  ),
2419
- current_page: z2.coerce.number().positive().optional().describe("Page number for pagination (starts at 1)"),
2420
- page_size: z2.coerce.number().positive().max(100).optional().describe("Number of results per page (max 100)")
2498
+ current_page: z3.coerce.number().int().positive().optional().describe("Page number for pagination (starts at 1)"),
2499
+ page_size: z3.coerce.number().int().positive().max(100).optional().describe("Number of results per page (max 100)")
2421
2500
  }
2422
2501
  };
2423
2502
  function registerAuditTools(server, service) {
@@ -2470,30 +2549,30 @@ function registerAuditTools(server, service) {
2470
2549
  }
2471
2550
 
2472
2551
  // src/tools/collections.tools.ts
2473
- import { z as z3 } from "zod";
2552
+ import { z as z4 } from "zod";
2474
2553
  var COLLECTIONS_TOOL_SCHEMAS = {
2475
2554
  listCollections: {
2476
- workspace_id: z3.string().optional().describe("Filter by workspace ID"),
2477
- search: z3.string().optional().describe("Search collections by name"),
2478
- current_page: z3.coerce.number().positive().optional().describe("Page number for pagination"),
2479
- page_size: z3.coerce.number().positive().max(100).optional().describe("Results per page (max 100)")
2555
+ workspace_id: z4.string().optional().describe("Filter by workspace ID"),
2556
+ search: z4.string().optional().describe("Search collections by name"),
2557
+ current_page: z4.coerce.number().int().positive().optional().describe("Page number for pagination"),
2558
+ page_size: z4.coerce.number().int().positive().max(100).optional().describe("Results per page (max 100)")
2480
2559
  },
2481
2560
  createCollection: {
2482
- name: z3.string().describe(
2561
+ name: z4.string().describe(
2483
2562
  "Collection name (e.g., 'hourlink', 'apizone', 'research-pilot')"
2484
2563
  ),
2485
- workspace_id: z3.string().optional().describe("Workspace ID to create collection in")
2564
+ workspace_id: z4.string().optional().describe("Workspace ID to create collection in")
2486
2565
  },
2487
2566
  getCollection: {
2488
- collection_id: z3.string().describe("Collection ID or slug to retrieve")
2567
+ collection_id: z4.string().describe("Collection ID or slug to retrieve")
2489
2568
  },
2490
2569
  updateCollection: {
2491
- collection_id: z3.string().describe("Collection ID to update"),
2492
- name: z3.string().optional().describe("New name for the collection"),
2493
- description: z3.string().optional().describe("New description for the collection")
2570
+ collection_id: z4.string().describe("Collection ID to update"),
2571
+ name: z4.string().optional().describe("New name for the collection"),
2572
+ description: z4.string().optional().describe("New description for the collection")
2494
2573
  },
2495
2574
  deleteCollection: {
2496
- collection_id: z3.string().describe("Collection ID to delete")
2575
+ collection_id: z4.string().describe("Collection ID to delete")
2497
2576
  }
2498
2577
  };
2499
2578
  function registerCollectionsTools(server, service) {
@@ -2614,69 +2693,69 @@ function registerCollectionsTools(server, service) {
2614
2693
  }
2615
2694
 
2616
2695
  // src/tools/configs.tools.ts
2617
- import { z as z4 } from "zod";
2696
+ import { z as z5 } from "zod";
2618
2697
  var CONFIGS_TOOL_SCHEMAS = {
2619
2698
  listConfigs: {
2620
- current_page: z4.coerce.number().positive().optional().describe("Page number for pagination"),
2621
- page_size: z4.coerce.number().positive().max(100).optional().describe("Number of results per page (max 100)")
2699
+ current_page: z5.coerce.number().int().positive().optional().describe("Page number for pagination"),
2700
+ page_size: z5.coerce.number().int().positive().max(100).optional().describe("Number of results per page (max 100)")
2622
2701
  },
2623
2702
  getConfig: {
2624
- slug: z4.string().describe(
2703
+ slug: z5.string().describe(
2625
2704
  "The unique identifier (slug) of the configuration to retrieve. This can be found in the configuration's URL or from the list_configs tool response"
2626
2705
  )
2627
2706
  },
2628
2707
  createConfig: {
2629
- name: z4.string().describe("Name for the new configuration"),
2630
- workspace_id: z4.string().optional().describe("Workspace ID to create config in"),
2631
- cache_mode: z4.enum(["simple", "semantic"]).optional().describe("Cache mode: 'simple' or 'semantic'"),
2632
- cache_max_age: z4.coerce.number().positive().optional().describe("Cache max age in seconds"),
2633
- retry_attempts: z4.coerce.number().positive().max(5).optional().describe("Number of retry attempts (1-5)"),
2634
- retry_on_status_codes: z4.array(z4.coerce.number()).optional().describe("HTTP status codes to retry on (e.g., [429, 500, 502, 503])"),
2635
- strategy_mode: z4.enum(["loadbalance", "fallback"]).optional().describe("Routing strategy: 'loadbalance' or 'fallback'"),
2636
- targets: z4.array(
2637
- z4.object({
2638
- provider: z4.string().optional(),
2639
- virtual_key: z4.string().optional()
2708
+ name: z5.string().describe("Name for the new configuration"),
2709
+ workspace_id: z5.string().optional().describe("Workspace ID to create config in"),
2710
+ cache_mode: z5.enum(["simple", "semantic"]).optional().describe("Cache mode: 'simple' or 'semantic'"),
2711
+ cache_max_age: z5.coerce.number().positive().optional().describe("Cache max age in seconds"),
2712
+ retry_attempts: z5.coerce.number().positive().max(5).optional().describe("Number of retry attempts (1-5)"),
2713
+ retry_on_status_codes: z5.array(z5.coerce.number()).optional().describe("HTTP status codes to retry on (e.g., [429, 500, 502, 503])"),
2714
+ strategy_mode: z5.enum(["loadbalance", "fallback"]).optional().describe("Routing strategy: 'loadbalance' or 'fallback'"),
2715
+ targets: z5.array(
2716
+ z5.object({
2717
+ provider: z5.string().optional(),
2718
+ virtual_key: z5.string().optional()
2640
2719
  }).refine((t) => t.provider || t.virtual_key, {
2641
2720
  message: "Each target must have at least provider or virtual_key"
2642
2721
  })
2643
2722
  ).optional().describe("Array of target providers with virtual keys")
2644
2723
  },
2645
2724
  updateConfig: {
2646
- slug: z4.string().describe("Configuration slug to update"),
2647
- name: z4.string().optional().describe("New name for the configuration"),
2648
- status: z4.enum(["active", "inactive"]).optional().describe("Configuration status"),
2649
- cache_mode: z4.enum(["simple", "semantic"]).optional().describe("Cache mode: 'simple' or 'semantic'"),
2650
- cache_max_age: z4.coerce.number().positive().optional().describe("Cache max age in seconds"),
2651
- retry_attempts: z4.coerce.number().positive().max(5).optional().describe("Number of retry attempts (1-5)"),
2652
- retry_on_status_codes: z4.array(z4.coerce.number()).optional().describe("HTTP status codes to retry on"),
2653
- strategy_mode: z4.enum(["loadbalance", "fallback"]).optional().describe("Routing strategy"),
2654
- targets: z4.array(
2655
- z4.object({
2656
- provider: z4.string().optional(),
2657
- virtual_key: z4.string().optional()
2725
+ slug: z5.string().describe("Configuration slug to update"),
2726
+ name: z5.string().optional().describe("New name for the configuration"),
2727
+ status: z5.enum(["active", "inactive"]).optional().describe("Configuration status"),
2728
+ cache_mode: z5.enum(["simple", "semantic"]).optional().describe("Cache mode: 'simple' or 'semantic'"),
2729
+ cache_max_age: z5.coerce.number().positive().optional().describe("Cache max age in seconds"),
2730
+ retry_attempts: z5.coerce.number().positive().max(5).optional().describe("Number of retry attempts (1-5)"),
2731
+ retry_on_status_codes: z5.array(z5.coerce.number()).optional().describe("HTTP status codes to retry on"),
2732
+ strategy_mode: z5.enum(["loadbalance", "fallback"]).optional().describe("Routing strategy"),
2733
+ targets: z5.array(
2734
+ z5.object({
2735
+ provider: z5.string().optional(),
2736
+ virtual_key: z5.string().optional()
2658
2737
  }).refine((t) => t.provider || t.virtual_key, {
2659
2738
  message: "Each target must have at least provider or virtual_key"
2660
2739
  })
2661
2740
  ).optional().describe("Array of target providers")
2662
2741
  },
2663
2742
  deleteConfig: {
2664
- slug: z4.string().describe("Configuration slug to delete")
2743
+ slug: z5.string().describe("Configuration slug to delete")
2665
2744
  },
2666
2745
  listConfigVersions: {
2667
- slug: z4.string().describe("Configuration slug to list versions for")
2746
+ slug: z5.string().describe("Configuration slug to list versions for")
2668
2747
  }
2669
2748
  };
2670
- var configPayloadSchema = z4.object({
2671
- cache_mode: z4.enum(["simple", "semantic"]).optional(),
2672
- cache_max_age: z4.coerce.number().positive().optional(),
2673
- retry_attempts: z4.coerce.number().positive().max(5).optional(),
2674
- retry_on_status_codes: z4.array(z4.coerce.number()).optional(),
2675
- strategy_mode: z4.enum(["loadbalance", "fallback"]).optional(),
2676
- targets: z4.array(
2677
- z4.object({
2678
- provider: z4.string().optional(),
2679
- virtual_key: z4.string().optional()
2749
+ var configPayloadSchema = z5.object({
2750
+ cache_mode: z5.enum(["simple", "semantic"]).optional(),
2751
+ cache_max_age: z5.coerce.number().positive().optional(),
2752
+ retry_attempts: z5.coerce.number().positive().max(5).optional(),
2753
+ retry_on_status_codes: z5.array(z5.coerce.number()).optional(),
2754
+ strategy_mode: z5.enum(["loadbalance", "fallback"]).optional(),
2755
+ targets: z5.array(
2756
+ z5.object({
2757
+ provider: z5.string().optional(),
2758
+ virtual_key: z5.string().optional()
2680
2759
  })
2681
2760
  ).optional()
2682
2761
  });
@@ -2893,53 +2972,53 @@ function registerConfigsTools(server, service) {
2893
2972
  }
2894
2973
 
2895
2974
  // src/tools/guardrails.tools.ts
2896
- import { z as z5 } from "zod";
2897
- var guardrailCheckSchema = z5.object({
2898
- id: z5.string().describe("Check identifier (e.g., 'default.jwt', 'default.pii')"),
2899
- name: z5.string().optional().describe("Display name for the check"),
2900
- is_enabled: z5.boolean().optional().describe("Whether the check is enabled"),
2901
- parameters: z5.record(z5.string(), z5.unknown()).optional().describe("Check-specific configuration parameters")
2975
+ import { z as z6 } from "zod";
2976
+ var guardrailCheckSchema = z6.object({
2977
+ id: z6.string().describe("Check identifier (e.g., 'default.jwt', 'default.pii')"),
2978
+ name: z6.string().optional().describe("Display name for the check"),
2979
+ is_enabled: z6.boolean().optional().describe("Whether the check is enabled"),
2980
+ parameters: z6.record(z6.string(), z6.unknown()).optional().describe("Check-specific configuration parameters")
2902
2981
  });
2903
- var guardrailFeedbackSchema = z5.object({
2904
- value: z5.coerce.number().optional().describe("Feedback value"),
2905
- weight: z5.coerce.number().optional().describe("Feedback weight"),
2906
- metadata: z5.record(z5.string(), z5.unknown()).optional().describe("Additional metadata")
2982
+ var guardrailFeedbackSchema = z6.object({
2983
+ value: z6.coerce.number().optional().describe("Feedback value"),
2984
+ weight: z6.coerce.number().optional().describe("Feedback weight"),
2985
+ metadata: z6.record(z6.string(), z6.unknown()).optional().describe("Additional metadata")
2907
2986
  });
2908
- var guardrailActionSchema = z5.object({
2909
- deny: z5.boolean().optional().describe("Whether to deny the request on check failure"),
2910
- async: z5.boolean().optional().describe("Whether to run checks asynchronously"),
2987
+ var guardrailActionSchema = z6.object({
2988
+ deny: z6.boolean().optional().describe("Whether to deny the request on check failure"),
2989
+ async: z6.boolean().optional().describe("Whether to run checks asynchronously"),
2911
2990
  on_success: guardrailFeedbackSchema.optional().describe("Feedback configuration for successful checks"),
2912
2991
  on_fail: guardrailFeedbackSchema.optional().describe("Feedback configuration for failed checks"),
2913
- on_fail_action: z5.string().optional().describe("Simple action on failure (e.g., 'block')"),
2914
- message: z5.string().optional().describe("Message to return when guardrail triggers")
2992
+ on_fail_action: z6.string().optional().describe("Simple action on failure (e.g., 'block')"),
2993
+ message: z6.string().optional().describe("Message to return when guardrail triggers")
2915
2994
  });
2916
2995
  var GUARDRAILS_TOOL_SCHEMAS = {
2917
2996
  listGuardrails: {
2918
- workspace_id: z5.string().optional().describe("Filter guardrails by workspace ID"),
2919
- organisation_id: z5.string().optional().describe("Filter guardrails by organization ID"),
2920
- page_size: z5.coerce.number().min(1).max(100).optional().describe("Number of items per page (1-100, default: 100)"),
2921
- current_page: z5.coerce.number().positive().optional().describe("Page number for pagination")
2997
+ workspace_id: z6.string().optional().describe("Filter guardrails by workspace ID"),
2998
+ organisation_id: z6.string().optional().describe("Filter guardrails by organization ID"),
2999
+ page_size: z6.coerce.number().int().min(1).max(100).optional().describe("Number of items per page (1-100, default: 100)"),
3000
+ current_page: z6.coerce.number().int().positive().optional().describe("Page number for pagination")
2922
3001
  },
2923
3002
  getGuardrail: {
2924
- guardrail_id: z5.string().describe("The guardrail UUID or slug (with guard_ prefix) to retrieve")
3003
+ guardrail_id: z6.string().describe("The guardrail UUID or slug (with guard_ prefix) to retrieve")
2925
3004
  },
2926
3005
  createGuardrail: {
2927
- name: z5.string().describe("Name of the guardrail"),
2928
- checks: z5.array(guardrailCheckSchema).min(1).describe("Array of checks to apply (at least one required)"),
3006
+ name: z6.string().describe("Name of the guardrail"),
3007
+ checks: z6.array(guardrailCheckSchema).min(1).describe("Array of checks to apply (at least one required)"),
2929
3008
  actions: guardrailActionSchema.describe(
2930
3009
  "Actions to take when guardrail checks pass or fail"
2931
3010
  ),
2932
- workspace_id: z5.string().optional().describe("Workspace ID to create the guardrail in"),
2933
- organisation_id: z5.string().optional().describe("Organisation ID (required if workspace_id not provided)")
3011
+ workspace_id: z6.string().optional().describe("Workspace ID to create the guardrail in"),
3012
+ organisation_id: z6.string().optional().describe("Organisation ID (required if workspace_id not provided)")
2934
3013
  },
2935
3014
  updateGuardrail: {
2936
- guardrail_id: z5.string().describe("The guardrail UUID or slug to update"),
2937
- name: z5.string().optional().describe("New name for the guardrail"),
2938
- checks: z5.array(guardrailCheckSchema).min(1).optional().describe("Updated array of checks to apply"),
3015
+ guardrail_id: z6.string().describe("The guardrail UUID or slug to update"),
3016
+ name: z6.string().optional().describe("New name for the guardrail"),
3017
+ checks: z6.array(guardrailCheckSchema).min(1).optional().describe("Updated array of checks to apply"),
2939
3018
  actions: guardrailActionSchema.optional().describe("Updated actions configuration")
2940
3019
  },
2941
3020
  deleteGuardrail: {
2942
- guardrail_id: z5.string().describe("The guardrail UUID or slug to delete")
3021
+ guardrail_id: z6.string().describe("The guardrail UUID or slug to delete")
2943
3022
  }
2944
3023
  };
2945
3024
  function registerGuardrailsTools(server, service) {
@@ -3089,7 +3168,7 @@ function registerGuardrailsTools(server, service) {
3089
3168
  }
3090
3169
 
3091
3170
  // src/tools/integrations.tools.ts
3092
- import { z as z6 } from "zod";
3171
+ import { z as z7 } from "zod";
3093
3172
 
3094
3173
  // src/lib/limits.ts
3095
3174
  var PERIODIC_RESET_DEFAULT = "monthly";
@@ -3134,91 +3213,91 @@ function buildRateLimits(params) {
3134
3213
  // src/tools/integrations.tools.ts
3135
3214
  var INTEGRATIONS_TOOL_SCHEMAS = {
3136
3215
  listIntegrations: {
3137
- current_page: z6.coerce.number().positive().optional().describe("Page number for pagination"),
3138
- page_size: z6.coerce.number().int().positive().max(100).optional().describe("Number of results per page (default 100, max 100)"),
3139
- workspace_id: z6.string().optional().describe("Filter integrations accessible by a specific workspace"),
3140
- type: z6.enum(["workspace", "organisation", "all"]).optional().describe(
3216
+ current_page: z7.coerce.number().int().positive().optional().describe("Page number for pagination"),
3217
+ page_size: z7.coerce.number().int().positive().max(100).optional().describe("Number of results per page (default 100, max 100)"),
3218
+ workspace_id: z7.string().optional().describe("Filter integrations accessible by a specific workspace"),
3219
+ type: z7.enum(["workspace", "organisation", "all"]).optional().describe(
3141
3220
  "Filter by integration type: 'workspace', 'organisation', or 'all' (default)"
3142
3221
  )
3143
3222
  },
3144
3223
  createIntegration: {
3145
- name: z6.string().describe("Human-readable name for the integration"),
3146
- ai_provider_id: z6.string().describe(
3224
+ name: z7.string().describe("Human-readable name for the integration"),
3225
+ ai_provider_id: z7.string().describe(
3147
3226
  "ID of the AI provider (e.g., 'openai', 'anthropic', 'azure-openai', 'aws-bedrock', 'vertex-ai')"
3148
3227
  ),
3149
- slug: z6.string().optional().describe(
3228
+ slug: z7.string().optional().describe(
3150
3229
  "URL-friendly identifier (auto-generated from name if not provided)"
3151
3230
  ),
3152
- key: z6.string().optional().describe("API key for the provider (if required)"),
3153
- description: z6.string().optional().describe("Optional description of the integration"),
3154
- workspace_id: z6.string().optional().describe("Workspace ID for workspace-scoped integrations"),
3155
- api_version: z6.string().optional().describe("API version (for Azure OpenAI)"),
3156
- resource_name: z6.string().optional().describe("Resource name (for Azure OpenAI)"),
3157
- deployment_name: z6.string().optional().describe("Deployment name (for Azure OpenAI)"),
3158
- aws_region: z6.string().optional().describe("AWS region (for AWS Bedrock)"),
3159
- aws_access_key_id: z6.string().optional().describe("AWS access key ID (for AWS Bedrock)"),
3160
- aws_secret_access_key: z6.string().optional().describe("AWS secret access key (for AWS Bedrock)"),
3161
- vertex_project_id: z6.string().optional().describe("GCP project ID (for Vertex AI)"),
3162
- vertex_region: z6.string().optional().describe("GCP region (for Vertex AI)"),
3163
- custom_host: z6.string().optional().describe("Custom base URL for the provider")
3231
+ key: z7.string().optional().describe("API key for the provider (if required)"),
3232
+ description: z7.string().optional().describe("Optional description of the integration"),
3233
+ workspace_id: z7.string().optional().describe("Workspace ID for workspace-scoped integrations"),
3234
+ api_version: z7.string().optional().describe("API version (for Azure OpenAI)"),
3235
+ resource_name: z7.string().optional().describe("Resource name (for Azure OpenAI)"),
3236
+ deployment_name: z7.string().optional().describe("Deployment name (for Azure OpenAI)"),
3237
+ aws_region: z7.string().optional().describe("AWS region (for AWS Bedrock)"),
3238
+ aws_access_key_id: z7.string().optional().describe("AWS access key ID (for AWS Bedrock)"),
3239
+ aws_secret_access_key: z7.string().optional().describe("AWS secret access key (for AWS Bedrock)"),
3240
+ vertex_project_id: z7.string().optional().describe("GCP project ID (for Vertex AI)"),
3241
+ vertex_region: z7.string().optional().describe("GCP region (for Vertex AI)"),
3242
+ custom_host: z7.string().optional().describe("Custom base URL for the provider")
3164
3243
  },
3165
3244
  getIntegration: {
3166
- slug: z6.string().describe("The unique slug identifier of the integration to retrieve")
3245
+ slug: z7.string().describe("The unique slug identifier of the integration to retrieve")
3167
3246
  },
3168
3247
  updateIntegration: {
3169
- slug: z6.string().describe("The slug of the integration to update"),
3170
- name: z6.string().optional().describe("New human-readable name for the integration"),
3171
- key: z6.string().optional().describe("New API key for the provider"),
3172
- description: z6.string().optional().describe("New description for the integration"),
3173
- api_version: z6.string().optional().describe("New API version (for Azure OpenAI)"),
3174
- resource_name: z6.string().optional().describe("New resource name (for Azure OpenAI)"),
3175
- deployment_name: z6.string().optional().describe("New deployment name (for Azure OpenAI)"),
3176
- aws_region: z6.string().optional().describe("New AWS region (for AWS Bedrock)"),
3177
- aws_access_key_id: z6.string().optional().describe("New AWS access key ID (for AWS Bedrock)"),
3178
- aws_secret_access_key: z6.string().optional().describe("New AWS secret access key (for AWS Bedrock)"),
3179
- vertex_project_id: z6.string().optional().describe("New GCP project ID (for Vertex AI)"),
3180
- vertex_region: z6.string().optional().describe("New GCP region (for Vertex AI)"),
3181
- custom_host: z6.string().optional().describe("New custom base URL for the provider")
3248
+ slug: z7.string().describe("The slug of the integration to update"),
3249
+ name: z7.string().optional().describe("New human-readable name for the integration"),
3250
+ key: z7.string().optional().describe("New API key for the provider"),
3251
+ description: z7.string().optional().describe("New description for the integration"),
3252
+ api_version: z7.string().optional().describe("New API version (for Azure OpenAI)"),
3253
+ resource_name: z7.string().optional().describe("New resource name (for Azure OpenAI)"),
3254
+ deployment_name: z7.string().optional().describe("New deployment name (for Azure OpenAI)"),
3255
+ aws_region: z7.string().optional().describe("New AWS region (for AWS Bedrock)"),
3256
+ aws_access_key_id: z7.string().optional().describe("New AWS access key ID (for AWS Bedrock)"),
3257
+ aws_secret_access_key: z7.string().optional().describe("New AWS secret access key (for AWS Bedrock)"),
3258
+ vertex_project_id: z7.string().optional().describe("New GCP project ID (for Vertex AI)"),
3259
+ vertex_region: z7.string().optional().describe("New GCP region (for Vertex AI)"),
3260
+ custom_host: z7.string().optional().describe("New custom base URL for the provider")
3182
3261
  },
3183
3262
  deleteIntegration: {
3184
- slug: z6.string().describe("The slug of the integration to delete")
3263
+ slug: z7.string().describe("The slug of the integration to delete")
3185
3264
  },
3186
3265
  listIntegrationModels: {
3187
- slug: z6.string().describe("The slug of the integration"),
3188
- current_page: z6.coerce.number().positive().optional().describe("Page number for pagination"),
3189
- page_size: z6.coerce.number().int().positive().max(100).optional().describe("Number of results per page")
3266
+ slug: z7.string().describe("The slug of the integration"),
3267
+ current_page: z7.coerce.number().int().positive().optional().describe("Page number for pagination"),
3268
+ page_size: z7.coerce.number().int().positive().max(100).optional().describe("Number of results per page")
3190
3269
  },
3191
3270
  updateIntegrationModels: {
3192
- slug: z6.string().describe("The slug of the integration"),
3193
- models: z6.array(
3194
- z6.object({
3195
- slug: z6.string().describe("The model slug identifier"),
3196
- model_name: z6.string().optional().describe(
3271
+ slug: z7.string().describe("The slug of the integration"),
3272
+ models: z7.array(
3273
+ z7.object({
3274
+ slug: z7.string().describe("The model slug identifier"),
3275
+ model_name: z7.string().optional().describe(
3197
3276
  "Display name for the model (required for custom models)"
3198
3277
  ),
3199
- enabled: z6.boolean().describe("Whether the model is enabled"),
3200
- is_custom: z6.boolean().optional().describe("Whether this is a custom model (default: false)")
3278
+ enabled: z7.boolean().describe("Whether the model is enabled"),
3279
+ is_custom: z7.boolean().optional().describe("Whether this is a custom model (default: false)")
3201
3280
  })
3202
3281
  ).describe("Array of model configurations to update")
3203
3282
  },
3204
3283
  deleteIntegrationModel: {
3205
- slug: z6.string().describe("The slug of the integration"),
3206
- model_slug: z6.string().describe("The slug of the model to delete")
3284
+ slug: z7.string().describe("The slug of the integration"),
3285
+ model_slug: z7.string().describe("The slug of the model to delete")
3207
3286
  },
3208
3287
  listIntegrationWorkspaces: {
3209
- slug: z6.string().describe("The slug of the integration"),
3210
- current_page: z6.coerce.number().positive().optional().describe("Page number for pagination"),
3211
- page_size: z6.coerce.number().int().positive().max(100).optional().describe("Number of results per page")
3288
+ slug: z7.string().describe("The slug of the integration"),
3289
+ current_page: z7.coerce.number().int().positive().optional().describe("Page number for pagination"),
3290
+ page_size: z7.coerce.number().int().positive().max(100).optional().describe("Number of results per page")
3212
3291
  },
3213
3292
  updateIntegrationWorkspaces: {
3214
- slug: z6.string().describe("The slug of the integration"),
3215
- workspaces: z6.array(
3216
- z6.object({
3217
- id: z6.string().describe("The workspace ID"),
3218
- enabled: z6.boolean().describe("Whether the workspace has access to this integration"),
3219
- credit_limit: z6.coerce.number().positive().optional().describe("Credit limit for this workspace"),
3220
- alert_threshold: z6.coerce.number().min(0).max(100).optional().describe("Alert threshold percentage (0-100)"),
3221
- rate_limit_rpm: z6.coerce.number().positive().optional().describe("Rate limit in requests per minute")
3293
+ slug: z7.string().describe("The slug of the integration"),
3294
+ workspaces: z7.array(
3295
+ z7.object({
3296
+ id: z7.string().describe("The workspace ID"),
3297
+ enabled: z7.boolean().describe("Whether the workspace has access to this integration"),
3298
+ credit_limit: z7.coerce.number().positive().optional().describe("Credit limit for this workspace"),
3299
+ alert_threshold: z7.coerce.number().min(0).max(100).optional().describe("Alert threshold percentage (0-100)"),
3300
+ rate_limit_rpm: z7.coerce.number().positive().optional().describe("Rate limit in requests per minute")
3222
3301
  })
3223
3302
  ).describe("Array of workspace configurations to update")
3224
3303
  }
@@ -3551,104 +3630,110 @@ function registerIntegrationsTools(server, service) {
3551
3630
  }
3552
3631
 
3553
3632
  // src/tools/keys.tools.ts
3554
- import { z as z7 } from "zod";
3633
+ import { z as z8 } from "zod";
3555
3634
  var KEYS_TOOL_SCHEMAS = {
3556
3635
  listVirtualKeys: {
3557
- current_page: z7.coerce.number().positive().optional().describe("Page number for pagination"),
3558
- page_size: z7.coerce.number().positive().max(100).optional().describe("Number of results per page (max 100)")
3636
+ current_page: z8.coerce.number().int().positive().optional().describe("Page number for pagination"),
3637
+ page_size: z8.coerce.number().int().positive().max(100).optional().describe("Number of results per page (max 100)")
3559
3638
  },
3560
3639
  createVirtualKey: {
3561
- name: z7.string().describe("Display name for the virtual key"),
3562
- provider: z7.string().describe(
3640
+ name: z8.string().describe("Display name for the virtual key"),
3641
+ provider: z8.string().describe(
3563
3642
  "Provider slug (e.g., 'openai', 'anthropic', 'azure-openai', 'google')"
3564
3643
  ),
3565
- key: z7.string().describe("The actual provider API key to store"),
3566
- note: z7.string().optional().describe("Optional note or description for this key"),
3567
- workspace_id: z7.string().optional().describe("Workspace ID to create the key in"),
3568
- api_version: z7.string().optional().describe("API version (for Azure OpenAI)"),
3569
- resource_name: z7.string().optional().describe("Resource name (for Azure OpenAI)"),
3570
- deployment_name: z7.string().optional().describe("Deployment name (for Azure OpenAI)"),
3571
- credit_limit: z7.coerce.number().positive().optional().describe("Maximum usage cost threshold"),
3572
- alert_threshold: z7.coerce.number().min(0).max(100).optional().describe(
3644
+ key: z8.string().describe("The actual provider API key to store"),
3645
+ note: z8.string().optional().describe("Optional note or description for this key"),
3646
+ workspace_id: z8.string().optional().describe("Workspace ID to create the key in"),
3647
+ api_version: z8.string().optional().describe("API version (for Azure OpenAI)"),
3648
+ resource_name: z8.string().optional().describe("Resource name (for Azure OpenAI)"),
3649
+ deployment_name: z8.string().optional().describe("Deployment name (for Azure OpenAI)"),
3650
+ credit_limit: z8.coerce.number().positive().optional().describe("Maximum usage cost threshold"),
3651
+ alert_threshold: z8.coerce.number().min(0).max(100).optional().describe(
3573
3652
  "Percentage of credit_limit at which to send alert emails (0-100)"
3574
3653
  ),
3575
- rate_limit_rpm: z7.coerce.number().positive().optional().describe("Requests per minute limit")
3654
+ rate_limit_rpm: z8.coerce.number().positive().optional().describe("Requests per minute limit")
3576
3655
  },
3577
3656
  getVirtualKey: {
3578
- slug: z7.string().describe("The unique slug identifier of the virtual key to retrieve")
3657
+ slug: z8.string().describe("The unique slug identifier of the virtual key to retrieve")
3579
3658
  },
3580
3659
  updateVirtualKey: {
3581
- slug: z7.string().describe("The slug of the virtual key to update"),
3582
- name: z7.string().optional().describe("New display name for the key"),
3583
- key: z7.string().optional().describe("New provider API key value"),
3584
- note: z7.string().optional().describe("New note or description"),
3585
- credit_limit: z7.coerce.number().positive().optional().describe("New credit limit for usage"),
3586
- alert_threshold: z7.coerce.number().min(0).max(100).optional().describe("New alert threshold percentage (0-100)"),
3587
- rate_limit_rpm: z7.coerce.number().positive().optional().describe("New rate limit in requests per minute")
3660
+ slug: z8.string().describe("The slug of the virtual key to update"),
3661
+ name: z8.string().optional().describe("New display name for the key"),
3662
+ key: z8.string().optional().describe("New provider API key value"),
3663
+ note: z8.string().optional().describe("New note or description"),
3664
+ credit_limit: z8.coerce.number().positive().optional().describe("New credit limit for usage"),
3665
+ alert_threshold: z8.coerce.number().min(0).max(100).optional().describe("New alert threshold percentage (0-100)"),
3666
+ rate_limit_rpm: z8.coerce.number().positive().optional().describe("New rate limit in requests per minute")
3588
3667
  },
3589
3668
  deleteVirtualKey: {
3590
- slug: z7.string().describe("The slug of the virtual key to delete")
3669
+ slug: z8.string().describe("The slug of the virtual key to delete")
3591
3670
  },
3592
3671
  createApiKey: {
3593
- type: z7.enum(["organisation", "workspace"]).describe(
3672
+ type: z8.enum(["organisation", "workspace"]).describe(
3594
3673
  "Key type: 'organisation' for org-wide access or 'workspace' for workspace-scoped"
3595
3674
  ),
3596
- sub_type: z7.enum(["user", "service"]).describe(
3675
+ sub_type: z8.enum(["user", "service"]).describe(
3597
3676
  "Sub-type: 'user' for user-associated keys or 'service' for service accounts"
3598
3677
  ),
3599
- name: z7.string().describe("Display name for the API key"),
3600
- description: z7.string().optional().describe("Optional description for the key"),
3601
- workspace_id: z7.string().optional().describe("Workspace ID (required for workspace-type keys)"),
3602
- user_id: z7.string().optional().describe("User ID (required for user sub-type keys)"),
3603
- scopes: z7.array(z7.string()).describe(
3678
+ name: z8.string().describe("Display name for the API key"),
3679
+ description: z8.string().optional().describe("Optional description for the key"),
3680
+ workspace_id: z8.string().optional().describe("Workspace ID (required for workspace-type keys)"),
3681
+ user_id: z8.string().optional().describe("User ID (required for user sub-type keys)"),
3682
+ scopes: z8.array(z8.string()).describe(
3604
3683
  "Permission scopes for the key (e.g., ['logs.read', 'analytics.read'])"
3605
3684
  ),
3606
- credit_limit: z7.coerce.number().positive().optional().describe("Credit limit for usage"),
3607
- alert_threshold: z7.coerce.number().min(0).max(100).optional().describe("Alert threshold percentage (0-100)"),
3608
- rate_limit_rpm: z7.coerce.number().positive().optional().describe("Rate limit in requests per minute"),
3609
- default_config_id: z7.string().optional().describe("Default configuration ID to use with this key"),
3610
- default_metadata: z7.record(z7.string(), z7.string()).optional().describe("Default metadata key-value pairs"),
3611
- alert_emails: z7.array(z7.string()).optional().describe("Email addresses for alerts"),
3612
- expires_at: z7.string().optional().describe("Expiration date in ISO 8601 format")
3685
+ credit_limit: z8.coerce.number().positive().optional().describe("Credit limit for usage"),
3686
+ alert_threshold: z8.coerce.number().min(0).max(100).optional().describe("Alert threshold percentage (0-100)"),
3687
+ rate_limit_rpm: z8.coerce.number().positive().optional().describe("Rate limit in requests per minute"),
3688
+ default_config_id: z8.string().optional().describe("Default configuration ID to use with this key"),
3689
+ default_metadata: z8.record(z8.string(), z8.string()).optional().describe("Default metadata key-value pairs"),
3690
+ alert_emails: z8.array(z8.string()).optional().describe("Email addresses for alerts"),
3691
+ expires_at: z8.string().optional().describe("Expiration date in ISO 8601 format")
3613
3692
  },
3614
3693
  listApiKeys: {
3615
- page_size: z7.coerce.number().positive().max(100).optional().describe("Number of results per page (max 100)"),
3616
- current_page: z7.coerce.number().positive().optional().describe("Page number for pagination"),
3617
- workspace_id: z7.string().optional().describe("Filter by workspace ID")
3694
+ page_size: z8.coerce.number().int().positive().max(100).optional().describe("Number of results per page (max 100)"),
3695
+ current_page: z8.coerce.number().int().positive().optional().describe("Page number for pagination"),
3696
+ workspace_id: z8.string().optional().describe("Filter by workspace ID")
3618
3697
  },
3619
3698
  getApiKey: {
3620
- id: z7.string().uuid().describe("The UUID of the API key to retrieve")
3699
+ id: z8.string().uuid().describe("The UUID of the API key to retrieve")
3621
3700
  },
3622
3701
  updateApiKey: {
3623
- id: z7.string().uuid().describe("The UUID of the API key to update"),
3624
- name: z7.string().optional().describe("New display name for the key"),
3625
- description: z7.string().optional().describe("New description for the key"),
3626
- scopes: z7.array(z7.string()).optional().describe("New permission scopes for the key"),
3627
- credit_limit: z7.coerce.number().positive().optional().describe("New credit limit for usage"),
3628
- alert_threshold: z7.coerce.number().min(0).max(100).optional().describe("New alert threshold percentage (0-100)"),
3629
- rate_limit_rpm: z7.coerce.number().positive().optional().describe("New rate limit in requests per minute"),
3630
- default_config_id: z7.string().optional().describe("New default configuration ID"),
3631
- default_metadata: z7.record(z7.string(), z7.string()).optional().describe("New default metadata key-value pairs"),
3632
- alert_emails: z7.array(z7.string()).optional().describe("New email addresses for alerts"),
3633
- expires_at: z7.string().nullable().optional().describe(
3702
+ id: z8.string().uuid().describe("The UUID of the API key to update"),
3703
+ name: z8.string().optional().describe("New display name for the key"),
3704
+ description: z8.string().optional().describe("New description for the key"),
3705
+ scopes: z8.array(z8.string()).optional().describe("New permission scopes for the key"),
3706
+ credit_limit: z8.coerce.number().positive().optional().describe("New credit limit for usage"),
3707
+ alert_threshold: z8.coerce.number().min(0).max(100).optional().describe("New alert threshold percentage (0-100)"),
3708
+ rate_limit_rpm: z8.coerce.number().positive().optional().describe("New rate limit in requests per minute"),
3709
+ default_config_id: z8.string().optional().describe("New default configuration ID"),
3710
+ default_metadata: z8.record(z8.string(), z8.string()).optional().describe("New default metadata key-value pairs"),
3711
+ alert_emails: z8.array(z8.string()).optional().describe("New email addresses for alerts"),
3712
+ expires_at: z8.string().nullable().optional().describe(
3634
3713
  "New expiration date in ISO 8601 format, or null to remove expiration"
3635
3714
  )
3636
3715
  },
3716
+ rotateApiKey: {
3717
+ id: z8.string().uuid().describe("API key UUID obtained from list_api_keys"),
3718
+ key_transition_period_ms: z8.coerce.number().int().min(18e5).optional().describe(
3719
+ "Overlap in milliseconds while the previous key remains valid; minimum 1,800,000 (30 minutes), for example 3,600,000 for 1 hour"
3720
+ )
3721
+ },
3637
3722
  deleteApiKey: {
3638
- id: z7.string().uuid().describe("The UUID of the API key to delete")
3723
+ id: z8.string().uuid().describe("The UUID of the API key to delete")
3639
3724
  }
3640
3725
  };
3641
- var createApiKeySchema = z7.object(KEYS_TOOL_SCHEMAS.createApiKey).superRefine((value, ctx) => {
3726
+ var createApiKeySchema = z8.object(KEYS_TOOL_SCHEMAS.createApiKey).superRefine((value, ctx) => {
3642
3727
  if (value.type === "workspace" && !value.workspace_id) {
3643
3728
  ctx.addIssue({
3644
- code: z7.ZodIssueCode.custom,
3729
+ code: z8.ZodIssueCode.custom,
3645
3730
  path: ["workspace_id"],
3646
3731
  message: "workspace_id is required when type is 'workspace'"
3647
3732
  });
3648
3733
  }
3649
3734
  if (value.sub_type === "user" && !value.user_id) {
3650
3735
  ctx.addIssue({
3651
- code: z7.ZodIssueCode.custom,
3736
+ code: z8.ZodIssueCode.custom,
3652
3737
  path: ["user_id"],
3653
3738
  message: "user_id is required when sub_type is 'user'"
3654
3739
  });
@@ -4004,40 +4089,71 @@ function registerKeysTools(server, service) {
4004
4089
  };
4005
4090
  }
4006
4091
  );
4092
+ server.tool(
4093
+ "rotate_api_key",
4094
+ "Rotate an API key without changing its identity or scopes. The new secret is returned once and exposed to this MCP transcript, while the previous secret remains valid until key_transition_expires_at. Store the new key securely, update callers during the transition window, and never log either secret.",
4095
+ KEYS_TOOL_SCHEMAS.rotateApiKey,
4096
+ {
4097
+ title: "Rotate API Key",
4098
+ readOnlyHint: false,
4099
+ destructiveHint: true,
4100
+ idempotentHint: false,
4101
+ openWorldHint: true
4102
+ },
4103
+ async (params) => {
4104
+ const result = await service.keys.rotateApiKey(params.id, {
4105
+ key_transition_period_ms: params.key_transition_period_ms
4106
+ });
4107
+ return {
4108
+ content: [
4109
+ {
4110
+ type: "text",
4111
+ text: JSON.stringify({
4112
+ message: `Successfully rotated API key "${result.id}"`,
4113
+ warning: "Copy this new key now; it is returned only once. Replace callers before key_transition_expires_at and never log either key.",
4114
+ id: result.id,
4115
+ key: result.key,
4116
+ key_transition_expires_at: result.key_transition_expires_at
4117
+ })
4118
+ }
4119
+ ]
4120
+ };
4121
+ }
4122
+ );
4007
4123
  }
4008
4124
 
4009
4125
  // src/tools/labels.tools.ts
4010
- import { z as z8 } from "zod";
4126
+ import { z as z9 } from "zod";
4011
4127
  var LABELS_TOOL_SCHEMAS = {
4012
4128
  createPromptLabel: {
4013
- name: z8.string().describe("Name of the label"),
4014
- organisation_id: z8.string().optional().describe("Organisation ID to create the label in"),
4015
- workspace_id: z8.string().optional().describe("Workspace ID to create the label in"),
4016
- description: z8.string().optional().describe("Description of the label"),
4017
- color_code: z8.string().regex(/^#[0-9A-Fa-f]{6}$/).optional().describe(
4129
+ name: z9.string().describe("Name of the label"),
4130
+ organisation_id: z9.string().optional().describe("Organisation ID to create the label in"),
4131
+ workspace_id: z9.string().optional().describe("Workspace ID to create the label in"),
4132
+ description: z9.string().optional().describe("Description of the label"),
4133
+ color_code: z9.string().regex(/^#[0-9A-Fa-f]{6}$/).optional().describe(
4018
4134
  "Hex format, e.g. '#FF5733'. Optional \u2014 omit for default color."
4019
4135
  )
4020
4136
  },
4021
4137
  listPromptLabels: {
4022
- organisation_id: z8.string().optional().describe("Filter by organisation ID"),
4023
- workspace_id: z8.string().optional().describe("Filter by workspace ID"),
4024
- search: z8.string().optional().describe("Search labels by name"),
4025
- current_page: z8.coerce.number().positive().optional().describe("Page number for pagination"),
4026
- page_size: z8.coerce.number().positive().max(100).optional().describe("Results per page (max 100)")
4138
+ organisation_id: z9.string().optional().describe("Filter by organisation ID"),
4139
+ workspace_id: z9.string().optional().describe("Filter by workspace ID"),
4140
+ search: z9.string().optional().describe("Search labels by name"),
4141
+ current_page: z9.coerce.number().int().positive().optional().describe("Page number for pagination"),
4142
+ page_size: z9.coerce.number().int().positive().max(100).optional().describe("Results per page (max 100)")
4027
4143
  },
4028
4144
  getPromptLabel: {
4029
- label_id: z8.string().describe("Label ID to retrieve"),
4030
- organisation_id: z8.string().optional().describe("Organisation ID for filtering"),
4031
- workspace_id: z8.string().optional().describe("Workspace ID for filtering")
4145
+ label_id: z9.string().describe("Label ID to retrieve"),
4146
+ organisation_id: z9.string().optional().describe("Organisation ID for filtering"),
4147
+ workspace_id: z9.string().optional().describe("Workspace ID for filtering")
4032
4148
  },
4033
4149
  updatePromptLabel: {
4034
- label_id: z8.string().describe("Label ID to update"),
4035
- name: z8.string().optional().describe("New name for the label"),
4036
- description: z8.string().optional().describe("New description"),
4037
- color_code: z8.string().regex(/^#[0-9A-Fa-f]{6}$/).optional().describe("New hex color code (e.g., '#FF5733')")
4150
+ label_id: z9.string().describe("Label ID to update"),
4151
+ name: z9.string().optional().describe("New name for the label"),
4152
+ description: z9.string().optional().describe("New description"),
4153
+ color_code: z9.string().regex(/^#[0-9A-Fa-f]{6}$/).optional().describe("New hex color code (e.g., '#FF5733')")
4038
4154
  },
4039
4155
  deletePromptLabel: {
4040
- label_id: z8.string().describe("Label ID to delete")
4156
+ label_id: z9.string().describe("Label ID to delete")
4041
4157
  }
4042
4158
  };
4043
4159
  function registerLabelsTools(server, service) {
@@ -4177,86 +4293,86 @@ function registerLabelsTools(server, service) {
4177
4293
  }
4178
4294
 
4179
4295
  // src/tools/limits.tools.ts
4180
- import { z as z9 } from "zod";
4181
- var conditionSchema = z9.object({
4182
- field: z9.string().describe(
4296
+ import { z as z10 } from "zod";
4297
+ var conditionSchema = z10.object({
4298
+ field: z10.string().describe(
4183
4299
  "The field to match on (e.g., 'virtual_key', 'api_key', 'user_id', 'metadata.key')"
4184
4300
  ),
4185
- operator: z9.string().describe("The comparison operator (e.g., 'is', 'contains', 'is_not')"),
4186
- value: z9.string().describe("The value to match against")
4301
+ operator: z10.string().describe("The comparison operator (e.g., 'is', 'contains', 'is_not')"),
4302
+ value: z10.string().describe("The value to match against")
4187
4303
  });
4188
4304
  var LIMITS_TOOL_SCHEMAS = {
4189
4305
  listRateLimits: {
4190
- workspace_id: z9.string().optional().describe("Filter rate limits by workspace ID")
4306
+ workspace_id: z10.string().optional().describe("Filter rate limits by workspace ID")
4191
4307
  },
4192
4308
  getRateLimit: {
4193
- id: z9.string().describe("The unique identifier of the rate limit")
4309
+ id: z10.string().describe("The unique identifier of the rate limit")
4194
4310
  },
4195
4311
  createRateLimit: {
4196
- conditions: z9.array(conditionSchema).describe(
4312
+ conditions: z10.array(conditionSchema).describe(
4197
4313
  "Array of conditions that determine which requests this rate limit applies to"
4198
4314
  ),
4199
- group_by: z9.array(z9.string()).describe(
4315
+ group_by: z10.array(z10.string()).describe(
4200
4316
  "Array of fields to group the rate limit by (e.g., ['virtual_key'], ['api_key', 'user_id'])"
4201
4317
  ),
4202
- type: z9.enum(["requests", "tokens"]).describe("What to rate limit: 'requests' or 'tokens'"),
4203
- unit: z9.enum(["rpm", "rph", "rpd"]).describe(
4318
+ type: z10.enum(["requests", "tokens"]).describe("What to rate limit: 'requests' or 'tokens'"),
4319
+ unit: z10.enum(["rpm", "rph", "rpd"]).describe(
4204
4320
  "Time unit: 'rpm' (per minute), 'rph' (per hour), or 'rpd' (per day)"
4205
4321
  ),
4206
- value: z9.coerce.number().positive().describe("The maximum allowed value per unit (e.g., 100 rpm)"),
4207
- name: z9.string().optional().describe("Optional name for the rate limit"),
4208
- workspace_id: z9.string().optional().describe("Workspace ID to scope the limit to"),
4209
- organisation_id: z9.string().optional().describe("Organisation ID to scope the limit to")
4322
+ value: z10.coerce.number().positive().describe("The maximum allowed value per unit (e.g., 100 rpm)"),
4323
+ name: z10.string().optional().describe("Optional name for the rate limit"),
4324
+ workspace_id: z10.string().optional().describe("Workspace ID to scope the limit to"),
4325
+ organisation_id: z10.string().optional().describe("Organisation ID to scope the limit to")
4210
4326
  },
4211
4327
  updateRateLimit: {
4212
- id: z9.string().describe("The unique identifier of the rate limit"),
4213
- name: z9.string().optional().describe("New name for the rate limit"),
4214
- unit: z9.enum(["rpm", "rph", "rpd"]).optional().describe(
4328
+ id: z10.string().describe("The unique identifier of the rate limit"),
4329
+ name: z10.string().optional().describe("New name for the rate limit"),
4330
+ unit: z10.enum(["rpm", "rph", "rpd"]).optional().describe(
4215
4331
  "New time unit: 'rpm' (per minute), 'rph' (per hour), or 'rpd' (per day)"
4216
4332
  ),
4217
- value: z9.coerce.number().positive().optional().describe("New maximum allowed value per unit")
4333
+ value: z10.coerce.number().positive().optional().describe("New maximum allowed value per unit")
4218
4334
  },
4219
4335
  deleteRateLimit: {
4220
- id: z9.string().describe("The unique identifier of the rate limit")
4336
+ id: z10.string().describe("The unique identifier of the rate limit")
4221
4337
  },
4222
4338
  listUsageLimits: {
4223
- workspace_id: z9.string().optional().describe("Filter usage limits by workspace ID")
4339
+ workspace_id: z10.string().optional().describe("Filter usage limits by workspace ID")
4224
4340
  },
4225
4341
  getUsageLimit: {
4226
- id: z9.string().describe("The unique identifier of the usage limit")
4342
+ id: z10.string().describe("The unique identifier of the usage limit")
4227
4343
  },
4228
4344
  createUsageLimit: {
4229
- conditions: z9.array(conditionSchema).describe(
4345
+ conditions: z10.array(conditionSchema).describe(
4230
4346
  "Array of conditions that determine which requests this usage limit applies to"
4231
4347
  ),
4232
- group_by: z9.array(z9.string()).describe(
4348
+ group_by: z10.array(z10.string()).describe(
4233
4349
  "Array of fields to group the usage limit by (e.g., ['virtual_key'], ['api_key', 'user_id'])"
4234
4350
  ),
4235
- type: z9.enum(["cost", "tokens"]).describe("What to limit: 'cost' (in dollars) or 'tokens'"),
4236
- credit_limit: z9.coerce.number().positive().describe("The maximum allowed usage (cost in dollars or token count)"),
4237
- name: z9.string().optional().describe("Optional name for the usage limit"),
4238
- alert_threshold: z9.coerce.number().optional().describe("Percentage threshold (0-100) at which to send an alert"),
4239
- periodic_reset: z9.enum(["monthly", "weekly"]).optional().describe("Automatically reset usage counters on this schedule"),
4240
- workspace_id: z9.string().optional().describe("Workspace ID to scope the limit to"),
4241
- organisation_id: z9.string().optional().describe("Organisation ID to scope the limit to")
4351
+ type: z10.enum(["cost", "tokens"]).describe("What to limit: 'cost' (in dollars) or 'tokens'"),
4352
+ credit_limit: z10.coerce.number().positive().describe("The maximum allowed usage (cost in dollars or token count)"),
4353
+ name: z10.string().optional().describe("Optional name for the usage limit"),
4354
+ alert_threshold: z10.coerce.number().optional().describe("Percentage threshold (0-100) at which to send an alert"),
4355
+ periodic_reset: z10.enum(["monthly", "weekly"]).optional().describe("Automatically reset usage counters on this schedule"),
4356
+ workspace_id: z10.string().optional().describe("Workspace ID to scope the limit to"),
4357
+ organisation_id: z10.string().optional().describe("Organisation ID to scope the limit to")
4242
4358
  },
4243
4359
  updateUsageLimit: {
4244
- id: z9.string().describe("The unique identifier of the usage limit"),
4245
- name: z9.string().optional().describe("New name for the usage limit"),
4246
- credit_limit: z9.coerce.number().positive().optional().describe("New maximum allowed usage value"),
4247
- alert_threshold: z9.coerce.number().optional().describe("New alert threshold percentage (0-100)"),
4248
- periodic_reset: z9.enum(["monthly", "weekly"]).optional().describe("New periodic reset schedule"),
4249
- reset_usage_for_value: z9.string().optional().describe("Reset usage counters for a specific group_by value")
4360
+ id: z10.string().describe("The unique identifier of the usage limit"),
4361
+ name: z10.string().optional().describe("New name for the usage limit"),
4362
+ credit_limit: z10.coerce.number().positive().optional().describe("New maximum allowed usage value"),
4363
+ alert_threshold: z10.coerce.number().optional().describe("New alert threshold percentage (0-100)"),
4364
+ periodic_reset: z10.enum(["monthly", "weekly"]).optional().describe("New periodic reset schedule"),
4365
+ reset_usage_for_value: z10.string().optional().describe("Reset usage counters for a specific group_by value")
4250
4366
  },
4251
4367
  deleteUsageLimit: {
4252
- id: z9.string().describe("The unique identifier of the usage limit")
4368
+ id: z10.string().describe("The unique identifier of the usage limit")
4253
4369
  },
4254
4370
  listUsageLimitEntities: {
4255
- limit_id: z9.string().describe("Usage limit policy ID")
4371
+ limit_id: z10.string().describe("Usage limit policy ID")
4256
4372
  },
4257
4373
  resetUsageLimitEntity: {
4258
- limit_id: z9.string().describe("Usage limit policy ID"),
4259
- entity_id: z9.string().describe("Entity ID to reset usage for")
4374
+ limit_id: z10.string().describe("Usage limit policy ID"),
4375
+ entity_id: z10.string().describe("Entity ID to reset usage for")
4260
4376
  }
4261
4377
  };
4262
4378
  function formatRateLimit(limit) {
@@ -4562,8 +4678,8 @@ function registerLimitsTools(server, service) {
4562
4678
  }
4563
4679
 
4564
4680
  // src/tools/logging.tools.ts
4565
- import { z as z10 } from "zod";
4566
- var logExportFieldSchema = z10.enum([
4681
+ import { z as z11 } from "zod";
4682
+ var logExportFieldSchema = z11.enum([
4567
4683
  "id",
4568
4684
  "trace_id",
4569
4685
  "created_at",
@@ -4587,64 +4703,64 @@ var logExportFieldSchema = z10.enum([
4587
4703
  ]);
4588
4704
  var LOGGING_TOOL_SCHEMAS = {
4589
4705
  insertLog: {
4590
- request_url: z10.string().optional().describe("The endpoint URL being called"),
4591
- request_provider: z10.string().optional().describe("AI provider name (e.g., 'openai', 'anthropic')"),
4592
- request_method: z10.string().optional().default("post").describe("HTTP method used (defaults to 'post')"),
4593
- request_headers: z10.record(z10.string(), z10.string()).optional().describe("Request headers as key-value pairs"),
4594
- request_body: z10.record(z10.string(), z10.unknown()).optional().describe("Request payload/body"),
4595
- response_status: z10.coerce.number().optional().default(200).describe("HTTP response status code (defaults to 200)"),
4596
- response_headers: z10.record(z10.string(), z10.string()).optional().describe("Response headers as key-value pairs"),
4597
- response_body: z10.record(z10.string(), z10.unknown()).optional().describe("Response payload/body"),
4598
- response_time: z10.coerce.number().optional().describe("Response latency in milliseconds"),
4599
- streaming_mode: z10.boolean().optional().default(false).describe("Whether the response was streamed"),
4600
- metadata_organization: z10.string().optional().describe("Organization identifier for the log"),
4601
- metadata_user: z10.string().optional().describe("User identifier for the log"),
4602
- metadata_trace_id: z10.string().optional().describe("Trace ID for distributed tracing"),
4603
- metadata_span_id: z10.string().optional().describe("Span ID for tracing"),
4604
- metadata_span_name: z10.string().optional().describe("Span name for tracing"),
4605
- metadata_parent_span_id: z10.string().optional().describe("Parent span ID for tracing"),
4606
- metadata_custom: z10.record(z10.string(), z10.unknown()).optional().describe("Additional custom metadata key-value pairs")
4706
+ request_url: z11.string().optional().describe("The endpoint URL being called"),
4707
+ request_provider: z11.string().optional().describe("AI provider name (e.g., 'openai', 'anthropic')"),
4708
+ request_method: z11.string().optional().default("post").describe("HTTP method used (defaults to 'post')"),
4709
+ request_headers: z11.record(z11.string(), z11.string()).optional().describe("Request headers as key-value pairs"),
4710
+ request_body: z11.record(z11.string(), z11.unknown()).optional().describe("Request payload/body"),
4711
+ response_status: z11.coerce.number().optional().default(200).describe("HTTP response status code (defaults to 200)"),
4712
+ response_headers: z11.record(z11.string(), z11.string()).optional().describe("Response headers as key-value pairs"),
4713
+ response_body: z11.record(z11.string(), z11.unknown()).optional().describe("Response payload/body"),
4714
+ response_time: z11.coerce.number().optional().describe("Response latency in milliseconds"),
4715
+ streaming_mode: z11.boolean().optional().default(false).describe("Whether the response was streamed"),
4716
+ metadata_organization: z11.string().optional().describe("Organization identifier for the log"),
4717
+ metadata_user: z11.string().optional().describe("User identifier for the log"),
4718
+ metadata_trace_id: z11.string().optional().describe("Trace ID for distributed tracing"),
4719
+ metadata_span_id: z11.string().optional().describe("Span ID for tracing"),
4720
+ metadata_span_name: z11.string().optional().describe("Span name for tracing"),
4721
+ metadata_parent_span_id: z11.string().optional().describe("Parent span ID for tracing"),
4722
+ metadata_custom: z11.record(z11.string(), z11.unknown()).optional().describe("Additional custom metadata key-value pairs")
4607
4723
  },
4608
4724
  createLogExport: {
4609
- workspace_id: z10.string().optional().describe("Workspace ID for the export"),
4610
- description: z10.string().optional().describe("Human-readable description for the export job"),
4611
- time_min: z10.string().describe(
4725
+ workspace_id: z11.string().optional().describe("Workspace ID for the export"),
4726
+ description: z11.string().optional().describe("Human-readable description for the export job"),
4727
+ time_min: z11.string().describe(
4612
4728
  "Minimum time filter in date format (e.g., '2024-01-01' or ISO 8601)"
4613
4729
  ),
4614
- time_max: z10.string().describe(
4730
+ time_max: z11.string().describe(
4615
4731
  "Maximum time filter in date format (e.g., '2024-01-31' or ISO 8601)"
4616
4732
  ),
4617
- cost_min: z10.coerce.number().optional().describe("Minimum cost filter"),
4618
- cost_max: z10.coerce.number().optional().describe("Maximum cost filter"),
4619
- total_units_min: z10.coerce.number().optional().describe("Minimum total units (tokens) filter"),
4620
- total_units_max: z10.coerce.number().optional().describe("Maximum total units (tokens) filter"),
4621
- ai_model: z10.array(z10.string()).optional().describe("Filter by specific AI model names"),
4622
- requested_fields: z10.array(logExportFieldSchema).describe(
4733
+ cost_min: z11.coerce.number().optional().describe("Minimum cost filter"),
4734
+ cost_max: z11.coerce.number().optional().describe("Maximum cost filter"),
4735
+ total_units_min: z11.coerce.number().optional().describe("Minimum total units (tokens) filter"),
4736
+ total_units_max: z11.coerce.number().optional().describe("Maximum total units (tokens) filter"),
4737
+ ai_model: z11.array(z11.string()).optional().describe("Filter by specific AI model names"),
4738
+ requested_fields: z11.array(logExportFieldSchema).describe(
4623
4739
  "Fields to include in export: id, trace_id, created_at, request, response, is_success, ai_org, ai_model, req_units, res_units, total_units, request_url, cost, cost_currency, response_time, response_status_code, mode, config, prompt_slug, metadata"
4624
4740
  )
4625
4741
  },
4626
4742
  listLogExports: {
4627
- workspace_id: z10.string().describe("Workspace ID to list exports for (required)")
4743
+ workspace_id: z11.string().describe("Workspace ID to list exports for (required)")
4628
4744
  },
4629
4745
  getLogExport: {
4630
- export_id: z10.string().describe("The unique ID of the log export")
4746
+ export_id: z11.string().describe("The unique ID of the log export")
4631
4747
  },
4632
4748
  startLogExport: {
4633
- export_id: z10.string().describe("The unique ID of the log export to start")
4749
+ export_id: z11.string().describe("The unique ID of the log export to start")
4634
4750
  },
4635
4751
  cancelLogExport: {
4636
- export_id: z10.string().describe("The unique ID of the log export to cancel")
4752
+ export_id: z11.string().describe("The unique ID of the log export to cancel")
4637
4753
  },
4638
4754
  downloadLogExport: {
4639
- export_id: z10.string().describe("The unique ID of the log export to download")
4755
+ export_id: z11.string().describe("The unique ID of the log export to download")
4640
4756
  },
4641
4757
  updateLogExport: {
4642
- export_id: z10.string().describe("The unique ID of the log export to update"),
4643
- workspace_id: z10.string().optional().describe("Workspace ID for the export"),
4644
- time_of_generation_max: z10.string().optional().describe(
4758
+ export_id: z11.string().describe("The unique ID of the log export to update"),
4759
+ workspace_id: z11.string().optional().describe("Workspace ID for the export"),
4760
+ time_of_generation_max: z11.string().optional().describe(
4645
4761
  "Maximum time filter in date format (e.g., '2024-07-25' or ISO 8601)"
4646
4762
  ),
4647
- requested_fields: z10.array(logExportFieldSchema).optional().describe(
4763
+ requested_fields: z11.array(logExportFieldSchema).optional().describe(
4648
4764
  "Fields to include in export: id, trace_id, created_at, request, response, is_success, ai_org, ai_model, req_units, res_units, total_units, request_url, cost, cost_currency, response_time, response_status_code, mode, config, prompt_slug, metadata"
4649
4765
  )
4650
4766
  }
@@ -4885,73 +5001,73 @@ function registerLoggingTools(server, service) {
4885
5001
  }
4886
5002
 
4887
5003
  // src/tools/mcp-integrations.tools.ts
4888
- import { z as z11 } from "zod";
5004
+ import { z as z12 } from "zod";
4889
5005
  var MCP_INTEGRATIONS_TOOL_SCHEMAS = {
4890
5006
  listMcpIntegrations: {
4891
- current_page: z11.coerce.number().positive().optional().describe("Page number for pagination"),
4892
- page_size: z11.coerce.number().int().positive().max(100).optional().describe("Number of results per page (max 100)"),
4893
- workspace_id: z11.string().optional().describe("Filter by workspace ID")
5007
+ current_page: z12.coerce.number().int().positive().optional().describe("Page number for pagination"),
5008
+ page_size: z12.coerce.number().int().positive().max(100).optional().describe("Number of results per page (max 100)"),
5009
+ workspace_id: z12.string().optional().describe("Filter by workspace ID")
4894
5010
  },
4895
5011
  createMcpIntegration: {
4896
- name: z11.string().describe("Display name for the MCP integration"),
4897
- url: z11.string().describe("URL endpoint of the MCP server to integrate"),
4898
- auth_type: z11.enum(["oauth_auto", "headers", "none"]).describe(
5012
+ name: z12.string().describe("Display name for the MCP integration"),
5013
+ url: z12.string().describe("URL endpoint of the MCP server to integrate"),
5014
+ auth_type: z12.enum(["oauth_auto", "headers", "none"]).describe(
4899
5015
  "Authentication type: 'none', 'headers' (custom headers), or 'oauth_auto' (OAuth)"
4900
5016
  ),
4901
- transport: z11.enum(["http", "sse"]).describe(
5017
+ transport: z12.enum(["http", "sse"]).describe(
4902
5018
  "MCP transport protocol: 'http' (streamable HTTP) or 'sse' (server-sent events)"
4903
5019
  ),
4904
- slug: z11.string().optional().describe("Custom slug. Auto-generated if omitted"),
4905
- description: z11.string().optional().describe("Description of the MCP integration"),
4906
- custom_headers: z11.record(z11.string(), z11.string()).optional().describe(
5020
+ slug: z12.string().optional().describe("Custom slug. Auto-generated if omitted"),
5021
+ description: z12.string().optional().describe("Description of the MCP integration"),
5022
+ custom_headers: z12.record(z12.string(), z12.string()).optional().describe(
4907
5023
  'Custom headers for authentication (e.g. { "Authorization": "Bearer xxx" }). Sent via configurations.custom_headers'
4908
5024
  ),
4909
- workspace_id: z11.string().optional().describe(
5025
+ workspace_id: z12.string().optional().describe(
4910
5026
  "Workspace ID \u2014 required when using organization admin API keys"
4911
5027
  )
4912
5028
  },
4913
5029
  getMcpIntegration: {
4914
- id: z11.string().describe("The MCP integration ID or slug to retrieve")
5030
+ id: z12.string().describe("The MCP integration ID or slug to retrieve")
4915
5031
  },
4916
5032
  updateMcpIntegration: {
4917
- id: z11.string().describe("The MCP integration ID or slug to update"),
4918
- name: z11.string().optional().describe("New display name"),
4919
- description: z11.string().optional().describe("New description"),
4920
- url: z11.string().optional().describe("New URL endpoint"),
4921
- auth_type: z11.enum(["oauth_auto", "headers", "none"]).optional().describe("New authentication type"),
4922
- transport: z11.enum(["http", "sse"]).optional().describe("New transport protocol"),
4923
- custom_headers: z11.record(z11.string(), z11.string()).optional().describe(
5033
+ id: z12.string().describe("The MCP integration ID or slug to update"),
5034
+ name: z12.string().optional().describe("New display name"),
5035
+ description: z12.string().optional().describe("New description"),
5036
+ url: z12.string().optional().describe("New URL endpoint"),
5037
+ auth_type: z12.enum(["oauth_auto", "headers", "none"]).optional().describe("New authentication type"),
5038
+ transport: z12.enum(["http", "sse"]).optional().describe("New transport protocol"),
5039
+ custom_headers: z12.record(z12.string(), z12.string()).optional().describe(
4924
5040
  "New custom headers for authentication. Sent via configurations.custom_headers"
4925
5041
  )
4926
5042
  },
4927
5043
  deleteMcpIntegration: {
4928
- id: z11.string().describe("The MCP integration ID or slug to delete")
5044
+ id: z12.string().describe("The MCP integration ID or slug to delete")
4929
5045
  },
4930
5046
  getMcpIntegrationMetadata: {
4931
- id: z11.string().describe("The MCP integration ID or slug")
5047
+ id: z12.string().describe("The MCP integration ID or slug")
4932
5048
  },
4933
5049
  listMcpIntegrationCapabilities: {
4934
- id: z11.string().describe("The MCP integration ID or slug")
5050
+ id: z12.string().describe("The MCP integration ID or slug")
4935
5051
  },
4936
5052
  updateMcpIntegrationCapabilities: {
4937
- id: z11.string().describe("The MCP integration ID or slug"),
4938
- capabilities: z11.array(
4939
- z11.object({
4940
- name: z11.string().describe("Capability name"),
4941
- type: z11.enum(["tool", "prompt", "resource"]).describe("Capability type"),
4942
- enabled: z11.boolean().describe("Whether to enable the capability")
5053
+ id: z12.string().describe("The MCP integration ID or slug"),
5054
+ capabilities: z12.array(
5055
+ z12.object({
5056
+ name: z12.string().describe("Capability name"),
5057
+ type: z12.enum(["tool", "prompt", "resource"]).describe("Capability type"),
5058
+ enabled: z12.boolean().describe("Whether to enable the capability")
4943
5059
  })
4944
5060
  ).min(1).describe("Array of capability updates")
4945
5061
  },
4946
5062
  listMcpIntegrationWorkspaces: {
4947
- id: z11.string().describe("The MCP integration ID or slug")
5063
+ id: z12.string().describe("The MCP integration ID or slug")
4948
5064
  },
4949
5065
  updateMcpIntegrationWorkspaces: {
4950
- id: z11.string().describe("The MCP integration ID or slug"),
4951
- workspaces: z11.array(
4952
- z11.object({
4953
- id: z11.string().describe("Workspace ID"),
4954
- enabled: z11.boolean().describe("Whether workspace has access")
5066
+ id: z12.string().describe("The MCP integration ID or slug"),
5067
+ workspaces: z12.array(
5068
+ z12.object({
5069
+ id: z12.string().describe("Workspace ID"),
5070
+ enabled: z12.boolean().describe("Whether workspace has access")
4955
5071
  })
4956
5072
  ).min(1).describe("Array of workspace access updates")
4957
5073
  }
@@ -5243,7 +5359,7 @@ function registerMcpIntegrationsTools(server, service) {
5243
5359
  }
5244
5360
 
5245
5361
  // src/tools/mcp-servers.tools.ts
5246
- import { z as z12 } from "zod";
5362
+ import { z as z13 } from "zod";
5247
5363
 
5248
5364
  // src/tools/utils.ts
5249
5365
  function formatFullName(firstName, lastName) {
@@ -5253,56 +5369,56 @@ function formatFullName(firstName, lastName) {
5253
5369
  // src/tools/mcp-servers.tools.ts
5254
5370
  var MCP_SERVERS_TOOL_SCHEMAS = {
5255
5371
  listMcpServers: {
5256
- current_page: z12.coerce.number().positive().optional().describe("Page number for pagination"),
5257
- page_size: z12.coerce.number().int().positive().max(100).optional().describe("Number of results per page (max 100)"),
5258
- workspace_id: z12.string().optional().describe("Filter by workspace ID")
5372
+ current_page: z13.coerce.number().int().positive().optional().describe("Page number for pagination"),
5373
+ page_size: z13.coerce.number().int().positive().max(100).optional().describe("Number of results per page (max 100)"),
5374
+ workspace_id: z13.string().optional().describe("Filter by workspace ID")
5259
5375
  },
5260
5376
  createMcpServer: {
5261
- name: z12.string().describe("Display name for the MCP server"),
5262
- mcp_integration_id: z12.string().describe("ID or slug of the MCP integration this server belongs to"),
5263
- slug: z12.string().optional().describe("Custom slug. Auto-generated if omitted"),
5264
- description: z12.string().optional().describe("Description of the MCP server")
5377
+ name: z13.string().describe("Display name for the MCP server"),
5378
+ mcp_integration_id: z13.string().describe("ID or slug of the MCP integration this server belongs to"),
5379
+ slug: z13.string().optional().describe("Custom slug. Auto-generated if omitted"),
5380
+ description: z13.string().optional().describe("Description of the MCP server")
5265
5381
  },
5266
5382
  getMcpServer: {
5267
- id: z12.string().describe("The MCP server ID or slug to retrieve")
5383
+ id: z13.string().describe("The MCP server ID or slug to retrieve")
5268
5384
  },
5269
5385
  updateMcpServer: {
5270
- id: z12.string().describe("The MCP server ID or slug to update"),
5271
- name: z12.string().optional().describe("New display name"),
5272
- description: z12.string().optional().describe("New description")
5386
+ id: z13.string().describe("The MCP server ID or slug to update"),
5387
+ name: z13.string().optional().describe("New display name"),
5388
+ description: z13.string().optional().describe("New description")
5273
5389
  },
5274
5390
  deleteMcpServer: {
5275
- id: z12.string().describe("The MCP server ID or slug to delete")
5391
+ id: z13.string().describe("The MCP server ID or slug to delete")
5276
5392
  },
5277
5393
  testMcpServer: {
5278
- id: z12.string().describe("The MCP server ID or slug to test")
5394
+ id: z13.string().describe("The MCP server ID or slug to test")
5279
5395
  },
5280
5396
  listMcpServerCapabilities: {
5281
- id: z12.string().describe("The MCP server ID or slug"),
5282
- current_page: z12.coerce.number().positive().optional().describe("Page number for pagination"),
5283
- page_size: z12.coerce.number().positive().max(100).optional().describe("Number of results per page (max 100)")
5397
+ id: z13.string().describe("The MCP server ID or slug"),
5398
+ current_page: z13.coerce.number().int().positive().optional().describe("Page number for pagination"),
5399
+ page_size: z13.coerce.number().int().positive().max(100).optional().describe("Number of results per page (max 100)")
5284
5400
  },
5285
5401
  updateMcpServerCapabilities: {
5286
- id: z12.string().describe("The MCP server ID or slug"),
5287
- capabilities: z12.array(
5288
- z12.object({
5289
- name: z12.string().describe("Capability name"),
5290
- type: z12.enum(["tool", "prompt", "resource"]).describe("Capability type"),
5291
- enabled: z12.boolean().describe("Whether to enable the capability")
5402
+ id: z13.string().describe("The MCP server ID or slug"),
5403
+ capabilities: z13.array(
5404
+ z13.object({
5405
+ name: z13.string().describe("Capability name"),
5406
+ type: z13.enum(["tool", "prompt", "resource"]).describe("Capability type"),
5407
+ enabled: z13.boolean().describe("Whether to enable the capability")
5292
5408
  })
5293
5409
  ).min(1).describe("Array of capability updates")
5294
5410
  },
5295
5411
  listMcpServerUserAccess: {
5296
- id: z12.string().describe("The MCP server ID or slug"),
5297
- current_page: z12.coerce.number().positive().optional().describe("Page number for pagination"),
5298
- page_size: z12.coerce.number().positive().max(100).optional().describe("Number of results per page (max 100)")
5412
+ id: z13.string().describe("The MCP server ID or slug"),
5413
+ current_page: z13.coerce.number().int().positive().optional().describe("Page number for pagination"),
5414
+ page_size: z13.coerce.number().int().positive().max(100).optional().describe("Number of results per page (max 100)")
5299
5415
  },
5300
5416
  updateMcpServerUserAccess: {
5301
- id: z12.string().describe("The MCP server ID or slug"),
5302
- users: z12.array(
5303
- z12.object({
5304
- user_id: z12.string().describe("User ID"),
5305
- enabled: z12.boolean().describe("Whether user has access")
5417
+ id: z13.string().describe("The MCP server ID or slug"),
5418
+ users: z13.array(
5419
+ z13.object({
5420
+ user_id: z13.string().describe("User ID"),
5421
+ enabled: z13.boolean().describe("Whether user has access")
5306
5422
  })
5307
5423
  ).min(1).describe("Array of user access updates")
5308
5424
  }
@@ -5546,40 +5662,40 @@ function registerMcpServersTools(server, service) {
5546
5662
  }
5547
5663
 
5548
5664
  // src/tools/partials.tools.ts
5549
- import { z as z13 } from "zod";
5665
+ import { z as z14 } from "zod";
5550
5666
  var PARTIALS_TOOL_SCHEMAS = {
5551
5667
  createPromptPartial: {
5552
- name: z13.string().describe("Display name for the partial"),
5553
- string: z13.string().describe("The partial content/template string"),
5554
- workspace_id: z13.string().optional().describe(
5668
+ name: z14.string().describe("Display name for the partial"),
5669
+ string: z14.string().describe("The partial content/template string"),
5670
+ workspace_id: z14.string().optional().describe(
5555
5671
  "Workspace ID to create partial in (required for org-level API keys)"
5556
5672
  ),
5557
- version_description: z13.string().optional().describe("Description for this version")
5673
+ version_description: z14.string().optional().describe("Description for this version")
5558
5674
  },
5559
5675
  listPromptPartials: {
5560
- collection_id: z13.string().optional().describe(
5676
+ collection_id: z14.string().optional().describe(
5561
5677
  "Filter by collection ID. Optional \u2014 omit to list all partials across collections"
5562
5678
  )
5563
5679
  },
5564
5680
  getPromptPartial: {
5565
- prompt_partial_id: z13.string().describe("Prompt partial ID or slug to retrieve")
5681
+ prompt_partial_id: z14.string().describe("Prompt partial ID or slug to retrieve")
5566
5682
  },
5567
5683
  updatePromptPartial: {
5568
- prompt_partial_id: z13.string().describe("Prompt partial ID or slug to update"),
5569
- name: z13.string().optional().describe("New display name for the partial"),
5570
- string: z13.string().optional().describe("New content for the partial"),
5571
- description: z13.string().optional().describe("Description for this version"),
5572
- status: z13.enum(["active", "archived"]).optional().describe("New status for the partial")
5684
+ prompt_partial_id: z14.string().describe("Prompt partial ID or slug to update"),
5685
+ name: z14.string().optional().describe("New display name for the partial"),
5686
+ string: z14.string().optional().describe("New content for the partial"),
5687
+ description: z14.string().optional().describe("Description for this version"),
5688
+ status: z14.enum(["active", "archived"]).optional().describe("New status for the partial")
5573
5689
  },
5574
5690
  deletePromptPartial: {
5575
- prompt_partial_id: z13.string().describe("Prompt partial ID or slug to delete")
5691
+ prompt_partial_id: z14.string().describe("Prompt partial ID or slug to delete")
5576
5692
  },
5577
5693
  listPartialVersions: {
5578
- prompt_partial_id: z13.string().describe("Prompt partial ID or slug to list versions for")
5694
+ prompt_partial_id: z14.string().describe("Prompt partial ID or slug to list versions for")
5579
5695
  },
5580
5696
  publishPartial: {
5581
- prompt_partial_id: z13.string().describe("Prompt partial ID or slug"),
5582
- version: z13.coerce.number().positive().describe("Version number to publish as default")
5697
+ prompt_partial_id: z14.string().describe("Prompt partial ID or slug"),
5698
+ version: z14.coerce.number().positive().describe("Version number to publish as default")
5583
5699
  }
5584
5700
  };
5585
5701
  function registerPartialsTools(server, service) {
@@ -5765,57 +5881,57 @@ function registerPartialsTools(server, service) {
5765
5881
  }
5766
5882
 
5767
5883
  // src/tools/prompts.tools.ts
5768
- import { z as z15 } from "zod";
5884
+ import { z as z16 } from "zod";
5769
5885
 
5770
5886
  // src/lib/schemas.ts
5771
- import { z as z14 } from "zod";
5772
- var PromptFunctionSchema = z14.object({
5773
- name: z14.string().describe("Function name"),
5774
- description: z14.string().optional().describe("Function description"),
5775
- parameters: z14.record(z14.string(), z14.unknown()).optional().describe("Function parameters schema")
5887
+ import { z as z15 } from "zod";
5888
+ var PromptFunctionSchema = z15.object({
5889
+ name: z15.string().describe("Function name"),
5890
+ description: z15.string().optional().describe("Function description"),
5891
+ parameters: z15.record(z15.string(), z15.unknown()).optional().describe("Function parameters schema")
5776
5892
  });
5777
- var PromptToolSchema = z14.object({
5778
- type: z14.literal("function").describe("Tool type"),
5893
+ var PromptToolSchema = z15.object({
5894
+ type: z15.literal("function").describe("Tool type"),
5779
5895
  function: PromptFunctionSchema.describe("Function definition")
5780
5896
  });
5781
- var HyperparametersSchema = z14.object({
5782
- max_tokens: z14.coerce.number().positive().optional().describe("Maximum tokens to generate"),
5783
- temperature: z14.coerce.number().min(0).max(2).optional().describe("Sampling temperature (0-2)"),
5784
- top_p: z14.coerce.number().min(0).max(1).optional().describe("Top-p sampling (0-1)"),
5785
- top_k: z14.coerce.number().positive().optional().describe("Top-k sampling"),
5786
- presence_penalty: z14.coerce.number().min(-2).max(2).optional().describe("Presence penalty (-2 to 2)"),
5787
- frequency_penalty: z14.coerce.number().min(-2).max(2).optional().describe("Frequency penalty (-2 to 2)"),
5788
- stop: z14.array(z14.string()).optional().describe("Stop sequences")
5897
+ var HyperparametersSchema = z15.object({
5898
+ max_tokens: z15.coerce.number().positive().optional().describe("Maximum tokens to generate"),
5899
+ temperature: z15.coerce.number().min(0).max(2).optional().describe("Sampling temperature (0-2)"),
5900
+ top_p: z15.coerce.number().min(0).max(1).optional().describe("Top-p sampling (0-1)"),
5901
+ top_k: z15.coerce.number().positive().optional().describe("Top-k sampling"),
5902
+ presence_penalty: z15.coerce.number().min(-2).max(2).optional().describe("Presence penalty (-2 to 2)"),
5903
+ frequency_penalty: z15.coerce.number().min(-2).max(2).optional().describe("Frequency penalty (-2 to 2)"),
5904
+ stop: z15.array(z15.string()).optional().describe("Stop sequences")
5789
5905
  });
5790
- var PromptAppIdentifierSchema = z14.string().min(1).describe(
5906
+ var PromptAppIdentifierSchema = z15.string().min(1).describe(
5791
5907
  "App identifier (REQUIRED). Use your deployed app name, for example 'hourlink' or 'support-console'."
5792
5908
  );
5793
- var PromptEnvironmentIdentifierSchema = z14.string().min(1).describe(
5909
+ var PromptEnvironmentIdentifierSchema = z15.string().min(1).describe(
5794
5910
  "Environment identifier (REQUIRED). Use your environment name, for example 'dev', 'staging', 'prod', or 'qa'."
5795
5911
  );
5796
- var BillingMetadataSchema = z14.object({
5797
- client_id: z14.string().describe("Client ID for billing attribution (REQUIRED)"),
5912
+ var BillingMetadataSchema = z15.object({
5913
+ client_id: z15.string().describe("Client ID for billing attribution (REQUIRED)"),
5798
5914
  app: PromptAppIdentifierSchema,
5799
5915
  env: PromptEnvironmentIdentifierSchema,
5800
- project_id: z14.string().optional().describe("Project ID for granular billing"),
5801
- feature: z14.string().optional().describe("Feature name for tracking")
5916
+ project_id: z15.string().optional().describe("Project ID for granular billing"),
5917
+ feature: z15.string().optional().describe("Feature name for tracking")
5802
5918
  });
5803
- var ToolChoiceSchema = z14.object({
5804
- mode: z14.enum(["auto", "none", "function"]).describe(
5919
+ var ToolChoiceSchema = z15.object({
5920
+ mode: z15.enum(["auto", "none", "function"]).describe(
5805
5921
  "Tool choice mode: auto lets the model decide, none disables tool use, function forces one function by name"
5806
5922
  ),
5807
- function_name: z14.string().optional().describe("Required when mode is 'function'; ignored otherwise")
5923
+ function_name: z15.string().optional().describe("Required when mode is 'function'; ignored otherwise")
5808
5924
  }).superRefine((value, ctx) => {
5809
5925
  if (value.mode === "function" && !value.function_name) {
5810
5926
  ctx.addIssue({
5811
- code: z14.ZodIssueCode.custom,
5927
+ code: z15.ZodIssueCode.custom,
5812
5928
  path: ["function_name"],
5813
5929
  message: "function_name is required when mode is 'function'"
5814
5930
  });
5815
5931
  }
5816
5932
  if (value.mode !== "function" && value.function_name !== void 0) {
5817
5933
  ctx.addIssue({
5818
- code: z14.ZodIssueCode.custom,
5934
+ code: z15.ZodIssueCode.custom,
5819
5935
  path: ["function_name"],
5820
5936
  message: "function_name is only allowed when mode is 'function'"
5821
5937
  });
@@ -5837,98 +5953,98 @@ function toPromptToolChoice(toolChoice) {
5837
5953
  }
5838
5954
 
5839
5955
  // src/tools/prompts.tools.ts
5840
- var PROMPT_VARIABLES_SCHEMA = z15.record(z15.string(), z15.union([z15.string(), z15.coerce.number(), z15.boolean()])).describe("Variable values to substitute into the template");
5841
- var PROMPT_TEMPLATE_CONTENT_BLOCK_SCHEMA = z15.object({
5842
- type: z15.string().describe("Content block type"),
5843
- text: z15.string().optional().describe("Text content for text-based blocks")
5956
+ var PROMPT_VARIABLES_SCHEMA = z16.record(z16.string(), z16.union([z16.string(), z16.coerce.number(), z16.boolean()])).describe("Variable values to substitute into the template");
5957
+ var PROMPT_TEMPLATE_CONTENT_BLOCK_SCHEMA = z16.object({
5958
+ type: z16.string().describe("Content block type"),
5959
+ text: z16.string().optional().describe("Text content for text-based blocks")
5844
5960
  }).passthrough().describe("Content block within a structured chat message");
5845
- var PROMPT_TEMPLATE_MESSAGE_SCHEMA = z15.object({
5846
- role: z15.enum(["system", "user", "assistant"]).describe("Message role in the chat template"),
5847
- content: z15.array(PROMPT_TEMPLATE_CONTENT_BLOCK_SCHEMA).describe("Message content blocks")
5961
+ var PROMPT_TEMPLATE_MESSAGE_SCHEMA = z16.object({
5962
+ role: z16.enum(["system", "user", "assistant"]).describe("Message role in the chat template"),
5963
+ content: z16.array(PROMPT_TEMPLATE_CONTENT_BLOCK_SCHEMA).describe("Message content blocks")
5848
5964
  }).passthrough().describe("Structured chat message in a prompt template");
5849
5965
  var PROMPTS_TOOL_SCHEMAS = {
5850
5966
  createPrompt: {
5851
- name: z15.string().describe("Display name for the prompt"),
5852
- collection_id: z15.string().describe(
5967
+ name: z16.string().describe("Display name for the prompt"),
5968
+ collection_id: z16.string().describe(
5853
5969
  "Collection ID to organize the prompt in (use list_collections to find)"
5854
5970
  ),
5855
- string: z15.string().optional().describe(
5971
+ string: z16.string().optional().describe(
5856
5972
  "Legacy prompt template string. Use plain text for single-message prompts, or a JSON-encoded messages array string for multi-message chat prompts."
5857
5973
  ),
5858
- messages: z15.array(PROMPT_TEMPLATE_MESSAGE_SCHEMA).optional().describe(
5974
+ messages: z16.array(PROMPT_TEMPLATE_MESSAGE_SCHEMA).optional().describe(
5859
5975
  "Structured chat template alias. Serialized to the legacy string format before creation."
5860
5976
  ),
5861
- parameters: z15.record(z15.string(), z15.unknown()).describe("Default values for template variables"),
5862
- virtual_key: z15.string().describe("Virtual key slug for model access"),
5863
- model: z15.string().optional().describe(
5977
+ parameters: z16.record(z16.string(), z16.unknown()).describe("Default values for template variables"),
5978
+ virtual_key: z16.string().describe("Virtual key slug for model access"),
5979
+ model: z16.string().optional().describe(
5864
5980
  "Model identifier (e.g., 'gpt-4', 'claude-3-opus'). Required unless ai_model_id or finetune_id is provided"
5865
5981
  ),
5866
- ai_model_id: z15.string().optional().describe(
5982
+ ai_model_id: z16.string().optional().describe(
5867
5983
  "AI model ID (alternative to model). Required unless model or finetune_id is provided"
5868
5984
  ),
5869
- finetune_id: z15.string().optional().describe(
5985
+ finetune_id: z16.string().optional().describe(
5870
5986
  "Fine-tune ID (alternative to model). Required unless model or ai_model_id is provided"
5871
5987
  ),
5872
- version_description: z15.string().optional().describe("Description for this prompt version"),
5873
- template_metadata: z15.record(z15.string(), z15.unknown()).optional().describe("Custom metadata (app, env, source_file, etc.)"),
5874
- functions: z15.array(PromptFunctionSchema).optional().describe("Function definitions for function calling"),
5875
- tools: z15.array(PromptToolSchema).optional().describe("Tool definitions for tool use"),
5988
+ version_description: z16.string().optional().describe("Description for this prompt version"),
5989
+ template_metadata: z16.record(z16.string(), z16.unknown()).optional().describe("Custom metadata (app, env, source_file, etc.)"),
5990
+ functions: z16.array(PromptFunctionSchema).optional().describe("Function definitions for function calling"),
5991
+ tools: z16.array(PromptToolSchema).optional().describe("Tool definitions for tool use"),
5876
5992
  tool_choice: ToolChoiceSchema.optional().describe("Tool choice strategy"),
5877
- dry_run: z15.boolean().optional().describe("When true, validate without creating")
5993
+ dry_run: z16.boolean().optional().describe("When true, validate without creating")
5878
5994
  },
5879
5995
  listPrompts: {
5880
- collection_id: z15.string().optional().describe(
5996
+ collection_id: z16.string().optional().describe(
5881
5997
  "Filter by collection ID (recommended for app-specific prompts)"
5882
5998
  ),
5883
- workspace_id: z15.string().optional().describe("Filter by workspace ID"),
5884
- search: z15.string().optional().describe("Search prompts by name"),
5885
- current_page: z15.coerce.number().positive().optional().describe("Page number for pagination"),
5886
- page_size: z15.coerce.number().positive().max(100).optional().describe("Results per page (max 100)")
5999
+ workspace_id: z16.string().optional().describe("Filter by workspace ID"),
6000
+ search: z16.string().optional().describe("Search prompts by name"),
6001
+ current_page: z16.coerce.number().int().positive().optional().describe("Page number for pagination"),
6002
+ page_size: z16.coerce.number().int().positive().max(100).optional().describe("Results per page (max 100)")
5887
6003
  },
5888
6004
  getPrompt: {
5889
- prompt_id: z15.string().describe("Prompt ID or slug to retrieve")
6005
+ prompt_id: z16.string().describe("Prompt ID or slug to retrieve")
5890
6006
  },
5891
6007
  updatePrompt: {
5892
- prompt_id: z15.string().describe("Prompt ID or slug to update"),
5893
- name: z15.string().optional().describe("New display name for the prompt"),
5894
- collection_id: z15.string().optional().describe("Move to a different collection"),
5895
- string: z15.string().optional().describe(
6008
+ prompt_id: z16.string().describe("Prompt ID or slug to update"),
6009
+ name: z16.string().optional().describe("New display name for the prompt"),
6010
+ collection_id: z16.string().optional().describe("Move to a different collection"),
6011
+ string: z16.string().optional().describe(
5896
6012
  "Legacy prompt template string. Use plain text for single-message prompts, or a JSON-encoded messages array string for multi-message chat prompts."
5897
6013
  ),
5898
- messages: z15.array(PROMPT_TEMPLATE_MESSAGE_SCHEMA).optional().describe(
6014
+ messages: z16.array(PROMPT_TEMPLATE_MESSAGE_SCHEMA).optional().describe(
5899
6015
  "Structured chat template alias for updates. Serialized to the legacy string format before the prompt is updated."
5900
6016
  ),
5901
- parameters: z15.record(z15.string(), z15.unknown()).optional().describe("New default values for template variables"),
5902
- model: z15.string().optional().describe("New model identifier"),
5903
- virtual_key: z15.string().optional().describe("New virtual key slug"),
5904
- version_description: z15.string().optional().describe("Description for this version"),
5905
- template_metadata: z15.record(z15.string(), z15.unknown()).optional().describe("New metadata"),
5906
- functions: z15.array(PromptFunctionSchema).optional().describe("New function definitions"),
5907
- tools: z15.array(PromptToolSchema).optional().describe("New tool definitions"),
6017
+ parameters: z16.record(z16.string(), z16.unknown()).optional().describe("New default values for template variables"),
6018
+ model: z16.string().optional().describe("New model identifier"),
6019
+ virtual_key: z16.string().optional().describe("New virtual key slug"),
6020
+ version_description: z16.string().optional().describe("Description for this version"),
6021
+ template_metadata: z16.record(z16.string(), z16.unknown()).optional().describe("New metadata"),
6022
+ functions: z16.array(PromptFunctionSchema).optional().describe("New function definitions"),
6023
+ tools: z16.array(PromptToolSchema).optional().describe("New tool definitions"),
5908
6024
  tool_choice: ToolChoiceSchema.optional().describe(
5909
6025
  "New tool choice strategy"
5910
6026
  ),
5911
- dry_run: z15.boolean().optional().describe("When true, validate without updating")
6027
+ dry_run: z16.boolean().optional().describe("When true, validate without updating")
5912
6028
  },
5913
6029
  deletePrompt: {
5914
- prompt_id: z15.string().describe("Prompt ID or slug to delete")
6030
+ prompt_id: z16.string().describe("Prompt ID or slug to delete")
5915
6031
  },
5916
6032
  publishPrompt: {
5917
- prompt_id: z15.string().describe("Prompt ID or slug to publish"),
5918
- version: z15.coerce.number().positive().describe("Version number to publish as the default")
6033
+ prompt_id: z16.string().describe("Prompt ID or slug to publish"),
6034
+ version: z16.coerce.number().positive().describe("Version number to publish as the default")
5919
6035
  },
5920
6036
  listPromptVersions: {
5921
- prompt_id: z15.string().describe("Prompt ID or slug to list versions for")
6037
+ prompt_id: z16.string().describe("Prompt ID or slug to list versions for")
5922
6038
  },
5923
6039
  renderPrompt: {
5924
- prompt_id: z15.string().describe("Prompt ID or slug to render"),
6040
+ prompt_id: z16.string().describe("Prompt ID or slug to render"),
5925
6041
  variables: PROMPT_VARIABLES_SCHEMA,
5926
6042
  hyperparameters: HyperparametersSchema.optional().describe(
5927
6043
  "Override default hyperparameters"
5928
6044
  )
5929
6045
  },
5930
6046
  runPromptCompletion: {
5931
- prompt_id: z15.string().describe("Prompt ID or slug to execute"),
6047
+ prompt_id: z16.string().describe("Prompt ID or slug to execute"),
5932
6048
  variables: PROMPT_VARIABLES_SCHEMA,
5933
6049
  metadata: BillingMetadataSchema.describe(
5934
6050
  "Billing metadata - client_id, app, env are REQUIRED for cost attribution"
@@ -5938,54 +6054,54 @@ var PROMPTS_TOOL_SCHEMAS = {
5938
6054
  )
5939
6055
  },
5940
6056
  migratePrompt: {
5941
- name: z15.string().describe("Prompt name to create or find for update"),
6057
+ name: z16.string().describe("Prompt name to create or find for update"),
5942
6058
  app: PromptAppIdentifierSchema,
5943
6059
  env: PromptEnvironmentIdentifierSchema,
5944
- collection_id: z15.string().describe("Collection ID to search in and create under"),
5945
- string: z15.string().optional().describe(
6060
+ collection_id: z16.string().describe("Collection ID to search in and create under"),
6061
+ string: z16.string().optional().describe(
5946
6062
  "Legacy prompt template string with {{variable}} mustache syntax."
5947
6063
  ),
5948
- messages: z15.array(PROMPT_TEMPLATE_MESSAGE_SCHEMA).optional().describe(
6064
+ messages: z16.array(PROMPT_TEMPLATE_MESSAGE_SCHEMA).optional().describe(
5949
6065
  "Structured chat template alias for migrations. Serialized to the legacy string format before the prompt is created or updated."
5950
6066
  ),
5951
- parameters: z15.record(z15.string(), z15.unknown()).describe("Default values for template variables"),
5952
- virtual_key: z15.string().describe("Virtual key slug for model access"),
5953
- model: z15.string().optional().describe("Model identifier"),
5954
- version_description: z15.string().optional().describe("Description for this version"),
5955
- template_metadata: z15.record(z15.string(), z15.unknown()).optional().describe("Additional custom metadata"),
5956
- functions: z15.array(PromptFunctionSchema).optional().describe("Function definitions"),
5957
- tools: z15.array(PromptToolSchema).optional().describe("Tool definitions"),
6067
+ parameters: z16.record(z16.string(), z16.unknown()).describe("Default values for template variables"),
6068
+ virtual_key: z16.string().describe("Virtual key slug for model access"),
6069
+ model: z16.string().optional().describe("Model identifier"),
6070
+ version_description: z16.string().optional().describe("Description for this version"),
6071
+ template_metadata: z16.record(z16.string(), z16.unknown()).optional().describe("Additional custom metadata"),
6072
+ functions: z16.array(PromptFunctionSchema).optional().describe("Function definitions"),
6073
+ tools: z16.array(PromptToolSchema).optional().describe("Tool definitions"),
5958
6074
  tool_choice: ToolChoiceSchema.optional().describe("Tool choice strategy"),
5959
- dry_run: z15.boolean().optional().describe(
6075
+ dry_run: z16.boolean().optional().describe(
5960
6076
  "When true, only check what action would be taken without making changes"
5961
6077
  )
5962
6078
  },
5963
6079
  promotePrompt: {
5964
- source_prompt_id: z15.string().describe("Source prompt ID or slug (e.g., staging prompt)"),
5965
- target_collection_id: z15.string().describe("Target collection ID for the promoted prompt"),
5966
- target_name: z15.string().optional().describe(
6080
+ source_prompt_id: z16.string().describe("Source prompt ID or slug (e.g., staging prompt)"),
6081
+ target_collection_id: z16.string().describe("Target collection ID for the promoted prompt"),
6082
+ target_name: z16.string().optional().describe(
5967
6083
  "Target prompt name (defaults to source name with env suffix replaced)"
5968
6084
  ),
5969
6085
  target_env: PromptEnvironmentIdentifierSchema,
5970
- virtual_key: z15.string().optional().describe(
6086
+ virtual_key: z16.string().optional().describe(
5971
6087
  "Virtual key ID to use (defaults to source prompt's virtual_key)"
5972
6088
  )
5973
6089
  },
5974
6090
  validateCompletionMetadata: {
5975
- client_id: z15.string().optional().describe("Client ID for billing attribution"),
6091
+ client_id: z16.string().optional().describe("Client ID for billing attribution"),
5976
6092
  app: PromptAppIdentifierSchema.optional(),
5977
6093
  env: PromptEnvironmentIdentifierSchema.optional(),
5978
- project_id: z15.string().optional().describe("Project ID for granular billing"),
5979
- feature: z15.string().optional().describe("Feature name for tracking")
6094
+ project_id: z16.string().optional().describe("Project ID for granular billing"),
6095
+ feature: z16.string().optional().describe("Feature name for tracking")
5980
6096
  },
5981
6097
  getPromptVersion: {
5982
- prompt_id: z15.string().describe("Prompt ID or slug"),
5983
- version_id: z15.string().describe("Version UUID to retrieve")
6098
+ prompt_id: z16.string().describe("Prompt ID or slug"),
6099
+ version_id: z16.string().describe("Version UUID to retrieve")
5984
6100
  },
5985
6101
  updatePromptVersion: {
5986
- prompt_id: z15.string().describe("Prompt ID or slug"),
5987
- version_id: z15.string().describe("Version UUID to update"),
5988
- label_id: z15.string().nullable().describe(
6102
+ prompt_id: z16.string().describe("Prompt ID or slug"),
6103
+ version_id: z16.string().describe("Version UUID to update"),
6104
+ label_id: z16.string().nullable().describe(
5989
6105
  "Label ID to assign to this version, or null to remove the label"
5990
6106
  )
5991
6107
  }
@@ -6419,7 +6535,7 @@ function registerPromptsTools(server, service) {
6419
6535
  );
6420
6536
  server.tool(
6421
6537
  "migrate_prompt",
6422
- "Create or update a prompt in one idempotent step for CI/CD and prompt-as-code flows, unlike create_prompt which always makes a new prompt. Looks up the prompt by name within collection_id: if found it adds a new version (nothing is overwritten), otherwise it creates the prompt; dry_run reports what would happen without changing anything. Stores app/env in template_metadata; get collection_id from list_collections. Returns the action taken (created or updated), dry_run flag, prompt id, slug, and version id.",
6538
+ "Create or update a prompt in one idempotent step for CI/CD and prompt-as-code flows, unlike create_prompt which always makes a new prompt. Looks up the prompt by name within collection_id: if missing it creates the prompt, if found with different content it adds a new version (nothing is overwritten), and if the content already matches it no-ops; dry_run reports what would happen without changing anything. Stores app/env in template_metadata; get collection_id from list_collections. Returns the action taken (created, updated, or unchanged), dry_run flag, message, prompt id, slug, and version id.",
6423
6539
  PROMPTS_TOOL_SCHEMAS.migratePrompt,
6424
6540
  {
6425
6541
  readOnlyHint: false,
@@ -6575,68 +6691,68 @@ function registerPromptsTools(server, service) {
6575
6691
  }
6576
6692
 
6577
6693
  // src/tools/providers.tools.ts
6578
- import { z as z16 } from "zod";
6694
+ import { z as z17 } from "zod";
6579
6695
  var PROVIDERS_TOOL_SCHEMAS = {
6580
6696
  listProviders: {
6581
- current_page: z16.coerce.number().positive().optional().describe("Page number for pagination"),
6582
- page_size: z16.coerce.number().int().positive().max(100).optional().describe("Number of results per page (max 100, default 50)"),
6583
- workspace_id: z16.string().optional().describe(
6697
+ current_page: z17.coerce.number().int().positive().optional().describe("Page number for pagination"),
6698
+ page_size: z17.coerce.number().int().positive().max(100).optional().describe("Number of results per page (max 100, default 50)"),
6699
+ workspace_id: z17.string().optional().describe(
6584
6700
  "Workspace ID - required when using organization admin keys, optional with workspace API keys"
6585
6701
  )
6586
6702
  },
6587
6703
  createProvider: {
6588
- name: z16.string().describe("Display name for the provider"),
6589
- integration_id: z16.string().describe(
6704
+ name: z17.string().describe("Display name for the provider"),
6705
+ integration_id: z17.string().describe(
6590
6706
  "Integration slug for the provider (e.g., 'openai', 'anthropic', 'azure-openai')"
6591
6707
  ),
6592
- workspace_id: z16.string().optional().describe(
6708
+ workspace_id: z17.string().optional().describe(
6593
6709
  "Workspace ID - required when using organization admin API keys"
6594
6710
  ),
6595
- slug: z16.string().optional().describe(
6711
+ slug: z17.string().optional().describe(
6596
6712
  "Custom slug for the provider. Auto-generated with random suffix if omitted"
6597
6713
  ),
6598
- note: z16.string().optional().describe("Optional note or description for the provider"),
6599
- credit_limit: z16.coerce.number().positive().optional().describe("Credit limit for usage"),
6600
- alert_threshold: z16.coerce.number().min(0).max(100).optional().describe("Alert threshold percentage (0-100)"),
6601
- usage_limit_type: z16.enum(["cost", "tokens"]).optional().describe(
6714
+ note: z17.string().optional().describe("Optional note or description for the provider"),
6715
+ credit_limit: z17.coerce.number().positive().optional().describe("Credit limit for usage"),
6716
+ alert_threshold: z17.coerce.number().min(0).max(100).optional().describe("Alert threshold percentage (0-100)"),
6717
+ usage_limit_type: z17.enum(["cost", "tokens"]).optional().describe(
6602
6718
  "Type of usage limit: 'cost' (monetary) or 'tokens' (token count). Defaults to 'cost'."
6603
6719
  ),
6604
- periodic_reset: z16.enum(["monthly", "weekly"]).optional().describe(
6720
+ periodic_reset: z17.enum(["monthly", "weekly"]).optional().describe(
6605
6721
  "Period for resetting usage limits: 'monthly' or 'weekly'. Defaults to 'monthly'."
6606
6722
  ),
6607
- rate_limit_value: z16.coerce.number().positive().optional().describe("Must be provided together with rate_limit_unit."),
6608
- rate_limit_unit: z16.enum(["rpm", "rph", "rpd"]).optional().describe(
6723
+ rate_limit_value: z17.coerce.number().positive().optional().describe("Must be provided together with rate_limit_unit."),
6724
+ rate_limit_unit: z17.enum(["rpm", "rph", "rpd"]).optional().describe(
6609
6725
  "Must be provided together with rate_limit_value. Values: 'rpm' (requests/min), 'rph' (requests/hour), or 'rpd' (requests/day)."
6610
6726
  ),
6611
- expires_at: z16.string().optional().describe("Expiration date in ISO 8601 format")
6727
+ expires_at: z17.string().optional().describe("Expiration date in ISO 8601 format")
6612
6728
  },
6613
6729
  getProvider: {
6614
- slug: z16.string().describe("The unique slug identifier of the provider to retrieve"),
6615
- workspace_id: z16.string().optional().describe("Workspace ID - required when using organization admin keys")
6730
+ slug: z17.string().describe("The unique slug identifier of the provider to retrieve"),
6731
+ workspace_id: z17.string().optional().describe("Workspace ID - required when using organization admin keys")
6616
6732
  },
6617
6733
  updateProvider: {
6618
- slug: z16.string().describe("The slug of the provider to update"),
6619
- workspace_id: z16.string().optional().describe("Workspace ID - required when using organization admin keys"),
6620
- name: z16.string().optional().describe("New display name for the provider"),
6621
- note: z16.string().optional().describe("New note or description for the provider"),
6622
- credit_limit: z16.coerce.number().positive().optional().describe("New credit limit for usage"),
6623
- alert_threshold: z16.coerce.number().min(0).max(100).optional().describe("New alert threshold percentage (0-100)"),
6624
- usage_limit_type: z16.enum(["cost", "tokens"]).optional().describe(
6734
+ slug: z17.string().describe("The slug of the provider to update"),
6735
+ workspace_id: z17.string().optional().describe("Workspace ID - required when using organization admin keys"),
6736
+ name: z17.string().optional().describe("New display name for the provider"),
6737
+ note: z17.string().optional().describe("New note or description for the provider"),
6738
+ credit_limit: z17.coerce.number().positive().optional().describe("New credit limit for usage"),
6739
+ alert_threshold: z17.coerce.number().min(0).max(100).optional().describe("New alert threshold percentage (0-100)"),
6740
+ usage_limit_type: z17.enum(["cost", "tokens"]).optional().describe(
6625
6741
  "Type of usage limit: 'cost' (monetary) or 'tokens' (token count). Defaults to 'cost'."
6626
6742
  ),
6627
- periodic_reset: z16.enum(["monthly", "weekly"]).optional().describe(
6743
+ periodic_reset: z17.enum(["monthly", "weekly"]).optional().describe(
6628
6744
  "Period for resetting usage limits: 'monthly' or 'weekly'. Defaults to 'monthly'."
6629
6745
  ),
6630
- rate_limit_value: z16.coerce.number().positive().optional().describe("New rate limit value"),
6631
- rate_limit_unit: z16.enum(["rpm", "rph", "rpd"]).optional().describe(
6746
+ rate_limit_value: z17.coerce.number().positive().optional().describe("New rate limit value"),
6747
+ rate_limit_unit: z17.enum(["rpm", "rph", "rpd"]).optional().describe(
6632
6748
  "Rate limit unit: 'rpm' (requests per minute), 'rph' (requests per hour), or 'rpd' (requests per day)"
6633
6749
  ),
6634
- expires_at: z16.string().optional().describe("New expiration date in ISO 8601 format"),
6635
- reset_usage: z16.boolean().optional().describe("Set to true to reset accumulated usage metrics")
6750
+ expires_at: z17.string().optional().describe("New expiration date in ISO 8601 format"),
6751
+ reset_usage: z17.boolean().optional().describe("Set to true to reset accumulated usage metrics")
6636
6752
  },
6637
6753
  deleteProvider: {
6638
- slug: z16.string().describe("The slug of the provider to delete"),
6639
- workspace_id: z16.string().optional().describe("Workspace ID - required when using organization admin keys")
6754
+ slug: z17.string().describe("The slug of the provider to delete"),
6755
+ workspace_id: z17.string().optional().describe("Workspace ID - required when using organization admin keys")
6640
6756
  }
6641
6757
  };
6642
6758
  function registerProvidersTools(server, service) {
@@ -6817,30 +6933,427 @@ function registerProvidersTools(server, service) {
6817
6933
  );
6818
6934
  }
6819
6935
 
6936
+ // src/tools/secret-references.tools.ts
6937
+ import { z as z18 } from "zod";
6938
+ var authFields = {
6939
+ aws_auth_type: z18.enum(["accessKey", "assumedRole", "serviceRole"]).describe(
6940
+ "AWS authentication mode: accessKey uses a key pair, assumedRole uses an IAM role, and serviceRole uses the runtime workload identity"
6941
+ ),
6942
+ aws_access_key_id: z18.string().min(1).describe("AWS access key ID; required when aws_auth_type is accessKey"),
6943
+ aws_secret_access_key: z18.string().min(1).describe(
6944
+ "AWS secret access key; required when aws_auth_type is accessKey and exposed to the MCP transcript"
6945
+ ),
6946
+ aws_region: z18.string().min(1).describe("AWS region containing the secret, for example us-east-1"),
6947
+ aws_role_arn: z18.string().min(1).describe(
6948
+ "IAM role ARN to assume; required when aws_auth_type is assumedRole"
6949
+ ),
6950
+ aws_external_id: z18.string().nullable().describe("Optional external ID required by the target IAM role"),
6951
+ azure_auth_mode: z18.enum(["entra", "managed", "default"]).describe(
6952
+ "Azure authentication mode: entra uses a client secret, managed uses managed identity, and default uses the runtime credential chain"
6953
+ ),
6954
+ azure_entra_tenant_id: z18.string().min(1).describe("Microsoft Entra tenant ID; required for entra authentication"),
6955
+ azure_entra_client_id: z18.string().min(1).describe(
6956
+ "Microsoft Entra application client ID; required for entra authentication"
6957
+ ),
6958
+ azure_entra_client_secret: z18.string().min(1).describe(
6959
+ "Microsoft Entra client secret; required for entra authentication and exposed to the MCP transcript"
6960
+ ),
6961
+ azure_managed_client_id: z18.string().min(1).describe(
6962
+ "Optional client ID of a user-assigned managed identity; omit for the system-assigned identity"
6963
+ ),
6964
+ azure_vault_url: z18.url().describe(
6965
+ "Azure Key Vault URL, for example https://example.vault.azure.net"
6966
+ ),
6967
+ vault_auth_type: z18.enum(["token", "approle", "kubernetes"]).describe(
6968
+ "HashiCorp Vault authentication mode: token, AppRole, or Kubernetes"
6969
+ ),
6970
+ vault_addr: z18.url().describe("Base URL of the HashiCorp Vault server"),
6971
+ vault_token: z18.string().min(1).describe(
6972
+ "HashiCorp Vault token; required for token authentication and exposed to the MCP transcript"
6973
+ ),
6974
+ vault_namespace: z18.string().min(1).describe("Optional HashiCorp Vault Enterprise namespace"),
6975
+ vault_role_id: z18.string().min(1).describe(
6976
+ "HashiCorp Vault AppRole role ID; required for approle authentication"
6977
+ ),
6978
+ vault_secret_id: z18.string().min(1).describe(
6979
+ "HashiCorp Vault AppRole secret ID; required for approle authentication and exposed to the MCP transcript"
6980
+ ),
6981
+ vault_role: z18.string().min(1).describe("HashiCorp Vault Kubernetes auth role name")
6982
+ };
6983
+ var authConfigSchema = z18.union([
6984
+ z18.object({
6985
+ aws_auth_type: z18.literal("accessKey").describe("Use an AWS access key ID and secret access key"),
6986
+ aws_access_key_id: authFields.aws_access_key_id,
6987
+ aws_secret_access_key: authFields.aws_secret_access_key,
6988
+ aws_region: authFields.aws_region
6989
+ }).strict(),
6990
+ z18.object({
6991
+ aws_auth_type: z18.literal("assumedRole").describe("Assume the specified AWS IAM role"),
6992
+ aws_role_arn: authFields.aws_role_arn,
6993
+ aws_external_id: authFields.aws_external_id.optional(),
6994
+ aws_region: authFields.aws_region
6995
+ }).strict(),
6996
+ z18.object({
6997
+ aws_auth_type: z18.literal("serviceRole").describe("Use the AWS workload or service role available at runtime"),
6998
+ aws_region: z18.string().optional().describe(
6999
+ "Optional AWS region containing the secret, for example us-east-1"
7000
+ )
7001
+ }).strict(),
7002
+ z18.object({
7003
+ azure_auth_mode: z18.literal("entra").describe(
7004
+ "Authenticate with a Microsoft Entra application client secret"
7005
+ ),
7006
+ azure_entra_tenant_id: authFields.azure_entra_tenant_id,
7007
+ azure_entra_client_id: authFields.azure_entra_client_id,
7008
+ azure_entra_client_secret: authFields.azure_entra_client_secret,
7009
+ azure_vault_url: authFields.azure_vault_url
7010
+ }).strict(),
7011
+ z18.object({
7012
+ azure_auth_mode: z18.literal("managed").describe("Authenticate with an Azure managed identity"),
7013
+ azure_managed_client_id: authFields.azure_managed_client_id.optional(),
7014
+ azure_vault_url: authFields.azure_vault_url
7015
+ }).strict(),
7016
+ z18.object({
7017
+ azure_auth_mode: z18.literal("default").describe("Use Azure's default runtime credential chain"),
7018
+ azure_vault_url: authFields.azure_vault_url
7019
+ }).strict(),
7020
+ z18.object({
7021
+ vault_auth_type: z18.literal("token").describe("Authenticate to HashiCorp Vault with a token"),
7022
+ vault_addr: authFields.vault_addr,
7023
+ vault_token: authFields.vault_token,
7024
+ vault_namespace: authFields.vault_namespace.optional()
7025
+ }).strict(),
7026
+ z18.object({
7027
+ vault_auth_type: z18.literal("approle").describe("Authenticate to HashiCorp Vault with AppRole credentials"),
7028
+ vault_addr: authFields.vault_addr,
7029
+ vault_role_id: authFields.vault_role_id,
7030
+ vault_secret_id: authFields.vault_secret_id,
7031
+ vault_namespace: authFields.vault_namespace.optional()
7032
+ }).strict(),
7033
+ z18.object({
7034
+ vault_auth_type: z18.literal("kubernetes").describe(
7035
+ "Authenticate to HashiCorp Vault with a Kubernetes service account"
7036
+ ),
7037
+ vault_addr: authFields.vault_addr,
7038
+ vault_role: authFields.vault_role,
7039
+ vault_namespace: authFields.vault_namespace.optional()
7040
+ }).strict()
7041
+ ]);
7042
+ var updateAuthConfigSchema = z18.union([
7043
+ z18.object({
7044
+ aws_auth_type: authFields.aws_auth_type.optional(),
7045
+ aws_access_key_id: authFields.aws_access_key_id.optional(),
7046
+ aws_secret_access_key: authFields.aws_secret_access_key.optional(),
7047
+ aws_region: z18.string().optional().describe("AWS region containing the secret, for example us-east-1"),
7048
+ aws_role_arn: authFields.aws_role_arn.optional(),
7049
+ aws_external_id: authFields.aws_external_id.optional()
7050
+ }).strict(),
7051
+ z18.object({
7052
+ azure_auth_mode: authFields.azure_auth_mode.optional(),
7053
+ azure_entra_tenant_id: authFields.azure_entra_tenant_id.optional(),
7054
+ azure_entra_client_id: authFields.azure_entra_client_id.optional(),
7055
+ azure_entra_client_secret: authFields.azure_entra_client_secret.optional(),
7056
+ azure_managed_client_id: z18.string().optional().describe(
7057
+ "Optional client ID of a user-assigned managed identity; omit for the system-assigned identity"
7058
+ ),
7059
+ azure_vault_url: authFields.azure_vault_url.optional()
7060
+ }).strict(),
7061
+ z18.object({
7062
+ vault_auth_type: authFields.vault_auth_type.optional(),
7063
+ vault_addr: authFields.vault_addr.optional(),
7064
+ vault_token: authFields.vault_token.optional(),
7065
+ vault_namespace: z18.string().optional().describe("Optional HashiCorp Vault Enterprise namespace"),
7066
+ vault_role_id: authFields.vault_role_id.optional(),
7067
+ vault_secret_id: authFields.vault_secret_id.optional(),
7068
+ vault_role: authFields.vault_role.optional()
7069
+ }).strict()
7070
+ ]);
7071
+ var managerTypeSchema = z18.enum(["aws_sm", "azure_kv", "hashicorp_vault"]).describe(
7072
+ "External secret manager: aws_sm for AWS Secrets Manager, azure_kv for Azure Key Vault, or hashicorp_vault for HashiCorp Vault; must match the auth_config field family"
7073
+ );
7074
+ var tagsSchema = z18.record(z18.string(), z18.string()).describe("Tag filters or metadata as string key-value pairs");
7075
+ var SECRET_REFERENCE_TOOL_SCHEMAS = {
7076
+ create: {
7077
+ name: z18.string().min(1).max(255).describe("Human-readable name"),
7078
+ manager_type: managerTypeSchema,
7079
+ auth_config: authConfigSchema.describe(
7080
+ "Choose exactly one documented authentication shape matching manager_type. Credentials are sent to Portkey and visible in the MCP transcript; prefer workload identity or short-lived credentials when available."
7081
+ ),
7082
+ secret_path: z18.string().max(1024).describe("Path of the secret in the external secret manager"),
7083
+ organisation_id: z18.string().uuid().optional().describe(
7084
+ "Organisation UUID; required when the MCP server is not authenticated with a Portkey API key"
7085
+ ),
7086
+ slug: z18.string().max(255).regex(/^[a-zA-Z0-9_-]+$/).optional().describe(
7087
+ "Optional stable slug containing only letters, numbers, underscores, or hyphens; Portkey generates one when omitted"
7088
+ ),
7089
+ description: z18.string().max(1024).nullable().optional().describe("Optional description; use null to leave it empty"),
7090
+ secret_key: z18.string().max(255).nullable().optional().describe(
7091
+ "Optional key within a structured external secret; null uses the whole secret value"
7092
+ ),
7093
+ allow_all_workspaces: z18.boolean().optional().describe(
7094
+ "Whether every workspace may use this reference; defaults to true and cannot be true with allowed_workspaces"
7095
+ ),
7096
+ allowed_workspaces: z18.array(z18.string()).min(1).optional().describe(
7097
+ "Workspace UUIDs or slugs allowed to use this reference; omit when allow_all_workspaces is true"
7098
+ ),
7099
+ tags: tagsSchema.nullable().optional().describe(
7100
+ "Optional string key-value tags for filtering and organization"
7101
+ )
7102
+ },
7103
+ list: {
7104
+ manager_type: managerTypeSchema.optional().describe(
7105
+ "Filter by external secret manager: aws_sm, azure_kv, or hashicorp_vault"
7106
+ ),
7107
+ tags: tagsSchema.optional().describe("Return references matching these tags"),
7108
+ search: z18.string().min(1).max(255).optional().describe("Search references by name"),
7109
+ current_page: z18.coerce.number().int().nonnegative().optional().describe("Zero-based page number; defaults to 0"),
7110
+ page_size: z18.coerce.number().int().min(1).max(100).optional().describe("References per page, from 1 to 100; defaults to 20")
7111
+ },
7112
+ get: {
7113
+ id: z18.string().min(1).describe("Secret Reference UUID or slug")
7114
+ },
7115
+ update: {
7116
+ id: z18.string().min(1).describe("Secret Reference UUID or slug"),
7117
+ name: z18.string().min(1).max(255).optional().describe("New human-readable name"),
7118
+ description: z18.string().max(1024).nullable().optional().describe("New description, or null to clear it"),
7119
+ auth_config: updateAuthConfigSchema.optional().describe(
7120
+ "Provide at least one changed authentication field to merge into the existing configuration; choose one AWS, Azure, or HashiCorp field family and do not mix families"
7121
+ ),
7122
+ secret_path: z18.string().max(1024).optional().describe("New path of the secret in the external secret manager"),
7123
+ secret_key: z18.string().max(255).nullable().optional().describe(
7124
+ "New key within a structured secret, or null to use the whole value"
7125
+ ),
7126
+ allow_all_workspaces: z18.boolean().optional().describe(
7127
+ "Whether every workspace may use this reference; cannot be true with allowed_workspaces"
7128
+ ),
7129
+ allowed_workspaces: z18.array(z18.string()).min(1).optional().describe(
7130
+ "Replacement list of workspace UUIDs or slugs allowed to use this reference; supplying it sets allow_all_workspaces=false"
7131
+ ),
7132
+ tags: tagsSchema.nullable().optional().describe("Replacement string key-value tags, or null to clear them")
7133
+ },
7134
+ delete: {
7135
+ id: z18.string().min(1).describe("Secret Reference UUID or slug")
7136
+ }
7137
+ };
7138
+ function validateWorkspaceAccess(value) {
7139
+ if (value.allow_all_workspaces === true && value.allowed_workspaces) {
7140
+ throw new Error(
7141
+ "allow_all_workspaces=true is mutually exclusive with allowed_workspaces"
7142
+ );
7143
+ }
7144
+ }
7145
+ function validateManagerAuth(managerType, authConfig) {
7146
+ const matches = managerType === "aws_sm" && "aws_auth_type" in authConfig || managerType === "azure_kv" && "azure_auth_mode" in authConfig || managerType === "hashicorp_vault" && "vault_auth_type" in authConfig;
7147
+ if (!matches) {
7148
+ throw new Error(`auth_config does not match manager_type ${managerType}`);
7149
+ }
7150
+ }
7151
+ function validateAuthUpdate(authConfig) {
7152
+ if (Object.keys(authConfig).length === 0) {
7153
+ throw new Error("auth_config update must contain at least one field");
7154
+ }
7155
+ const families = new Set(
7156
+ Object.keys(authConfig).map((key) => {
7157
+ if (key.startsWith("aws_")) return "AWS";
7158
+ if (key.startsWith("azure_")) return "Azure";
7159
+ if (key.startsWith("vault_")) return "HashiCorp Vault";
7160
+ return "unknown";
7161
+ })
7162
+ );
7163
+ if (families.size > 1) {
7164
+ throw new Error(
7165
+ "auth_config update must contain fields for exactly one secret-manager family"
7166
+ );
7167
+ }
7168
+ }
7169
+ var SENSITIVE_AUTH_FIELD = /(?:secret|token|password|credential|access_key_id)/i;
7170
+ function redactAuthConfig(authConfig) {
7171
+ return Object.fromEntries(
7172
+ Object.entries(authConfig).map(([key, value]) => {
7173
+ if (SENSITIVE_AUTH_FIELD.test(key)) return [key, "[REDACTED]"];
7174
+ if (value && typeof value === "object" && !Array.isArray(value)) {
7175
+ return [key, redactAuthConfig(value)];
7176
+ }
7177
+ return [key, value];
7178
+ })
7179
+ );
7180
+ }
7181
+ function registerSecretReferencesTools(server, service) {
7182
+ server.tool(
7183
+ "create_secret_reference",
7184
+ "Create a reference to a secret stored in AWS Secrets Manager, Azure Key Vault, or HashiCorp Vault. Authentication credentials are sent to Portkey and exposed to this MCP transcript; use short-lived or workload identity modes when possible. Returns the new UUID and slug, never the resolved external secret.",
7185
+ SECRET_REFERENCE_TOOL_SCHEMAS.create,
7186
+ {
7187
+ title: "Create Secret Reference",
7188
+ readOnlyHint: false,
7189
+ destructiveHint: false,
7190
+ idempotentHint: false,
7191
+ openWorldHint: true
7192
+ },
7193
+ async (params) => {
7194
+ validateWorkspaceAccess(params);
7195
+ validateManagerAuth(params.manager_type, params.auth_config);
7196
+ const result = await service.secretReferences.createSecretReference(params);
7197
+ return {
7198
+ content: [
7199
+ {
7200
+ type: "text",
7201
+ text: JSON.stringify({
7202
+ message: `Successfully created Secret Reference "${result.slug}"`,
7203
+ id: result.id,
7204
+ slug: result.slug
7205
+ })
7206
+ }
7207
+ ]
7208
+ };
7209
+ }
7210
+ );
7211
+ server.tool(
7212
+ "list_secret_references",
7213
+ "List Secret References without returning authentication configuration or resolved secret values. Filter by manager type, tags, or name and use a returned UUID or slug with get_secret_reference.",
7214
+ SECRET_REFERENCE_TOOL_SCHEMAS.list,
7215
+ {
7216
+ title: "List Secret References",
7217
+ readOnlyHint: true,
7218
+ destructiveHint: false,
7219
+ idempotentHint: true,
7220
+ openWorldHint: true
7221
+ },
7222
+ async (params) => {
7223
+ const result = await service.secretReferences.listSecretReferences({
7224
+ ...params,
7225
+ tags: params.tags ? JSON.stringify(params.tags) : void 0
7226
+ });
7227
+ return {
7228
+ content: [
7229
+ {
7230
+ type: "text",
7231
+ text: JSON.stringify({
7232
+ total: result.total,
7233
+ secret_references: result.data.map((reference) => ({
7234
+ id: reference.id,
7235
+ name: reference.name,
7236
+ slug: reference.slug,
7237
+ manager_type: reference.manager_type,
7238
+ status: reference.status,
7239
+ created_at: reference.created_at,
7240
+ last_updated_at: reference.last_updated_at
7241
+ }))
7242
+ })
7243
+ }
7244
+ ]
7245
+ };
7246
+ }
7247
+ );
7248
+ server.tool(
7249
+ "get_secret_reference",
7250
+ "Retrieve one Secret Reference by UUID or slug. Portkey masks sensitive authentication fields for non-system users; the tool returns metadata and the masked auth configuration, not the resolved external secret value.",
7251
+ SECRET_REFERENCE_TOOL_SCHEMAS.get,
7252
+ {
7253
+ title: "Get Secret Reference",
7254
+ readOnlyHint: true,
7255
+ destructiveHint: false,
7256
+ idempotentHint: true,
7257
+ openWorldHint: true
7258
+ },
7259
+ async ({ id }) => {
7260
+ const result = await service.secretReferences.getSecretReference(id);
7261
+ return {
7262
+ content: [
7263
+ {
7264
+ type: "text",
7265
+ text: JSON.stringify({
7266
+ ...result,
7267
+ auth_config: redactAuthConfig(result.auth_config)
7268
+ })
7269
+ }
7270
+ ]
7271
+ };
7272
+ }
7273
+ );
7274
+ server.tool(
7275
+ "update_secret_reference",
7276
+ "Update at least one selected field on a Secret Reference. auth_config is merged into the existing manager-specific configuration. allowed_workspaces replaces all workspace mappings and sets allow_all_workspaces=false; allow_all_workspaces=true removes workspace-specific mappings. Credential values are sent to Portkey and exposed to the MCP transcript.",
7277
+ SECRET_REFERENCE_TOOL_SCHEMAS.update,
7278
+ {
7279
+ title: "Update Secret Reference",
7280
+ readOnlyHint: false,
7281
+ destructiveHint: true,
7282
+ idempotentHint: true,
7283
+ openWorldHint: true
7284
+ },
7285
+ async ({ id, ...updates }) => {
7286
+ validateWorkspaceAccess(updates);
7287
+ if (Object.keys(updates).length === 0) {
7288
+ throw new Error("Provide at least one field to update");
7289
+ }
7290
+ if (updates.auth_config) validateAuthUpdate(updates.auth_config);
7291
+ await service.secretReferences.updateSecretReference(id, updates);
7292
+ return {
7293
+ content: [
7294
+ {
7295
+ type: "text",
7296
+ text: JSON.stringify({
7297
+ message: `Successfully updated Secret Reference "${id}"`,
7298
+ success: true
7299
+ })
7300
+ }
7301
+ ]
7302
+ };
7303
+ }
7304
+ );
7305
+ server.tool(
7306
+ "delete_secret_reference",
7307
+ "Permanently delete a Secret Reference. This is irreversible and integrations or virtual keys using it can fail to resolve credentials immediately; confirm dependencies before deletion.",
7308
+ SECRET_REFERENCE_TOOL_SCHEMAS.delete,
7309
+ {
7310
+ title: "Delete Secret Reference",
7311
+ readOnlyHint: false,
7312
+ destructiveHint: true,
7313
+ idempotentHint: true,
7314
+ openWorldHint: true
7315
+ },
7316
+ async ({ id }) => {
7317
+ const result = await service.secretReferences.deleteSecretReference(id);
7318
+ return {
7319
+ content: [
7320
+ {
7321
+ type: "text",
7322
+ text: JSON.stringify({
7323
+ message: `Successfully deleted Secret Reference "${id}"`,
7324
+ success: result.success
7325
+ })
7326
+ }
7327
+ ]
7328
+ };
7329
+ }
7330
+ );
7331
+ }
7332
+
6820
7333
  // src/tools/tracing.tools.ts
6821
- import { z as z17 } from "zod";
7334
+ import { z as z19 } from "zod";
6822
7335
  var TRACING_TOOL_SCHEMAS = {
6823
7336
  createFeedback: {
6824
- trace_id: z17.string().describe(
7337
+ trace_id: z19.string().describe(
6825
7338
  "The trace ID to associate the feedback with. This links feedback to a specific request/generation."
6826
7339
  ),
6827
- value: z17.coerce.number().describe(
7340
+ value: z19.coerce.number().describe(
6828
7341
  "Feedback value/rating. Common patterns: 1 for positive (thumbs up), 0 for negative (thumbs down), or use a scale like 1-5."
6829
7342
  ),
6830
- weight: z17.coerce.number().positive().optional().describe(
7343
+ weight: z19.coerce.number().positive().optional().describe(
6831
7344
  "Optional weighting factor for the feedback. Use to give more importance to certain feedback."
6832
7345
  ),
6833
- metadata: z17.record(z17.string(), z17.unknown()).optional().describe(
7346
+ metadata: z19.record(z19.string(), z19.unknown()).optional().describe(
6834
7347
  "Optional custom metadata for categorization and analysis (e.g., feedback_source, category, user_segment)."
6835
7348
  )
6836
7349
  },
6837
7350
  updateFeedback: {
6838
- id: z17.string().describe("The unique identifier of the feedback to update"),
6839
- value: z17.coerce.number().optional().describe(
7351
+ id: z19.string().describe("The unique identifier of the feedback to update"),
7352
+ value: z19.coerce.number().optional().describe(
6840
7353
  "New feedback value/rating. Common patterns: 1 for positive, 0 for negative."
6841
7354
  ),
6842
- weight: z17.coerce.number().positive().optional().describe("New weighting factor for the feedback"),
6843
- metadata: z17.record(z17.string(), z17.unknown()).optional().describe("New or updated custom metadata for the feedback")
7355
+ weight: z19.coerce.number().positive().optional().describe("New weighting factor for the feedback"),
7356
+ metadata: z19.record(z19.string(), z19.unknown()).optional().describe("New or updated custom metadata for the feedback")
6844
7357
  }
6845
7358
  };
6846
7359
  function registerTracingTools(server, service) {
@@ -6896,77 +7409,77 @@ function registerTracingTools(server, service) {
6896
7409
  }
6897
7410
 
6898
7411
  // src/tools/users.tools.ts
6899
- import { z as z18 } from "zod";
7412
+ import { z as z20 } from "zod";
6900
7413
  var USERS_TOOL_SCHEMAS = {
6901
7414
  listAllUsers: {
6902
- current_page: z18.coerce.number().positive().optional().describe("Page number for pagination"),
6903
- page_size: z18.coerce.number().positive().max(100).optional().describe("Number of results per page (max 100)")
7415
+ current_page: z20.coerce.number().int().positive().optional().describe("Page number for pagination"),
7416
+ page_size: z20.coerce.number().int().positive().max(100).optional().describe("Number of results per page (max 100)")
6904
7417
  },
6905
7418
  inviteUser: {
6906
- email: z18.string().email().describe("Email address of the user to invite"),
6907
- role: z18.enum(["admin", "member"]).describe(
7419
+ email: z20.string().email().describe("Email address of the user to invite"),
7420
+ role: z20.enum(["admin", "member"]).describe(
6908
7421
  "Organization-level role: 'admin' for full access, 'member' for limited access"
6909
7422
  ),
6910
- first_name: z18.string().optional().describe("User's first name"),
6911
- last_name: z18.string().optional().describe("User's last name"),
6912
- workspaces: z18.array(
6913
- z18.object({
6914
- id: z18.string().describe(
7423
+ first_name: z20.string().optional().describe("User's first name"),
7424
+ last_name: z20.string().optional().describe("User's last name"),
7425
+ workspaces: z20.array(
7426
+ z20.object({
7427
+ id: z20.string().describe(
6915
7428
  "Workspace ID/slug where the user will be granted access"
6916
7429
  ),
6917
- role: z18.enum(["admin", "member", "manager"]).describe(
7430
+ role: z20.enum(["admin", "member", "manager"]).describe(
6918
7431
  "Workspace-level role: 'admin' for full access, 'manager' for workspace management, 'member' for basic access"
6919
7432
  )
6920
7433
  })
6921
7434
  ).describe(
6922
7435
  "List of workspaces and corresponding roles to grant to the user"
6923
7436
  ),
6924
- workspace_api_key_details: z18.object({
6925
- name: z18.string().optional().describe("Name of the API key to be created"),
6926
- expiry: z18.string().optional().describe("Expiration date for the API key (ISO8601 format)"),
6927
- metadata: z18.record(z18.string(), z18.string()).optional().describe("Additional metadata key-value pairs for the API key"),
6928
- scopes: z18.array(z18.string()).describe("List of permission scopes for the API key")
7437
+ workspace_api_key_details: z20.object({
7438
+ name: z20.string().optional().describe("Name of the API key to be created"),
7439
+ expiry: z20.string().optional().describe("Expiration date for the API key (ISO8601 format)"),
7440
+ metadata: z20.record(z20.string(), z20.string()).optional().describe("Additional metadata key-value pairs for the API key"),
7441
+ scopes: z20.array(z20.string()).describe("List of permission scopes for the API key")
6929
7442
  }).optional().describe("Optional API key to be created for the user")
6930
7443
  },
6931
7444
  getUserStats: {
6932
- time_of_generation_min: z18.string().describe(
7445
+ time_of_generation_min: z20.string().describe(
6933
7446
  "Start time for the analytics period (ISO8601 format, e.g., '2024-01-01T00:00:00Z')"
6934
7447
  ),
6935
- time_of_generation_max: z18.string().describe(
7448
+ time_of_generation_max: z20.string().describe(
6936
7449
  "End time for the analytics period (ISO8601 format, e.g., '2024-02-01T00:00:00Z')"
6937
7450
  ),
6938
- total_units_min: z18.coerce.number().positive().optional().describe("Minimum number of total tokens to filter by"),
6939
- total_units_max: z18.coerce.number().positive().optional().describe("Maximum number of total tokens to filter by"),
6940
- cost_min: z18.coerce.number().positive().optional().describe("Minimum cost in cents to filter by"),
6941
- cost_max: z18.coerce.number().positive().optional().describe("Maximum cost in cents to filter by"),
6942
- status_code: z18.string().optional().describe("Filter by specific HTTP status codes (comma-separated)"),
6943
- virtual_keys: z18.string().optional().describe("Filter by specific virtual key slugs (comma-separated)"),
6944
- page_size: z18.coerce.number().positive().max(100).optional().describe("Number of results per page (max 100)")
7451
+ total_units_min: z20.coerce.number().positive().optional().describe("Minimum number of total tokens to filter by"),
7452
+ total_units_max: z20.coerce.number().positive().optional().describe("Maximum number of total tokens to filter by"),
7453
+ cost_min: z20.coerce.number().positive().optional().describe("Minimum cost in cents to filter by"),
7454
+ cost_max: z20.coerce.number().positive().optional().describe("Maximum cost in cents to filter by"),
7455
+ status_code: z20.string().optional().describe("Filter by specific HTTP status codes (comma-separated)"),
7456
+ virtual_keys: z20.string().optional().describe("Filter by specific virtual key slugs (comma-separated)"),
7457
+ page_size: z20.coerce.number().int().positive().max(100).optional().describe("Number of results per page (max 100)")
6945
7458
  },
6946
7459
  getUser: {
6947
- user_id: z18.string().describe("The user ID to retrieve")
7460
+ user_id: z20.string().describe("The user ID to retrieve")
6948
7461
  },
6949
7462
  updateUser: {
6950
- user_id: z18.string().describe("The user ID to update"),
6951
- first_name: z18.string().optional().describe("New first name"),
6952
- last_name: z18.string().optional().describe("New last name"),
6953
- role: z18.enum(["admin", "member"]).optional().describe("New organization-level role")
7463
+ user_id: z20.string().describe("The user ID to update"),
7464
+ first_name: z20.string().optional().describe("New first name"),
7465
+ last_name: z20.string().optional().describe("New last name"),
7466
+ role: z20.enum(["admin", "member"]).optional().describe("New organization-level role")
6954
7467
  },
6955
7468
  deleteUser: {
6956
- user_id: z18.string().describe("The user ID to delete")
7469
+ user_id: z20.string().describe("The user ID to delete")
6957
7470
  },
6958
7471
  listUserInvites: {
6959
- current_page: z18.coerce.number().positive().optional().describe("Page number for pagination"),
6960
- page_size: z18.coerce.number().positive().max(100).optional().describe("Number of results per page (max 100)")
7472
+ current_page: z20.coerce.number().int().positive().optional().describe("Page number for pagination"),
7473
+ page_size: z20.coerce.number().int().positive().max(100).optional().describe("Number of results per page (max 100)")
6961
7474
  },
6962
7475
  getUserInvite: {
6963
- invite_id: z18.string().describe("The invite ID to retrieve")
7476
+ invite_id: z20.string().describe("The invite ID to retrieve")
6964
7477
  },
6965
7478
  deleteUserInvite: {
6966
- invite_id: z18.string().describe("The invite ID to delete")
7479
+ invite_id: z20.string().describe("The invite ID to delete")
6967
7480
  },
6968
7481
  resendUserInvite: {
6969
- invite_id: z18.string().describe("The invite ID to resend")
7482
+ invite_id: z20.string().describe("The invite ID to resend")
6970
7483
  }
6971
7484
  };
6972
7485
  function formatUser(user) {
@@ -7192,59 +7705,59 @@ function registerUsersTools(server, service) {
7192
7705
  }
7193
7706
 
7194
7707
  // src/tools/workspaces.tools.ts
7195
- import { z as z19 } from "zod";
7708
+ import { z as z21 } from "zod";
7196
7709
  var WORKSPACES_TOOL_SCHEMAS = {
7197
7710
  listWorkspaces: {
7198
- page_size: z19.coerce.number().positive().max(100).optional().describe("Number of workspaces to return per page (max 100)"),
7199
- current_page: z19.coerce.number().positive().optional().describe("Page number to retrieve when results are paginated")
7711
+ page_size: z21.coerce.number().int().positive().max(100).optional().describe("Number of workspaces to return per page (max 100)"),
7712
+ current_page: z21.coerce.number().int().positive().optional().describe("Page number to retrieve when results are paginated")
7200
7713
  },
7201
7714
  getWorkspace: {
7202
- workspace_id: z19.string().describe(
7715
+ workspace_id: z21.string().describe(
7203
7716
  "The unique identifier of the workspace to retrieve. This can be found in the workspace's URL or from the list_workspaces tool response"
7204
7717
  )
7205
7718
  },
7206
7719
  createWorkspace: {
7207
- name: z19.string().describe("Name of the workspace"),
7208
- slug: z19.string().optional().describe("URL-friendly slug (auto-generated if not provided)"),
7209
- description: z19.string().optional().describe("Description of the workspace"),
7210
- is_default: z19.coerce.number().optional().describe("Set as default workspace (1 = yes, 0 = no)"),
7211
- metadata: z19.record(z19.string(), z19.string()).optional().describe("Custom metadata key-value pairs")
7720
+ name: z21.string().describe("Name of the workspace"),
7721
+ slug: z21.string().optional().describe("URL-friendly slug (auto-generated if not provided)"),
7722
+ description: z21.string().optional().describe("Description of the workspace"),
7723
+ is_default: z21.coerce.number().optional().describe("Set as default workspace (1 = yes, 0 = no)"),
7724
+ metadata: z21.record(z21.string(), z21.string()).optional().describe("Custom metadata key-value pairs")
7212
7725
  },
7213
7726
  updateWorkspace: {
7214
- workspace_id: z19.string().describe("The workspace ID to update"),
7215
- name: z19.string().optional().describe("New name for the workspace"),
7216
- slug: z19.string().optional().describe("New slug for the workspace"),
7217
- description: z19.string().optional().describe("New description"),
7218
- is_default: z19.coerce.number().optional().describe("Set as default workspace (1 = yes, 0 = no)"),
7219
- metadata: z19.record(z19.string(), z19.string()).optional().describe("New metadata key-value pairs")
7727
+ workspace_id: z21.string().describe("The workspace ID to update"),
7728
+ name: z21.string().optional().describe("New name for the workspace"),
7729
+ slug: z21.string().optional().describe("New slug for the workspace"),
7730
+ description: z21.string().optional().describe("New description"),
7731
+ is_default: z21.coerce.number().optional().describe("Set as default workspace (1 = yes, 0 = no)"),
7732
+ metadata: z21.record(z21.string(), z21.string()).optional().describe("New metadata key-value pairs")
7220
7733
  },
7221
7734
  deleteWorkspace: {
7222
- workspace_id: z19.string().describe("The workspace ID to delete")
7735
+ workspace_id: z21.string().describe("The workspace ID to delete")
7223
7736
  },
7224
7737
  addWorkspaceMember: {
7225
- workspace_id: z19.string().describe("The workspace ID to add the member to"),
7226
- user_id: z19.string().uuid(
7738
+ workspace_id: z21.string().describe("The workspace ID to add the member to"),
7739
+ user_id: z21.string().uuid(
7227
7740
  "user_id must be a valid UUID (use list_all_users to find user IDs)"
7228
7741
  ).describe(
7229
7742
  "The user ID to add (must be a valid UUID from list_all_users, not an email address)"
7230
7743
  ),
7231
- role: z19.enum(["admin", "member", "manager"]).describe("Role in the workspace")
7744
+ role: z21.enum(["admin", "member", "manager"]).describe("Role in the workspace")
7232
7745
  },
7233
7746
  listWorkspaceMembers: {
7234
- workspace_id: z19.string().describe("The workspace ID to list members for")
7747
+ workspace_id: z21.string().describe("The workspace ID to list members for")
7235
7748
  },
7236
7749
  getWorkspaceMember: {
7237
- workspace_id: z19.string().describe("The workspace ID"),
7238
- user_id: z19.string().describe("The user ID to retrieve")
7750
+ workspace_id: z21.string().describe("The workspace ID"),
7751
+ user_id: z21.string().describe("The user ID to retrieve")
7239
7752
  },
7240
7753
  updateWorkspaceMember: {
7241
- workspace_id: z19.string().describe("The workspace ID"),
7242
- user_id: z19.string().describe("The user ID to update"),
7243
- role: z19.enum(["admin", "member", "manager"]).describe("New role in the workspace")
7754
+ workspace_id: z21.string().describe("The workspace ID"),
7755
+ user_id: z21.string().describe("The user ID to update"),
7756
+ role: z21.enum(["admin", "member", "manager"]).describe("New role in the workspace")
7244
7757
  },
7245
7758
  removeWorkspaceMember: {
7246
- workspace_id: z19.string().describe("The workspace ID"),
7247
- user_id: z19.string().describe("The user ID to remove")
7759
+ workspace_id: z21.string().describe("The workspace ID"),
7760
+ user_id: z21.string().describe("The user ID to remove")
7248
7761
  }
7249
7762
  };
7250
7763
  function formatWorkspaceDefaults(defaults) {
@@ -7531,6 +8044,7 @@ var TOOL_DOMAIN_REGISTRARS = [
7531
8044
  ["tracing", registerTracingTools],
7532
8045
  ["logging", registerLoggingTools],
7533
8046
  ["providers", registerProvidersTools],
8047
+ ["secret-references", registerSecretReferencesTools],
7534
8048
  ["integrations", registerIntegrationsTools],
7535
8049
  ["mcp-integrations", registerMcpIntegrationsTools],
7536
8050
  ["mcp-servers", registerMcpServersTools]
@@ -7653,13 +8167,81 @@ function getToolErrorMessage(error) {
7653
8167
  return String(error);
7654
8168
  }
7655
8169
  var STANDARD_TOOL_OUTPUT_SCHEMA = {
7656
- ok: z20.boolean().describe("Whether the tool call succeeded and returned structured data"),
7657
- data: z20.unknown().optional().describe("Structured success payload when ok is true"),
7658
- error: z20.object({
7659
- message: z20.string().describe("Human-readable error message"),
7660
- details: z20.unknown().optional().describe("Optional structured error details")
8170
+ ok: z22.boolean().describe("Whether the tool call succeeded and returned structured data"),
8171
+ data: z22.unknown().optional().describe("Structured success payload when ok is true"),
8172
+ error: z22.object({
8173
+ message: z22.string().describe("Human-readable error message"),
8174
+ details: z22.unknown().optional().describe("Optional structured error details")
7661
8175
  }).optional().describe("Structured error payload when ok is false")
7662
8176
  };
8177
+ var TOOL_SUCCESS_DATA_SCHEMAS = {
8178
+ rotate_api_key: z22.object({
8179
+ message: z22.string().describe("Rotation confirmation"),
8180
+ warning: z22.string().describe("Required handling guidance for the one-time secret"),
8181
+ id: z22.string().uuid().describe("Rotated API key UUID"),
8182
+ key: z22.string().describe("New API key secret, returned only once"),
8183
+ key_transition_expires_at: z22.iso.datetime().describe("Time when the previous key stops working")
8184
+ }),
8185
+ create_secret_reference: z22.object({
8186
+ message: z22.string().describe("Creation confirmation"),
8187
+ id: z22.string().uuid().describe("New Secret Reference UUID"),
8188
+ slug: z22.string().describe("New Secret Reference slug")
8189
+ }),
8190
+ list_secret_references: z22.object({
8191
+ total: z22.number().int().nonnegative().describe("Total matching references"),
8192
+ secret_references: z22.array(
8193
+ z22.object({
8194
+ id: z22.string().uuid().describe("Secret Reference UUID"),
8195
+ name: z22.string().describe("Human-readable name"),
8196
+ slug: z22.string().describe("Stable Secret Reference slug"),
8197
+ manager_type: SecretManagerTypeSchema.describe(
8198
+ "External secret manager type"
8199
+ ),
8200
+ status: z22.literal("ACTIVE").describe("Current reference status"),
8201
+ created_at: z22.iso.datetime().describe("ISO 8601 creation timestamp"),
8202
+ last_updated_at: z22.iso.datetime().describe("ISO 8601 last-update timestamp")
8203
+ })
8204
+ ).describe(
8205
+ "Current page of Secret References without authentication values"
8206
+ )
8207
+ }),
8208
+ get_secret_reference: z22.object({
8209
+ id: z22.string().uuid().describe("Secret Reference UUID"),
8210
+ organisation_id: z22.string().uuid().describe("Owning organisation UUID"),
8211
+ name: z22.string().describe("Human-readable name"),
8212
+ slug: z22.string().describe("Stable Secret Reference slug"),
8213
+ description: z22.string().nullable().describe("Reference description"),
8214
+ manager_type: SecretManagerTypeSchema.describe(
8215
+ "External secret manager type"
8216
+ ),
8217
+ secret_path: z22.string().describe("Path in the external secret manager"),
8218
+ secret_key: z22.string().nullable().describe("Selected key within a structured secret"),
8219
+ allow_all_workspaces: z22.boolean().describe("Whether all workspaces may use the reference"),
8220
+ tags: z22.record(z22.string(), z22.string()).nullable().describe("String metadata tags"),
8221
+ status: z22.literal("ACTIVE").describe("Current reference status"),
8222
+ created_by: z22.string().describe("Creator identifier"),
8223
+ created_at: z22.iso.datetime().describe("ISO 8601 creation timestamp"),
8224
+ last_updated_at: z22.iso.datetime().describe("ISO 8601 last-update timestamp"),
8225
+ auth_config: z22.record(z22.string(), z22.unknown()).describe("Authentication configuration with sensitive values redacted"),
8226
+ object: z22.literal("secret-reference").describe("Portkey object type")
8227
+ }),
8228
+ update_secret_reference: z22.object({
8229
+ message: z22.string().describe("Update confirmation"),
8230
+ success: z22.literal(true).describe("Whether the update succeeded")
8231
+ }),
8232
+ delete_secret_reference: z22.object({
8233
+ message: z22.string().describe("Deletion confirmation"),
8234
+ success: z22.literal(true).describe("Whether the deletion succeeded")
8235
+ })
8236
+ };
8237
+ function getToolOutputSchema(toolName) {
8238
+ const dataSchema = TOOL_SUCCESS_DATA_SCHEMAS[toolName];
8239
+ if (!dataSchema) return STANDARD_TOOL_OUTPUT_SCHEMA;
8240
+ return {
8241
+ ...STANDARD_TOOL_OUTPUT_SCHEMA,
8242
+ data: dataSchema.optional().describe("Structured success payload when ok is true")
8243
+ };
8244
+ }
7663
8245
  function isStandardToolEnvelope(value) {
7664
8246
  if (!isRecord(value) || typeof value.ok !== "boolean") {
7665
8247
  return false;
@@ -7806,7 +8388,7 @@ function createSafeToolServer(server) {
7806
8388
  {
7807
8389
  ...registration.description ? { description: registration.description } : {},
7808
8390
  ...registration.inputSchema !== void 0 ? { inputSchema: registration.inputSchema } : {},
7809
- outputSchema: STANDARD_TOOL_OUTPUT_SCHEMA,
8391
+ outputSchema: getToolOutputSchema(name),
7810
8392
  annotations: registration.annotations
7811
8393
  },
7812
8394
  registration.callback
@@ -7841,7 +8423,7 @@ function registerAllTools(server, service, options = {}) {
7841
8423
  }
7842
8424
 
7843
8425
  // src/lib/auth.ts
7844
- import crypto3 from "node:crypto";
8426
+ import crypto2 from "node:crypto";
7845
8427
  import { createRemoteJWKSet, jwtVerify } from "jose";
7846
8428
  var AUTH_SCHEMES = {
7847
8429
  bearer: "Bearer"
@@ -7956,9 +8538,9 @@ function extractBearerToken(req) {
7956
8538
  return token.trim();
7957
8539
  }
7958
8540
  function timingSafeEqual(a, b) {
7959
- const left = crypto3.createHash("sha256").update(a, "utf8").digest();
7960
- const right = crypto3.createHash("sha256").update(b, "utf8").digest();
7961
- return crypto3.timingSafeEqual(left, right);
8541
+ const left = crypto2.createHash("sha256").update(a, "utf8").digest();
8542
+ const right = crypto2.createHash("sha256").update(b, "utf8").digest();
8543
+ return crypto2.timingSafeEqual(left, right);
7962
8544
  }
7963
8545
  var jwksCache = /* @__PURE__ */ new Map();
7964
8546
  async function verifyClerkToken(token, config) {
@@ -8022,10 +8604,17 @@ async function mcpAuthMiddleware(req, res, next) {
8022
8604
  }
8023
8605
 
8024
8606
  // src/lib/config.ts
8607
+ function parseStrictInteger(value) {
8608
+ if (!/^\d+$/.test(value)) {
8609
+ return Number.NaN;
8610
+ }
8611
+ const parsed = Number(value);
8612
+ return Number.isSafeInteger(parsed) ? parsed : Number.NaN;
8613
+ }
8025
8614
  function getServerConfig() {
8026
8615
  const transport = process.env.MCP_TRANSPORT?.trim() || "stdio";
8027
8616
  const sessionMode = process.env.MCP_SESSION_MODE?.trim().toLowerCase() || "stateful";
8028
- const eventStoreMode = process.env.MCP_EVENT_STORE?.trim().toLowerCase() || (sessionMode === "stateless" ? "memory" : "off");
8617
+ const eventStoreMode = process.env.MCP_EVENT_STORE?.trim().toLowerCase() || "off";
8029
8618
  if (transport !== "stdio" && transport !== "http") {
8030
8619
  throw new Error(
8031
8620
  `Invalid MCP_TRANSPORT value: ${transport}. Must be 'stdio' or 'http'`
@@ -8041,13 +8630,12 @@ function getServerConfig() {
8041
8630
  `Invalid MCP_EVENT_STORE value: ${eventStoreMode}. Must be 'off', 'memory', or 'redis'`
8042
8631
  );
8043
8632
  }
8044
- const port = Number.parseInt(
8045
- process.env.PORT?.trim() || process.env.MCP_PORT?.trim() || "3000",
8046
- 10
8047
- );
8633
+ const portVariable = process.env.PORT?.trim() ? "PORT" : "MCP_PORT";
8634
+ const portValue = process.env.PORT?.trim() || process.env.MCP_PORT?.trim() || "3000";
8635
+ const port = parseStrictInteger(portValue);
8048
8636
  if (Number.isNaN(port) || port < 1 || port > 65535) {
8049
8637
  throw new Error(
8050
- `Invalid MCP_PORT value: ${process.env.MCP_PORT}. Must be a valid port number (1-65535)`
8638
+ `Invalid ${portVariable} value: ${portValue}. Must be a valid port number (1-65535)`
8051
8639
  );
8052
8640
  }
8053
8641
  let host;
@@ -8061,21 +8649,28 @@ function getServerConfig() {
8061
8649
  host = "127.0.0.1";
8062
8650
  }
8063
8651
  const sessionTimeoutStr = (process.env.MCP_SESSION_TIMEOUT || "3600000").trim();
8064
- const sessionTimeout = Number.parseInt(sessionTimeoutStr, 10);
8652
+ const sessionTimeout = parseStrictInteger(sessionTimeoutStr);
8065
8653
  if (Number.isNaN(sessionTimeout) || sessionTimeout < 0) {
8066
8654
  throw new Error(
8067
8655
  `Invalid MCP_SESSION_TIMEOUT value: ${sessionTimeoutStr}. Must be a non-negative number`
8068
8656
  );
8069
8657
  }
8658
+ const shutdownTimeoutStr = (process.env.MCP_SHUTDOWN_TIMEOUT_MS || "10000").trim();
8659
+ const shutdownTimeout = parseStrictInteger(shutdownTimeoutStr);
8660
+ if (Number.isNaN(shutdownTimeout) || shutdownTimeout <= 0) {
8661
+ throw new Error(
8662
+ `Invalid MCP_SHUTDOWN_TIMEOUT_MS value: ${shutdownTimeoutStr}. Must be a positive integer`
8663
+ );
8664
+ }
8070
8665
  const maxSessionsStr = (process.env.MCP_MAX_SESSIONS || "100").trim();
8071
- const maxSessions = Number.parseInt(maxSessionsStr, 10);
8666
+ const maxSessions = parseStrictInteger(maxSessionsStr);
8072
8667
  if (!Number.isInteger(maxSessions) || maxSessions <= 0) {
8073
8668
  throw new Error(
8074
8669
  `Invalid MCP_MAX_SESSIONS value: ${maxSessionsStr}. Must be a positive integer`
8075
8670
  );
8076
8671
  }
8077
8672
  const eventStoreTtlStr = (process.env.MCP_EVENT_TTL_SECONDS || "3600").trim();
8078
- const eventStoreTtlSeconds = Number.parseInt(eventStoreTtlStr, 10);
8673
+ const eventStoreTtlSeconds = parseStrictInteger(eventStoreTtlStr);
8079
8674
  if (Number.isNaN(eventStoreTtlSeconds) || eventStoreTtlSeconds <= 0) {
8080
8675
  throw new Error(
8081
8676
  `Invalid MCP_EVENT_TTL_SECONDS value: ${eventStoreTtlStr}. Must be a positive integer`
@@ -8114,6 +8709,7 @@ function getServerConfig() {
8114
8709
  host,
8115
8710
  maxSessions,
8116
8711
  sessionTimeout,
8712
+ shutdownTimeout,
8117
8713
  tls: {
8118
8714
  enabled: tlsEnabled,
8119
8715
  keyPath,
@@ -8124,6 +8720,7 @@ function getServerConfig() {
8124
8720
  }
8125
8721
 
8126
8722
  // src/lib/event-store.ts
8723
+ import { randomUUID } from "node:crypto";
8127
8724
  var EVENT_STORE_CLEANUP_INTERVAL_MS = 3e4;
8128
8725
  var SAFE_EVENT_ID_PATTERN = /^[\w-]{1,128}$/;
8129
8726
  function assertSafeRedisId(id, kind) {
@@ -8135,10 +8732,10 @@ function assertSafeRedisId(id, kind) {
8135
8732
  return id;
8136
8733
  }
8137
8734
  var InMemoryEventStore = class {
8138
- sequence = 0;
8139
8735
  ttlMs;
8140
8736
  events = /* @__PURE__ */ new Map();
8141
8737
  streamEvents = /* @__PURE__ */ new Map();
8738
+ activeReplayStreams = /* @__PURE__ */ new Set();
8142
8739
  lastCleanupAt = 0;
8143
8740
  constructor(ttlSeconds) {
8144
8741
  this.ttlMs = ttlSeconds * 1e3;
@@ -8194,8 +8791,7 @@ var InMemoryEventStore = class {
8194
8791
  }
8195
8792
  async storeEvent(streamId, message) {
8196
8793
  this.maybeCleanupExpired();
8197
- this.sequence += 1;
8198
- const eventId = String(this.sequence);
8794
+ const eventId = randomUUID();
8199
8795
  this.events.set(eventId, {
8200
8796
  streamId,
8201
8797
  message,
@@ -8211,6 +8807,26 @@ var InMemoryEventStore = class {
8211
8807
  this.maybeCleanupExpired(now);
8212
8808
  return this.getEventIfUnexpired(eventId, now)?.streamId;
8213
8809
  }
8810
+ async acquireReplayLease(eventId) {
8811
+ const streamId = await this.getStreamIdForEventId(eventId);
8812
+ if (!streamId) {
8813
+ return { status: "missing" };
8814
+ }
8815
+ if (this.activeReplayStreams.has(streamId)) {
8816
+ return { status: "conflict" };
8817
+ }
8818
+ this.activeReplayStreams.add(streamId);
8819
+ let released = false;
8820
+ return {
8821
+ status: "acquired",
8822
+ release: async () => {
8823
+ if (!released) {
8824
+ released = true;
8825
+ this.activeReplayStreams.delete(streamId);
8826
+ }
8827
+ }
8828
+ };
8829
+ }
8214
8830
  async replayEventsAfter(lastEventId, {
8215
8831
  send
8216
8832
  }) {
@@ -8257,10 +8873,21 @@ var RedisEventStore = class {
8257
8873
  streamEventsKey(streamId) {
8258
8874
  return `${this.keyPrefix}:stream:${assertSafeRedisId(streamId, "streamId")}:events`;
8259
8875
  }
8876
+ replayLeaseKey(streamId) {
8877
+ return `${this.keyPrefix}:stream:${assertSafeRedisId(streamId, "streamId")}:replay-lease`;
8878
+ }
8260
8879
  async ensureConnected() {
8261
8880
  if (!this.client) {
8262
8881
  const { createClient } = await import("redis");
8263
- this.client = createClient({ url: this.redisUrl });
8882
+ this.client = createClient({
8883
+ url: this.redisUrl,
8884
+ // node-redis v6 defaults to RESP3, a 5-second command timeout, and a
8885
+ // 30-second keepalive delay. Keep the event store's v5 behavior stable
8886
+ // while taking the v6 fixes and supported runtime baseline.
8887
+ RESP: 2,
8888
+ socket: { keepAliveInitialDelay: 5e3 },
8889
+ commandOptions: { timeout: void 0 }
8890
+ });
8264
8891
  this.client.on("error", (error) => {
8265
8892
  Logger.error("Redis event store error", {
8266
8893
  metadata: {
@@ -8289,17 +8916,19 @@ var RedisEventStore = class {
8289
8916
  async storeEvent(streamId, message) {
8290
8917
  await this.ensureConnected();
8291
8918
  const client = this.getConnectedClient();
8292
- const eventId = String(await client.incr(this.counterKey()));
8919
+ const sequence = await client.incr(this.counterKey());
8920
+ const eventId = randomUUID();
8293
8921
  const eventKey = this.eventKey(eventId);
8294
8922
  const streamKey = this.streamEventsKey(streamId);
8295
8923
  const tx = client.multi();
8296
8924
  tx.hSet(eventKey, {
8297
8925
  streamId,
8926
+ sequence: String(sequence),
8298
8927
  message: JSON.stringify(message)
8299
8928
  });
8300
8929
  tx.expire(eventKey, this.ttlSeconds);
8301
8930
  tx.zAdd(streamKey, {
8302
- score: Number(eventId),
8931
+ score: sequence,
8303
8932
  value: eventId
8304
8933
  });
8305
8934
  tx.expire(streamKey, this.ttlSeconds);
@@ -8317,6 +8946,36 @@ var RedisEventStore = class {
8317
8946
  );
8318
8947
  return streamId || void 0;
8319
8948
  }
8949
+ async acquireReplayLease(eventId) {
8950
+ const streamId = await this.getStreamIdForEventId(eventId);
8951
+ if (!streamId) {
8952
+ return { status: "missing" };
8953
+ }
8954
+ const client = this.getConnectedClient();
8955
+ const leaseKey = this.replayLeaseKey(streamId);
8956
+ const ownerToken = randomUUID();
8957
+ const acquired = await client.set(leaseKey, ownerToken, {
8958
+ NX: true,
8959
+ PX: 6e4
8960
+ });
8961
+ if (acquired !== "OK") {
8962
+ return { status: "conflict" };
8963
+ }
8964
+ let released = false;
8965
+ return {
8966
+ status: "acquired",
8967
+ release: async () => {
8968
+ if (released) {
8969
+ return;
8970
+ }
8971
+ released = true;
8972
+ await client.eval(
8973
+ "if redis.call('GET', KEYS[1]) == ARGV[1] then return redis.call('DEL', KEYS[1]) else return 0 end",
8974
+ { keys: [leaseKey], arguments: [ownerToken] }
8975
+ );
8976
+ }
8977
+ };
8978
+ }
8320
8979
  async replayEventsAfter(lastEventId, {
8321
8980
  send
8322
8981
  }) {
@@ -8327,9 +8986,9 @@ var RedisEventStore = class {
8327
8986
  if (!streamId) {
8328
8987
  throw new Error(`Event not found for replay: ${lastEventId}`);
8329
8988
  }
8330
- const baseScore = Number(lastEventId);
8989
+ const baseScore = Number(baseEvent.sequence);
8331
8990
  if (!Number.isFinite(baseScore)) {
8332
- throw new Error(`Invalid replay event ID: ${lastEventId}`);
8991
+ throw new Error(`Invalid replay sequence for event: ${lastEventId}`);
8333
8992
  }
8334
8993
  const eventIds = await client.zRangeByScore(
8335
8994
  this.streamEventsKey(streamId),
@@ -8370,7 +9029,7 @@ var RedisEventStore = class {
8370
9029
  }
8371
9030
  }
8372
9031
  if (this.client.isOpen) {
8373
- await this.client.quit();
9032
+ await this.client.close();
8374
9033
  }
8375
9034
  }
8376
9035
  };
@@ -8383,9 +9042,11 @@ function createManagedEventStore(config) {
8383
9042
  };
8384
9043
  }
8385
9044
  if (config.eventStore.mode === "memory") {
9045
+ const memoryStore = new InMemoryEventStore(config.eventStore.ttlSeconds);
8386
9046
  return {
8387
9047
  mode: "memory",
8388
- eventStore: new InMemoryEventStore(config.eventStore.ttlSeconds),
9048
+ eventStore: memoryStore,
9049
+ acquireReplayLease: (eventId) => memoryStore.acquireReplayLease(eventId),
8389
9050
  close: async () => {
8390
9051
  }
8391
9052
  };
@@ -8398,6 +9059,7 @@ function createManagedEventStore(config) {
8398
9059
  return {
8399
9060
  mode: "redis",
8400
9061
  eventStore: redisStore,
9062
+ acquireReplayLease: (eventId) => redisStore.acquireReplayLease(eventId),
8401
9063
  close: async () => {
8402
9064
  await redisStore.close();
8403
9065
  }
@@ -8407,7 +9069,7 @@ function createManagedEventStore(config) {
8407
9069
  // src/lib/mcp-server.ts
8408
9070
  import { readFileSync } from "node:fs";
8409
9071
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
8410
- import { z as z21 } from "zod";
9072
+ import { z as z23 } from "zod";
8411
9073
  var PACKAGE_JSON_URL_CANDIDATES = [
8412
9074
  new URL("../../package.json", import.meta.url),
8413
9075
  new URL("../package.json", import.meta.url)
@@ -8480,8 +9142,8 @@ function registerServerPromptsAndResources(server) {
8480
9142
  title: "Plan Portkey Admin Workflow",
8481
9143
  description: "Create a concise, safe plan for a Portkey Admin API task using this MCP server.",
8482
9144
  argsSchema: {
8483
- task: z21.string().min(1).max(500).describe("Portkey admin task to plan, such as promoting a prompt"),
8484
- area: z21.string().max(80).optional().describe(
9145
+ task: z23.string().min(1).max(500).describe("Portkey admin task to plan, such as promoting a prompt"),
9146
+ area: z23.string().max(80).optional().describe(
8485
9147
  "Optional Portkey area, such as prompts, analytics, configs, or users"
8486
9148
  )
8487
9149
  }
@@ -8576,7 +9238,16 @@ function parseOriginParts(value) {
8576
9238
  }
8577
9239
  }
8578
9240
  function normalizeHostWithoutPort(value) {
8579
- return value.trim().toLowerCase().split(":")[0];
9241
+ const normalized = value.trim().toLowerCase();
9242
+ if (normalized.startsWith("[")) {
9243
+ const bracketEnd = normalized.indexOf("]");
9244
+ if (bracketEnd < 0) {
9245
+ return normalized;
9246
+ }
9247
+ const remainder = normalized.slice(bracketEnd + 1);
9248
+ return remainder === "" || /^:\d+$/.test(remainder) ? normalized.slice(0, bracketEnd + 1) : normalized;
9249
+ }
9250
+ return normalized.split(":", 1)[0];
8580
9251
  }
8581
9252
  function isOriginMatch(origin, allowedOrigin) {
8582
9253
  const originParts = parseOriginParts(origin);
@@ -8600,7 +9271,14 @@ function resolveAllowedOrigins() {
8600
9271
  return parsed;
8601
9272
  }
8602
9273
  }
8603
- return ["http://localhost", "https://localhost"];
9274
+ return [
9275
+ "http://localhost",
9276
+ "https://localhost",
9277
+ "http://127.0.0.1",
9278
+ "https://127.0.0.1",
9279
+ "http://[::1]",
9280
+ "https://[::1]"
9281
+ ];
8604
9282
  }
8605
9283
  var ALLOWED_ORIGINS = resolveAllowedOrigins();
8606
9284
  function getAllowedOrigins() {
@@ -8669,7 +9347,8 @@ function parsePositiveIntegerEnv(name, fallback) {
8669
9347
  if (raw === void 0) {
8670
9348
  return fallback;
8671
9349
  }
8672
- const parsed = Number.parseInt(raw.trim(), 10);
9350
+ const normalized = raw.trim();
9351
+ const parsed = /^\d+$/.test(normalized) ? Number(normalized) : Number.NaN;
8673
9352
  if (Number.isFinite(parsed) && Number.isInteger(parsed) && parsed > 0) {
8674
9353
  return parsed;
8675
9354
  }
@@ -8951,6 +9630,17 @@ var SessionStore = class {
8951
9630
  };
8952
9631
 
8953
9632
  // src/lib/http-app.ts
9633
+ function waitForResponseWritable(response) {
9634
+ return new Promise((resolve) => {
9635
+ const done = () => {
9636
+ response.off("drain", done);
9637
+ response.off("close", done);
9638
+ resolve();
9639
+ };
9640
+ response.once("drain", done);
9641
+ response.once("close", done);
9642
+ });
9643
+ }
8954
9644
  function getReadyCheckMode() {
8955
9645
  const readyCheckMode = process.env.MCP_READY_CHECK_MODE?.trim().toLowerCase() || "local";
8956
9646
  if (readyCheckMode !== "local" && readyCheckMode !== "portkey") {
@@ -9114,7 +9804,7 @@ function getMcpProtocolVersion(req) {
9114
9804
  }
9115
9805
  function validateRequiredProtocolVersion(protocolVersion, expectedProtocolVersion) {
9116
9806
  if (!protocolVersion) {
9117
- return "Bad Request: MCP-Protocol-Version header is required for requests after initialization";
9807
+ return void 0;
9118
9808
  }
9119
9809
  if (!SUPPORTED_PROTOCOL_VERSIONS.includes(protocolVersion)) {
9120
9810
  const safe = sanitizeProtocolVersion(protocolVersion);
@@ -9146,6 +9836,8 @@ function createHttpAppRuntime() {
9146
9836
  const isStatefulSessionMode = config.sessionMode === "stateful";
9147
9837
  const publicBaseUrl = buildConfiguredPublicBaseUrl(config);
9148
9838
  const sessionStore = new SessionStore(config.maxSessions);
9839
+ const activeStatelessConnections = /* @__PURE__ */ new Set();
9840
+ const activeReplayOperations = /* @__PURE__ */ new Set();
9149
9841
  const app = express();
9150
9842
  let isReady = false;
9151
9843
  let server;
@@ -9154,11 +9846,31 @@ function createHttpAppRuntime() {
9154
9846
  let sigintHandler;
9155
9847
  let sigtermHandler;
9156
9848
  async function handleStatelessRequest(req, res, context, parsedBody, toolDomains) {
9849
+ let replayStreamId;
9850
+ let responseDisconnected = false;
9851
+ const storedMessages = /* @__PURE__ */ new WeakSet();
9852
+ const sharedEventStore = managedEventStore.eventStore;
9853
+ const requestEventStore = sharedEventStore ? {
9854
+ storeEvent: async (streamId, message) => {
9855
+ replayStreamId ??= streamId;
9856
+ storedMessages.add(message);
9857
+ return sharedEventStore.storeEvent(streamId, message);
9858
+ },
9859
+ getStreamIdForEventId: async (eventId) => sharedEventStore.getStreamIdForEventId?.(eventId),
9860
+ replayEventsAfter: (lastEventId, options) => sharedEventStore.replayEventsAfter(lastEventId, options)
9861
+ } : void 0;
9157
9862
  const transport = new StreamableHTTPServerTransport({
9158
9863
  sessionIdGenerator: void 0,
9159
- eventStore: managedEventStore.eventStore
9864
+ eventStore: requestEventStore
9160
9865
  });
9161
9866
  const { server: mcpServer } = createMcpServer({ toolDomains });
9867
+ const requestMessages = Array.isArray(parsedBody) ? parsedBody : [parsedBody];
9868
+ const pendingRequestIds = /* @__PURE__ */ new Set();
9869
+ for (const message of requestMessages) {
9870
+ if (isRecord(message) && typeof message.method === "string" && (typeof message.id === "string" || typeof message.id === "number")) {
9871
+ pendingRequestIds.add(message.id);
9872
+ }
9873
+ }
9162
9874
  let closePromise;
9163
9875
  const closeConnection = () => {
9164
9876
  if (!closePromise) {
@@ -9169,16 +9881,60 @@ function createHttpAppRuntime() {
9169
9881
  error: error instanceof Error ? error.message : String(error)
9170
9882
  }
9171
9883
  });
9884
+ }).finally(() => {
9885
+ activeStatelessConnections.delete(closeConnection);
9172
9886
  });
9173
9887
  }
9174
9888
  return closePromise;
9175
9889
  };
9890
+ activeStatelessConnections.add(closeConnection);
9891
+ const originalSend = transport.send.bind(transport);
9892
+ transport.send = async (message, options) => {
9893
+ if ((responseDisconnected || res.destroyed) && replayStreamId && sharedEventStore) {
9894
+ await sharedEventStore.storeEvent(replayStreamId, message);
9895
+ storedMessages.add(message);
9896
+ } else {
9897
+ try {
9898
+ await originalSend(message, options);
9899
+ } catch (error) {
9900
+ const disconnected = error instanceof Error && error.message.startsWith(
9901
+ "No connection established for request ID:"
9902
+ );
9903
+ if (!disconnected || !replayStreamId || !sharedEventStore) {
9904
+ throw error;
9905
+ }
9906
+ if (!storedMessages.has(message)) {
9907
+ await sharedEventStore.storeEvent(replayStreamId, message);
9908
+ storedMessages.add(message);
9909
+ }
9910
+ }
9911
+ if ((responseDisconnected || res.destroyed) && replayStreamId && sharedEventStore && !storedMessages.has(message)) {
9912
+ await sharedEventStore.storeEvent(replayStreamId, message);
9913
+ storedMessages.add(message);
9914
+ }
9915
+ }
9916
+ if ("id" in message && ("result" in message || "error" in message)) {
9917
+ pendingRequestIds.delete(message.id);
9918
+ if (pendingRequestIds.size === 0) {
9919
+ queueMicrotask(() => {
9920
+ void closeConnection();
9921
+ });
9922
+ }
9923
+ }
9924
+ };
9176
9925
  res.once("close", () => {
9177
- void closeConnection();
9926
+ if (pendingRequestIds.size > 0 && replayStreamId) {
9927
+ responseDisconnected = true;
9928
+ } else {
9929
+ void closeConnection();
9930
+ }
9178
9931
  });
9179
9932
  try {
9180
9933
  await mcpServer.connect(transport);
9181
9934
  await transport.handleRequest(req, res, parsedBody);
9935
+ if (pendingRequestIds.size === 0) {
9936
+ await closeConnection();
9937
+ }
9182
9938
  } catch (error) {
9183
9939
  await closeConnection();
9184
9940
  throw error;
@@ -9208,10 +9964,15 @@ function createHttpAppRuntime() {
9208
9964
  app.use(mcpAuthMiddleware);
9209
9965
  app.use(
9210
9966
  (err, _req, res, next) => {
9211
- if (err && typeof err === "object" && "type" in err && err.type === "entity.too.large") {
9967
+ const errorType = err && typeof err === "object" && "type" in err ? err.type : void 0;
9968
+ if (errorType === "entity.too.large") {
9212
9969
  res.status(413).json({ error: "Payload too large" });
9213
9970
  return;
9214
9971
  }
9972
+ if (errorType === "entity.parse.failed") {
9973
+ res.status(400).json({ error: "Malformed JSON request body" });
9974
+ return;
9975
+ }
9215
9976
  next(err);
9216
9977
  }
9217
9978
  );
@@ -9370,6 +10131,15 @@ function createHttpAppRuntime() {
9370
10131
  return;
9371
10132
  }
9372
10133
  if (!isStatefulSessionMode) {
10134
+ if (activeStatelessConnections.size >= config.maxSessions) {
10135
+ respondJsonRpcClientError(
10136
+ res,
10137
+ 503,
10138
+ `Maximum active stateless request limit reached (${config.maxSessions})`,
10139
+ -32e3
10140
+ );
10141
+ return;
10142
+ }
9373
10143
  if (!isInitializeRequest(req.body)) {
9374
10144
  const protocolError = validateRequiredProtocolVersion(
9375
10145
  protocolVersionHeader
@@ -9438,7 +10208,7 @@ function createHttpAppRuntime() {
9438
10208
  }
9439
10209
  hasReservedSessionSlot = true;
9440
10210
  const newTransport = new StreamableHTTPServerTransport({
9441
- sessionIdGenerator: () => randomUUID(),
10211
+ sessionIdGenerator: () => randomUUID2(),
9442
10212
  eventStore: managedEventStore.eventStore,
9443
10213
  onsessioninitialized: (id) => {
9444
10214
  sessionStore.set(id, {
@@ -9508,19 +10278,6 @@ function createHttpAppRuntime() {
9508
10278
  }
9509
10279
  });
9510
10280
  app.get("/mcp", async (req, res) => {
9511
- if (!isStatefulSessionMode) {
9512
- res.status(405).json({
9513
- jsonrpc: "2.0",
9514
- error: {
9515
- code: -32e3,
9516
- message: "GET /mcp is not used in stateless session mode"
9517
- },
9518
- id: null
9519
- });
9520
- return;
9521
- }
9522
- const sessionId = req.headers["mcp-session-id"];
9523
- const protocolVersionHeader = getMcpProtocolVersion(req);
9524
10281
  let requestedToolDomains;
9525
10282
  try {
9526
10283
  requestedToolDomains = parseRequestedToolDomains(req.query.tools);
@@ -9532,6 +10289,158 @@ function createHttpAppRuntime() {
9532
10289
  );
9533
10290
  return;
9534
10291
  }
10292
+ if (!isStatefulSessionMode) {
10293
+ if (activeReplayOperations.size >= config.maxSessions) {
10294
+ respondJsonRpcClientError(
10295
+ res,
10296
+ 503,
10297
+ `Maximum active stateless replay limit reached (${config.maxSessions})`,
10298
+ -32e3
10299
+ );
10300
+ return;
10301
+ }
10302
+ if (!managedEventStore.eventStore || !managedEventStore.acquireReplayLease) {
10303
+ res.setHeader("Allow", "POST");
10304
+ respondJsonRpcClientError(
10305
+ res,
10306
+ 405,
10307
+ "Stateless GET /mcp replay requires MCP_EVENT_STORE=memory or redis",
10308
+ -32e3
10309
+ );
10310
+ return;
10311
+ }
10312
+ const lastEventId = req.headers["last-event-id"];
10313
+ if (typeof lastEventId !== "string" || lastEventId.length === 0) {
10314
+ res.setHeader("Allow", "POST");
10315
+ respondJsonRpcClientError(
10316
+ res,
10317
+ 405,
10318
+ "Stateless GET /mcp only supports replay with Last-Event-ID",
10319
+ -32e3
10320
+ );
10321
+ return;
10322
+ }
10323
+ if (!req.headers.accept?.includes("text/event-stream")) {
10324
+ respondJsonRpcClientError(
10325
+ res,
10326
+ 406,
10327
+ "Not Acceptable: Client must accept text/event-stream",
10328
+ -32e3
10329
+ );
10330
+ return;
10331
+ }
10332
+ const protocolError = validateRequiredProtocolVersion(
10333
+ getMcpProtocolVersion(req)
10334
+ );
10335
+ if (protocolError) {
10336
+ respondJsonRpcClientError(res, 400, protocolError, -32e3);
10337
+ return;
10338
+ }
10339
+ const replayEventStore = managedEventStore.eventStore;
10340
+ if (!replayEventStore) {
10341
+ return;
10342
+ }
10343
+ try {
10344
+ const lease = await managedEventStore.acquireReplayLease(lastEventId);
10345
+ if (lease.status !== "acquired") {
10346
+ if (lease.status === "missing") {
10347
+ respondJsonRpcClientError(
10348
+ res,
10349
+ 400,
10350
+ "Invalid event ID format",
10351
+ -32e3
10352
+ );
10353
+ return;
10354
+ }
10355
+ respondJsonRpcClientError(
10356
+ res,
10357
+ 409,
10358
+ "Conflict: Stream already has an active replay connection",
10359
+ -32e3
10360
+ );
10361
+ return;
10362
+ }
10363
+ const replayOperation = (async () => {
10364
+ try {
10365
+ res.status(200);
10366
+ res.setHeader("Content-Type", "text/event-stream");
10367
+ res.setHeader("Cache-Control", "no-cache, no-transform");
10368
+ res.flushHeaders();
10369
+ let cursor = lastEventId;
10370
+ let finalResponseSeen = false;
10371
+ const deadline = Date.now() + 25e3;
10372
+ while (isReady && !res.destroyed && !finalResponseSeen) {
10373
+ await replayEventStore.replayEventsAfter(cursor, {
10374
+ send: async (eventId, message) => {
10375
+ cursor = eventId;
10376
+ finalResponseSeen = "id" in message && ("result" in message || "error" in message);
10377
+ if (!res.write(
10378
+ `event: message
10379
+ id: ${eventId}
10380
+ data: ${JSON.stringify(message)}
10381
+
10382
+ `
10383
+ )) {
10384
+ await waitForResponseWritable(res);
10385
+ }
10386
+ }
10387
+ });
10388
+ if (finalResponseSeen || res.destroyed) {
10389
+ break;
10390
+ }
10391
+ if (Date.now() >= deadline) {
10392
+ res.write(`id: ${cursor}
10393
+ data:
10394
+
10395
+ `);
10396
+ break;
10397
+ }
10398
+ await new Promise((resolvePoll) => setTimeout(resolvePoll, 100));
10399
+ }
10400
+ if (!res.writableEnded && !res.destroyed) {
10401
+ await new Promise((resolveResponse) => {
10402
+ const done = () => resolveResponse();
10403
+ res.once("finish", done);
10404
+ res.once("close", done);
10405
+ res.end();
10406
+ });
10407
+ }
10408
+ } finally {
10409
+ try {
10410
+ await lease.release();
10411
+ } catch (error) {
10412
+ Logger.error("Failed to release stateless replay lease", {
10413
+ metadata: {
10414
+ error: error instanceof Error ? error.message : String(error)
10415
+ }
10416
+ });
10417
+ }
10418
+ }
10419
+ })();
10420
+ activeReplayOperations.add(replayOperation);
10421
+ try {
10422
+ await replayOperation;
10423
+ } finally {
10424
+ activeReplayOperations.delete(replayOperation);
10425
+ }
10426
+ } catch (error) {
10427
+ if (res.headersSent) {
10428
+ Logger.error("GET /mcp stateless replay failed", {
10429
+ metadata: {
10430
+ error: error instanceof Error ? error.message : String(error)
10431
+ }
10432
+ });
10433
+ if (!res.writableEnded) {
10434
+ res.end();
10435
+ }
10436
+ } else {
10437
+ respondJsonRpcInternalError(res, "GET /mcp stateless", error);
10438
+ }
10439
+ }
10440
+ return;
10441
+ }
10442
+ const sessionId = req.headers["mcp-session-id"];
10443
+ const protocolVersionHeader = getMcpProtocolVersion(req);
9535
10444
  if (!sessionId) {
9536
10445
  res.status(400).json({
9537
10446
  jsonrpc: "2.0",
@@ -9667,6 +10576,13 @@ function createHttpAppRuntime() {
9667
10576
  if (isStatefulSessionMode) {
9668
10577
  await sessionStore.closeAll();
9669
10578
  }
10579
+ await Promise.allSettled(
10580
+ Array.from(
10581
+ activeStatelessConnections,
10582
+ (closeConnection) => closeConnection()
10583
+ )
10584
+ );
10585
+ await Promise.allSettled(activeReplayOperations);
9670
10586
  } finally {
9671
10587
  await managedEventStore.close();
9672
10588
  }
@@ -9715,7 +10631,7 @@ function createHttpAppRuntime() {
9715
10631
  console.log(" GET /ready - Readiness check");
9716
10632
  console.log(" POST /mcp - MCP requests");
9717
10633
  console.log(
9718
- ` GET /mcp - ${isStatefulSessionMode ? "SSE notifications" : "Not used in stateless mode"}`
10634
+ ` GET /mcp - ${isStatefulSessionMode ? "SSE notifications and replay" : managedEventStore.eventStore ? "SSE replay (requires Last-Event-ID)" : "Unavailable (event store off)"}`
9719
10635
  );
9720
10636
  console.log(
9721
10637
  ` DELETE /mcp - ${isStatefulSessionMode ? "Close session" : "Not used in stateless mode"}`
@@ -9730,9 +10646,7 @@ function createHttpAppRuntime() {
9730
10646
  async function shutdown(signal) {
9731
10647
  console.log(`
9732
10648
  [MCP] Received ${signal}, shutting down gracefully...`);
9733
- const rawShutdownTimeout = process.env.MCP_SHUTDOWN_TIMEOUT_MS?.trim();
9734
- const parsedShutdownTimeout = rawShutdownTimeout ? Number.parseInt(rawShutdownTimeout, 10) : 1e4;
9735
- const shutdownTimeoutMs = Number.isFinite(parsedShutdownTimeout) && parsedShutdownTimeout > 0 ? parsedShutdownTimeout : 1e4;
10649
+ const shutdownTimeoutMs = config.shutdownTimeout;
9736
10650
  const forceExitTimer = setTimeout(() => {
9737
10651
  console.error(
9738
10652
  `[MCP] Forced shutdown after ${shutdownTimeoutMs}ms timeout`