portkey-admin-mcp 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/build/index.js CHANGED
@@ -1438,9 +1438,6 @@ var TracingService = class extends BaseService {
1438
1438
  data
1439
1439
  );
1440
1440
  }
1441
- async getTrace(id) {
1442
- return this.get(`/logs/${this.encodePathSegment(id)}`);
1443
- }
1444
1441
  };
1445
1442
 
1446
1443
  // src/services/users.service.ts
@@ -1674,23 +1671,99 @@ var baseAnalyticsSchema = {
1674
1671
  prompt_token_max: z.coerce.number().positive().optional().describe("Maximum number of prompt tokens"),
1675
1672
  completion_token_min: z.coerce.number().positive().optional().describe("Minimum number of completion tokens"),
1676
1673
  completion_token_max: z.coerce.number().positive().optional().describe("Maximum number of completion tokens"),
1677
- status_code: z.string().optional().describe("Filter by specific HTTP status codes (comma-separated)"),
1674
+ status_code: z.string().optional().describe(
1675
+ "Legacy Portkey query param for HTTP status codes. Comma-separated string; prefer status_codes for structured inputs."
1676
+ ),
1678
1677
  weighted_feedback_min: z.coerce.number().min(-10).max(10).optional().describe("Minimum weighted feedback score (-10 to 10)"),
1679
1678
  weighted_feedback_max: z.coerce.number().min(-10).max(10).optional().describe("Maximum weighted feedback score (-10 to 10)"),
1680
- virtual_keys: z.string().optional().describe("Filter by specific virtual key slugs (comma-separated)"),
1681
- configs: z.string().optional().describe("Filter by specific config slugs (comma-separated)"),
1679
+ virtual_keys: z.string().optional().describe(
1680
+ "Legacy Portkey query param for virtual key slugs. Comma-separated string; prefer virtual_key_slugs for structured inputs."
1681
+ ),
1682
+ configs: z.string().optional().describe(
1683
+ "Legacy Portkey query param for config slugs. Comma-separated string; prefer config_slugs for structured inputs."
1684
+ ),
1685
+ status_codes: z.array(z.string()).optional().describe(
1686
+ "Structured alias for status_code. Use an array of HTTP status codes; normalized to the legacy comma-separated Portkey query param."
1687
+ ),
1688
+ virtual_key_slugs: z.array(z.string()).optional().describe(
1689
+ "Structured alias for virtual_keys. Use an array of virtual key slugs; normalized to the legacy comma-separated Portkey query param."
1690
+ ),
1691
+ config_slugs: z.array(z.string()).optional().describe(
1692
+ "Structured alias for configs. Use an array of config slugs; normalized to the legacy comma-separated Portkey query param."
1693
+ ),
1682
1694
  workspace_slug: z.string().optional().describe("Filter by specific workspace"),
1683
- api_key_ids: z.string().optional().describe("Filter by specific API key UUIDs (comma-separated)"),
1695
+ api_key_ids: z.preprocess((value) => {
1696
+ if (value == null) {
1697
+ return value;
1698
+ }
1699
+ if (Array.isArray(value)) {
1700
+ return value.map((item) => String(item)).join(",");
1701
+ }
1702
+ return value;
1703
+ }, z.string().optional()).describe(
1704
+ "Legacy Portkey query param for API key UUIDs. Comma-separated string; request_analytics also accepts an array and normalizes it to this form."
1705
+ ),
1684
1706
  metadata: z.string().optional().describe(
1685
- `Stringified JSON object for metadata filtering, e.g. '{"env":"prod","app":"myapp"}'.`
1707
+ `Legacy Portkey query param for metadata filtering. Stringified JSON object, e.g. '{"env":"prod","app":"myapp"}'; prefer metadata_filter for structured inputs.`
1686
1708
  ),
1687
1709
  ai_org_model: z.string().optional().describe(
1688
- "Filter by provider and model, format: 'provider__model' with double underscore, e.g. 'openai__gpt-4' or 'anthropic__claude-3-opus'. Comma-separated for multiple."
1710
+ "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."
1711
+ ),
1712
+ provider_models: z.array(z.string()).optional().describe(
1713
+ "Structured alias for ai_org_model. Use provider__model strings in an array; normalized to the legacy comma-separated Portkey query param."
1714
+ ),
1715
+ trace_id: z.string().optional().describe(
1716
+ "Legacy Portkey query param for trace IDs. Comma-separated string; prefer trace_ids for structured inputs."
1717
+ ),
1718
+ trace_ids: z.array(z.string()).optional().describe(
1719
+ "Structured alias for trace_id. Use an array of trace IDs; normalized to the legacy comma-separated Portkey query param."
1720
+ ),
1721
+ span_id: z.string().optional().describe(
1722
+ "Legacy Portkey query param for span IDs. Comma-separated string; prefer span_ids for structured inputs."
1723
+ ),
1724
+ span_ids: z.array(z.string()).optional().describe(
1725
+ "Structured alias for span_id. Use an array of span IDs; normalized to the legacy comma-separated Portkey query param."
1726
+ ),
1727
+ metadata_filter: z.record(z.string(), z.unknown()).optional().describe(
1728
+ "Structured alias for metadata. Use an object such as { env: 'prod' }; normalized to a JSON string before the request is sent."
1689
1729
  ),
1690
- trace_id: z.string().optional().describe("Filter by trace IDs (comma-separated)"),
1691
- span_id: z.string().optional().describe("Filter by span IDs (comma-separated)"),
1692
1730
  prompt_slug: z.string().optional().describe("Filter by prompt slug")
1693
1731
  };
1732
+ var requestAnalyticsSchema = {
1733
+ ...baseAnalyticsSchema,
1734
+ status_codes: z.array(z.string()).optional().describe(
1735
+ "Structured alias for status_code. Use an array of HTTP status codes; normalized to the legacy comma-separated Portkey query param."
1736
+ ),
1737
+ virtual_key_slugs: z.array(z.string()).optional().describe(
1738
+ "Structured alias for virtual_keys. Use an array of virtual key slugs; normalized to the legacy comma-separated Portkey query param."
1739
+ ),
1740
+ config_slugs: z.array(z.string()).optional().describe(
1741
+ "Structured alias for configs. Use an array of config slugs; normalized to the legacy comma-separated Portkey query param."
1742
+ ),
1743
+ api_key_ids: z.preprocess((value) => {
1744
+ if (value == null) {
1745
+ return value;
1746
+ }
1747
+ if (Array.isArray(value)) {
1748
+ return value.map((item) => String(item)).join(",");
1749
+ }
1750
+ return value;
1751
+ }, z.string().optional()).describe(
1752
+ "API key UUIDs. Accepts the legacy comma-separated string or a structured array; normalized to the legacy Portkey query param before the request is sent."
1753
+ ),
1754
+ trace_ids: z.array(z.string()).optional().describe(
1755
+ "Structured alias for trace_id. Use an array of trace IDs; normalized to the legacy comma-separated Portkey query param."
1756
+ ),
1757
+ span_ids: z.array(z.string()).optional().describe(
1758
+ "Structured alias for span_id. Use an array of span IDs; normalized to the legacy comma-separated Portkey query param."
1759
+ ),
1760
+ provider_models: z.array(z.string()).optional().describe(
1761
+ "Structured alias for ai_org_model. Use provider__model strings in an array; normalized to the legacy comma-separated Portkey query param."
1762
+ ),
1763
+ metadata_filter: z.record(z.string(), z.unknown()).optional().describe(
1764
+ "Structured alias for metadata. Use an object such as { env: 'prod' }; normalized to a JSON string before the request is sent."
1765
+ )
1766
+ };
1694
1767
  var paginatedAnalyticsSchema = {
1695
1768
  ...baseAnalyticsSchema,
1696
1769
  current_page: z.coerce.number().positive().optional().describe("Page number for pagination"),
@@ -1717,13 +1790,88 @@ function formatGroupedAnalytics(analytics, groupLabel) {
1717
1790
  [groupLabel]: analytics.data
1718
1791
  };
1719
1792
  }
1793
+ function normalizeCommaSeparatedParam(value) {
1794
+ if (value == null) {
1795
+ return void 0;
1796
+ }
1797
+ if (Array.isArray(value)) {
1798
+ return value.map((item) => String(item)).join(",");
1799
+ }
1800
+ if (typeof value === "string") {
1801
+ return value;
1802
+ }
1803
+ return void 0;
1804
+ }
1805
+ function normalizeMetadataFilter(value) {
1806
+ if (value == null) {
1807
+ return void 0;
1808
+ }
1809
+ if (typeof value === "string") {
1810
+ return value;
1811
+ }
1812
+ if (typeof value === "object") {
1813
+ return JSON.stringify(value);
1814
+ }
1815
+ return void 0;
1816
+ }
1817
+ function normalizeAnalyticsParams(params) {
1818
+ const {
1819
+ status_codes,
1820
+ virtual_key_slugs,
1821
+ config_slugs,
1822
+ api_key_ids,
1823
+ trace_ids,
1824
+ span_ids,
1825
+ provider_models,
1826
+ metadata_filter,
1827
+ ...legacyParams
1828
+ } = params;
1829
+ const normalizedParams = {
1830
+ ...legacyParams
1831
+ };
1832
+ const statusCode = normalizeCommaSeparatedParam(status_codes) ?? normalizeCommaSeparatedParam(legacyParams.status_code);
1833
+ if (statusCode !== void 0) {
1834
+ normalizedParams.status_code = statusCode;
1835
+ }
1836
+ const virtualKeys = normalizeCommaSeparatedParam(virtual_key_slugs) ?? normalizeCommaSeparatedParam(legacyParams.virtual_keys);
1837
+ if (virtualKeys !== void 0) {
1838
+ normalizedParams.virtual_keys = virtualKeys;
1839
+ }
1840
+ const configs = normalizeCommaSeparatedParam(config_slugs) ?? normalizeCommaSeparatedParam(legacyParams.configs);
1841
+ if (configs !== void 0) {
1842
+ normalizedParams.configs = configs;
1843
+ }
1844
+ const apiKeyIds = normalizeCommaSeparatedParam(api_key_ids) ?? normalizeCommaSeparatedParam(legacyParams.api_key_ids);
1845
+ if (apiKeyIds !== void 0) {
1846
+ normalizedParams.api_key_ids = apiKeyIds;
1847
+ }
1848
+ const metadata = normalizeMetadataFilter(metadata_filter) ?? normalizeMetadataFilter(legacyParams.metadata);
1849
+ if (metadata !== void 0) {
1850
+ normalizedParams.metadata = metadata;
1851
+ }
1852
+ const providerModels = normalizeCommaSeparatedParam(provider_models) ?? normalizeCommaSeparatedParam(legacyParams.ai_org_model);
1853
+ if (providerModels !== void 0) {
1854
+ normalizedParams.ai_org_model = providerModels;
1855
+ }
1856
+ const traceId = normalizeCommaSeparatedParam(trace_ids) ?? normalizeCommaSeparatedParam(legacyParams.trace_id);
1857
+ if (traceId !== void 0) {
1858
+ normalizedParams.trace_id = traceId;
1859
+ }
1860
+ const spanId = normalizeCommaSeparatedParam(span_ids) ?? normalizeCommaSeparatedParam(legacyParams.span_id);
1861
+ if (spanId !== void 0) {
1862
+ normalizedParams.span_id = spanId;
1863
+ }
1864
+ return normalizedParams;
1865
+ }
1720
1866
  function registerAnalyticsTools(server, service) {
1721
1867
  server.tool(
1722
1868
  "get_cost_analytics",
1723
- "Retrieve detailed cost analytics data over time, including total costs and averages per request",
1869
+ "Returns time-series of total and average cost per request over the specified period. Use to track spending trends and identify cost spikes. Differs from get_token_analytics which measures token consumption, not monetary cost. Requires time_of_generation_min and time_of_generation_max.",
1724
1870
  baseAnalyticsSchema,
1725
1871
  async (params) => {
1726
- const analytics = await service.analytics.getCostAnalytics(params);
1872
+ const analytics = await service.analytics.getCostAnalytics(
1873
+ normalizeAnalyticsParams(params)
1874
+ );
1727
1875
  const dataPoints = analytics.data_points.map((point) => ({
1728
1876
  timestamp: point.timestamp,
1729
1877
  total_cost: point.total,
@@ -1751,10 +1899,12 @@ function registerAnalyticsTools(server, service) {
1751
1899
  );
1752
1900
  server.tool(
1753
1901
  "get_request_analytics",
1754
- "Retrieve request analytics as time-series data, showing total, successful, and failed requests over time",
1755
- baseAnalyticsSchema,
1902
+ "Returns time-series of total, successful, and failed request counts over the specified period. Use to monitor traffic volume and success/failure trends. Differs from get_error_analytics which only shows error counts. Requires time_of_generation_min and time_of_generation_max.",
1903
+ requestAnalyticsSchema,
1756
1904
  async (params) => {
1757
- const analytics = await service.analytics.getRequestAnalytics(params);
1905
+ const analytics = await service.analytics.getRequestAnalytics(
1906
+ normalizeAnalyticsParams(params)
1907
+ );
1758
1908
  const dataPoints = analytics.data_points.map((point) => ({
1759
1909
  timestamp: point.timestamp,
1760
1910
  total: point.total,
@@ -1784,10 +1934,12 @@ function registerAnalyticsTools(server, service) {
1784
1934
  );
1785
1935
  server.tool(
1786
1936
  "get_token_analytics",
1787
- "Retrieve token usage analytics as time-series data, showing total, prompt, and completion tokens over time",
1937
+ "Returns time-series of total, prompt, and completion token counts over the specified period. Use to track token consumption and identify usage patterns. Differs from get_cost_analytics which shows monetary cost, not token volume. Requires time_of_generation_min and time_of_generation_max.",
1788
1938
  baseAnalyticsSchema,
1789
1939
  async (params) => {
1790
- const analytics = await service.analytics.getTokenAnalytics(params);
1940
+ const analytics = await service.analytics.getTokenAnalytics(
1941
+ normalizeAnalyticsParams(params)
1942
+ );
1791
1943
  const dataPoints = analytics.data_points.map((point) => ({
1792
1944
  timestamp: point.timestamp,
1793
1945
  total: point.total,
@@ -1817,10 +1969,12 @@ function registerAnalyticsTools(server, service) {
1817
1969
  );
1818
1970
  server.tool(
1819
1971
  "get_latency_analytics",
1820
- "Retrieve latency analytics as time-series data, showing average, p50, p90, and p99 latency percentiles over time",
1972
+ "Returns time-series of avg, p50, p90, and p99 latency percentiles in ms over the specified period. Use to monitor response times and detect latency regressions. Differs from get_cache_hit_latency which only measures latency for cached responses. Requires time_of_generation_min and time_of_generation_max.",
1821
1973
  baseAnalyticsSchema,
1822
1974
  async (params) => {
1823
- const analytics = await service.analytics.getLatencyAnalytics(params);
1975
+ const analytics = await service.analytics.getLatencyAnalytics(
1976
+ normalizeAnalyticsParams(params)
1977
+ );
1824
1978
  const dataPoints = analytics.data_points.map((point) => ({
1825
1979
  timestamp: point.timestamp,
1826
1980
  avg: point.avg,
@@ -1852,10 +2006,12 @@ function registerAnalyticsTools(server, service) {
1852
2006
  );
1853
2007
  server.tool(
1854
2008
  "get_error_analytics",
1855
- "Retrieve error count analytics as time-series data, showing total error counts over time",
2009
+ "Returns time-series of total error counts over the specified period. Use for high-level error trend monitoring. For error breakdown by status code, use get_error_status_codes_analytics or get_error_stacks_analytics; for error rate as a percentage, use get_error_rate_analytics. Requires time_of_generation_min and time_of_generation_max.",
1856
2010
  baseAnalyticsSchema,
1857
2011
  async (params) => {
1858
- const analytics = await service.analytics.getErrorAnalytics(params);
2012
+ const analytics = await service.analytics.getErrorAnalytics(
2013
+ normalizeAnalyticsParams(params)
2014
+ );
1859
2015
  const dataPoints = analytics.data_points.map((point) => ({
1860
2016
  timestamp: point.timestamp,
1861
2017
  total_errors: point.total
@@ -1881,10 +2037,12 @@ function registerAnalyticsTools(server, service) {
1881
2037
  );
1882
2038
  server.tool(
1883
2039
  "get_error_rate_analytics",
1884
- "Retrieve error rate analytics as time-series data, showing the percentage of failed requests over time",
2040
+ "Returns time-series of error rate as a percentage of total requests over the specified period. Use to track reliability trends and SLA compliance. Differs from get_error_analytics which shows absolute error counts, not percentages. Requires time_of_generation_min and time_of_generation_max.",
1885
2041
  baseAnalyticsSchema,
1886
2042
  async (params) => {
1887
- const analytics = await service.analytics.getErrorRateAnalytics(params);
2043
+ const analytics = await service.analytics.getErrorRateAnalytics(
2044
+ normalizeAnalyticsParams(params)
2045
+ );
1888
2046
  const dataPoints = analytics.data_points.map((point) => ({
1889
2047
  timestamp: point.timestamp,
1890
2048
  error_rate_percent: point.rate
@@ -1910,10 +2068,12 @@ function registerAnalyticsTools(server, service) {
1910
2068
  );
1911
2069
  server.tool(
1912
2070
  "get_cache_hit_latency",
1913
- "Retrieve cache hit latency analytics as time-series data, showing total and average latency for cache hits over time",
2071
+ "Returns time-series of latency specifically for cache hits over the specified period. Use to evaluate cache performance and response speed for cached requests. Differs from get_latency_analytics which measures latency across all requests. Requires time_of_generation_min and time_of_generation_max.",
1914
2072
  baseAnalyticsSchema,
1915
2073
  async (params) => {
1916
- const analytics = await service.analytics.getCacheHitLatency(params);
2074
+ const analytics = await service.analytics.getCacheHitLatency(
2075
+ normalizeAnalyticsParams(params)
2076
+ );
1917
2077
  const dataPoints = analytics.data_points.map((point) => ({
1918
2078
  timestamp: point.timestamp,
1919
2079
  total: point.total,
@@ -1941,10 +2101,12 @@ function registerAnalyticsTools(server, service) {
1941
2101
  );
1942
2102
  server.tool(
1943
2103
  "get_cache_hit_rate",
1944
- "Retrieve cache hit rate analytics as time-series data, showing hit rate percentage, total hits, and misses over time",
2104
+ "Returns time-series of cache hit rate percentage, total hits, and misses over the specified period. Use to evaluate cache effectiveness and tune caching strategy. Unrelated to get_cache_hit_latency which measures speed of cached responses, not hit/miss ratio. Requires time_of_generation_min and time_of_generation_max.",
1945
2105
  baseAnalyticsSchema,
1946
2106
  async (params) => {
1947
- const analytics = await service.analytics.getCacheHitRate(params);
2107
+ const analytics = await service.analytics.getCacheHitRate(
2108
+ normalizeAnalyticsParams(params)
2109
+ );
1948
2110
  const dataPoints = analytics.data_points.map((point) => ({
1949
2111
  timestamp: point.timestamp,
1950
2112
  rate: point.rate,
@@ -1974,10 +2136,12 @@ function registerAnalyticsTools(server, service) {
1974
2136
  );
1975
2137
  server.tool(
1976
2138
  "get_users_analytics",
1977
- "Retrieve user activity analytics over time, showing active and new user counts",
2139
+ "Returns time-series of active and new user counts over the specified period. Use for user growth tracking and adoption metrics. Differs from get_user_requests_analytics which shows per-user request breakdown, and get_analytics_group_users which shows per-user cost/token data. Requires time_of_generation_min and time_of_generation_max.",
1978
2140
  baseAnalyticsSchema,
1979
2141
  async (params) => {
1980
- const analytics = await service.analytics.getUsersAnalytics(params);
2142
+ const analytics = await service.analytics.getUsersAnalytics(
2143
+ normalizeAnalyticsParams(params)
2144
+ );
1981
2145
  const dataPoints = analytics.data_points.map((point) => ({
1982
2146
  timestamp: point.timestamp,
1983
2147
  active_users: point.active_users,
@@ -2005,10 +2169,12 @@ function registerAnalyticsTools(server, service) {
2005
2169
  );
2006
2170
  server.tool(
2007
2171
  "get_error_stacks_analytics",
2008
- "Retrieve error analytics broken down by status code stacks over time",
2172
+ "Returns errors broken down by status code stacks (e.g., 429, 500, 502) over the specified period. Use to identify which error types are most common and how they trend. Differs from get_error_status_codes_analytics which shows unique code distribution rather than stacked/cumulative breakdown. Requires time_of_generation_min and time_of_generation_max.",
2009
2173
  baseAnalyticsSchema,
2010
2174
  async (params) => {
2011
- const analytics = await service.analytics.getErrorStacksAnalytics(params);
2175
+ const analytics = await service.analytics.getErrorStacksAnalytics(
2176
+ normalizeAnalyticsParams(params)
2177
+ );
2012
2178
  return {
2013
2179
  content: [
2014
2180
  {
@@ -2025,10 +2191,12 @@ function registerAnalyticsTools(server, service) {
2025
2191
  );
2026
2192
  server.tool(
2027
2193
  "get_error_status_codes_analytics",
2028
- "Retrieve unique error status code distribution analytics over time",
2194
+ "Returns distribution of unique HTTP error status codes over the specified period. Use to see which status codes are occurring and their frequency. Differs from get_error_stacks_analytics which shows stacked/cumulative error breakdown rather than individual code distribution. Requires time_of_generation_min and time_of_generation_max.",
2029
2195
  baseAnalyticsSchema,
2030
2196
  async (params) => {
2031
- const analytics = await service.analytics.getErrorStatusCodesAnalytics(params);
2197
+ const analytics = await service.analytics.getErrorStatusCodesAnalytics(
2198
+ normalizeAnalyticsParams(params)
2199
+ );
2032
2200
  return {
2033
2201
  content: [
2034
2202
  {
@@ -2045,10 +2213,12 @@ function registerAnalyticsTools(server, service) {
2045
2213
  );
2046
2214
  server.tool(
2047
2215
  "get_user_requests_analytics",
2048
- "Retrieve per-user request count analytics over time",
2216
+ "Returns per-user request count breakdown over the specified period. Use to identify heavy users and per-user traffic patterns. Differs from get_users_analytics which shows aggregate active/new user counts, not individual user breakdowns. Requires time_of_generation_min and time_of_generation_max.",
2049
2217
  baseAnalyticsSchema,
2050
2218
  async (params) => {
2051
- const analytics = await service.analytics.getUserRequestsAnalytics(params);
2219
+ const analytics = await service.analytics.getUserRequestsAnalytics(
2220
+ normalizeAnalyticsParams(params)
2221
+ );
2052
2222
  return {
2053
2223
  content: [
2054
2224
  {
@@ -2065,10 +2235,12 @@ function registerAnalyticsTools(server, service) {
2065
2235
  );
2066
2236
  server.tool(
2067
2237
  "get_rescued_requests_analytics",
2068
- "Retrieve analytics for requests rescued by retry or fallback strategies over time",
2238
+ "Returns time-series of requests saved by retry or fallback strategies over the specified period. Use to evaluate the effectiveness of your Portkey configs' resilience features. Only relevant if configs include retry or fallback targets. Requires time_of_generation_min and time_of_generation_max.",
2069
2239
  baseAnalyticsSchema,
2070
2240
  async (params) => {
2071
- const analytics = await service.analytics.getRescuedRequestsAnalytics(params);
2241
+ const analytics = await service.analytics.getRescuedRequestsAnalytics(
2242
+ normalizeAnalyticsParams(params)
2243
+ );
2072
2244
  return {
2073
2245
  content: [
2074
2246
  {
@@ -2085,10 +2257,12 @@ function registerAnalyticsTools(server, service) {
2085
2257
  );
2086
2258
  server.tool(
2087
2259
  "get_feedback_analytics",
2088
- "Retrieve feedback submission analytics over time",
2260
+ "Returns time-series of feedback submission counts over the specified period. Use to track feedback volume trends. For breakdown by model, use get_feedback_models_analytics; for score distribution, use get_feedback_scores_analytics; for weighted scores, use get_feedback_weighted_analytics. Requires time_of_generation_min and time_of_generation_max.",
2089
2261
  baseAnalyticsSchema,
2090
2262
  async (params) => {
2091
- const analytics = await service.analytics.getFeedbackAnalytics(params);
2263
+ const analytics = await service.analytics.getFeedbackAnalytics(
2264
+ normalizeAnalyticsParams(params)
2265
+ );
2092
2266
  return {
2093
2267
  content: [
2094
2268
  {
@@ -2105,10 +2279,12 @@ function registerAnalyticsTools(server, service) {
2105
2279
  );
2106
2280
  server.tool(
2107
2281
  "get_feedback_models_analytics",
2108
- "Retrieve feedback analytics grouped by AI model over time",
2282
+ "Returns feedback counts grouped by AI model over the specified period. Use to compare user satisfaction and feedback volume across different models. Differs from get_feedback_analytics which shows total volume without model breakdown. Requires time_of_generation_min and time_of_generation_max.",
2109
2283
  baseAnalyticsSchema,
2110
2284
  async (params) => {
2111
- const analytics = await service.analytics.getFeedbackModelsAnalytics(params);
2285
+ const analytics = await service.analytics.getFeedbackModelsAnalytics(
2286
+ normalizeAnalyticsParams(params)
2287
+ );
2112
2288
  return {
2113
2289
  content: [
2114
2290
  {
@@ -2125,10 +2301,12 @@ function registerAnalyticsTools(server, service) {
2125
2301
  );
2126
2302
  server.tool(
2127
2303
  "get_feedback_scores_analytics",
2128
- "Retrieve feedback score distribution analytics over time",
2304
+ "Returns distribution of raw feedback score values over the specified period. Use to understand score patterns (e.g., mostly positive vs mixed). Differs from get_feedback_weighted_analytics which applies weight factors for calibrated metrics. Requires time_of_generation_min and time_of_generation_max.",
2129
2305
  baseAnalyticsSchema,
2130
2306
  async (params) => {
2131
- const analytics = await service.analytics.getFeedbackScoresAnalytics(params);
2307
+ const analytics = await service.analytics.getFeedbackScoresAnalytics(
2308
+ normalizeAnalyticsParams(params)
2309
+ );
2132
2310
  return {
2133
2311
  content: [
2134
2312
  {
@@ -2145,10 +2323,12 @@ function registerAnalyticsTools(server, service) {
2145
2323
  );
2146
2324
  server.tool(
2147
2325
  "get_feedback_weighted_analytics",
2148
- "Retrieve weighted feedback analytics over time",
2326
+ "Returns weighted feedback scores over the specified period, applying the weight factor set during feedback creation. Use for calibrated quality metrics where different feedback types have different importance. Differs from get_feedback_scores_analytics which shows raw unweighted scores. Requires time_of_generation_min and time_of_generation_max.",
2149
2327
  baseAnalyticsSchema,
2150
2328
  async (params) => {
2151
- const analytics = await service.analytics.getFeedbackWeightedAnalytics(params);
2329
+ const analytics = await service.analytics.getFeedbackWeightedAnalytics(
2330
+ normalizeAnalyticsParams(params)
2331
+ );
2152
2332
  return {
2153
2333
  content: [
2154
2334
  {
@@ -2165,10 +2345,12 @@ function registerAnalyticsTools(server, service) {
2165
2345
  );
2166
2346
  server.tool(
2167
2347
  "get_analytics_group_users",
2168
- "Retrieve analytics data grouped by user with pagination",
2348
+ "Returns analytics data aggregated per user with pagination, showing each user's request count, cost, and token usage. Use for per-user billing, audit, or identifying top consumers. Differs from get_users_analytics which shows aggregate active/new user counts over time. Requires time_of_generation_min and time_of_generation_max.",
2169
2349
  paginatedAnalyticsSchema,
2170
2350
  async (params) => {
2171
- const analytics = await service.analytics.getAnalyticsGroupUsers(params);
2351
+ const analytics = await service.analytics.getAnalyticsGroupUsers(
2352
+ normalizeAnalyticsParams(params)
2353
+ );
2172
2354
  return {
2173
2355
  content: [
2174
2356
  {
@@ -2185,10 +2367,12 @@ function registerAnalyticsTools(server, service) {
2185
2367
  );
2186
2368
  server.tool(
2187
2369
  "get_analytics_group_models",
2188
- "Retrieve analytics data grouped by AI model with pagination",
2370
+ "Returns analytics data aggregated per AI model with pagination, showing each model's request count, cost, and token usage. Use to compare model costs, popularity, and efficiency. Requires time_of_generation_min and time_of_generation_max.",
2189
2371
  paginatedAnalyticsSchema,
2190
2372
  async (params) => {
2191
- const analytics = await service.analytics.getAnalyticsGroupModels(params);
2373
+ const analytics = await service.analytics.getAnalyticsGroupModels(
2374
+ normalizeAnalyticsParams(params)
2375
+ );
2192
2376
  return {
2193
2377
  content: [
2194
2378
  {
@@ -2205,13 +2389,13 @@ function registerAnalyticsTools(server, service) {
2205
2389
  );
2206
2390
  server.tool(
2207
2391
  "get_analytics_group_metadata",
2208
- "Retrieve analytics data grouped by a specific metadata key with pagination",
2392
+ "Returns analytics data grouped by a custom metadata key (e.g., 'env', 'app', 'client_id') with pagination. Use for custom breakdowns like per-environment or per-feature cost analysis. Requires the metadata_key parameter in addition to time_of_generation_min and time_of_generation_max.",
2209
2393
  analyticsGroupMetadataSchema,
2210
2394
  async (params) => {
2211
2395
  const { metadata_key, ...analyticsParams } = params;
2212
2396
  const analytics = await service.analytics.getAnalyticsGroupMetadata(
2213
2397
  metadata_key,
2214
- analyticsParams
2398
+ normalizeAnalyticsParams(analyticsParams)
2215
2399
  );
2216
2400
  return {
2217
2401
  content: [
@@ -2255,7 +2439,7 @@ var AUDIT_TOOL_SCHEMAS = {
2255
2439
  function registerAuditTools(server, service) {
2256
2440
  server.tool(
2257
2441
  "list_audit_logs",
2258
- "Retrieve audit logs for your Portkey organization. Audit logs track all administrative actions including user management, configuration changes, and access events. Supports filtering by time range, actor, action type, and resource.",
2442
+ "Retrieve audit logs for your Portkey organization. Use this for compliance and security reviews. Audit logs track all administrative actions including user management, configuration changes, and access events. Unlike analytics tools which show aggregated metrics, audit logs show individual action events with actor details. Supports filtering by time range, actor, action type, and resource.",
2259
2443
  AUDIT_TOOL_SCHEMAS.listAuditLogs,
2260
2444
  async (params) => {
2261
2445
  const result = await service.audit.listAuditLogs({
@@ -2335,7 +2519,7 @@ var COLLECTIONS_TOOL_SCHEMAS = {
2335
2519
  function registerCollectionsTools(server, service) {
2336
2520
  server.tool(
2337
2521
  "list_collections",
2338
- "List all prompt collections in your Portkey organization. Collections group prompts by app (e.g., hourlink, apizone, research-pilot).",
2522
+ "List all prompt collections in your Portkey organization. Collections organize prompts by application (e.g., hourlink, apizone, research-pilot). Use to discover collection_id values before creating or listing prompts. Returns id, name, and slug per collection.",
2339
2523
  COLLECTIONS_TOOL_SCHEMAS.listCollections,
2340
2524
  async (params) => {
2341
2525
  const collections = await service.collections.listCollections(params);
@@ -2365,7 +2549,7 @@ function registerCollectionsTools(server, service) {
2365
2549
  );
2366
2550
  server.tool(
2367
2551
  "create_collection",
2368
- "Create a new prompt collection for organizing prompts by app. Use one collection per app (hourlink, apizone, research-pilot).",
2552
+ "Create a new prompt collection for organizing prompts by app. Use one collection per app (hourlink, apizone, research-pilot). Returns the new collection_id and slug needed for create_prompt.",
2369
2553
  COLLECTIONS_TOOL_SCHEMAS.createCollection,
2370
2554
  async (params) => {
2371
2555
  const result = await service.collections.createCollection(params);
@@ -2389,7 +2573,7 @@ function registerCollectionsTools(server, service) {
2389
2573
  );
2390
2574
  server.tool(
2391
2575
  "get_collection",
2392
- "Retrieve detailed information about a specific collection",
2576
+ "Retrieve full details of a specific collection by ID or slug, including name, slug, and workspace_id. Use get_collection when you have a specific ID; use list_collections to browse all collections.",
2393
2577
  COLLECTIONS_TOOL_SCHEMAS.getCollection,
2394
2578
  async (params) => {
2395
2579
  const collection = await service.collections.getCollection(
@@ -2418,7 +2602,7 @@ function registerCollectionsTools(server, service) {
2418
2602
  );
2419
2603
  server.tool(
2420
2604
  "update_collection",
2421
- "Update a collection's name or description",
2605
+ "Update a collection's display name or description. Does not affect prompts within the collection.",
2422
2606
  COLLECTIONS_TOOL_SCHEMAS.updateCollection,
2423
2607
  async (params) => {
2424
2608
  await service.collections.updateCollection(params.collection_id, {
@@ -2444,7 +2628,7 @@ function registerCollectionsTools(server, service) {
2444
2628
  );
2445
2629
  server.tool(
2446
2630
  "delete_collection",
2447
- "Delete a collection by ID. This action cannot be undone. Prompts in this collection will become orphaned.",
2631
+ "Delete a prompt collection by ID. This action cannot be undone. Prompts inside the collection are not deleted but lose their grouping and move to the top level. Reassign prompts to another collection first if organization must be preserved.",
2448
2632
  COLLECTIONS_TOOL_SCHEMAS.deleteCollection,
2449
2633
  async (params) => {
2450
2634
  const result = await service.collections.deleteCollection(
@@ -2542,7 +2726,7 @@ function hasConfigSettings(config) {
2542
2726
  function registerConfigsTools(server, service) {
2543
2727
  server.tool(
2544
2728
  "list_configs",
2545
- "Retrieve all configurations in your Portkey organization, including their status and workspace associations",
2729
+ "Retrieve all configurations in your Portkey organization, including their status and workspace associations. Configs define request routing behavior (cache, retry, fallback, load balancing). Use to discover config slugs before inspecting or modifying them.",
2546
2730
  CONFIGS_TOOL_SCHEMAS.listConfigs,
2547
2731
  async () => {
2548
2732
  const configs = await service.configs.listConfigs();
@@ -2576,7 +2760,7 @@ function registerConfigsTools(server, service) {
2576
2760
  );
2577
2761
  server.tool(
2578
2762
  "get_config",
2579
- "Retrieve detailed information about a specific configuration, including cache settings, retry policies, and routing strategy",
2763
+ "Retrieve detailed information about a specific configuration, including cache settings, retry policies, routing strategy, and targets. Use when you need to inspect a config's full settings or clone an existing config's structure.",
2580
2764
  CONFIGS_TOOL_SCHEMAS.getConfig,
2581
2765
  async (params) => {
2582
2766
  const response = await service.configs.getConfig(params.slug);
@@ -2620,7 +2804,7 @@ function registerConfigsTools(server, service) {
2620
2804
  );
2621
2805
  server.tool(
2622
2806
  "create_config",
2623
- "Create a new configuration with cache, retry, and routing settings. At least one setting is required: cache (cache_mode/cache_max_age), retry (retry_attempts/retry_on_status_codes), strategy_mode, or targets.",
2807
+ "Create a new configuration that defines how AI requests are routed, cached, retried, and load-balanced across providers. At least one setting is required: cache (cache_mode/cache_max_age), retry (retry_attempts/retry_on_status_codes), strategy_mode, or targets.",
2624
2808
  CONFIGS_TOOL_SCHEMAS.createConfig,
2625
2809
  async (params) => {
2626
2810
  const config = buildConfigPayload(params);
@@ -2660,7 +2844,7 @@ function registerConfigsTools(server, service) {
2660
2844
  );
2661
2845
  server.tool(
2662
2846
  "update_config",
2663
- "Update an existing configuration's cache, retry, or routing settings",
2847
+ "Update an existing configuration's cache, retry, or routing settings. Creates a new version; only provided fields are updated, unspecified fields remain unchanged.",
2664
2848
  CONFIGS_TOOL_SCHEMAS.updateConfig,
2665
2849
  async (params) => {
2666
2850
  const config = buildConfigPayload(params);
@@ -2695,7 +2879,7 @@ function registerConfigsTools(server, service) {
2695
2879
  );
2696
2880
  server.tool(
2697
2881
  "delete_config",
2698
- "Delete a configuration by slug. This action cannot be undone.",
2882
+ "Delete a configuration by slug. This action cannot be undone and removes all versions. Requests and API keys referencing this config slug will fail immediately. Use list_config_versions first to review history; audit dependent API keys before deleting.",
2699
2883
  CONFIGS_TOOL_SCHEMAS.deleteConfig,
2700
2884
  async (params) => {
2701
2885
  const result = await service.configs.deleteConfig(params.slug);
@@ -2718,7 +2902,7 @@ function registerConfigsTools(server, service) {
2718
2902
  );
2719
2903
  server.tool(
2720
2904
  "list_config_versions",
2721
- "List all versions of a configuration to view its change history",
2905
+ "List all versions of a configuration to view its change history. Use to audit past changes, compare versions, or find a specific version ID for rollback.",
2722
2906
  CONFIGS_TOOL_SCHEMAS.listConfigVersions,
2723
2907
  async (params) => {
2724
2908
  const result = await service.configs.listConfigVersions(params.slug);
@@ -2800,7 +2984,7 @@ var GUARDRAILS_TOOL_SCHEMAS = {
2800
2984
  function registerGuardrailsTools(server, service) {
2801
2985
  server.tool(
2802
2986
  "list_guardrails",
2803
- "List all guardrails in your Portkey organization with optional filtering by workspace or organization",
2987
+ "List all guardrails in your Portkey organization with optional filtering by workspace or organization. Guardrails are content moderation and security policies applied to AI requests. Use to discover guardrail IDs and slugs before inspecting or modifying them.",
2804
2988
  GUARDRAILS_TOOL_SCHEMAS.listGuardrails,
2805
2989
  async (params) => {
2806
2990
  const result = await service.guardrails.listGuardrails(params);
@@ -2834,7 +3018,7 @@ function registerGuardrailsTools(server, service) {
2834
3018
  );
2835
3019
  server.tool(
2836
3020
  "get_guardrail",
2837
- "Retrieve detailed information about a specific guardrail, including its checks and actions configuration",
3021
+ "Retrieve detailed information about a specific guardrail, including its full checks and actions configuration. Use when you need to inspect or modify a guardrail's rules, or to understand what checks are applied before updating.",
2838
3022
  GUARDRAILS_TOOL_SCHEMAS.getGuardrail,
2839
3023
  async (params) => {
2840
3024
  const guardrail = await service.guardrails.getGuardrail(
@@ -2869,7 +3053,7 @@ function registerGuardrailsTools(server, service) {
2869
3053
  );
2870
3054
  server.tool(
2871
3055
  "create_guardrail",
2872
- "Create a new guardrail with specified checks and actions for content moderation and security. checks is an array of check objects with id (e.g. 'default.jwt', 'default.pii'), optional name, is_enabled boolean, and parameters object.",
3056
+ "Create a new guardrail with specified checks and actions for content moderation and security. Guardrails are applied to requests via configs -- create the guardrail first, then reference it in a config. checks is an array of check objects with id (e.g. 'default.jwt', 'default.pii'), optional name, is_enabled boolean, and parameters object.",
2873
3057
  GUARDRAILS_TOOL_SCHEMAS.createGuardrail,
2874
3058
  async (params) => {
2875
3059
  const result = await service.guardrails.createGuardrail({
@@ -2900,7 +3084,7 @@ function registerGuardrailsTools(server, service) {
2900
3084
  );
2901
3085
  server.tool(
2902
3086
  "update_guardrail",
2903
- "Update an existing guardrail's name, checks, or actions configuration",
3087
+ "Update an existing guardrail's name, checks, or actions configuration. Creates a new version of the guardrail; existing references in configs continue working with the latest version.",
2904
3088
  GUARDRAILS_TOOL_SCHEMAS.updateGuardrail,
2905
3089
  async (params) => {
2906
3090
  const updateData = {};
@@ -2938,7 +3122,7 @@ function registerGuardrailsTools(server, service) {
2938
3122
  );
2939
3123
  server.tool(
2940
3124
  "delete_guardrail",
2941
- "Delete a guardrail by its ID or slug. This action cannot be undone.",
3125
+ "Delete a guardrail by its ID or slug. This action cannot be undone. Configs referencing this guardrail as a before/after request hook will stop enforcing it, silently dropping the safety check. Review dependent configs before deleting.",
2942
3126
  GUARDRAILS_TOOL_SCHEMAS.deleteGuardrail,
2943
3127
  async (params) => {
2944
3128
  const result = await service.guardrails.deleteGuardrail(
@@ -3101,7 +3285,7 @@ var INTEGRATIONS_TOOL_SCHEMAS = {
3101
3285
  function registerIntegrationsTools(server, service) {
3102
3286
  server.tool(
3103
3287
  "list_integrations",
3104
- "List all integrations in your Portkey organization with optional filtering by workspace or type",
3288
+ "List org-level connections to AI providers (OpenAI, Anthropic, Azure, etc.) with optional filtering by workspace or type. Use to discover integration slugs for other integration tools. Returns paginated results with id, slug, provider, and status. Differs from list_providers, which shows workspace-scoped provider instances.",
3105
3289
  INTEGRATIONS_TOOL_SCHEMAS.listIntegrations,
3106
3290
  async (params) => {
3107
3291
  const integrations = await service.integrations.listIntegrations({
@@ -3187,7 +3371,7 @@ function registerIntegrationsTools(server, service) {
3187
3371
  );
3188
3372
  server.tool(
3189
3373
  "get_integration",
3190
- "Retrieve detailed information about a specific integration by its slug",
3374
+ "Retrieve detailed information about a specific integration by its slug. Returns full config including masked API key, workspace access settings, and allowed models. Use when you need provider-specific details or to audit an integration's configuration.",
3191
3375
  INTEGRATIONS_TOOL_SCHEMAS.getIntegration,
3192
3376
  async (params) => {
3193
3377
  const integration = await service.integrations.getIntegration(
@@ -3224,7 +3408,7 @@ function registerIntegrationsTools(server, service) {
3224
3408
  );
3225
3409
  server.tool(
3226
3410
  "update_integration",
3227
- "Update an existing integration's name, API key, description, or provider-specific configurations",
3411
+ "Update an existing integration's name, API key, description, or provider-specific configurations. API key changes take effect immediately. Changing provider-specific configs (Azure resource_name, Vertex region, etc.) may break active requests using this integration.",
3228
3412
  INTEGRATIONS_TOOL_SCHEMAS.updateIntegration,
3229
3413
  async (params) => {
3230
3414
  const configurations = {};
@@ -3271,7 +3455,7 @@ function registerIntegrationsTools(server, service) {
3271
3455
  );
3272
3456
  server.tool(
3273
3457
  "delete_integration",
3274
- "Delete an integration by slug. This action cannot be undone.",
3458
+ "Delete an integration by slug. This action cannot be undone. Removes the org-level provider connection; all dependent virtual keys and providers will stop working.",
3275
3459
  INTEGRATIONS_TOOL_SCHEMAS.deleteIntegration,
3276
3460
  async (params) => {
3277
3461
  const result = await service.integrations.deleteIntegration(params.slug);
@@ -3294,7 +3478,7 @@ function registerIntegrationsTools(server, service) {
3294
3478
  );
3295
3479
  server.tool(
3296
3480
  "list_integration_models",
3297
- "List all models available for a specific integration with their enabled status",
3481
+ "List which AI models are enabled for a specific integration, with their enabled/disabled status and custom flag. Use to check model availability before creating prompts or configs. Returns paginated results with model id, name, and enabled state.",
3298
3482
  INTEGRATIONS_TOOL_SCHEMAS.listIntegrationModels,
3299
3483
  async (params) => {
3300
3484
  const models = await service.integrations.listIntegrationModels(
@@ -3332,7 +3516,7 @@ function registerIntegrationsTools(server, service) {
3332
3516
  );
3333
3517
  server.tool(
3334
3518
  "update_integration_models",
3335
- "Update model access settings for an integration - enable/disable models or add custom models",
3519
+ "Enable/disable specific models or register custom model names for an integration. Changes affect all workspaces using this integration. Pass an array of model configurations with slug, enabled state, and optional is_custom flag.",
3336
3520
  INTEGRATIONS_TOOL_SCHEMAS.updateIntegrationModels,
3337
3521
  async (params) => {
3338
3522
  const result = await service.integrations.updateIntegrationModels(
@@ -3361,7 +3545,7 @@ function registerIntegrationsTools(server, service) {
3361
3545
  );
3362
3546
  server.tool(
3363
3547
  "delete_integration_model",
3364
- "Delete a specific custom model from an integration",
3548
+ "Delete a specific custom model from an integration. Only custom models can be deleted; built-in models should be disabled via update_integration_models instead. Returns success status.",
3365
3549
  INTEGRATIONS_TOOL_SCHEMAS.deleteIntegrationModel,
3366
3550
  async (params) => {
3367
3551
  const result = await service.integrations.deleteIntegrationModel(
@@ -3387,7 +3571,7 @@ function registerIntegrationsTools(server, service) {
3387
3571
  );
3388
3572
  server.tool(
3389
3573
  "list_integration_workspaces",
3390
- "List all workspaces that have access to a specific integration",
3574
+ "List which workspaces can access a specific integration, including their usage limits and rate limits. Use to audit workspace access and review per-workspace spending/rate configurations. Returns paginated results.",
3391
3575
  INTEGRATIONS_TOOL_SCHEMAS.listIntegrationWorkspaces,
3392
3576
  async (params) => {
3393
3577
  const workspaces = await service.integrations.listIntegrationWorkspaces(
@@ -3426,7 +3610,7 @@ function registerIntegrationsTools(server, service) {
3426
3610
  );
3427
3611
  server.tool(
3428
3612
  "update_integration_workspaces",
3429
- "Update workspace access settings for an integration - enable/disable workspace access and configure limits",
3613
+ "Control which workspaces can use an integration and set per-workspace usage/rate limits. Pass an array of workspace configurations with id, enabled state, and optional credit_limit, alert_threshold, and rate_limit_rpm.",
3430
3614
  INTEGRATIONS_TOOL_SCHEMAS.updateIntegrationWorkspaces,
3431
3615
  async (params) => {
3432
3616
  const result = await service.integrations.updateIntegrationWorkspaces(
@@ -3554,7 +3738,7 @@ var KEYS_TOOL_SCHEMAS = {
3554
3738
  function registerKeysTools(server, service) {
3555
3739
  server.tool(
3556
3740
  "list_virtual_keys",
3557
- "Retrieve all virtual keys in your Portkey organization, including their usage limits, rate limits, and status",
3741
+ "List virtual keys that securely store provider API keys (OpenAI, Anthropic, etc.) in your Portkey organization. Use to discover virtual key slugs referenced in prompts and configs. Returns all keys with their usage limits, rate limits, and status.",
3558
3742
  KEYS_TOOL_SCHEMAS.listVirtualKeys,
3559
3743
  async () => {
3560
3744
  const virtualKeys = await service.keys.listVirtualKeys();
@@ -3595,7 +3779,7 @@ function registerKeysTools(server, service) {
3595
3779
  );
3596
3780
  server.tool(
3597
3781
  "create_virtual_key",
3598
- "Create a new virtual key for a provider (e.g., openai, anthropic). Virtual keys securely store provider API keys.",
3782
+ "Securely store a provider API key as a virtual key. The original key is encrypted and never returned after creation. Use the returned slug to reference this key in prompts and configs. Supports optional usage/rate limits.",
3599
3783
  KEYS_TOOL_SCHEMAS.createVirtualKey,
3600
3784
  async (params) => {
3601
3785
  const result = await service.keys.createVirtualKey({
@@ -3634,7 +3818,7 @@ function registerKeysTools(server, service) {
3634
3818
  );
3635
3819
  server.tool(
3636
3820
  "get_virtual_key",
3637
- "Retrieve detailed information about a specific virtual key by its slug",
3821
+ "Retrieve detailed information about a specific virtual key by its slug. Returns key metadata with a masked version of the stored API key. Use to check usage limits, rate limits, and status.",
3638
3822
  KEYS_TOOL_SCHEMAS.getVirtualKey,
3639
3823
  async (params) => {
3640
3824
  const virtualKey = await service.keys.getVirtualKey(params.slug);
@@ -3672,7 +3856,7 @@ function registerKeysTools(server, service) {
3672
3856
  );
3673
3857
  server.tool(
3674
3858
  "update_virtual_key",
3675
- "Update an existing virtual key's name, API key, note, or limits",
3859
+ "Update an existing virtual key's name, API key, note, or limits. Can rotate the underlying provider API key by passing a new key value. Changes to limits take effect immediately.",
3676
3860
  KEYS_TOOL_SCHEMAS.updateVirtualKey,
3677
3861
  async (params) => {
3678
3862
  const result = await service.keys.updateVirtualKey(params.slug, {
@@ -3706,7 +3890,7 @@ function registerKeysTools(server, service) {
3706
3890
  );
3707
3891
  server.tool(
3708
3892
  "delete_virtual_key",
3709
- "Delete a virtual key by slug. This action cannot be undone.",
3893
+ "Delete a virtual key by slug. This action cannot be undone. Prompts and configs referencing this key will fail; ensure no active resources depend on it before deleting.",
3710
3894
  KEYS_TOOL_SCHEMAS.deleteVirtualKey,
3711
3895
  async (params) => {
3712
3896
  const result = await service.keys.deleteVirtualKey(params.slug);
@@ -3729,7 +3913,7 @@ function registerKeysTools(server, service) {
3729
3913
  );
3730
3914
  server.tool(
3731
3915
  "create_api_key",
3732
- "Create a new Portkey API key for authentication. Organisation-level keys provide full access, workspace keys are scoped. Scopes control read/write permissions to specific resources (logs, analytics, prompts, etc.).",
3916
+ "Create a new Portkey API key for authentication. Organisation-level keys provide full access, workspace keys are scoped. Scopes control read/write permissions to specific resources (logs, analytics, prompts, etc.). Returns the key value only once at creation time \u2014 save it immediately.",
3733
3917
  KEYS_TOOL_SCHEMAS.createApiKey,
3734
3918
  async (params) => {
3735
3919
  if (params.type === "workspace" && !params.workspace_id) {
@@ -3800,7 +3984,7 @@ function registerKeysTools(server, service) {
3800
3984
  );
3801
3985
  server.tool(
3802
3986
  "list_api_keys",
3803
- "List all API keys in your Portkey organization with optional pagination and workspace filtering",
3987
+ "List Portkey API keys (not provider keys \u2014 use list_virtual_keys for those) with optional pagination and workspace filtering. Use to audit access and review key scopes, limits, and expiration across your organization.",
3804
3988
  KEYS_TOOL_SCHEMAS.listApiKeys,
3805
3989
  async (params) => {
3806
3990
  const apiKeys = await service.keys.listApiKeys({
@@ -3853,7 +4037,7 @@ function registerKeysTools(server, service) {
3853
4037
  );
3854
4038
  server.tool(
3855
4039
  "get_api_key",
3856
- "Retrieve detailed information about a specific API key by its UUID",
4040
+ "Retrieve detailed information about a specific API key by its UUID. Returns key metadata without the secret key value. Use to check scopes, usage/rate limits, defaults, and expiration.",
3857
4041
  KEYS_TOOL_SCHEMAS.getApiKey,
3858
4042
  async (params) => {
3859
4043
  const apiKey = await service.keys.getApiKey(params.id);
@@ -3900,7 +4084,7 @@ function registerKeysTools(server, service) {
3900
4084
  );
3901
4085
  server.tool(
3902
4086
  "update_api_key",
3903
- "Update an existing API key's name, description, scopes, or limits",
4087
+ "Update an existing API key's name, description, scopes, or limits. Can modify scopes, usage/rate limits, defaults, and expiration. Cannot change key type or sub_type after creation.",
3904
4088
  KEYS_TOOL_SCHEMAS.updateApiKey,
3905
4089
  async (params) => {
3906
4090
  const result = await service.keys.updateApiKey(params.id, {
@@ -3938,7 +4122,7 @@ function registerKeysTools(server, service) {
3938
4122
  );
3939
4123
  server.tool(
3940
4124
  "delete_api_key",
3941
- "Delete an API key by UUID. This action cannot be undone.",
4125
+ "Delete an API key by UUID. This action cannot be undone. Immediately revokes authentication; active sessions using this key will fail.",
3942
4126
  KEYS_TOOL_SCHEMAS.deleteApiKey,
3943
4127
  async (params) => {
3944
4128
  const result = await service.keys.deleteApiKey(params.id);
@@ -3998,7 +4182,7 @@ var LABELS_TOOL_SCHEMAS = {
3998
4182
  function registerLabelsTools(server, service) {
3999
4183
  server.tool(
4000
4184
  "create_prompt_label",
4001
- "Create a new prompt label to categorize and organize prompts. Labels can be color-coded and scoped to workspaces or organizations.",
4185
+ "Create a new prompt label to categorize prompt versions (e.g., 'production', 'staging', 'experiment'). Requires either organisation_id or workspace_id to set the label's scope. Returns the new label's id. Use update_prompt_version to assign labels to specific prompt versions.",
4002
4186
  LABELS_TOOL_SCHEMAS.createPromptLabel,
4003
4187
  async (params) => {
4004
4188
  if (!params.organisation_id && !params.workspace_id) {
@@ -4038,7 +4222,7 @@ function registerLabelsTools(server, service) {
4038
4222
  );
4039
4223
  server.tool(
4040
4224
  "list_prompt_labels",
4041
- "List all prompt labels in your Portkey organization with optional filtering by workspace, organisation, or search query",
4225
+ "List all prompt labels with optional filtering by workspace, organisation, or search query. Returns id, name, color_code, and status for each label. Use to discover label IDs before assigning them to prompt versions via update_prompt_version.",
4042
4226
  LABELS_TOOL_SCHEMAS.listPromptLabels,
4043
4227
  async (params) => {
4044
4228
  const result = await service.labels.listLabels(params);
@@ -4070,7 +4254,7 @@ function registerLabelsTools(server, service) {
4070
4254
  );
4071
4255
  server.tool(
4072
4256
  "get_prompt_label",
4073
- "Retrieve detailed information about a specific prompt label",
4257
+ "Retrieve full details of a specific prompt label including its scope (organisation_id vs workspace_id), color, and status. Use when you need to inspect a label's properties before updating it.",
4074
4258
  LABELS_TOOL_SCHEMAS.getPromptLabel,
4075
4259
  async (params) => {
4076
4260
  const label = await service.labels.getLabel(params.label_id, {
@@ -4104,7 +4288,7 @@ function registerLabelsTools(server, service) {
4104
4288
  );
4105
4289
  server.tool(
4106
4290
  "update_prompt_label",
4107
- "Update an existing prompt label's name, description, or color",
4291
+ "Update a prompt label's name, description, or color_code. Changes apply to the label definition only; existing prompt version assignments using this label are not affected.",
4108
4292
  LABELS_TOOL_SCHEMAS.updatePromptLabel,
4109
4293
  async (params) => {
4110
4294
  const { label_id, ...updateData } = params;
@@ -4128,7 +4312,7 @@ function registerLabelsTools(server, service) {
4128
4312
  );
4129
4313
  server.tool(
4130
4314
  "delete_prompt_label",
4131
- "Delete a prompt label by ID. This action cannot be undone.",
4315
+ "Delete a prompt label by ID. This action cannot be undone. Prompt versions carrying this label lose it, and any workflow resolving prompts by this label (e.g., 'production', 'staging') will fail until reassigned. Audit label usage via list_prompts before deleting.",
4132
4316
  LABELS_TOOL_SCHEMAS.deletePromptLabel,
4133
4317
  async (params) => {
4134
4318
  await service.labels.deleteLabel(params.label_id);
@@ -4280,7 +4464,7 @@ function formatUsageLimitEntity(entity) {
4280
4464
  function registerLimitsTools(server, service) {
4281
4465
  server.tool(
4282
4466
  "list_rate_limits",
4283
- "Retrieve all rate limits in your Portkey organization. Rate limits control how many requests or tokens can be consumed per time unit (rpm/rph/rpd).",
4467
+ "Retrieve all rate limits in your Portkey organization. Use to discover existing rate limit policies before creating new ones. Returns an array of rate limits each containing id, type, unit, value, and status. Rate limits control how many requests or tokens can be consumed per time unit (rpm/rph/rpd).",
4284
4468
  LIMITS_TOOL_SCHEMAS.listRateLimits,
4285
4469
  async (params) => {
4286
4470
  const result = await service.limits.listRateLimits(params.workspace_id);
@@ -4303,7 +4487,7 @@ function registerLimitsTools(server, service) {
4303
4487
  );
4304
4488
  server.tool(
4305
4489
  "get_rate_limit",
4306
- "Retrieve detailed information about a specific rate limit by its ID",
4490
+ "Retrieve detailed information about a specific rate limit by its ID. Returns full detail including conditions and group_by fields. Use when you have a specific rate limit ID from list_rate_limits and need to inspect its complete configuration.",
4307
4491
  LIMITS_TOOL_SCHEMAS.getRateLimit,
4308
4492
  async (params) => {
4309
4493
  const result = await service.limits.getRateLimit(params.id);
@@ -4319,7 +4503,7 @@ function registerLimitsTools(server, service) {
4319
4503
  );
4320
4504
  server.tool(
4321
4505
  "create_rate_limit",
4322
- "Create a new rate limit policy to control request/token consumption per time unit. Requires conditions to match against and group_by to specify how limits are applied.",
4506
+ "Create a new rate limit policy to throttle requests in real-time by controlling request/token consumption per time unit. Differs from usage limits, which cap cumulative consumption over time. Requires conditions to match against and group_by to specify how limits are applied.",
4323
4507
  LIMITS_TOOL_SCHEMAS.createRateLimit,
4324
4508
  async (params) => {
4325
4509
  const result = await service.limits.createRateLimit({
@@ -4351,7 +4535,7 @@ function registerLimitsTools(server, service) {
4351
4535
  );
4352
4536
  server.tool(
4353
4537
  "update_rate_limit",
4354
- "Update an existing rate limit's name, unit, or value",
4538
+ "Update an existing rate limit's name, unit, or value. Only name, unit, and value can be changed after creation; conditions and group_by are immutable. Returns the updated rate limit object.",
4355
4539
  LIMITS_TOOL_SCHEMAS.updateRateLimit,
4356
4540
  async (params) => {
4357
4541
  const result = await service.limits.updateRateLimit(params.id, {
@@ -4378,7 +4562,7 @@ function registerLimitsTools(server, service) {
4378
4562
  );
4379
4563
  server.tool(
4380
4564
  "delete_rate_limit",
4381
- "Delete a rate limit by ID. This action cannot be undone.",
4565
+ "Delete a rate limit policy by ID. This action cannot be undone. Requests previously throttled by this policy will no longer be limited; review dependent configs and virtual keys first to avoid unexpected traffic spikes.",
4382
4566
  LIMITS_TOOL_SCHEMAS.deleteRateLimit,
4383
4567
  async (params) => {
4384
4568
  await service.limits.deleteRateLimit(params.id);
@@ -4401,7 +4585,7 @@ function registerLimitsTools(server, service) {
4401
4585
  );
4402
4586
  server.tool(
4403
4587
  "list_usage_limits",
4404
- "Retrieve all usage limits in your Portkey organization. Usage limits control how much cost or tokens can be consumed, with optional periodic resets.",
4588
+ "Retrieve all usage limits in your Portkey organization. Differs from rate limits: usage limits cap total cumulative cost or tokens over time, optionally resetting on a weekly or monthly schedule. Returns an array of usage limits with id, type, credit_limit, status, and reset schedule.",
4405
4589
  LIMITS_TOOL_SCHEMAS.listUsageLimits,
4406
4590
  async (params) => {
4407
4591
  const result = await service.limits.listUsageLimits(params.workspace_id);
@@ -4424,7 +4608,7 @@ function registerLimitsTools(server, service) {
4424
4608
  );
4425
4609
  server.tool(
4426
4610
  "get_usage_limit",
4427
- "Retrieve detailed information about a specific usage limit by its ID",
4611
+ "Retrieve detailed information about a specific usage limit by its ID. Returns full detail including conditions, group_by, credit_limit, alert_threshold, and periodic reset schedule.",
4428
4612
  LIMITS_TOOL_SCHEMAS.getUsageLimit,
4429
4613
  async (params) => {
4430
4614
  const result = await service.limits.getUsageLimit(params.id);
@@ -4440,7 +4624,7 @@ function registerLimitsTools(server, service) {
4440
4624
  );
4441
4625
  server.tool(
4442
4626
  "create_usage_limit",
4443
- "Create a new usage limit policy to control cost or token consumption. Requires conditions to match against and group_by to specify how limits are applied.",
4627
+ "Create a new usage limit policy to enforce spending or token budgets over time. Differs from rate limits, which control real-time request velocity. Requires conditions to match against and group_by to specify how limits are applied. Supports optional periodic resets and alert thresholds.",
4444
4628
  LIMITS_TOOL_SCHEMAS.createUsageLimit,
4445
4629
  async (params) => {
4446
4630
  const result = await service.limits.createUsageLimit({
@@ -4473,7 +4657,7 @@ function registerLimitsTools(server, service) {
4473
4657
  );
4474
4658
  server.tool(
4475
4659
  "update_usage_limit",
4476
- "Update an existing usage limit's configuration",
4660
+ "Update an existing usage limit's configuration. Modifiable fields: name, credit_limit, alert_threshold, periodic_reset, and reset_usage_for_value. Conditions and group_by are immutable after creation.",
4477
4661
  LIMITS_TOOL_SCHEMAS.updateUsageLimit,
4478
4662
  async (params) => {
4479
4663
  const result = await service.limits.updateUsageLimit(params.id, {
@@ -4502,7 +4686,7 @@ function registerLimitsTools(server, service) {
4502
4686
  );
4503
4687
  server.tool(
4504
4688
  "delete_usage_limit",
4505
- "Delete a usage limit by ID. This action cannot be undone.",
4689
+ "Delete a usage limit policy by ID. This action cannot be undone. Budgets and quotas enforced by this policy are removed immediately and tracked entities lose accumulated usage state. Use list_usage_limit_entities first to review impact before deleting.",
4506
4690
  LIMITS_TOOL_SCHEMAS.deleteUsageLimit,
4507
4691
  async (params) => {
4508
4692
  await service.limits.deleteUsageLimit(params.id);
@@ -4525,7 +4709,7 @@ function registerLimitsTools(server, service) {
4525
4709
  );
4526
4710
  server.tool(
4527
4711
  "list_usage_limit_entities",
4528
- "List all entities tracked against a usage limit policy, showing current usage per entity",
4712
+ "List all entities (individual keys, users, or groups) tracked against a usage limit policy. Shows current consumption per entity, useful for monitoring who is approaching or has exceeded their budget.",
4529
4713
  LIMITS_TOOL_SCHEMAS.listUsageLimitEntities,
4530
4714
  async (params) => {
4531
4715
  const result = await service.limits.listUsageLimitEntities(
@@ -4550,7 +4734,7 @@ function registerLimitsTools(server, service) {
4550
4734
  );
4551
4735
  server.tool(
4552
4736
  "reset_usage_limit_entity",
4553
- "Reset accumulated usage for a specific entity on a usage limit policy",
4737
+ "Reset the accumulated usage counter to zero for a specific entity on a usage limit policy. Does not delete the entity or the policy itself. Use when an entity needs its budget restored before the next scheduled periodic reset.",
4554
4738
  LIMITS_TOOL_SCHEMAS.resetUsageLimitEntity,
4555
4739
  async (params) => {
4556
4740
  await service.limits.resetUsageLimitEntity(
@@ -4667,7 +4851,7 @@ var LOGGING_TOOL_SCHEMAS = {
4667
4851
  function registerLoggingTools(server, service) {
4668
4852
  server.tool(
4669
4853
  "insert_log",
4670
- "Insert a log entry (or multiple entries) into Portkey for tracking AI requests and responses. request_provider must match a configured integration (e.g. 'openai', 'anthropic'). Use metadata_span_id and metadata_parent_span_id to create trace hierarchies.",
4854
+ "Insert a log entry (or multiple entries) into Portkey for tracking AI requests and responses. Use this for external or custom logs not routed through the Portkey gateway. request_provider must match a configured integration (e.g. 'openai', 'anthropic'). Use metadata_span_id and metadata_parent_span_id to create trace hierarchies.",
4671
4855
  LOGGING_TOOL_SCHEMAS.insertLog,
4672
4856
  async (params) => {
4673
4857
  const entry = {
@@ -4715,7 +4899,7 @@ function registerLoggingTools(server, service) {
4715
4899
  );
4716
4900
  server.tool(
4717
4901
  "create_log_export",
4718
- "Create a new log export job to export logs matching specified filters. time_min/time_max accept ISO 8601 format ('2024-01-01T00:00:00Z'). requested_fields selects which columns to include.",
4902
+ "Create a new log export job definition with filters and field selection. This only creates the job \u2014 you must call start_log_export to begin processing, then poll get_log_export to check status. time_min/time_max accept ISO 8601 format ('2024-01-01T00:00:00Z'). Returns the export ID and matching log count.",
4719
4903
  LOGGING_TOOL_SCHEMAS.createLogExport,
4720
4904
  async (params) => {
4721
4905
  const result = await service.logging.createLogExport({
@@ -4753,7 +4937,7 @@ function registerLoggingTools(server, service) {
4753
4937
  );
4754
4938
  server.tool(
4755
4939
  "list_log_exports",
4756
- "List all log export jobs for a workspace",
4940
+ "List all log export jobs for a workspace. Returns each export with its current status (pending/running/completed/failed), filters, and timestamps. Use this to find export_ids for subsequent get, start, cancel, or download operations.",
4757
4941
  LOGGING_TOOL_SCHEMAS.listLogExports,
4758
4942
  async (params) => {
4759
4943
  const result = await service.logging.listLogExports({
@@ -4788,7 +4972,7 @@ function registerLoggingTools(server, service) {
4788
4972
  );
4789
4973
  server.tool(
4790
4974
  "get_log_export",
4791
- "Get details of a specific log export by its ID",
4975
+ "Get details of a specific log export by its ID. Use this to check the current status of an export (pending/running/completed/failed) and view its full configuration. Unlike list_log_exports which returns summaries of all exports, this returns complete detail for a single export including filters and requested fields.",
4792
4976
  LOGGING_TOOL_SCHEMAS.getLogExport,
4793
4977
  async (params) => {
4794
4978
  const result = await service.logging.getLogExport(params.export_id);
@@ -4819,7 +5003,7 @@ function registerLoggingTools(server, service) {
4819
5003
  );
4820
5004
  server.tool(
4821
5005
  "start_log_export",
4822
- "Start a log export job that was previously created",
5006
+ "Trigger processing of a previously created log export job. You must call create_log_export first to define the export before starting it. After starting, poll get_log_export to monitor progress until status is 'completed', then use download_log_export to retrieve results.",
4823
5007
  LOGGING_TOOL_SCHEMAS.startLogExport,
4824
5008
  async (params) => {
4825
5009
  const result = await service.logging.startLogExport(params.export_id);
@@ -4843,7 +5027,7 @@ function registerLoggingTools(server, service) {
4843
5027
  );
4844
5028
  server.tool(
4845
5029
  "cancel_log_export",
4846
- "Cancel a running log export job",
5030
+ "Cancel a running or pending log export job. This permanently stops the export \u2014 it cannot be resumed after cancellation. To export the same data, create a new export job with create_log_export.",
4847
5031
  LOGGING_TOOL_SCHEMAS.cancelLogExport,
4848
5032
  async (params) => {
4849
5033
  const result = await service.logging.cancelLogExport(params.export_id);
@@ -5058,7 +5242,7 @@ function formatMcpIntegrationWorkspace(workspace) {
5058
5242
  function registerMcpIntegrationsTools(server, service) {
5059
5243
  server.tool(
5060
5244
  "list_mcp_integrations",
5061
- "List all MCP integrations in your Portkey organization with optional pagination and workspace filtering",
5245
+ "List all MCP integrations in your Portkey organization with optional pagination and workspace filtering. MCP integrations connect external MCP servers to your Portkey org. Use to discover integration IDs needed by other tools. Differs from list_mcp_servers which shows server instances under an integration. Returns paginated array of integrations with total count and has_more flag.",
5062
5246
  MCP_INTEGRATIONS_TOOL_SCHEMAS.listMcpIntegrations,
5063
5247
  async (params) => {
5064
5248
  const result = await service.mcpIntegrations.listMcpIntegrations(params);
@@ -5082,7 +5266,7 @@ function registerMcpIntegrationsTools(server, service) {
5082
5266
  );
5083
5267
  server.tool(
5084
5268
  "create_mcp_integration",
5085
- "Create a new MCP integration in Portkey for connecting external MCP servers to your organization",
5269
+ "Create a new MCP integration by registering an external MCP server URL with auth configuration. After creation, use create_mcp_server to add server instances and update_mcp_integration_capabilities to control which tools are exposed. Returns the new integration's id and slug.",
5086
5270
  MCP_INTEGRATIONS_TOOL_SCHEMAS.createMcpIntegration,
5087
5271
  async (params) => {
5088
5272
  if (params.auth_type === "headers" && (!params.custom_headers || Object.keys(params.custom_headers).length === 0)) {
@@ -5121,7 +5305,7 @@ function registerMcpIntegrationsTools(server, service) {
5121
5305
  );
5122
5306
  server.tool(
5123
5307
  "get_mcp_integration",
5124
- "Retrieve detailed information about a specific MCP integration by ID or slug",
5308
+ "Retrieve detailed information about a specific MCP integration by ID or slug. Returns full integration config including auth type, transport, and configuration keys (header values are masked). Use to inspect Portkey-side connection details. Differs from get_mcp_integration_metadata which returns the external server's self-reported info.",
5125
5309
  MCP_INTEGRATIONS_TOOL_SCHEMAS.getMcpIntegration,
5126
5310
  async (params) => {
5127
5311
  const integration = await service.mcpIntegrations.getMcpIntegration(
@@ -5139,7 +5323,7 @@ function registerMcpIntegrationsTools(server, service) {
5139
5323
  );
5140
5324
  server.tool(
5141
5325
  "update_mcp_integration",
5142
- "Update an existing MCP integration's name, description, URL, auth, or transport",
5326
+ "Update an existing MCP integration's name, description, URL, auth, or transport. Changing url or auth_type may break active connections. Changes take effect immediately for all connected users.",
5143
5327
  MCP_INTEGRATIONS_TOOL_SCHEMAS.updateMcpIntegration,
5144
5328
  async (params) => {
5145
5329
  const { id, custom_headers, ...rest } = params;
@@ -5166,7 +5350,7 @@ function registerMcpIntegrationsTools(server, service) {
5166
5350
  );
5167
5351
  server.tool(
5168
5352
  "delete_mcp_integration",
5169
- "Delete an MCP integration. This action cannot be undone.",
5353
+ "Delete an MCP integration permanently. Also removes all MCP servers under this integration. Connected users will lose access immediately. This action cannot be undone.",
5170
5354
  MCP_INTEGRATIONS_TOOL_SCHEMAS.deleteMcpIntegration,
5171
5355
  async (params) => {
5172
5356
  await service.mcpIntegrations.deleteMcpIntegration(params.id);
@@ -5189,7 +5373,7 @@ function registerMcpIntegrationsTools(server, service) {
5189
5373
  );
5190
5374
  server.tool(
5191
5375
  "get_mcp_integration_metadata",
5192
- "Retrieve metadata for a specific MCP integration",
5376
+ "Retrieve server-reported metadata for an MCP integration including name, version, protocol, and sync status. Use to verify the external server is responding and check its capabilities. Differs from get_mcp_integration which shows Portkey-side config.",
5193
5377
  MCP_INTEGRATIONS_TOOL_SCHEMAS.getMcpIntegrationMetadata,
5194
5378
  async (params) => {
5195
5379
  const metadata = await service.mcpIntegrations.getMcpIntegrationMetadata(
@@ -5211,7 +5395,7 @@ function registerMcpIntegrationsTools(server, service) {
5211
5395
  );
5212
5396
  server.tool(
5213
5397
  "list_mcp_integration_capabilities",
5214
- "List all capabilities (tools, resources, prompts) available on an MCP integration",
5398
+ "List all capabilities (tools, resources, prompts) the external MCP server exposes on an integration. Use before update_mcp_integration_capabilities to see what can be enabled or disabled. Returns total count and array of capabilities with their enabled status.",
5215
5399
  MCP_INTEGRATIONS_TOOL_SCHEMAS.listMcpIntegrationCapabilities,
5216
5400
  async (params) => {
5217
5401
  const result = await service.mcpIntegrations.listMcpIntegrationCapabilities(params.id);
@@ -5231,7 +5415,7 @@ function registerMcpIntegrationsTools(server, service) {
5231
5415
  );
5232
5416
  server.tool(
5233
5417
  "update_mcp_integration_capabilities",
5234
- "Bulk enable or disable capabilities on an MCP integration",
5418
+ "Bulk enable or disable capabilities on an MCP integration to control which MCP tools, resources, and prompts are available to users. Disabled capabilities are hidden from connected clients. Changes take effect immediately.",
5235
5419
  MCP_INTEGRATIONS_TOOL_SCHEMAS.updateMcpIntegrationCapabilities,
5236
5420
  async (params) => {
5237
5421
  await service.mcpIntegrations.updateMcpIntegrationCapabilities(
@@ -5259,7 +5443,7 @@ function registerMcpIntegrationsTools(server, service) {
5259
5443
  );
5260
5444
  server.tool(
5261
5445
  "list_mcp_integration_workspaces",
5262
- "List workspace access settings for an MCP integration",
5446
+ "List which workspaces have access to an MCP integration. Returns global access setting and per-workspace enabled status. Use to audit access before modifying permissions with update_mcp_integration_workspaces.",
5263
5447
  MCP_INTEGRATIONS_TOOL_SCHEMAS.listMcpIntegrationWorkspaces,
5264
5448
  async (params) => {
5265
5449
  const result = await service.mcpIntegrations.listMcpIntegrationWorkspaces(
@@ -5287,7 +5471,7 @@ function registerMcpIntegrationsTools(server, service) {
5287
5471
  );
5288
5472
  server.tool(
5289
5473
  "update_mcp_integration_workspaces",
5290
- "Bulk update workspace access for an MCP integration",
5474
+ "Grant or revoke workspace access to an MCP integration in bulk. Changes affect all users in the workspace immediately. Use list_mcp_integration_workspaces first to see current access state.",
5291
5475
  MCP_INTEGRATIONS_TOOL_SCHEMAS.updateMcpIntegrationWorkspaces,
5292
5476
  async (params) => {
5293
5477
  await service.mcpIntegrations.updateMcpIntegrationWorkspaces(params.id, {
@@ -5402,7 +5586,7 @@ function formatMcpServerUserAccess(user) {
5402
5586
  function registerMcpServersTools(server, service) {
5403
5587
  server.tool(
5404
5588
  "list_mcp_servers",
5405
- "List all MCP servers in your Portkey organization with optional pagination and workspace filtering",
5589
+ "List all MCP servers in your Portkey organization with optional pagination and workspace filtering. MCP servers are instances under MCP integrations. Use to discover server IDs needed by other tools. Differs from list_mcp_integrations which shows the parent integration connections. Returns paginated array of servers with total count.",
5406
5590
  MCP_SERVERS_TOOL_SCHEMAS.listMcpServers,
5407
5591
  async (params) => {
5408
5592
  const result = await service.mcpServers.listMcpServers(params);
@@ -5425,7 +5609,7 @@ function registerMcpServersTools(server, service) {
5425
5609
  );
5426
5610
  server.tool(
5427
5611
  "create_mcp_server",
5428
- "Register a new MCP server under an existing MCP integration",
5612
+ "Register a new MCP server instance under an existing MCP integration. Use list_mcp_integrations to find the mcp_integration_id first. Returns the new server's id and slug.",
5429
5613
  MCP_SERVERS_TOOL_SCHEMAS.createMcpServer,
5430
5614
  async (params) => {
5431
5615
  const result = await service.mcpServers.createMcpServer(params);
@@ -5449,7 +5633,7 @@ function registerMcpServersTools(server, service) {
5449
5633
  );
5450
5634
  server.tool(
5451
5635
  "get_mcp_server",
5452
- "Retrieve detailed information about a specific MCP server by ID or slug",
5636
+ "Retrieve detailed information about a specific MCP server by ID or slug. Returns server details including linked integration ID and status. Use to check server configuration and health.",
5453
5637
  MCP_SERVERS_TOOL_SCHEMAS.getMcpServer,
5454
5638
  async (params) => {
5455
5639
  const mcpServer = await service.mcpServers.getMcpServer(params.id);
@@ -5465,7 +5649,7 @@ function registerMcpServersTools(server, service) {
5465
5649
  );
5466
5650
  server.tool(
5467
5651
  "update_mcp_server",
5468
- "Update an existing MCP server's name or description",
5652
+ "Update an existing MCP server's name or description. Only name and description can be changed on a server. To change the URL or auth configuration, update the parent MCP integration instead.",
5469
5653
  MCP_SERVERS_TOOL_SCHEMAS.updateMcpServer,
5470
5654
  async (params) => {
5471
5655
  const { id, ...data } = params;
@@ -5489,7 +5673,7 @@ function registerMcpServersTools(server, service) {
5489
5673
  );
5490
5674
  server.tool(
5491
5675
  "delete_mcp_server",
5492
- "Delete an MCP server. This action cannot be undone.",
5676
+ "Delete an MCP server instance by ID. This action cannot be undone. Connected users and workspaces lose access immediately, and workspace access grants to this server are removed. Verify no active integrations depend on it before deleting.",
5493
5677
  MCP_SERVERS_TOOL_SCHEMAS.deleteMcpServer,
5494
5678
  async (params) => {
5495
5679
  await service.mcpServers.deleteMcpServer(params.id);
@@ -5512,7 +5696,7 @@ function registerMcpServersTools(server, service) {
5512
5696
  );
5513
5697
  server.tool(
5514
5698
  "test_mcp_server",
5515
- "Test connectivity to an MCP server to verify it is reachable and responding",
5699
+ "Send a connectivity check to an MCP server to verify it is reachable and responding. Returns success/failure, response time in ms, and any error message. Use to diagnose connection issues before investigating configuration.",
5516
5700
  MCP_SERVERS_TOOL_SCHEMAS.testMcpServer,
5517
5701
  async (params) => {
5518
5702
  const result = await service.mcpServers.testMcpServer(params.id);
@@ -5528,7 +5712,7 @@ function registerMcpServersTools(server, service) {
5528
5712
  );
5529
5713
  server.tool(
5530
5714
  "list_mcp_server_capabilities",
5531
- "List all capabilities (tools, resources, prompts) exposed by an MCP server",
5715
+ "List all capabilities (tools, resources, prompts) exposed by an MCP server instance. Differs from list_mcp_integration_capabilities which shows integration-level capability settings. Returns total count and array of capabilities.",
5532
5716
  MCP_SERVERS_TOOL_SCHEMAS.listMcpServerCapabilities,
5533
5717
  async (params) => {
5534
5718
  const result = await service.mcpServers.listMcpServerCapabilities(
@@ -5550,7 +5734,7 @@ function registerMcpServersTools(server, service) {
5550
5734
  );
5551
5735
  server.tool(
5552
5736
  "update_mcp_server_capabilities",
5553
- "Bulk enable or disable capabilities on an MCP server",
5737
+ "Enable or disable specific capabilities on an MCP server instance. Overrides integration-level capability settings for this server. Changes take effect immediately for connected users.",
5554
5738
  MCP_SERVERS_TOOL_SCHEMAS.updateMcpServerCapabilities,
5555
5739
  async (params) => {
5556
5740
  await service.mcpServers.updateMcpServerCapabilities(params.id, {
@@ -5575,7 +5759,7 @@ function registerMcpServersTools(server, service) {
5575
5759
  );
5576
5760
  server.tool(
5577
5761
  "list_mcp_server_user_access",
5578
- "List user access settings for an MCP server",
5762
+ "List per-user access settings for an MCP server including override flags and connection status. Returns default_user_access setting and array of users. Use to audit who can access this server before modifying permissions.",
5579
5763
  MCP_SERVERS_TOOL_SCHEMAS.listMcpServerUserAccess,
5580
5764
  async (params) => {
5581
5765
  const result = await service.mcpServers.listMcpServerUserAccess(
@@ -5601,7 +5785,7 @@ function registerMcpServersTools(server, service) {
5601
5785
  );
5602
5786
  server.tool(
5603
5787
  "update_mcp_server_user_access",
5604
- "Bulk update user access for an MCP server",
5788
+ "Grant or revoke individual user access to an MCP server. Overrides the default_user_access setting for specified users. Changes take effect immediately.",
5605
5789
  MCP_SERVERS_TOOL_SCHEMAS.updateMcpServerUserAccess,
5606
5790
  async (params) => {
5607
5791
  await service.mcpServers.updateMcpServerUserAccess(params.id, {
@@ -5666,7 +5850,7 @@ var PARTIALS_TOOL_SCHEMAS = {
5666
5850
  function registerPartialsTools(server, service) {
5667
5851
  server.tool(
5668
5852
  "create_prompt_partial",
5669
- "Create a new prompt partial (reusable text snippet) that can be included in prompts using mustache syntax like {{> partial_name}}",
5853
+ "Create a new prompt partial (reusable text snippet) that can be included in prompts using mustache syntax like {{> partial_name}}. After creation, use publish_partial to make it the default version. Returns id, slug, and version_id.",
5670
5854
  PARTIALS_TOOL_SCHEMAS.createPromptPartial,
5671
5855
  async (params) => {
5672
5856
  const result = await service.partials.createPromptPartial({
@@ -5696,7 +5880,7 @@ function registerPartialsTools(server, service) {
5696
5880
  );
5697
5881
  server.tool(
5698
5882
  "list_prompt_partials",
5699
- "List all prompt partials in your Portkey organization with optional filtering by collection",
5883
+ "List all prompt partials in your Portkey organization with optional filtering by collection. Returns all partials with id, slug, name, and status. Use to discover partial IDs or check if a partial already exists before creating.",
5700
5884
  PARTIALS_TOOL_SCHEMAS.listPromptPartials,
5701
5885
  async (params) => {
5702
5886
  const partials = await service.partials.listPromptPartials(params);
@@ -5727,7 +5911,7 @@ function registerPartialsTools(server, service) {
5727
5911
  );
5728
5912
  server.tool(
5729
5913
  "get_prompt_partial",
5730
- "Retrieve detailed information about a specific prompt partial including its content and version info",
5914
+ "Retrieve detailed information about a specific prompt partial. Returns the partial's content string and current version info. Use to inspect content before including it in a prompt via {{> partial_name}}.",
5731
5915
  PARTIALS_TOOL_SCHEMAS.getPromptPartial,
5732
5916
  async (params) => {
5733
5917
  const partial = await service.partials.getPromptPartial(
@@ -5788,7 +5972,7 @@ function registerPartialsTools(server, service) {
5788
5972
  );
5789
5973
  server.tool(
5790
5974
  "delete_prompt_partial",
5791
- "Delete a prompt partial by ID. This action cannot be undone.",
5975
+ "Delete a prompt partial by ID. This action cannot be undone. Prompts referencing this partial via {{> name}} will fail to render. Ensure no active prompts depend on it.",
5792
5976
  PARTIALS_TOOL_SCHEMAS.deletePromptPartial,
5793
5977
  async (params) => {
5794
5978
  await service.partials.deletePromptPartial(params.prompt_partial_id);
@@ -5811,7 +5995,7 @@ function registerPartialsTools(server, service) {
5811
5995
  );
5812
5996
  server.tool(
5813
5997
  "list_partial_versions",
5814
- "List all versions of a prompt partial to view its change history",
5998
+ "List all versions of a prompt partial to view its change history. Returns all versions with content preview. Use to find a version number before calling publish_partial to roll back or promote a version.",
5815
5999
  PARTIALS_TOOL_SCHEMAS.listPartialVersions,
5816
6000
  async (params) => {
5817
6001
  const versions = await service.partials.listPartialVersions(
@@ -5846,7 +6030,7 @@ function registerPartialsTools(server, service) {
5846
6030
  );
5847
6031
  server.tool(
5848
6032
  "publish_partial",
5849
- "Publish a specific version of a prompt partial, making it the default version",
6033
+ "Publish a specific version of a prompt partial, making it the default version. After publishing, all prompts using {{> partial_name}} will resolve to this version's content.",
5850
6034
  PARTIALS_TOOL_SCHEMAS.publishPartial,
5851
6035
  async (params) => {
5852
6036
  await service.partials.publishPartial(params.prompt_partial_id, {
@@ -5947,14 +6131,25 @@ function toPromptToolChoice(toolChoice) {
5947
6131
 
5948
6132
  // src/tools/prompts.tools.ts
5949
6133
  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");
6134
+ var PROMPT_TEMPLATE_CONTENT_BLOCK_SCHEMA = z15.object({
6135
+ type: z15.string().describe("Content block type"),
6136
+ text: z15.string().optional().describe("Text content for text-based blocks")
6137
+ }).passthrough().describe("Content block within a structured chat message");
6138
+ var PROMPT_TEMPLATE_MESSAGE_SCHEMA = z15.object({
6139
+ role: z15.enum(["system", "user", "assistant"]).describe("Message role in the chat template"),
6140
+ content: z15.array(PROMPT_TEMPLATE_CONTENT_BLOCK_SCHEMA).describe("Message content blocks")
6141
+ }).passthrough().describe("Structured chat message in a prompt template");
5950
6142
  var PROMPTS_TOOL_SCHEMAS = {
5951
6143
  createPrompt: {
5952
6144
  name: z15.string().describe("Display name for the prompt"),
5953
6145
  collection_id: z15.string().describe(
5954
6146
  "Collection ID to organize the prompt in (use list_collections to find)"
5955
6147
  ),
5956
- string: z15.string().describe(
5957
- `The prompt template. Plain text OR a JSON-encoded messages array string for multi-message chat prompts: '[{"role":"system","content":[{"type":"text","text":"..."}]},{"role":"user","content":[{"type":"text","text":"{{input}}"}]}]'. Use get_prompt on an existing prompt to see the exact format.`
6148
+ string: z15.string().optional().describe(
6149
+ "Legacy prompt template string. Use plain text for single-message prompts, or a JSON-encoded messages array string for multi-message chat prompts."
6150
+ ),
6151
+ messages: z15.array(PROMPT_TEMPLATE_MESSAGE_SCHEMA).optional().describe(
6152
+ "Structured chat template alias. Serialized to the legacy string format before creation."
5958
6153
  ),
5959
6154
  parameters: z15.record(z15.string(), z15.unknown()).describe("Default values for template variables"),
5960
6155
  virtual_key: z15.string().describe("Virtual key slug for model access"),
@@ -5991,7 +6186,10 @@ var PROMPTS_TOOL_SCHEMAS = {
5991
6186
  name: z15.string().optional().describe("New display name for the prompt"),
5992
6187
  collection_id: z15.string().optional().describe("Move to a different collection"),
5993
6188
  string: z15.string().optional().describe(
5994
- "Updated prompt template. Plain text OR a JSON-encoded messages array string for multi-message chat prompts. Use get_prompt to see the current format before updating."
6189
+ "Legacy prompt template string. Use plain text for single-message prompts, or a JSON-encoded messages array string for multi-message chat prompts."
6190
+ ),
6191
+ messages: z15.array(PROMPT_TEMPLATE_MESSAGE_SCHEMA).optional().describe(
6192
+ "Structured chat template alias for updates. Serialized to the legacy string format before the prompt is updated."
5995
6193
  ),
5996
6194
  parameters: z15.record(z15.string(), z15.unknown()).optional().describe("New default values for template variables"),
5997
6195
  model: z15.string().optional().describe("New model identifier"),
@@ -6037,7 +6235,12 @@ var PROMPTS_TOOL_SCHEMAS = {
6037
6235
  app: PromptAppIdentifierSchema,
6038
6236
  env: PromptEnvironmentIdentifierSchema,
6039
6237
  collection_id: z15.string().describe("Collection ID to search in and create under"),
6040
- string: z15.string().describe("Prompt template string with {{variable}} mustache syntax"),
6238
+ string: z15.string().optional().describe(
6239
+ "Legacy prompt template string with {{variable}} mustache syntax."
6240
+ ),
6241
+ messages: z15.array(PROMPT_TEMPLATE_MESSAGE_SCHEMA).optional().describe(
6242
+ "Structured chat template alias for migrations. Serialized to the legacy string format before the prompt is created or updated."
6243
+ ),
6041
6244
  parameters: z15.record(z15.string(), z15.unknown()).describe("Default values for template variables"),
6042
6245
  virtual_key: z15.string().describe("Virtual key slug for model access"),
6043
6246
  model: z15.string().optional().describe("Model identifier"),
@@ -6080,6 +6283,15 @@ var PROMPTS_TOOL_SCHEMAS = {
6080
6283
  )
6081
6284
  }
6082
6285
  };
6286
+ function normalizePromptTemplateString(params) {
6287
+ if (params.string !== void 0) {
6288
+ return params.string;
6289
+ }
6290
+ if (params.messages !== void 0) {
6291
+ return JSON.stringify(params.messages);
6292
+ }
6293
+ return void 0;
6294
+ }
6083
6295
  function extractPromptTemplateString(template) {
6084
6296
  const inner = typeof template === "object" && template !== null && "string" in template ? template.string : template;
6085
6297
  if (inner === void 0) {
@@ -6143,14 +6355,14 @@ function formatPromptListResponse(prompts, params) {
6143
6355
  function registerPromptsTools(server, service) {
6144
6356
  server.tool(
6145
6357
  "create_prompt",
6146
- `Create a new prompt template in Portkey. Supports both single-message and multi-message (chat) templates.
6358
+ `Create a new prompt template in Portkey. Supports both the legacy string template and a structured messages alias for chat prompts.
6147
6359
 
6148
- IMPORTANT: The "string" parameter accepts TWO formats:
6360
+ IMPORTANT: The "string" parameter accepts TWO legacy formats:
6149
6361
  1. Plain text: "Hello {{name}}, how can I help?"
6150
6362
  2. Multi-message JSON array (MUST be a JSON-encoded string):
6151
6363
  '[{"role":"system","content":[{"type":"text","text":"You are a helpful assistant."}]},{"role":"user","content":[{"type":"text","text":"{{user_input}}"}]}]'
6152
6364
 
6153
- Most production prompts use format #2 (multi-message). Use get_prompt to see examples of the format.`,
6365
+ For structured prompts, prefer the "messages" alias and let the server serialize it to the legacy string format.`,
6154
6366
  PROMPTS_TOOL_SCHEMAS.createPrompt,
6155
6367
  async (params) => {
6156
6368
  if (!params.model && !params.ai_model_id && !params.finetune_id) {
@@ -6164,6 +6376,18 @@ Most production prompts use format #2 (multi-message). Use get_prompt to see exa
6164
6376
  isError: true
6165
6377
  };
6166
6378
  }
6379
+ const templateString = normalizePromptTemplateString(params);
6380
+ if (templateString === void 0) {
6381
+ return {
6382
+ content: [
6383
+ {
6384
+ type: "text",
6385
+ text: "Error creating prompt: Provide either string or messages"
6386
+ }
6387
+ ],
6388
+ isError: true
6389
+ };
6390
+ }
6167
6391
  if (params.dry_run) {
6168
6392
  return {
6169
6393
  content: [
@@ -6178,7 +6402,7 @@ Most production prompts use format #2 (multi-message). Use get_prompt to see exa
6178
6402
  name: params.name,
6179
6403
  collection_id: params.collection_id,
6180
6404
  model: params.model,
6181
- template_length: params.string.length,
6405
+ template_length: templateString.length,
6182
6406
  parameter_count: Object.keys(params.parameters ?? {}).length
6183
6407
  }
6184
6408
  },
@@ -6192,17 +6416,17 @@ Most production prompts use format #2 (multi-message). Use get_prompt to see exa
6192
6416
  const result = await service.prompts.createPrompt({
6193
6417
  name: params.name,
6194
6418
  collection_id: params.collection_id,
6195
- string: params.string,
6419
+ string: templateString,
6196
6420
  parameters: params.parameters,
6197
6421
  virtual_key: params.virtual_key,
6198
- model: params.model,
6199
- ai_model_id: params.ai_model_id,
6200
- finetune_id: params.finetune_id,
6201
- version_description: params.version_description,
6202
- template_metadata: params.template_metadata,
6203
- functions: params.functions,
6204
- tools: params.tools,
6205
- tool_choice: toPromptToolChoice(params.tool_choice)
6422
+ ...params.model !== void 0 ? { model: params.model } : {},
6423
+ ...params.ai_model_id !== void 0 ? { ai_model_id: params.ai_model_id } : {},
6424
+ ...params.finetune_id !== void 0 ? { finetune_id: params.finetune_id } : {},
6425
+ ...params.version_description !== void 0 ? { version_description: params.version_description } : {},
6426
+ ...params.template_metadata !== void 0 ? { template_metadata: params.template_metadata } : {},
6427
+ ...params.functions !== void 0 ? { functions: params.functions } : {},
6428
+ ...params.tools !== void 0 ? { tools: params.tools } : {},
6429
+ ...params.tool_choice !== void 0 ? { tool_choice: toPromptToolChoice(params.tool_choice) } : {}
6206
6430
  });
6207
6431
  return {
6208
6432
  content: [
@@ -6225,7 +6449,7 @@ Most production prompts use format #2 (multi-message). Use get_prompt to see exa
6225
6449
  );
6226
6450
  server.tool(
6227
6451
  "list_prompts",
6228
- "List all prompts in your Portkey organization with optional filtering by collection, workspace, or search query",
6452
+ "List all prompts in your Portkey organization with optional filtering by collection, workspace, or search query. Returns paginated results with id, name, slug, model, and status. Use collection_id to filter by app. Use to discover prompt_id values before calling get_prompt.",
6229
6453
  PROMPTS_TOOL_SCHEMAS.listPrompts,
6230
6454
  async (params) => {
6231
6455
  const prompts = await service.prompts.listPrompts(params);
@@ -6314,15 +6538,19 @@ When updating a prompt, pass the same format back in the "string" field of updat
6314
6538
  "update_prompt",
6315
6539
  `Update an existing prompt template. Creates a new version. Uses patch mode \u2014 only provided fields are updated, others are kept from the current version.
6316
6540
 
6317
- IMPORTANT: The "string" parameter accepts the same two formats as create_prompt:
6541
+ IMPORTANT: The legacy "string" parameter accepts the same two formats as create_prompt:
6318
6542
  1. Plain text: "Hello {{name}}"
6319
6543
  2. Multi-message JSON array (MUST be a JSON-encoded string):
6320
6544
  '[{"role":"system","content":[{"type":"text","text":"..."}]},{"role":"user","content":[{"type":"text","text":"{{input}}"}]}]'
6321
6545
 
6322
- Use get_prompt first to see the current format, then pass the same format back. New versions are created in "archived" status \u2014 use publish_prompt to make active.`,
6546
+ For structured chat prompts, prefer the "messages" alias and let the server serialize it for you. New versions are created in "archived" status \u2014 use publish_prompt to make active.`,
6323
6547
  PROMPTS_TOOL_SCHEMAS.updatePrompt,
6324
6548
  async (params) => {
6325
- const { prompt_id, dry_run, ...updateData } = params;
6549
+ const { prompt_id, dry_run, messages, ...updateData } = params;
6550
+ const templateString = normalizePromptTemplateString({
6551
+ string: updateData.string,
6552
+ messages
6553
+ });
6326
6554
  if (dry_run) {
6327
6555
  const current = await service.prompts.getPrompt(prompt_id);
6328
6556
  return {
@@ -6347,8 +6575,17 @@ Use get_prompt first to see the current format, then pass the same format back.
6347
6575
  };
6348
6576
  }
6349
6577
  const result = await service.prompts.updatePrompt(prompt_id, {
6350
- ...updateData,
6351
- tool_choice: toPromptToolChoice(updateData.tool_choice)
6578
+ ...updateData.name !== void 0 ? { name: updateData.name } : {},
6579
+ ...updateData.collection_id !== void 0 ? { collection_id: updateData.collection_id } : {},
6580
+ ...templateString !== void 0 ? { string: templateString } : {},
6581
+ ...updateData.parameters !== void 0 ? { parameters: updateData.parameters } : {},
6582
+ ...updateData.model !== void 0 ? { model: updateData.model } : {},
6583
+ ...updateData.virtual_key !== void 0 ? { virtual_key: updateData.virtual_key } : {},
6584
+ ...updateData.version_description !== void 0 ? { version_description: updateData.version_description } : {},
6585
+ ...updateData.template_metadata !== void 0 ? { template_metadata: updateData.template_metadata } : {},
6586
+ ...updateData.functions !== void 0 ? { functions: updateData.functions } : {},
6587
+ ...updateData.tools !== void 0 ? { tools: updateData.tools } : {},
6588
+ ...updateData.tool_choice !== void 0 ? { tool_choice: toPromptToolChoice(updateData.tool_choice) } : {}
6352
6589
  });
6353
6590
  return {
6354
6591
  content: [
@@ -6371,7 +6608,7 @@ Use get_prompt first to see the current format, then pass the same format back.
6371
6608
  );
6372
6609
  server.tool(
6373
6610
  "delete_prompt",
6374
- "Delete a prompt by its ID. This action cannot be undone and will remove the prompt and all its versions.",
6611
+ "Delete a prompt and all its versions by ID. This action cannot be undone. Applications calling this prompt slug will fail immediately. Use list_prompt_versions first to review history; consider archiving via update_prompt status instead if an audit trail is needed.",
6375
6612
  PROMPTS_TOOL_SCHEMAS.deletePrompt,
6376
6613
  async (params) => {
6377
6614
  await service.prompts.deletePrompt(params.prompt_id);
@@ -6459,7 +6696,7 @@ Use get_prompt first to see the current format, then pass the same format back.
6459
6696
  );
6460
6697
  server.tool(
6461
6698
  "render_prompt",
6462
- "Render a prompt template by substituting variables, returning the final messages without executing",
6699
+ "Render a prompt template by substituting variables, returning the final messages without executing. Previews the final messages after variable substitution without sending to the AI model. Use to verify template output before running a completion. Differs from run_prompt_completion which actually calls the model.",
6463
6700
  PROMPTS_TOOL_SCHEMAS.renderPrompt,
6464
6701
  async (params) => {
6465
6702
  const result = await service.prompts.renderPrompt(params.prompt_id, {
@@ -6491,7 +6728,7 @@ Use get_prompt first to see the current format, then pass the same format back.
6491
6728
  );
6492
6729
  server.tool(
6493
6730
  "run_prompt_completion",
6494
- "Execute a prompt template with variables and get the model completion response. REQUIRES billing metadata (client_id, app, env). Use validate_completion_metadata first if uncertain.",
6731
+ "Execute a prompt template against the configured AI model and return the model's response. Costs money \u2014 use render_prompt to preview first. REQUIRES billing metadata (client_id, app, env). Use validate_completion_metadata first if uncertain.",
6495
6732
  PROMPTS_TOOL_SCHEMAS.runPromptCompletion,
6496
6733
  async (params) => {
6497
6734
  const result = await service.prompts.runPromptCompletion(
@@ -6530,24 +6767,36 @@ Use get_prompt first to see the current format, then pass the same format back.
6530
6767
  );
6531
6768
  server.tool(
6532
6769
  "migrate_prompt",
6533
- "Create or update a prompt based on whether it exists. Useful for CI/CD and prompt-as-code workflows. Finds existing prompts by name within the collection. The app and env values are added to template_metadata automatically.",
6770
+ "Create or update a prompt based on whether it exists. Useful for CI/CD and prompt-as-code workflows. Finds existing prompts by name within the collection. The app and env values are added to template_metadata automatically. For structured chat prompts, prefer the messages alias instead of hand-encoding JSON into string.",
6534
6771
  PROMPTS_TOOL_SCHEMAS.migratePrompt,
6535
6772
  async (params) => {
6773
+ const templateString = normalizePromptTemplateString(params);
6774
+ if (templateString === void 0) {
6775
+ return {
6776
+ content: [
6777
+ {
6778
+ type: "text",
6779
+ text: "Error migrating prompt: Provide either string or messages"
6780
+ }
6781
+ ],
6782
+ isError: true
6783
+ };
6784
+ }
6536
6785
  const result = await service.prompts.migratePrompt({
6537
6786
  name: params.name,
6538
6787
  app: params.app,
6539
6788
  env: params.env,
6540
6789
  collection_id: params.collection_id,
6541
- string: params.string,
6790
+ string: templateString,
6542
6791
  parameters: params.parameters,
6543
6792
  virtual_key: params.virtual_key,
6544
- model: params.model,
6545
- version_description: params.version_description,
6546
- template_metadata: params.template_metadata,
6547
- functions: params.functions,
6548
- tools: params.tools,
6549
- tool_choice: toPromptToolChoice(params.tool_choice),
6550
- dry_run: params.dry_run
6793
+ ...params.model !== void 0 ? { model: params.model } : {},
6794
+ ...params.version_description !== void 0 ? { version_description: params.version_description } : {},
6795
+ ...params.template_metadata !== void 0 ? { template_metadata: params.template_metadata } : {},
6796
+ ...params.functions !== void 0 ? { functions: params.functions } : {},
6797
+ ...params.tools !== void 0 ? { tools: params.tools } : {},
6798
+ ...params.tool_choice !== void 0 ? { tool_choice: toPromptToolChoice(params.tool_choice) } : {},
6799
+ ...params.dry_run !== void 0 ? { dry_run: params.dry_run } : {}
6551
6800
  });
6552
6801
  return {
6553
6802
  content: [
@@ -6610,7 +6859,7 @@ Use get_prompt first to see the current format, then pass the same format back.
6610
6859
  );
6611
6860
  server.tool(
6612
6861
  "validate_completion_metadata",
6613
- "Validate billing metadata before running a completion. Checks for required fields (client_id, app, env) and valid values.",
6862
+ "Validate billing metadata before running a completion. Checks for required fields (client_id, app, env) and valid values. Call this before run_prompt_completion to catch missing or invalid billing fields. Does not make any changes.",
6614
6863
  PROMPTS_TOOL_SCHEMAS.validateCompletionMetadata,
6615
6864
  async (params) => {
6616
6865
  const result = service.prompts.validateBillingMetadata(params);
@@ -6635,7 +6884,7 @@ Use get_prompt first to see the current format, then pass the same format back.
6635
6884
  );
6636
6885
  server.tool(
6637
6886
  "get_prompt_version",
6638
- "Retrieve a specific version of a prompt by its version ID",
6887
+ "Retrieve a specific version of a prompt by its version UUID. Use list_prompt_versions to find version IDs. Returns full template, parameters, and model config for that version.",
6639
6888
  PROMPTS_TOOL_SCHEMAS.getPromptVersion,
6640
6889
  async (params) => {
6641
6890
  const version = await service.prompts.getPromptVersion(
@@ -6654,7 +6903,7 @@ Use get_prompt first to see the current format, then pass the same format back.
6654
6903
  );
6655
6904
  server.tool(
6656
6905
  "update_prompt_version",
6657
- "Update a specific prompt version, e.g. to assign or remove a label",
6906
+ "Update a specific prompt version. Currently only supports assigning or removing a label. Use list_prompt_labels to find label IDs. Pass null to remove the current label.",
6658
6907
  PROMPTS_TOOL_SCHEMAS.updatePromptVersion,
6659
6908
  async (params) => {
6660
6909
  if (params.label_id === void 0) {
@@ -6762,7 +7011,7 @@ var PROVIDERS_TOOL_SCHEMAS = {
6762
7011
  function registerProvidersTools(server, service) {
6763
7012
  server.tool(
6764
7013
  "list_providers",
6765
- "List all providers in your Portkey organization with optional pagination and workspace filtering",
7014
+ "List workspace-scoped providers, which are instances of org-level integrations with their own usage and rate limits. Differs from list_integrations which shows org-level provider connections. Use to discover provider slugs for a workspace. Returns name, slug, limits, and status per provider.",
6766
7015
  PROVIDERS_TOOL_SCHEMAS.listProviders,
6767
7016
  async (params) => {
6768
7017
  const providers = await service.providers.listProviders({
@@ -6808,7 +7057,7 @@ function registerProvidersTools(server, service) {
6808
7057
  );
6809
7058
  server.tool(
6810
7059
  "create_provider",
6811
- "Create a new provider configuration in Portkey. Providers define integrations with AI model providers like OpenAI, Anthropic, etc.",
7060
+ "Create a workspace-scoped provider linked to an org-level integration. Use list_integrations to find the integration_id first. Providers inherit the integration's API key but can have independent usage limits, rate limits, and expiration. Returns the new provider's id and slug.",
6812
7061
  PROVIDERS_TOOL_SCHEMAS.createProvider,
6813
7062
  async (params) => {
6814
7063
  const result = await service.providers.createProvider({
@@ -6849,7 +7098,7 @@ function registerProvidersTools(server, service) {
6849
7098
  );
6850
7099
  server.tool(
6851
7100
  "get_provider",
6852
- "Retrieve detailed information about a specific provider by its slug",
7101
+ "Retrieve full provider details by slug, including usage limits, rate limits, and expiration. Use to check current consumption against limits or inspect provider configuration before updating.",
6853
7102
  PROVIDERS_TOOL_SCHEMAS.getProvider,
6854
7103
  async (params) => {
6855
7104
  const provider = await service.providers.getProvider(
@@ -6891,7 +7140,7 @@ function registerProvidersTools(server, service) {
6891
7140
  );
6892
7141
  server.tool(
6893
7142
  "update_provider",
6894
- "Update an existing provider's name, note, limits, or expiration",
7143
+ "Update a provider's name, note, usage limits, rate limits, or expiration. Set reset_usage to true to clear accumulated usage counters without changing the limit. Returns the updated provider's id and slug.",
6895
7144
  PROVIDERS_TOOL_SCHEMAS.updateProvider,
6896
7145
  async (params) => {
6897
7146
  const result = await service.providers.updateProvider(
@@ -6934,7 +7183,7 @@ function registerProvidersTools(server, service) {
6934
7183
  );
6935
7184
  server.tool(
6936
7185
  "delete_provider",
6937
- "Delete a provider by slug. This action cannot be undone.",
7186
+ "Delete a workspace-level provider by slug. This action cannot be undone. Virtual keys, configs, and prompts referencing this provider will stop working. Audit dependent resources first; use delete_integration for org-level provider connections instead.",
6938
7187
  PROVIDERS_TOOL_SCHEMAS.deleteProvider,
6939
7188
  async (params) => {
6940
7189
  await service.providers.deleteProvider(params.slug, params.workspace_id);
@@ -6981,15 +7230,12 @@ var TRACING_TOOL_SCHEMAS = {
6981
7230
  ),
6982
7231
  weight: z17.coerce.number().positive().optional().describe("New weighting factor for the feedback"),
6983
7232
  metadata: z17.record(z17.string(), z17.unknown()).optional().describe("New or updated custom metadata for the feedback")
6984
- },
6985
- getTrace: {
6986
- id: z17.string().describe("The unique identifier of the trace to retrieve")
6987
7233
  }
6988
7234
  };
6989
7235
  function registerTracingTools(server, service) {
6990
7236
  server.tool(
6991
7237
  "create_feedback",
6992
- "Create feedback for a specific trace/request. Use this to capture user feedback (thumbs up/down, ratings) on AI generations. Feedback is linked via trace_id and can include custom metadata for analysis.",
7238
+ "Create feedback for a specific trace/request. Use this to capture user feedback (thumbs up/down, ratings) on AI generations. Feedback is linked via trace_id and can include custom metadata for analysis. Trace IDs are surfaced in request logs and via log exports (create_log_export).",
6993
7239
  TRACING_TOOL_SCHEMAS.createFeedback,
6994
7240
  async (params) => {
6995
7241
  const result = await service.tracing.createFeedback({
@@ -7018,7 +7264,7 @@ function registerTracingTools(server, service) {
7018
7264
  );
7019
7265
  server.tool(
7020
7266
  "update_feedback",
7021
- "Update existing feedback by ID. Allows modifying the feedback value, weight, or metadata after initial creation.",
7267
+ "Update existing feedback by ID. Use this instead of create_feedback when feedback already exists and needs correction or refinement. Only value, weight, and metadata can be changed; the trace_id association is immutable. Returns the updated feedback status and IDs.",
7022
7268
  TRACING_TOOL_SCHEMAS.updateFeedback,
7023
7269
  async (params) => {
7024
7270
  const result = await service.tracing.updateFeedback(params.id, {
@@ -7044,51 +7290,6 @@ function registerTracingTools(server, service) {
7044
7290
  };
7045
7291
  }
7046
7292
  );
7047
- server.tool(
7048
- "get_trace",
7049
- "Retrieve detailed information about a specific trace by ID. Returns full request/response data, all spans, metadata, cost, token usage, and any associated feedback.",
7050
- TRACING_TOOL_SCHEMAS.getTrace,
7051
- async (params) => {
7052
- const result = await service.tracing.getTrace(params.id);
7053
- const trace = result.data;
7054
- return {
7055
- content: [
7056
- {
7057
- type: "text",
7058
- text: JSON.stringify(
7059
- {
7060
- success: result.success,
7061
- trace: {
7062
- id: trace.id,
7063
- trace_id: trace.trace_id,
7064
- request: trace.request,
7065
- response: trace.response,
7066
- metadata: trace.metadata,
7067
- workspace_id: trace.workspace_id,
7068
- organisation_id: trace.organisation_id,
7069
- cost: trace.cost,
7070
- tokens: trace.tokens,
7071
- spans: trace.spans?.map((span) => ({
7072
- span_id: span.span_id,
7073
- span_name: span.span_name,
7074
- parent_span_id: span.parent_span_id,
7075
- start_time: span.start_time,
7076
- end_time: span.end_time,
7077
- status: span.status,
7078
- attributes: span.attributes
7079
- })),
7080
- feedback: trace.feedback,
7081
- created_at: trace.created_at
7082
- }
7083
- },
7084
- null,
7085
- 2
7086
- )
7087
- }
7088
- ]
7089
- };
7090
- }
7091
- );
7092
7293
  }
7093
7294
 
7094
7295
  // src/tools/users.tools.ts
@@ -7192,7 +7393,7 @@ function formatUserAnalyticsGroup(group) {
7192
7393
  function registerUsersTools(server, service) {
7193
7394
  server.tool(
7194
7395
  "list_all_users",
7195
- "List all users in your Portkey organization, including their roles and account details",
7396
+ "List all users in your Portkey organization. Returns each user's ID, name, email, role, and timestamps. Use this for browsing or auditing the full member list; use get_user to fetch a single user by ID.",
7196
7397
  USERS_TOOL_SCHEMAS.listAllUsers,
7197
7398
  async () => {
7198
7399
  const users = await service.users.listUsers();
@@ -7239,7 +7440,7 @@ function registerUsersTools(server, service) {
7239
7440
  );
7240
7441
  server.tool(
7241
7442
  "get_user_stats",
7242
- "Retrieve detailed analytics data about user activity within a specified time range, including request counts and costs",
7443
+ "Retrieve per-user request count and cost analytics for a required time range (time_of_generation_min/max). Unlike get_users_analytics which tracks active/new user counts over time, this returns usage-based stats grouped by user. Supports filtering by cost, tokens, status codes, and virtual keys.",
7243
7444
  USERS_TOOL_SCHEMAS.getUserStats,
7244
7445
  async (params) => {
7245
7446
  const stats = await service.users.getUserGroupedData(params);
@@ -7262,7 +7463,7 @@ function registerUsersTools(server, service) {
7262
7463
  );
7263
7464
  server.tool(
7264
7465
  "get_user",
7265
- "Retrieve detailed information about a specific user by their ID",
7466
+ "Retrieve a single user's profile by their ID. Returns ID, name, email, role, and timestamps. Use this when you already have a user ID; use list_all_users to browse or search all organization members.",
7266
7467
  USERS_TOOL_SCHEMAS.getUser,
7267
7468
  async (params) => {
7268
7469
  const user = await service.users.getUser(params.user_id);
@@ -7278,7 +7479,7 @@ function registerUsersTools(server, service) {
7278
7479
  );
7279
7480
  server.tool(
7280
7481
  "update_user",
7281
- "Update a user's profile information including name and organization role",
7482
+ "Update a user's first name, last name, or organization role (admin/member). Cannot change the user's email address or workspace-level roles; use update_workspace_member for workspace roles.",
7282
7483
  USERS_TOOL_SCHEMAS.updateUser,
7283
7484
  async (params) => {
7284
7485
  const { user_id, ...updateData } = params;
@@ -7302,7 +7503,7 @@ function registerUsersTools(server, service) {
7302
7503
  );
7303
7504
  server.tool(
7304
7505
  "delete_user",
7305
- "Remove a user from your Portkey organization. Permanently removes the user and all their org/workspace memberships. Cannot be undone.",
7506
+ "Remove a user from your Portkey organization by ID. This action cannot be undone. Permanently removes org and workspace memberships and revokes the user's API keys; active sessions will fail immediately. Use delete_user_invite for pending invitations instead.",
7306
7507
  USERS_TOOL_SCHEMAS.deleteUser,
7307
7508
  async (params) => {
7308
7509
  await service.users.deleteUser(params.user_id);
@@ -7325,7 +7526,7 @@ function registerUsersTools(server, service) {
7325
7526
  );
7326
7527
  server.tool(
7327
7528
  "list_user_invites",
7328
- "List all pending and sent user invitations in your Portkey organization",
7529
+ "List all pending and sent user invitations in your Portkey organization. Returns each invite's ID, email, role, status, and expiry. Use this to check invitation status; use list_all_users for users who have already accepted.",
7329
7530
  USERS_TOOL_SCHEMAS.listUserInvites,
7330
7531
  async () => {
7331
7532
  const invites = await service.users.listUserInvites();
@@ -7348,7 +7549,7 @@ function registerUsersTools(server, service) {
7348
7549
  );
7349
7550
  server.tool(
7350
7551
  "get_user_invite",
7351
- "Retrieve details about a specific user invitation",
7552
+ "Retrieve a specific invitation by its invite ID. Returns the invite's email, role, status, creation date, and expiry. This looks up a pending invitation, not an existing user; use get_user for accepted members.",
7352
7553
  USERS_TOOL_SCHEMAS.getUserInvite,
7353
7554
  async (params) => {
7354
7555
  const invite = await service.users.getUserInvite(params.invite_id);
@@ -7364,7 +7565,7 @@ function registerUsersTools(server, service) {
7364
7565
  );
7365
7566
  server.tool(
7366
7567
  "delete_user_invite",
7367
- "Cancel and delete a pending user invitation",
7568
+ "Cancel and permanently delete a pending user invitation. This revokes the invite link so it can no longer be accepted. Does not remove existing users; use delete_user for that.",
7368
7569
  USERS_TOOL_SCHEMAS.deleteUserInvite,
7369
7570
  async (params) => {
7370
7571
  await service.users.deleteUserInvite(params.invite_id);
@@ -7387,7 +7588,7 @@ function registerUsersTools(server, service) {
7387
7588
  );
7388
7589
  server.tool(
7389
7590
  "resend_user_invite",
7390
- "Resend an invitation email to a pending user",
7591
+ "Resend the invitation email for a pending invite that has not yet been accepted. Use when the original email was lost or expired. The invite must still exist; check with get_user_invite first if unsure.",
7391
7592
  USERS_TOOL_SCHEMAS.resendUserInvite,
7392
7593
  async (params) => {
7393
7594
  await service.users.resendUserInvite(params.invite_id);
@@ -7517,7 +7718,7 @@ function formatWorkspaceDetail(workspace) {
7517
7718
  function registerWorkspacesTools(server, service) {
7518
7719
  server.tool(
7519
7720
  "list_workspaces",
7520
- "Retrieve all workspaces in your Portkey organization, including their configurations and metadata",
7721
+ "Retrieve a paginated list of all workspaces in your Portkey organization. Returns id, name, slug, and configuration for each workspace. Use this tool first to discover workspace_id values needed by other workspace-scoped operations.",
7521
7722
  WORKSPACES_TOOL_SCHEMAS.listWorkspaces,
7522
7723
  async (params) => {
7523
7724
  const workspaces = await service.workspaces.listWorkspaces(params);
@@ -7540,7 +7741,7 @@ function registerWorkspacesTools(server, service) {
7540
7741
  );
7541
7742
  server.tool(
7542
7743
  "get_workspace",
7543
- "Retrieve detailed information about a specific workspace, including its configuration, metadata, and user access details",
7744
+ "Retrieve full details for a single workspace by ID, including its configuration, metadata, and complete member list with roles. Unlike list_workspaces, this includes the full user roster \u2014 use it when you need member details or workspace membership counts.",
7544
7745
  WORKSPACES_TOOL_SCHEMAS.getWorkspace,
7545
7746
  async (params) => {
7546
7747
  const workspace = await service.workspaces.getWorkspace(
@@ -7558,7 +7759,7 @@ function registerWorkspacesTools(server, service) {
7558
7759
  );
7559
7760
  server.tool(
7560
7761
  "create_workspace",
7561
- "Create a new workspace in your Portkey organization",
7762
+ "Create a new workspace to isolate resources, API keys, and team members within your Portkey organization. A URL-friendly slug is auto-generated from the name if not provided. Returns the created workspace's id, name, and slug.",
7562
7763
  WORKSPACES_TOOL_SCHEMAS.createWorkspace,
7563
7764
  async (params) => {
7564
7765
  const workspace = await service.workspaces.createWorkspace({
@@ -7589,7 +7790,7 @@ function registerWorkspacesTools(server, service) {
7589
7790
  );
7590
7791
  server.tool(
7591
7792
  "update_workspace",
7592
- "Update an existing workspace's settings and metadata",
7793
+ "Update a workspace's name, slug, description, default status, or metadata. Only provided fields are changed; omitted fields remain unchanged. Warning: changing a workspace's slug may break existing references and URLs that depend on it.",
7593
7794
  WORKSPACES_TOOL_SCHEMAS.updateWorkspace,
7594
7795
  async (params) => {
7595
7796
  const { workspace_id, is_default, metadata, ...rest } = params;
@@ -7642,7 +7843,7 @@ function registerWorkspacesTools(server, service) {
7642
7843
  );
7643
7844
  server.tool(
7644
7845
  "add_workspace_member",
7645
- "Add a user to a workspace with a specific role",
7846
+ "Add an existing organization user to a workspace with a specified role (admin, manager, or member). Requires user_id as a UUID \u2014 use list_all_users to find it. For users not yet in the organization, use invite_user first.",
7646
7847
  WORKSPACES_TOOL_SCHEMAS.addWorkspaceMember,
7647
7848
  async (params) => {
7648
7849
  const member = await service.workspaces.addWorkspaceMember(
@@ -7671,7 +7872,7 @@ function registerWorkspacesTools(server, service) {
7671
7872
  );
7672
7873
  server.tool(
7673
7874
  "list_workspace_members",
7674
- "List all members of a workspace with their roles",
7875
+ "List all members of a workspace, returning each member's user_id, name, organization role, workspace role, and status. Use this to discover user_id values needed for get_workspace_member, update_workspace_member, or remove_workspace_member.",
7675
7876
  WORKSPACES_TOOL_SCHEMAS.listWorkspaceMembers,
7676
7877
  async (params) => {
7677
7878
  const members = await service.workspaces.listWorkspaceMembers(
@@ -7696,7 +7897,7 @@ function registerWorkspacesTools(server, service) {
7696
7897
  );
7697
7898
  server.tool(
7698
7899
  "get_workspace_member",
7699
- "Get details about a specific member of a workspace",
7900
+ "Get details about a single workspace member by workspace_id and user_id. Returns the member's name, organization role, workspace role, and status. Unlike list_workspace_members, this fetches a single member directly when you already know both IDs.",
7700
7901
  WORKSPACES_TOOL_SCHEMAS.getWorkspaceMember,
7701
7902
  async (params) => {
7702
7903
  const member = await service.workspaces.getWorkspaceMember(
@@ -7715,7 +7916,7 @@ function registerWorkspacesTools(server, service) {
7715
7916
  );
7716
7917
  server.tool(
7717
7918
  "update_workspace_member",
7718
- "Update a member's role in a workspace",
7919
+ "Update a workspace member's role. Only the role can be changed \u2014 valid values are admin, manager, or member. Use list_workspace_members or get_workspace_member to check the current role first.",
7719
7920
  WORKSPACES_TOOL_SCHEMAS.updateWorkspaceMember,
7720
7921
  async (params) => {
7721
7922
  const member = await service.workspaces.updateWorkspaceMember(
@@ -7744,7 +7945,7 @@ function registerWorkspacesTools(server, service) {
7744
7945
  );
7745
7946
  server.tool(
7746
7947
  "remove_workspace_member",
7747
- "Remove a user from a workspace",
7948
+ "Remove a user from a workspace, revoking their workspace-level access. This does not delete the user from the organization \u2014 use delete_user for full org removal. The user can be re-added later with add_workspace_member.",
7748
7949
  WORKSPACES_TOOL_SCHEMAS.removeWorkspaceMember,
7749
7950
  async (params) => {
7750
7951
  await service.workspaces.removeWorkspaceMember(
@@ -7795,6 +7996,9 @@ var TOOL_DOMAIN_NAMES = TOOL_DOMAIN_REGISTRARS.map(
7795
7996
  ([domain]) => domain
7796
7997
  );
7797
7998
  var TOOL_DOMAIN_NAME_SET = new Set(TOOL_DOMAIN_NAMES);
7999
+ function isToolDomain(value) {
8000
+ return TOOL_DOMAIN_NAME_SET.has(value);
8001
+ }
7798
8002
  function normalizeToolDomains(domains) {
7799
8003
  const selectedDomains = new Set(domains);
7800
8004
  return TOOL_DOMAIN_REGISTRARS.filter(
@@ -7822,6 +8026,37 @@ var DESTRUCTIVE_TOOL_PREFIXES = [
7822
8026
  "cancel_",
7823
8027
  "reset_"
7824
8028
  ];
8029
+ var ENTERPRISE_GATED_TOOL_NAMES = /* @__PURE__ */ new Set([
8030
+ "get_cost_analytics",
8031
+ "get_request_analytics",
8032
+ "get_token_analytics",
8033
+ "get_latency_analytics",
8034
+ "get_error_analytics",
8035
+ "get_error_rate_analytics",
8036
+ "get_cache_hit_latency",
8037
+ "get_cache_hit_rate",
8038
+ "get_users_analytics",
8039
+ "get_error_stacks_analytics",
8040
+ "get_error_status_codes_analytics",
8041
+ "get_user_requests_analytics",
8042
+ "get_rescued_requests_analytics",
8043
+ "get_feedback_analytics",
8044
+ "get_feedback_models_analytics",
8045
+ "get_feedback_scores_analytics",
8046
+ "get_feedback_weighted_analytics",
8047
+ "get_analytics_group_users",
8048
+ "get_analytics_group_models",
8049
+ "get_analytics_group_metadata",
8050
+ "list_audit_logs",
8051
+ "get_integration",
8052
+ "list_integration_models",
8053
+ "list_integration_workspaces",
8054
+ "list_all_users",
8055
+ "get_user",
8056
+ "list_user_invites",
8057
+ "get_user_stats"
8058
+ ]);
8059
+ var ENTERPRISE_GATED_DESCRIPTION_NOTE = "Enterprise-gated. Returns 403 on non-Enterprise Portkey plans.";
7825
8060
  function isToolAnnotationsLike(value) {
7826
8061
  if (!isRecord2(value)) {
7827
8062
  return false;
@@ -7870,6 +8105,15 @@ function inferToolAnnotations(toolName) {
7870
8105
  openWorldHint: true
7871
8106
  };
7872
8107
  }
8108
+ function augmentToolDescription(toolName, description) {
8109
+ if (!description || !ENTERPRISE_GATED_TOOL_NAMES.has(toolName)) {
8110
+ return description;
8111
+ }
8112
+ if (description.includes(ENTERPRISE_GATED_DESCRIPTION_NOTE)) {
8113
+ return description;
8114
+ }
8115
+ return `${description} ${ENTERPRISE_GATED_DESCRIPTION_NOTE}`;
8116
+ }
7873
8117
  function getToolErrorMessage(error) {
7874
8118
  if (error instanceof Error && error.message) {
7875
8119
  return error.message;
@@ -7974,6 +8218,7 @@ function buildToolRegistration(name, rest) {
7974
8218
  if (typeof args[0] === "string") {
7975
8219
  description = args.shift();
7976
8220
  }
8221
+ description = augmentToolDescription(name, description);
7977
8222
  let inputSchema;
7978
8223
  let annotations = inferredAnnotations;
7979
8224
  if (args.length === 1) {
@@ -8081,7 +8326,27 @@ function readPackageVersion() {
8081
8326
  return "0.0.0";
8082
8327
  }
8083
8328
  var PACKAGE_VERSION = readPackageVersion();
8084
- var SERVER_INSTRUCTIONS = "Portkey Admin API server. Use list_* tools for discovery and get_* tools for details. Analytics tools require time_of_generation_min/max. Prompt workflows: create_prompt -> publish_prompt. Always validate_completion_metadata before run_prompt_completion.";
8329
+ var SERVER_INSTRUCTIONS = "Portkey Admin API server. Use list_* tools for discovery and get_* tools for details. Analytics tools require time_of_generation_min/max. Prompt workflows: create_prompt -> publish_prompt. Always validate_completion_metadata before run_prompt_completion. If the server is configured with only some domains, stay within that subset instead of assuming every Portkey admin tool is available.";
8330
+ function parseConfiguredToolDomains(rawValue = process.env.PORTKEY_TOOL_DOMAINS?.trim() || process.env.MCP_TOOL_DOMAINS?.trim()) {
8331
+ if (!rawValue) {
8332
+ return void 0;
8333
+ }
8334
+ const requestedDomains = rawValue.split(",").map((value) => value.trim().toLowerCase()).filter((value) => value.length > 0);
8335
+ if (requestedDomains.length === 0) {
8336
+ throw new Error(
8337
+ `Invalid PORTKEY_TOOL_DOMAINS value. Expected one or more domains from: ${TOOL_DOMAIN_NAMES.join(", ")}`
8338
+ );
8339
+ }
8340
+ const invalidDomains = requestedDomains.filter(
8341
+ (value) => !isToolDomain(value)
8342
+ );
8343
+ if (invalidDomains.length > 0) {
8344
+ throw new Error(
8345
+ `Unknown tool domains in PORTKEY_TOOL_DOMAINS: ${invalidDomains.join(", ")}. Valid domains: ${TOOL_DOMAIN_NAMES.join(", ")}`
8346
+ );
8347
+ }
8348
+ return normalizeToolDomains(requestedDomains);
8349
+ }
8085
8350
  function createMcpServer(options = {}) {
8086
8351
  const service = getSharedPortkeyService();
8087
8352
  const server = new McpServer(
@@ -8096,7 +8361,9 @@ function createMcpServer(options = {}) {
8096
8361
  instructions: SERVER_INSTRUCTIONS
8097
8362
  }
8098
8363
  );
8099
- registerAllTools(server, service, { domains: options.toolDomains });
8364
+ registerAllTools(server, service, {
8365
+ domains: options.toolDomains ?? parseConfiguredToolDomains()
8366
+ });
8100
8367
  return {
8101
8368
  server,
8102
8369
  service