portkey-admin-mcp 0.2.0 → 0.3.1

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/server.js CHANGED
@@ -1453,9 +1453,6 @@ var TracingService = class extends BaseService {
1453
1453
  data
1454
1454
  );
1455
1455
  }
1456
- async getTrace(id) {
1457
- return this.get(`/logs/${this.encodePathSegment(id)}`);
1458
- }
1459
1456
  };
1460
1457
 
1461
1458
  // src/services/users.service.ts
@@ -1689,23 +1686,99 @@ var baseAnalyticsSchema = {
1689
1686
  prompt_token_max: z.coerce.number().positive().optional().describe("Maximum number of prompt tokens"),
1690
1687
  completion_token_min: z.coerce.number().positive().optional().describe("Minimum number of completion tokens"),
1691
1688
  completion_token_max: z.coerce.number().positive().optional().describe("Maximum number of completion tokens"),
1692
- status_code: z.string().optional().describe("Filter by specific HTTP status codes (comma-separated)"),
1689
+ status_code: z.string().optional().describe(
1690
+ "Legacy Portkey query param for HTTP status codes. Comma-separated string; prefer status_codes for structured inputs."
1691
+ ),
1693
1692
  weighted_feedback_min: z.coerce.number().min(-10).max(10).optional().describe("Minimum weighted feedback score (-10 to 10)"),
1694
1693
  weighted_feedback_max: z.coerce.number().min(-10).max(10).optional().describe("Maximum weighted feedback score (-10 to 10)"),
1695
- virtual_keys: z.string().optional().describe("Filter by specific virtual key slugs (comma-separated)"),
1696
- configs: z.string().optional().describe("Filter by specific config slugs (comma-separated)"),
1694
+ virtual_keys: z.string().optional().describe(
1695
+ "Legacy Portkey query param for virtual key slugs. Comma-separated string; prefer virtual_key_slugs for structured inputs."
1696
+ ),
1697
+ configs: z.string().optional().describe(
1698
+ "Legacy Portkey query param for config slugs. Comma-separated string; prefer config_slugs for structured inputs."
1699
+ ),
1700
+ status_codes: z.array(z.string()).optional().describe(
1701
+ "Structured alias for status_code. Use an array of HTTP status codes; normalized to the legacy comma-separated Portkey query param."
1702
+ ),
1703
+ virtual_key_slugs: z.array(z.string()).optional().describe(
1704
+ "Structured alias for virtual_keys. Use an array of virtual key slugs; normalized to the legacy comma-separated Portkey query param."
1705
+ ),
1706
+ config_slugs: z.array(z.string()).optional().describe(
1707
+ "Structured alias for configs. Use an array of config slugs; normalized to the legacy comma-separated Portkey query param."
1708
+ ),
1697
1709
  workspace_slug: z.string().optional().describe("Filter by specific workspace"),
1698
- api_key_ids: z.string().optional().describe("Filter by specific API key UUIDs (comma-separated)"),
1710
+ api_key_ids: z.preprocess((value) => {
1711
+ if (value == null) {
1712
+ return value;
1713
+ }
1714
+ if (Array.isArray(value)) {
1715
+ return value.map((item) => String(item)).join(",");
1716
+ }
1717
+ return value;
1718
+ }, z.string().optional()).describe(
1719
+ "Legacy Portkey query param for API key UUIDs. Comma-separated string; request_analytics also accepts an array and normalizes it to this form."
1720
+ ),
1699
1721
  metadata: z.string().optional().describe(
1700
- `Stringified JSON object for metadata filtering, e.g. '{"env":"prod","app":"myapp"}'.`
1722
+ `Legacy Portkey query param for metadata filtering. Stringified JSON object, e.g. '{"env":"prod","app":"myapp"}'; prefer metadata_filter for structured inputs.`
1701
1723
  ),
1702
1724
  ai_org_model: z.string().optional().describe(
1703
- "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."
1725
+ "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."
1726
+ ),
1727
+ provider_models: z.array(z.string()).optional().describe(
1728
+ "Structured alias for ai_org_model. Use provider__model strings in an array; normalized to the legacy comma-separated Portkey query param."
1729
+ ),
1730
+ trace_id: z.string().optional().describe(
1731
+ "Legacy Portkey query param for trace IDs. Comma-separated string; prefer trace_ids for structured inputs."
1732
+ ),
1733
+ trace_ids: z.array(z.string()).optional().describe(
1734
+ "Structured alias for trace_id. Use an array of trace IDs; normalized to the legacy comma-separated Portkey query param."
1735
+ ),
1736
+ span_id: z.string().optional().describe(
1737
+ "Legacy Portkey query param for span IDs. Comma-separated string; prefer span_ids for structured inputs."
1738
+ ),
1739
+ span_ids: z.array(z.string()).optional().describe(
1740
+ "Structured alias for span_id. Use an array of span IDs; normalized to the legacy comma-separated Portkey query param."
1741
+ ),
1742
+ metadata_filter: z.record(z.string(), z.unknown()).optional().describe(
1743
+ "Structured alias for metadata. Use an object such as { env: 'prod' }; normalized to a JSON string before the request is sent."
1704
1744
  ),
1705
- trace_id: z.string().optional().describe("Filter by trace IDs (comma-separated)"),
1706
- span_id: z.string().optional().describe("Filter by span IDs (comma-separated)"),
1707
1745
  prompt_slug: z.string().optional().describe("Filter by prompt slug")
1708
1746
  };
1747
+ var requestAnalyticsSchema = {
1748
+ ...baseAnalyticsSchema,
1749
+ status_codes: z.array(z.string()).optional().describe(
1750
+ "Structured alias for status_code. Use an array of HTTP status codes; normalized to the legacy comma-separated Portkey query param."
1751
+ ),
1752
+ virtual_key_slugs: z.array(z.string()).optional().describe(
1753
+ "Structured alias for virtual_keys. Use an array of virtual key slugs; normalized to the legacy comma-separated Portkey query param."
1754
+ ),
1755
+ config_slugs: z.array(z.string()).optional().describe(
1756
+ "Structured alias for configs. Use an array of config slugs; normalized to the legacy comma-separated Portkey query param."
1757
+ ),
1758
+ api_key_ids: z.preprocess((value) => {
1759
+ if (value == null) {
1760
+ return value;
1761
+ }
1762
+ if (Array.isArray(value)) {
1763
+ return value.map((item) => String(item)).join(",");
1764
+ }
1765
+ return value;
1766
+ }, z.string().optional()).describe(
1767
+ "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."
1768
+ ),
1769
+ trace_ids: z.array(z.string()).optional().describe(
1770
+ "Structured alias for trace_id. Use an array of trace IDs; normalized to the legacy comma-separated Portkey query param."
1771
+ ),
1772
+ span_ids: z.array(z.string()).optional().describe(
1773
+ "Structured alias for span_id. Use an array of span IDs; normalized to the legacy comma-separated Portkey query param."
1774
+ ),
1775
+ provider_models: z.array(z.string()).optional().describe(
1776
+ "Structured alias for ai_org_model. Use provider__model strings in an array; normalized to the legacy comma-separated Portkey query param."
1777
+ ),
1778
+ metadata_filter: z.record(z.string(), z.unknown()).optional().describe(
1779
+ "Structured alias for metadata. Use an object such as { env: 'prod' }; normalized to a JSON string before the request is sent."
1780
+ )
1781
+ };
1709
1782
  var paginatedAnalyticsSchema = {
1710
1783
  ...baseAnalyticsSchema,
1711
1784
  current_page: z.coerce.number().positive().optional().describe("Page number for pagination"),
@@ -1732,13 +1805,88 @@ function formatGroupedAnalytics(analytics, groupLabel) {
1732
1805
  [groupLabel]: analytics.data
1733
1806
  };
1734
1807
  }
1808
+ function normalizeCommaSeparatedParam(value) {
1809
+ if (value == null) {
1810
+ return void 0;
1811
+ }
1812
+ if (Array.isArray(value)) {
1813
+ return value.map((item) => String(item)).join(",");
1814
+ }
1815
+ if (typeof value === "string") {
1816
+ return value;
1817
+ }
1818
+ return void 0;
1819
+ }
1820
+ function normalizeMetadataFilter(value) {
1821
+ if (value == null) {
1822
+ return void 0;
1823
+ }
1824
+ if (typeof value === "string") {
1825
+ return value;
1826
+ }
1827
+ if (typeof value === "object") {
1828
+ return JSON.stringify(value);
1829
+ }
1830
+ return void 0;
1831
+ }
1832
+ function normalizeAnalyticsParams(params) {
1833
+ const {
1834
+ status_codes,
1835
+ virtual_key_slugs,
1836
+ config_slugs,
1837
+ api_key_ids,
1838
+ trace_ids,
1839
+ span_ids,
1840
+ provider_models,
1841
+ metadata_filter,
1842
+ ...legacyParams
1843
+ } = params;
1844
+ const normalizedParams = {
1845
+ ...legacyParams
1846
+ };
1847
+ const statusCode = normalizeCommaSeparatedParam(status_codes) ?? normalizeCommaSeparatedParam(legacyParams.status_code);
1848
+ if (statusCode !== void 0) {
1849
+ normalizedParams.status_code = statusCode;
1850
+ }
1851
+ const virtualKeys = normalizeCommaSeparatedParam(virtual_key_slugs) ?? normalizeCommaSeparatedParam(legacyParams.virtual_keys);
1852
+ if (virtualKeys !== void 0) {
1853
+ normalizedParams.virtual_keys = virtualKeys;
1854
+ }
1855
+ const configs = normalizeCommaSeparatedParam(config_slugs) ?? normalizeCommaSeparatedParam(legacyParams.configs);
1856
+ if (configs !== void 0) {
1857
+ normalizedParams.configs = configs;
1858
+ }
1859
+ const apiKeyIds = normalizeCommaSeparatedParam(api_key_ids) ?? normalizeCommaSeparatedParam(legacyParams.api_key_ids);
1860
+ if (apiKeyIds !== void 0) {
1861
+ normalizedParams.api_key_ids = apiKeyIds;
1862
+ }
1863
+ const metadata = normalizeMetadataFilter(metadata_filter) ?? normalizeMetadataFilter(legacyParams.metadata);
1864
+ if (metadata !== void 0) {
1865
+ normalizedParams.metadata = metadata;
1866
+ }
1867
+ const providerModels = normalizeCommaSeparatedParam(provider_models) ?? normalizeCommaSeparatedParam(legacyParams.ai_org_model);
1868
+ if (providerModels !== void 0) {
1869
+ normalizedParams.ai_org_model = providerModels;
1870
+ }
1871
+ const traceId = normalizeCommaSeparatedParam(trace_ids) ?? normalizeCommaSeparatedParam(legacyParams.trace_id);
1872
+ if (traceId !== void 0) {
1873
+ normalizedParams.trace_id = traceId;
1874
+ }
1875
+ const spanId = normalizeCommaSeparatedParam(span_ids) ?? normalizeCommaSeparatedParam(legacyParams.span_id);
1876
+ if (spanId !== void 0) {
1877
+ normalizedParams.span_id = spanId;
1878
+ }
1879
+ return normalizedParams;
1880
+ }
1735
1881
  function registerAnalyticsTools(server, service) {
1736
1882
  server.tool(
1737
1883
  "get_cost_analytics",
1738
- "Retrieve detailed cost analytics data over time, including total costs and averages per request",
1884
+ "Get cost time-series data with summary.total_cost, summary.average_cost_per_request, and per-bucket total/avg cost. Use this for spend analysis and spike detection; use get_token_analytics when you need token volume instead of monetary cost.",
1739
1885
  baseAnalyticsSchema,
1740
1886
  async (params) => {
1741
- const analytics = await service.analytics.getCostAnalytics(params);
1887
+ const analytics = await service.analytics.getCostAnalytics(
1888
+ normalizeAnalyticsParams(params)
1889
+ );
1742
1890
  const dataPoints = analytics.data_points.map((point) => ({
1743
1891
  timestamp: point.timestamp,
1744
1892
  total_cost: point.total,
@@ -1766,10 +1914,12 @@ function registerAnalyticsTools(server, service) {
1766
1914
  );
1767
1915
  server.tool(
1768
1916
  "get_request_analytics",
1769
- "Retrieve request analytics as time-series data, showing total, successful, and failed requests over time",
1770
- baseAnalyticsSchema,
1917
+ "Get request-volume time-series data with summary.total_requests, summary.successful_requests, summary.failed_requests, and per-bucket total/success/failed counts. Use this for traffic and reliability trends; use get_error_analytics when you only need error counts.",
1918
+ requestAnalyticsSchema,
1771
1919
  async (params) => {
1772
- const analytics = await service.analytics.getRequestAnalytics(params);
1920
+ const analytics = await service.analytics.getRequestAnalytics(
1921
+ normalizeAnalyticsParams(params)
1922
+ );
1773
1923
  const dataPoints = analytics.data_points.map((point) => ({
1774
1924
  timestamp: point.timestamp,
1775
1925
  total: point.total,
@@ -1799,10 +1949,12 @@ function registerAnalyticsTools(server, service) {
1799
1949
  );
1800
1950
  server.tool(
1801
1951
  "get_token_analytics",
1802
- "Retrieve token usage analytics as time-series data, showing total, prompt, and completion tokens over time",
1952
+ "Get token-usage time-series data with summary.total_tokens, summary.prompt_tokens, summary.completion_tokens, and per-bucket total/prompt/completion counts. Use this for consumption trends; use get_cost_analytics when you need spend instead of token volume.",
1803
1953
  baseAnalyticsSchema,
1804
1954
  async (params) => {
1805
- const analytics = await service.analytics.getTokenAnalytics(params);
1955
+ const analytics = await service.analytics.getTokenAnalytics(
1956
+ normalizeAnalyticsParams(params)
1957
+ );
1806
1958
  const dataPoints = analytics.data_points.map((point) => ({
1807
1959
  timestamp: point.timestamp,
1808
1960
  total: point.total,
@@ -1832,10 +1984,12 @@ function registerAnalyticsTools(server, service) {
1832
1984
  );
1833
1985
  server.tool(
1834
1986
  "get_latency_analytics",
1835
- "Retrieve latency analytics as time-series data, showing average, p50, p90, and p99 latency percentiles over time",
1987
+ "Get latency time-series data with summary.avg_latency_ms, summary.p50_latency_ms, summary.p90_latency_ms, summary.p99_latency_ms, and per-bucket latency percentiles in ms. Use this to spot slowdowns and regressions; use get_cache_hit_latency when you only want cache-hit latency.",
1836
1988
  baseAnalyticsSchema,
1837
1989
  async (params) => {
1838
- const analytics = await service.analytics.getLatencyAnalytics(params);
1990
+ const analytics = await service.analytics.getLatencyAnalytics(
1991
+ normalizeAnalyticsParams(params)
1992
+ );
1839
1993
  const dataPoints = analytics.data_points.map((point) => ({
1840
1994
  timestamp: point.timestamp,
1841
1995
  avg: point.avg,
@@ -1867,10 +2021,12 @@ function registerAnalyticsTools(server, service) {
1867
2021
  );
1868
2022
  server.tool(
1869
2023
  "get_error_analytics",
1870
- "Retrieve error count analytics as time-series data, showing total error counts over time",
2024
+ "Get error-count time-series data with summary.total_errors and per-bucket counts. Use this for high-level error trends; use get_error_rate_analytics for percentages, or get_error_status_codes_analytics and get_error_stacks_analytics for breakdowns.",
1871
2025
  baseAnalyticsSchema,
1872
2026
  async (params) => {
1873
- const analytics = await service.analytics.getErrorAnalytics(params);
2027
+ const analytics = await service.analytics.getErrorAnalytics(
2028
+ normalizeAnalyticsParams(params)
2029
+ );
1874
2030
  const dataPoints = analytics.data_points.map((point) => ({
1875
2031
  timestamp: point.timestamp,
1876
2032
  total_errors: point.total
@@ -1896,10 +2052,12 @@ function registerAnalyticsTools(server, service) {
1896
2052
  );
1897
2053
  server.tool(
1898
2054
  "get_error_rate_analytics",
1899
- "Retrieve error rate analytics as time-series data, showing the percentage of failed requests over time",
2055
+ "Get error-rate time-series data with summary.error_rate_percent and per-bucket percentages of total requests. Use this for reliability and SLA trends; use get_error_analytics for absolute error counts instead.",
1900
2056
  baseAnalyticsSchema,
1901
2057
  async (params) => {
1902
- const analytics = await service.analytics.getErrorRateAnalytics(params);
2058
+ const analytics = await service.analytics.getErrorRateAnalytics(
2059
+ normalizeAnalyticsParams(params)
2060
+ );
1903
2061
  const dataPoints = analytics.data_points.map((point) => ({
1904
2062
  timestamp: point.timestamp,
1905
2063
  error_rate_percent: point.rate
@@ -1925,10 +2083,12 @@ function registerAnalyticsTools(server, service) {
1925
2083
  );
1926
2084
  server.tool(
1927
2085
  "get_cache_hit_latency",
1928
- "Retrieve cache hit latency analytics as time-series data, showing total and average latency for cache hits over time",
2086
+ "Get cache-hit-only latency time-series data with summary.total_latency, summary.avg_latency, and per-bucket total/avg latency. Use this to evaluate cached-response speed; use get_latency_analytics for all requests.",
1929
2087
  baseAnalyticsSchema,
1930
2088
  async (params) => {
1931
- const analytics = await service.analytics.getCacheHitLatency(params);
2089
+ const analytics = await service.analytics.getCacheHitLatency(
2090
+ normalizeAnalyticsParams(params)
2091
+ );
1932
2092
  const dataPoints = analytics.data_points.map((point) => ({
1933
2093
  timestamp: point.timestamp,
1934
2094
  total: point.total,
@@ -1956,10 +2116,12 @@ function registerAnalyticsTools(server, service) {
1956
2116
  );
1957
2117
  server.tool(
1958
2118
  "get_cache_hit_rate",
1959
- "Retrieve cache hit rate analytics as time-series data, showing hit rate percentage, total hits, and misses over time",
2119
+ "Get cache-effectiveness time-series data with summary.hit_rate, summary.total_hits, summary.total_misses, and per-bucket hits/misses/rate. Use this to measure cache effectiveness; use get_cache_hit_latency for speed rather than hit/miss ratio.",
1960
2120
  baseAnalyticsSchema,
1961
2121
  async (params) => {
1962
- const analytics = await service.analytics.getCacheHitRate(params);
2122
+ const analytics = await service.analytics.getCacheHitRate(
2123
+ normalizeAnalyticsParams(params)
2124
+ );
1963
2125
  const dataPoints = analytics.data_points.map((point) => ({
1964
2126
  timestamp: point.timestamp,
1965
2127
  rate: point.rate,
@@ -1989,10 +2151,12 @@ function registerAnalyticsTools(server, service) {
1989
2151
  );
1990
2152
  server.tool(
1991
2153
  "get_users_analytics",
1992
- "Retrieve user activity analytics over time, showing active and new user counts",
2154
+ "Get user-growth time-series data with summary.total_active_users, summary.total_new_users, and per-bucket active/new user counts. Use this for growth and adoption trends; use get_user_requests_analytics for per-user traffic or get_analytics_group_users for per-user cost and token detail.",
1993
2155
  baseAnalyticsSchema,
1994
2156
  async (params) => {
1995
- const analytics = await service.analytics.getUsersAnalytics(params);
2157
+ const analytics = await service.analytics.getUsersAnalytics(
2158
+ normalizeAnalyticsParams(params)
2159
+ );
1996
2160
  const dataPoints = analytics.data_points.map((point) => ({
1997
2161
  timestamp: point.timestamp,
1998
2162
  active_users: point.active_users,
@@ -2020,10 +2184,12 @@ function registerAnalyticsTools(server, service) {
2020
2184
  );
2021
2185
  server.tool(
2022
2186
  "get_error_stacks_analytics",
2023
- "Retrieve error analytics broken down by status code stacks over time",
2187
+ "Get stacked error-series data grouped by HTTP status code over time, with summary and per-code series. Use this to see which error classes dominate; use get_error_status_codes_analytics for distinct-code distribution instead.",
2024
2188
  baseAnalyticsSchema,
2025
2189
  async (params) => {
2026
- const analytics = await service.analytics.getErrorStacksAnalytics(params);
2190
+ const analytics = await service.analytics.getErrorStacksAnalytics(
2191
+ normalizeAnalyticsParams(params)
2192
+ );
2027
2193
  return {
2028
2194
  content: [
2029
2195
  {
@@ -2040,10 +2206,12 @@ function registerAnalyticsTools(server, service) {
2040
2206
  );
2041
2207
  server.tool(
2042
2208
  "get_error_status_codes_analytics",
2043
- "Retrieve unique error status code distribution analytics over time",
2209
+ "Get HTTP error-code distribution time-series data with summary and per-code series. Use this to see which codes occur most often; use get_error_stacks_analytics for stacked or cumulative breakdowns.",
2044
2210
  baseAnalyticsSchema,
2045
2211
  async (params) => {
2046
- const analytics = await service.analytics.getErrorStatusCodesAnalytics(params);
2212
+ const analytics = await service.analytics.getErrorStatusCodesAnalytics(
2213
+ normalizeAnalyticsParams(params)
2214
+ );
2047
2215
  return {
2048
2216
  content: [
2049
2217
  {
@@ -2060,10 +2228,12 @@ function registerAnalyticsTools(server, service) {
2060
2228
  );
2061
2229
  server.tool(
2062
2230
  "get_user_requests_analytics",
2063
- "Retrieve per-user request count analytics over time",
2231
+ "Get per-user request-count time-series data with counts grouped by user. Use this to find heavy users and traffic concentration; use get_users_analytics for aggregate active and new user trends instead.",
2064
2232
  baseAnalyticsSchema,
2065
2233
  async (params) => {
2066
- const analytics = await service.analytics.getUserRequestsAnalytics(params);
2234
+ const analytics = await service.analytics.getUserRequestsAnalytics(
2235
+ normalizeAnalyticsParams(params)
2236
+ );
2067
2237
  return {
2068
2238
  content: [
2069
2239
  {
@@ -2080,10 +2250,12 @@ function registerAnalyticsTools(server, service) {
2080
2250
  );
2081
2251
  server.tool(
2082
2252
  "get_rescued_requests_analytics",
2083
- "Retrieve analytics for requests rescued by retry or fallback strategies over time",
2253
+ "Get rescued-request time-series data showing requests recovered by retry or fallback handling. Use this only when your configs include resilience features, and use it to measure how often recovery logic saved requests.",
2084
2254
  baseAnalyticsSchema,
2085
2255
  async (params) => {
2086
- const analytics = await service.analytics.getRescuedRequestsAnalytics(params);
2256
+ const analytics = await service.analytics.getRescuedRequestsAnalytics(
2257
+ normalizeAnalyticsParams(params)
2258
+ );
2087
2259
  return {
2088
2260
  content: [
2089
2261
  {
@@ -2100,10 +2272,12 @@ function registerAnalyticsTools(server, service) {
2100
2272
  );
2101
2273
  server.tool(
2102
2274
  "get_feedback_analytics",
2103
- "Retrieve feedback submission analytics over time",
2275
+ "Get feedback-submission time-series data with summary totals and per-bucket counts. Use this as the top-level feedback trend view; use get_feedback_models_analytics, get_feedback_scores_analytics, or get_feedback_weighted_analytics for breakdowns.",
2104
2276
  baseAnalyticsSchema,
2105
2277
  async (params) => {
2106
- const analytics = await service.analytics.getFeedbackAnalytics(params);
2278
+ const analytics = await service.analytics.getFeedbackAnalytics(
2279
+ normalizeAnalyticsParams(params)
2280
+ );
2107
2281
  return {
2108
2282
  content: [
2109
2283
  {
@@ -2120,10 +2294,12 @@ function registerAnalyticsTools(server, service) {
2120
2294
  );
2121
2295
  server.tool(
2122
2296
  "get_feedback_models_analytics",
2123
- "Retrieve feedback analytics grouped by AI model over time",
2297
+ "Get feedback time-series data grouped by model, with per-model counts over time. Use this to compare feedback volume and satisfaction across models; use get_feedback_analytics for the overall total instead.",
2124
2298
  baseAnalyticsSchema,
2125
2299
  async (params) => {
2126
- const analytics = await service.analytics.getFeedbackModelsAnalytics(params);
2300
+ const analytics = await service.analytics.getFeedbackModelsAnalytics(
2301
+ normalizeAnalyticsParams(params)
2302
+ );
2127
2303
  return {
2128
2304
  content: [
2129
2305
  {
@@ -2140,10 +2316,12 @@ function registerAnalyticsTools(server, service) {
2140
2316
  );
2141
2317
  server.tool(
2142
2318
  "get_feedback_scores_analytics",
2143
- "Retrieve feedback score distribution analytics over time",
2319
+ "Get raw feedback-score distribution time-series data with per-score buckets. Use this to understand sentiment mix; use get_feedback_weighted_analytics for calibrated scores with weighting.",
2144
2320
  baseAnalyticsSchema,
2145
2321
  async (params) => {
2146
- const analytics = await service.analytics.getFeedbackScoresAnalytics(params);
2322
+ const analytics = await service.analytics.getFeedbackScoresAnalytics(
2323
+ normalizeAnalyticsParams(params)
2324
+ );
2147
2325
  return {
2148
2326
  content: [
2149
2327
  {
@@ -2160,10 +2338,12 @@ function registerAnalyticsTools(server, service) {
2160
2338
  );
2161
2339
  server.tool(
2162
2340
  "get_feedback_weighted_analytics",
2163
- "Retrieve weighted feedback analytics over time",
2341
+ "Get weighted feedback-score time-series data using the weight recorded at feedback creation. Use this for calibrated quality metrics; use get_feedback_scores_analytics for the raw unweighted distribution.",
2164
2342
  baseAnalyticsSchema,
2165
2343
  async (params) => {
2166
- const analytics = await service.analytics.getFeedbackWeightedAnalytics(params);
2344
+ const analytics = await service.analytics.getFeedbackWeightedAnalytics(
2345
+ normalizeAnalyticsParams(params)
2346
+ );
2167
2347
  return {
2168
2348
  content: [
2169
2349
  {
@@ -2180,10 +2360,12 @@ function registerAnalyticsTools(server, service) {
2180
2360
  );
2181
2361
  server.tool(
2182
2362
  "get_analytics_group_users",
2183
- "Retrieve analytics data grouped by user with pagination",
2363
+ "Get a paginated per-user breakdown with total_groups, group_count, and a users array containing request count, cost, and token usage. Use this for billing, audits, or top-consumer analysis; use get_users_analytics for aggregate active and new user trends.",
2184
2364
  paginatedAnalyticsSchema,
2185
2365
  async (params) => {
2186
- const analytics = await service.analytics.getAnalyticsGroupUsers(params);
2366
+ const analytics = await service.analytics.getAnalyticsGroupUsers(
2367
+ normalizeAnalyticsParams(params)
2368
+ );
2187
2369
  return {
2188
2370
  content: [
2189
2371
  {
@@ -2200,10 +2382,12 @@ function registerAnalyticsTools(server, service) {
2200
2382
  );
2201
2383
  server.tool(
2202
2384
  "get_analytics_group_models",
2203
- "Retrieve analytics data grouped by AI model with pagination",
2385
+ "Get a paginated per-model breakdown with total_groups, group_count, and a models array containing request count, cost, and token usage. Use this to compare model cost, popularity, and efficiency; use get_token_analytics or get_cost_analytics for time-series trends instead.",
2204
2386
  paginatedAnalyticsSchema,
2205
2387
  async (params) => {
2206
- const analytics = await service.analytics.getAnalyticsGroupModels(params);
2388
+ const analytics = await service.analytics.getAnalyticsGroupModels(
2389
+ normalizeAnalyticsParams(params)
2390
+ );
2207
2391
  return {
2208
2392
  content: [
2209
2393
  {
@@ -2220,13 +2404,13 @@ function registerAnalyticsTools(server, service) {
2220
2404
  );
2221
2405
  server.tool(
2222
2406
  "get_analytics_group_metadata",
2223
- "Retrieve analytics data grouped by a specific metadata key with pagination",
2407
+ "Get a paginated metadata breakdown with total_groups, group_count, and a metadata_groups array grouped by the required metadata_key. Use this for custom breakdowns like per-environment or per-feature analysis; pass metadata_key in addition to the time window.",
2224
2408
  analyticsGroupMetadataSchema,
2225
2409
  async (params) => {
2226
2410
  const { metadata_key, ...analyticsParams } = params;
2227
2411
  const analytics = await service.analytics.getAnalyticsGroupMetadata(
2228
2412
  metadata_key,
2229
- analyticsParams
2413
+ normalizeAnalyticsParams(analyticsParams)
2230
2414
  );
2231
2415
  return {
2232
2416
  content: [
@@ -2270,7 +2454,7 @@ var AUDIT_TOOL_SCHEMAS = {
2270
2454
  function registerAuditTools(server, service) {
2271
2455
  server.tool(
2272
2456
  "list_audit_logs",
2273
- "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.",
2457
+ "List audit log events for a Portkey workspace or organization. Returns paginated action-level records with actor, resource, metadata, and timestamps for compliance or incident review; use this instead of analytics when you need individual events, not aggregates.",
2274
2458
  AUDIT_TOOL_SCHEMAS.listAuditLogs,
2275
2459
  async (params) => {
2276
2460
  const result = await service.audit.listAuditLogs({
@@ -2350,7 +2534,7 @@ var COLLECTIONS_TOOL_SCHEMAS = {
2350
2534
  function registerCollectionsTools(server, service) {
2351
2535
  server.tool(
2352
2536
  "list_collections",
2353
- "List all prompt collections in your Portkey organization. Collections group prompts by app (e.g., hourlink, apizone, research-pilot).",
2537
+ "List prompt collections in the workspace, optionally filtering by name or workspace. Returns ids, names, slugs, and timestamps so you can choose a collection_id before create_prompt, get_collection, or list_prompts.",
2354
2538
  COLLECTIONS_TOOL_SCHEMAS.listCollections,
2355
2539
  async (params) => {
2356
2540
  const collections = await service.collections.listCollections(params);
@@ -2380,7 +2564,7 @@ function registerCollectionsTools(server, service) {
2380
2564
  );
2381
2565
  server.tool(
2382
2566
  "create_collection",
2383
- "Create a new prompt collection for organizing prompts by app. Use one collection per app (hourlink, apizone, research-pilot).",
2567
+ "Create a new prompt collection for organizing prompts by app. Use this when you need a new namespace before create_prompt; returns the collection id and slug, and does not move any prompts.",
2384
2568
  COLLECTIONS_TOOL_SCHEMAS.createCollection,
2385
2569
  async (params) => {
2386
2570
  const result = await service.collections.createCollection(params);
@@ -2404,7 +2588,7 @@ function registerCollectionsTools(server, service) {
2404
2588
  );
2405
2589
  server.tool(
2406
2590
  "get_collection",
2407
- "Retrieve detailed information about a specific collection",
2591
+ "Fetch one collection by id or slug and return its name, slug, workspace, and timestamps. Use list_collections when browsing and get_collection when you already know the target.",
2408
2592
  COLLECTIONS_TOOL_SCHEMAS.getCollection,
2409
2593
  async (params) => {
2410
2594
  const collection = await service.collections.getCollection(
@@ -2433,7 +2617,7 @@ function registerCollectionsTools(server, service) {
2433
2617
  );
2434
2618
  server.tool(
2435
2619
  "update_collection",
2436
- "Update a collection's name or description",
2620
+ "Update a collection's name or description only. This does not move prompts or change membership, so use it for metadata changes rather than reorganization.",
2437
2621
  COLLECTIONS_TOOL_SCHEMAS.updateCollection,
2438
2622
  async (params) => {
2439
2623
  await service.collections.updateCollection(params.collection_id, {
@@ -2459,7 +2643,7 @@ function registerCollectionsTools(server, service) {
2459
2643
  );
2460
2644
  server.tool(
2461
2645
  "delete_collection",
2462
- "Delete a collection by ID. This action cannot be undone. Prompts in this collection will become orphaned.",
2646
+ "Delete a prompt collection by ID. This cannot be undone; prompts stay in the workspace but lose their collection grouping, so reassign them first if organization matters.",
2463
2647
  COLLECTIONS_TOOL_SCHEMAS.deleteCollection,
2464
2648
  async (params) => {
2465
2649
  const result = await service.collections.deleteCollection(
@@ -2557,7 +2741,7 @@ function hasConfigSettings(config) {
2557
2741
  function registerConfigsTools(server, service) {
2558
2742
  server.tool(
2559
2743
  "list_configs",
2560
- "Retrieve all configurations in your Portkey organization, including their status and workspace associations",
2744
+ "List configs in the org with id, slug, name, status, workspace, and timestamps. Use this summary view to find a slug; use get_config for the full routing, cache, retry, and target settings before updating or deleting.",
2561
2745
  CONFIGS_TOOL_SCHEMAS.listConfigs,
2562
2746
  async () => {
2563
2747
  const configs = await service.configs.listConfigs();
@@ -2591,7 +2775,7 @@ function registerConfigsTools(server, service) {
2591
2775
  );
2592
2776
  server.tool(
2593
2777
  "get_config",
2594
- "Retrieve detailed information about a specific configuration, including cache settings, retry policies, and routing strategy",
2778
+ "Get one config by slug and return its routing, cache, retry, and target settings. Requires a known slug; use list_configs to discover one before editing.",
2595
2779
  CONFIGS_TOOL_SCHEMAS.getConfig,
2596
2780
  async (params) => {
2597
2781
  const response = await service.configs.getConfig(params.slug);
@@ -2635,7 +2819,7 @@ function registerConfigsTools(server, service) {
2635
2819
  );
2636
2820
  server.tool(
2637
2821
  "create_config",
2638
- "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.",
2822
+ "Create a config that defines routing, cache, retry, and targets for requests. At least one of those settings is required; returns the new id and version_id.",
2639
2823
  CONFIGS_TOOL_SCHEMAS.createConfig,
2640
2824
  async (params) => {
2641
2825
  const config = buildConfigPayload(params);
@@ -2675,7 +2859,7 @@ function registerConfigsTools(server, service) {
2675
2859
  );
2676
2860
  server.tool(
2677
2861
  "update_config",
2678
- "Update an existing configuration's cache, retry, or routing settings",
2862
+ "Update a config by slug and create a new version. Only provided fields change; name and status are editable, while the slug stays fixed. Use list_config_versions if you need history first.",
2679
2863
  CONFIGS_TOOL_SCHEMAS.updateConfig,
2680
2864
  async (params) => {
2681
2865
  const config = buildConfigPayload(params);
@@ -2710,7 +2894,7 @@ function registerConfigsTools(server, service) {
2710
2894
  );
2711
2895
  server.tool(
2712
2896
  "delete_config",
2713
- "Delete a configuration by slug. This action cannot be undone.",
2897
+ "Delete a config by slug. This is permanent, removes all versions, and breaks anything still pointing at that slug; check list_config_versions first.",
2714
2898
  CONFIGS_TOOL_SCHEMAS.deleteConfig,
2715
2899
  async (params) => {
2716
2900
  const result = await service.configs.deleteConfig(params.slug);
@@ -2733,7 +2917,7 @@ function registerConfigsTools(server, service) {
2733
2917
  );
2734
2918
  server.tool(
2735
2919
  "list_config_versions",
2736
- "List all versions of a configuration to view its change history",
2920
+ "List every version of a config with version number, config payload, creator, and timestamp. Use this to audit history or compare revisions before update_config or delete_config.",
2737
2921
  CONFIGS_TOOL_SCHEMAS.listConfigVersions,
2738
2922
  async (params) => {
2739
2923
  const result = await service.configs.listConfigVersions(params.slug);
@@ -2815,7 +2999,7 @@ var GUARDRAILS_TOOL_SCHEMAS = {
2815
2999
  function registerGuardrailsTools(server, service) {
2816
3000
  server.tool(
2817
3001
  "list_guardrails",
2818
- "List all guardrails in your Portkey organization with optional filtering by workspace or organization",
3002
+ "List guardrails in the org with id, slug, status, ownership, and optional workspace/org filters. Use this to find IDs and slugs before get_guardrail, update_guardrail, or delete_guardrail.",
2819
3003
  GUARDRAILS_TOOL_SCHEMAS.listGuardrails,
2820
3004
  async (params) => {
2821
3005
  const result = await service.guardrails.listGuardrails(params);
@@ -2849,7 +3033,7 @@ function registerGuardrailsTools(server, service) {
2849
3033
  );
2850
3034
  server.tool(
2851
3035
  "get_guardrail",
2852
- "Retrieve detailed information about a specific guardrail, including its checks and actions configuration",
3036
+ "Fetch one guardrail with its full checks and actions. Use this before updating rules or when you need the exact enforcement policy.",
2853
3037
  GUARDRAILS_TOOL_SCHEMAS.getGuardrail,
2854
3038
  async (params) => {
2855
3039
  const guardrail = await service.guardrails.getGuardrail(
@@ -2884,7 +3068,7 @@ function registerGuardrailsTools(server, service) {
2884
3068
  );
2885
3069
  server.tool(
2886
3070
  "create_guardrail",
2887
- "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.",
3071
+ "Create a guardrail with checks and actions for request filtering. Create it first, then reference it from configs; the new version becomes the policy anchor for downstream use.",
2888
3072
  GUARDRAILS_TOOL_SCHEMAS.createGuardrail,
2889
3073
  async (params) => {
2890
3074
  const result = await service.guardrails.createGuardrail({
@@ -2915,7 +3099,7 @@ function registerGuardrailsTools(server, service) {
2915
3099
  );
2916
3100
  server.tool(
2917
3101
  "update_guardrail",
2918
- "Update an existing guardrail's name, checks, or actions configuration",
3102
+ "Update a guardrail's name, checks, or actions. This creates a new version, so configs keep pointing at the latest policy after the change.",
2919
3103
  GUARDRAILS_TOOL_SCHEMAS.updateGuardrail,
2920
3104
  async (params) => {
2921
3105
  const updateData = {};
@@ -2953,7 +3137,7 @@ function registerGuardrailsTools(server, service) {
2953
3137
  );
2954
3138
  server.tool(
2955
3139
  "delete_guardrail",
2956
- "Delete a guardrail by its ID or slug. This action cannot be undone.",
3140
+ "Delete a guardrail by id or slug. This is irreversible and removes the check from any configs that reference it, so review dependent configs first.",
2957
3141
  GUARDRAILS_TOOL_SCHEMAS.deleteGuardrail,
2958
3142
  async (params) => {
2959
3143
  const result = await service.guardrails.deleteGuardrail(
@@ -3116,7 +3300,7 @@ var INTEGRATIONS_TOOL_SCHEMAS = {
3116
3300
  function registerIntegrationsTools(server, service) {
3117
3301
  server.tool(
3118
3302
  "list_integrations",
3119
- "List all integrations in your Portkey organization with optional filtering by workspace or type",
3303
+ "List org-level AI provider connections with optional workspace or type filters. Use this to find integration slugs before model or workspace updates. Returns total plus id, name, slug, provider, status, description, workspace counts, and config summary.",
3120
3304
  INTEGRATIONS_TOOL_SCHEMAS.listIntegrations,
3121
3305
  async (params) => {
3122
3306
  const integrations = await service.integrations.listIntegrations({
@@ -3154,7 +3338,7 @@ function registerIntegrationsTools(server, service) {
3154
3338
  );
3155
3339
  server.tool(
3156
3340
  "create_integration",
3157
- "Create a new integration with an AI provider (e.g., OpenAI, Anthropic, Azure OpenAI, AWS Bedrock). Provider-specific params: Azure needs api_version + resource_name + deployment_name. AWS needs aws_region. Vertex AI needs vertex_project_id + vertex_region.",
3341
+ "Create an org-level provider integration. Some backends need provider-specific fields, and the new integration becomes the source for downstream providers and workspace access. Returns the new integration id and slug.",
3158
3342
  INTEGRATIONS_TOOL_SCHEMAS.createIntegration,
3159
3343
  async (params) => {
3160
3344
  const configurations = {};
@@ -3202,7 +3386,7 @@ function registerIntegrationsTools(server, service) {
3202
3386
  );
3203
3387
  server.tool(
3204
3388
  "get_integration",
3205
- "Retrieve detailed information about a specific integration by its slug",
3389
+ "Fetch one integration by slug, including masked key, workspace access, allowed models, and configuration metadata. Use this before editing provider-specific settings or auditing access.",
3206
3390
  INTEGRATIONS_TOOL_SCHEMAS.getIntegration,
3207
3391
  async (params) => {
3208
3392
  const integration = await service.integrations.getIntegration(
@@ -3239,7 +3423,7 @@ function registerIntegrationsTools(server, service) {
3239
3423
  );
3240
3424
  server.tool(
3241
3425
  "update_integration",
3242
- "Update an existing integration's name, API key, description, or provider-specific configurations",
3426
+ "Update an integration's name, key, or provider-specific config. Key and config changes take effect immediately and can disrupt dependent providers or live requests.",
3243
3427
  INTEGRATIONS_TOOL_SCHEMAS.updateIntegration,
3244
3428
  async (params) => {
3245
3429
  const configurations = {};
@@ -3286,7 +3470,7 @@ function registerIntegrationsTools(server, service) {
3286
3470
  );
3287
3471
  server.tool(
3288
3472
  "delete_integration",
3289
- "Delete an integration by slug. This action cannot be undone.",
3473
+ "Delete an integration by slug. This is irreversible and stops the org-level connection, which will break dependent virtual keys, providers, and workspace access.",
3290
3474
  INTEGRATIONS_TOOL_SCHEMAS.deleteIntegration,
3291
3475
  async (params) => {
3292
3476
  const result = await service.integrations.deleteIntegration(params.slug);
@@ -3309,7 +3493,7 @@ function registerIntegrationsTools(server, service) {
3309
3493
  );
3310
3494
  server.tool(
3311
3495
  "list_integration_models",
3312
- "List all models available for a specific integration with their enabled status",
3496
+ "List models enabled on an integration. Use this to verify model availability before creating prompts or configs. Returns total plus model ids, display names, enabled state, and custom-model markers.",
3313
3497
  INTEGRATIONS_TOOL_SCHEMAS.listIntegrationModels,
3314
3498
  async (params) => {
3315
3499
  const models = await service.integrations.listIntegrationModels(
@@ -3347,7 +3531,7 @@ function registerIntegrationsTools(server, service) {
3347
3531
  );
3348
3532
  server.tool(
3349
3533
  "update_integration_models",
3350
- "Update model access settings for an integration - enable/disable models or add custom models",
3534
+ "Enable, disable, or register custom models for an integration. This changes model availability for every workspace using it, so confirm the downstream impact first. Returns success and the number of models updated.",
3351
3535
  INTEGRATIONS_TOOL_SCHEMAS.updateIntegrationModels,
3352
3536
  async (params) => {
3353
3537
  const result = await service.integrations.updateIntegrationModels(
@@ -3376,7 +3560,7 @@ function registerIntegrationsTools(server, service) {
3376
3560
  );
3377
3561
  server.tool(
3378
3562
  "delete_integration_model",
3379
- "Delete a specific custom model from an integration",
3563
+ "Delete a custom model from an integration. Built-in models should be disabled instead, because deletion only applies to custom entries. Returns success after the custom model is removed.",
3380
3564
  INTEGRATIONS_TOOL_SCHEMAS.deleteIntegrationModel,
3381
3565
  async (params) => {
3382
3566
  const result = await service.integrations.deleteIntegrationModel(
@@ -3402,7 +3586,7 @@ function registerIntegrationsTools(server, service) {
3402
3586
  );
3403
3587
  server.tool(
3404
3588
  "list_integration_workspaces",
3405
- "List all workspaces that have access to a specific integration",
3589
+ "List workspaces that can use an integration, with their limits. Use this to audit access or confirm per-workspace cost and rate settings. Returns total plus workspace ids, names, enabled state, usage limits, and rate limits.",
3406
3590
  INTEGRATIONS_TOOL_SCHEMAS.listIntegrationWorkspaces,
3407
3591
  async (params) => {
3408
3592
  const workspaces = await service.integrations.listIntegrationWorkspaces(
@@ -3441,7 +3625,7 @@ function registerIntegrationsTools(server, service) {
3441
3625
  );
3442
3626
  server.tool(
3443
3627
  "update_integration_workspaces",
3444
- "Update workspace access settings for an integration - enable/disable workspace access and configure limits",
3628
+ "Control which workspaces can use an integration and set per-workspace limits. Access changes and new limits apply to downstream usage immediately. Returns success and the number of workspaces updated.",
3445
3629
  INTEGRATIONS_TOOL_SCHEMAS.updateIntegrationWorkspaces,
3446
3630
  async (params) => {
3447
3631
  const result = await service.integrations.updateIntegrationWorkspaces(
@@ -3569,7 +3753,7 @@ var KEYS_TOOL_SCHEMAS = {
3569
3753
  function registerKeysTools(server, service) {
3570
3754
  server.tool(
3571
3755
  "list_virtual_keys",
3572
- "Retrieve all virtual keys in your Portkey organization, including their usage limits, rate limits, and status",
3756
+ "List provider API keys stored as virtual keys in your Portkey org. Use this to find slugs before wiring prompts/configs or auditing limits. Returns total plus name, slug, status, usage limits, rate limits, reset state, and model config.",
3573
3757
  KEYS_TOOL_SCHEMAS.listVirtualKeys,
3574
3758
  async () => {
3575
3759
  const virtualKeys = await service.keys.listVirtualKeys();
@@ -3610,7 +3794,7 @@ function registerKeysTools(server, service) {
3610
3794
  );
3611
3795
  server.tool(
3612
3796
  "create_virtual_key",
3613
- "Create a new virtual key for a provider (e.g., openai, anthropic). Virtual keys securely store provider API keys.",
3797
+ "Store a provider API key as a virtual key. The raw key is encrypted and only returned at creation time, so save the returned slug and use it in prompts/configs. Optional usage and rate limits apply immediately, and the tool returns the new slug.",
3614
3798
  KEYS_TOOL_SCHEMAS.createVirtualKey,
3615
3799
  async (params) => {
3616
3800
  const result = await service.keys.createVirtualKey({
@@ -3649,7 +3833,7 @@ function registerKeysTools(server, service) {
3649
3833
  );
3650
3834
  server.tool(
3651
3835
  "get_virtual_key",
3652
- "Retrieve detailed information about a specific virtual key by its slug",
3836
+ "Fetch one virtual key by slug, including metadata, a masked secret, limits, status, and model config. Use this before updating or to inspect the current configuration.",
3653
3837
  KEYS_TOOL_SCHEMAS.getVirtualKey,
3654
3838
  async (params) => {
3655
3839
  const virtualKey = await service.keys.getVirtualKey(params.slug);
@@ -3687,7 +3871,7 @@ function registerKeysTools(server, service) {
3687
3871
  );
3688
3872
  server.tool(
3689
3873
  "update_virtual_key",
3690
- "Update an existing virtual key's name, API key, note, or limits",
3874
+ "Update a virtual key's name, secret, note, or limits. Rotating the key takes effect immediately, and limit changes apply to downstream prompts and configs using this slug. Returns the updated name, slug, and status.",
3691
3875
  KEYS_TOOL_SCHEMAS.updateVirtualKey,
3692
3876
  async (params) => {
3693
3877
  const result = await service.keys.updateVirtualKey(params.slug, {
@@ -3721,7 +3905,7 @@ function registerKeysTools(server, service) {
3721
3905
  );
3722
3906
  server.tool(
3723
3907
  "delete_virtual_key",
3724
- "Delete a virtual key by slug. This action cannot be undone.",
3908
+ "Delete a virtual key by slug. This is irreversible and will break prompts and configs that reference the slug, so confirm no active dependencies first. Returns success after removal.",
3725
3909
  KEYS_TOOL_SCHEMAS.deleteVirtualKey,
3726
3910
  async (params) => {
3727
3911
  const result = await service.keys.deleteVirtualKey(params.slug);
@@ -3744,7 +3928,7 @@ function registerKeysTools(server, service) {
3744
3928
  );
3745
3929
  server.tool(
3746
3930
  "create_api_key",
3747
- "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.).",
3931
+ "Create a Portkey API key for auth. Org keys grant broader access; workspace keys are scoped. The secret is only returned once, and using the key grants access immediately according to its scopes, defaults, and limits. Workspace keys require workspace_id and user keys require user_id.",
3748
3932
  KEYS_TOOL_SCHEMAS.createApiKey,
3749
3933
  async (params) => {
3750
3934
  if (params.type === "workspace" && !params.workspace_id) {
@@ -3815,7 +3999,7 @@ function registerKeysTools(server, service) {
3815
3999
  );
3816
4000
  server.tool(
3817
4001
  "list_api_keys",
3818
- "List all API keys in your Portkey organization with optional pagination and workspace filtering",
4002
+ "List Portkey API keys for auditing access, scopes, defaults, limits, and expiration. Use this for API keys only; use list_virtual_keys for provider keys. Returns total plus id, type, status, workspace/user scope, limits, defaults, alert emails, and creation mode.",
3819
4003
  KEYS_TOOL_SCHEMAS.listApiKeys,
3820
4004
  async (params) => {
3821
4005
  const apiKeys = await service.keys.listApiKeys({
@@ -3868,7 +4052,7 @@ function registerKeysTools(server, service) {
3868
4052
  );
3869
4053
  server.tool(
3870
4054
  "get_api_key",
3871
- "Retrieve detailed information about a specific API key by its UUID",
4055
+ "Fetch one API key by UUID without revealing the secret. Use this to inspect scopes, defaults, limits, expiration, and reset state before changing access.",
3872
4056
  KEYS_TOOL_SCHEMAS.getApiKey,
3873
4057
  async (params) => {
3874
4058
  const apiKey = await service.keys.getApiKey(params.id);
@@ -3915,7 +4099,7 @@ function registerKeysTools(server, service) {
3915
4099
  );
3916
4100
  server.tool(
3917
4101
  "update_api_key",
3918
- "Update an existing API key's name, description, scopes, or limits",
4102
+ "Update an API key's name, description, scopes, defaults, or limits. Changes affect what downstream callers can access; type and sub-type stay fixed after creation. Returns success after the update is applied.",
3919
4103
  KEYS_TOOL_SCHEMAS.updateApiKey,
3920
4104
  async (params) => {
3921
4105
  const result = await service.keys.updateApiKey(params.id, {
@@ -3953,7 +4137,7 @@ function registerKeysTools(server, service) {
3953
4137
  );
3954
4138
  server.tool(
3955
4139
  "delete_api_key",
3956
- "Delete an API key by UUID. This action cannot be undone.",
4140
+ "Delete an API key by UUID. This cannot be undone, revokes access immediately, and can break active sessions using the key. Returns success after revocation.",
3957
4141
  KEYS_TOOL_SCHEMAS.deleteApiKey,
3958
4142
  async (params) => {
3959
4143
  const result = await service.keys.deleteApiKey(params.id);
@@ -4013,7 +4197,7 @@ var LABELS_TOOL_SCHEMAS = {
4013
4197
  function registerLabelsTools(server, service) {
4014
4198
  server.tool(
4015
4199
  "create_prompt_label",
4016
- "Create a new prompt label to categorize and organize prompts. Labels can be color-coded and scoped to workspaces or organizations.",
4200
+ "Create a prompt label for tagging prompt versions such as production, staging, or experiment. Requires either organisation_id or workspace_id to set scope, returns the new label id, and does not assign it to any versions yet.",
4017
4201
  LABELS_TOOL_SCHEMAS.createPromptLabel,
4018
4202
  async (params) => {
4019
4203
  if (!params.organisation_id && !params.workspace_id) {
@@ -4053,7 +4237,7 @@ function registerLabelsTools(server, service) {
4053
4237
  );
4054
4238
  server.tool(
4055
4239
  "list_prompt_labels",
4056
- "List all prompt labels in your Portkey organization with optional filtering by workspace, organisation, or search query",
4240
+ "List labels across the workspace or organisation, with optional search and scope filters. Returns ids, names, colors, status, and timestamps so you can choose a label_id before get_prompt_label or update_prompt_version.",
4057
4241
  LABELS_TOOL_SCHEMAS.listPromptLabels,
4058
4242
  async (params) => {
4059
4243
  const result = await service.labels.listLabels(params);
@@ -4085,7 +4269,7 @@ function registerLabelsTools(server, service) {
4085
4269
  );
4086
4270
  server.tool(
4087
4271
  "get_prompt_label",
4088
- "Retrieve detailed information about a specific prompt label",
4272
+ "Fetch one label's full definition, including scope, color, and status. Use this when you already know the label_id; list_prompt_labels is better for browsing candidates.",
4089
4273
  LABELS_TOOL_SCHEMAS.getPromptLabel,
4090
4274
  async (params) => {
4091
4275
  const label = await service.labels.getLabel(params.label_id, {
@@ -4119,7 +4303,7 @@ function registerLabelsTools(server, service) {
4119
4303
  );
4120
4304
  server.tool(
4121
4305
  "update_prompt_label",
4122
- "Update an existing prompt label's name, description, or color",
4306
+ "Update a prompt label's name, description, or color only. This changes the label definition, not existing prompt-version assignments or history.",
4123
4307
  LABELS_TOOL_SCHEMAS.updatePromptLabel,
4124
4308
  async (params) => {
4125
4309
  const { label_id, ...updateData } = params;
@@ -4143,7 +4327,7 @@ function registerLabelsTools(server, service) {
4143
4327
  );
4144
4328
  server.tool(
4145
4329
  "delete_prompt_label",
4146
- "Delete a prompt label by ID. This action cannot be undone.",
4330
+ "Delete a prompt label by ID. This cannot be undone; versions carrying the label lose it, and any workflow resolving by that label will need a replacement.",
4147
4331
  LABELS_TOOL_SCHEMAS.deletePromptLabel,
4148
4332
  async (params) => {
4149
4333
  await service.labels.deleteLabel(params.label_id);
@@ -4295,7 +4479,7 @@ function formatUsageLimitEntity(entity) {
4295
4479
  function registerLimitsTools(server, service) {
4296
4480
  server.tool(
4297
4481
  "list_rate_limits",
4298
- "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).",
4482
+ "List rate limits in the org with id, type, unit, value, status, scope, conditions, and grouping. Use this to find an existing policy before get_rate_limit, update_rate_limit, or delete_rate_limit.",
4299
4483
  LIMITS_TOOL_SCHEMAS.listRateLimits,
4300
4484
  async (params) => {
4301
4485
  const result = await service.limits.listRateLimits(params.workspace_id);
@@ -4318,7 +4502,7 @@ function registerLimitsTools(server, service) {
4318
4502
  );
4319
4503
  server.tool(
4320
4504
  "get_rate_limit",
4321
- "Retrieve detailed information about a specific rate limit by its ID",
4505
+ "Get one rate limit by id and return its full conditions and grouping definition. Use list_rate_limits to discover ids or compare policies first.",
4322
4506
  LIMITS_TOOL_SCHEMAS.getRateLimit,
4323
4507
  async (params) => {
4324
4508
  const result = await service.limits.getRateLimit(params.id);
@@ -4334,7 +4518,7 @@ function registerLimitsTools(server, service) {
4334
4518
  );
4335
4519
  server.tool(
4336
4520
  "create_rate_limit",
4337
- "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.",
4521
+ "Create a request or token throttle with conditions, group_by, type, unit, and value. conditions and group_by are required; use usage limits when you need a cumulative budget instead.",
4338
4522
  LIMITS_TOOL_SCHEMAS.createRateLimit,
4339
4523
  async (params) => {
4340
4524
  const result = await service.limits.createRateLimit({
@@ -4366,7 +4550,7 @@ function registerLimitsTools(server, service) {
4366
4550
  );
4367
4551
  server.tool(
4368
4552
  "update_rate_limit",
4369
- "Update an existing rate limit's name, unit, or value",
4553
+ "Update a rate limit's name, unit, or value by id. Conditions and group_by are immutable after creation; use get_rate_limit first if you need the full policy.",
4370
4554
  LIMITS_TOOL_SCHEMAS.updateRateLimit,
4371
4555
  async (params) => {
4372
4556
  const result = await service.limits.updateRateLimit(params.id, {
@@ -4393,7 +4577,7 @@ function registerLimitsTools(server, service) {
4393
4577
  );
4394
4578
  server.tool(
4395
4579
  "delete_rate_limit",
4396
- "Delete a rate limit by ID. This action cannot be undone.",
4580
+ "Delete a rate limit by id. This is permanent and removes throttling immediately; review dependent configs and virtual keys before deleting.",
4397
4581
  LIMITS_TOOL_SCHEMAS.deleteRateLimit,
4398
4582
  async (params) => {
4399
4583
  await service.limits.deleteRateLimit(params.id);
@@ -4416,7 +4600,7 @@ function registerLimitsTools(server, service) {
4416
4600
  );
4417
4601
  server.tool(
4418
4602
  "list_usage_limits",
4419
- "Retrieve all usage limits in your Portkey organization. Usage limits control how much cost or tokens can be consumed, with optional periodic resets.",
4603
+ "List usage limits in the org with id, type, credit_limit, status, reset schedule, scope, conditions, and grouping. Use this before get_usage_limit, update_usage_limit, or delete_usage_limit.",
4420
4604
  LIMITS_TOOL_SCHEMAS.listUsageLimits,
4421
4605
  async (params) => {
4422
4606
  const result = await service.limits.listUsageLimits(params.workspace_id);
@@ -4439,7 +4623,7 @@ function registerLimitsTools(server, service) {
4439
4623
  );
4440
4624
  server.tool(
4441
4625
  "get_usage_limit",
4442
- "Retrieve detailed information about a specific usage limit by its ID",
4626
+ "Get one usage limit by id and return its full budget, threshold, grouping, and reset details. Use list_usage_limits to discover ids or compare policies first.",
4443
4627
  LIMITS_TOOL_SCHEMAS.getUsageLimit,
4444
4628
  async (params) => {
4445
4629
  const result = await service.limits.getUsageLimit(params.id);
@@ -4455,7 +4639,7 @@ function registerLimitsTools(server, service) {
4455
4639
  );
4456
4640
  server.tool(
4457
4641
  "create_usage_limit",
4458
- "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.",
4642
+ "Create a cumulative budget for cost or tokens with optional alerts and weekly or monthly resets. conditions and group_by are required; use rate limits when you need request throttling.",
4459
4643
  LIMITS_TOOL_SCHEMAS.createUsageLimit,
4460
4644
  async (params) => {
4461
4645
  const result = await service.limits.createUsageLimit({
@@ -4488,7 +4672,7 @@ function registerLimitsTools(server, service) {
4488
4672
  );
4489
4673
  server.tool(
4490
4674
  "update_usage_limit",
4491
- "Update an existing usage limit's configuration",
4675
+ "Update a usage limit's name, credit_limit, alert_threshold, reset schedule, or reset target by id. Conditions and group_by are immutable after creation.",
4492
4676
  LIMITS_TOOL_SCHEMAS.updateUsageLimit,
4493
4677
  async (params) => {
4494
4678
  const result = await service.limits.updateUsageLimit(params.id, {
@@ -4517,7 +4701,7 @@ function registerLimitsTools(server, service) {
4517
4701
  );
4518
4702
  server.tool(
4519
4703
  "delete_usage_limit",
4520
- "Delete a usage limit by ID. This action cannot be undone.",
4704
+ "Delete a usage limit by id. This is permanent, removes the budget immediately, and clears tracked usage state; check list_usage_limit_entities first if you need impact.",
4521
4705
  LIMITS_TOOL_SCHEMAS.deleteUsageLimit,
4522
4706
  async (params) => {
4523
4707
  await service.limits.deleteUsageLimit(params.id);
@@ -4540,7 +4724,7 @@ function registerLimitsTools(server, service) {
4540
4724
  );
4541
4725
  server.tool(
4542
4726
  "list_usage_limit_entities",
4543
- "List all entities tracked against a usage limit policy, showing current usage per entity",
4727
+ "List the entities currently tracked against a usage limit, including current usage. Use this to see who is near or over budget before reset_usage_limit_entity or delete_usage_limit.",
4544
4728
  LIMITS_TOOL_SCHEMAS.listUsageLimitEntities,
4545
4729
  async (params) => {
4546
4730
  const result = await service.limits.listUsageLimitEntities(
@@ -4565,7 +4749,7 @@ function registerLimitsTools(server, service) {
4565
4749
  );
4566
4750
  server.tool(
4567
4751
  "reset_usage_limit_entity",
4568
- "Reset accumulated usage for a specific entity on a usage limit policy",
4752
+ "Reset tracked usage for one entity under a usage limit. This changes accumulated usage for that entity only; use list_usage_limit_entities to confirm the target first.",
4569
4753
  LIMITS_TOOL_SCHEMAS.resetUsageLimitEntity,
4570
4754
  async (params) => {
4571
4755
  await service.limits.resetUsageLimitEntity(
@@ -4682,7 +4866,7 @@ var LOGGING_TOOL_SCHEMAS = {
4682
4866
  function registerLoggingTools(server, service) {
4683
4867
  server.tool(
4684
4868
  "insert_log",
4685
- "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.",
4869
+ "Insert log records for requests that bypassed the gateway. This writes request, response, and trace metadata into Portkey immediately, and the call will fail if request_provider does not match a configured integration. Use the span fields to stitch trace hierarchies together.",
4686
4870
  LOGGING_TOOL_SCHEMAS.insertLog,
4687
4871
  async (params) => {
4688
4872
  const entry = {
@@ -4730,7 +4914,7 @@ function registerLoggingTools(server, service) {
4730
4914
  );
4731
4915
  server.tool(
4732
4916
  "create_log_export",
4733
- "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.",
4917
+ "Create a log export definition with filters and requested fields. This only sets up the export and does not start processing; call start_log_export next, then use get_log_export or download_log_export to inspect or retrieve the finished result.",
4734
4918
  LOGGING_TOOL_SCHEMAS.createLogExport,
4735
4919
  async (params) => {
4736
4920
  const result = await service.logging.createLogExport({
@@ -4768,7 +4952,7 @@ function registerLoggingTools(server, service) {
4768
4952
  );
4769
4953
  server.tool(
4770
4954
  "list_log_exports",
4771
- "List all log export jobs for a workspace",
4955
+ "List log export jobs in a workspace with status, filters, and timestamps. Use this to find an export_id before calling get_log_export, start_log_export, cancel_log_export, or download_log_export.",
4772
4956
  LOGGING_TOOL_SCHEMAS.listLogExports,
4773
4957
  async (params) => {
4774
4958
  const result = await service.logging.listLogExports({
@@ -4803,7 +4987,7 @@ function registerLoggingTools(server, service) {
4803
4987
  );
4804
4988
  server.tool(
4805
4989
  "get_log_export",
4806
- "Get details of a specific log export by its ID",
4990
+ "Fetch one log export job by export_id and return its status, filters, requested fields, and file metadata. Use this when you already know the target; use list_log_exports for a workspace-wide overview.",
4807
4991
  LOGGING_TOOL_SCHEMAS.getLogExport,
4808
4992
  async (params) => {
4809
4993
  const result = await service.logging.getLogExport(params.export_id);
@@ -4834,7 +5018,7 @@ function registerLoggingTools(server, service) {
4834
5018
  );
4835
5019
  server.tool(
4836
5020
  "start_log_export",
4837
- "Start a log export job that was previously created",
5021
+ "Start processing a previously created log export job. This is asynchronous, only queues the export, and does not return rows or a download file; use get_log_export to poll progress and download_log_export after the job completes.",
4838
5022
  LOGGING_TOOL_SCHEMAS.startLogExport,
4839
5023
  async (params) => {
4840
5024
  const result = await service.logging.startLogExport(params.export_id);
@@ -4858,7 +5042,7 @@ function registerLoggingTools(server, service) {
4858
5042
  );
4859
5043
  server.tool(
4860
5044
  "cancel_log_export",
4861
- "Cancel a running log export job",
5045
+ "Cancel a pending or running log export job. This permanently stops that export, so create a new log export if you need the same data again.",
4862
5046
  LOGGING_TOOL_SCHEMAS.cancelLogExport,
4863
5047
  async (params) => {
4864
5048
  const result = await service.logging.cancelLogExport(params.export_id);
@@ -4882,7 +5066,7 @@ function registerLoggingTools(server, service) {
4882
5066
  );
4883
5067
  server.tool(
4884
5068
  "download_log_export",
4885
- "Get the download URL for a completed log export. Export must be in 'completed' status. Workflow: create_log_export -> start_log_export -> poll get_log_export until completed -> download_log_export.",
5069
+ "Get a signed URL for downloading a completed log export. The export must already be finished; use get_log_export to confirm readiness and start_log_export if it has not run yet.",
4886
5070
  LOGGING_TOOL_SCHEMAS.downloadLogExport,
4887
5071
  async (params) => {
4888
5072
  const result = await service.logging.downloadLogExport(params.export_id);
@@ -4906,7 +5090,7 @@ function registerLoggingTools(server, service) {
4906
5090
  );
4907
5091
  server.tool(
4908
5092
  "update_log_export",
4909
- "Update an existing log export configuration. Only time_of_generation_max, requested_fields, and workspace_id can be modified after creation.",
5093
+ "Update an existing log export configuration before or between export runs. Only workspace_id, time_of_generation_max, and requested_fields can change after creation, so use get_log_export to review the current job and start_log_export after the definition is ready.",
4910
5094
  LOGGING_TOOL_SCHEMAS.updateLogExport,
4911
5095
  async (params) => {
4912
5096
  const updateData = {};
@@ -5073,7 +5257,7 @@ function formatMcpIntegrationWorkspace(workspace) {
5073
5257
  function registerMcpIntegrationsTools(server, service) {
5074
5258
  server.tool(
5075
5259
  "list_mcp_integrations",
5076
- "List all MCP integrations in your Portkey organization with optional pagination and workspace filtering",
5260
+ "List MCP integrations in the organization. Returns paginated integration records plus total and has_more for discovering integration IDs; use get_mcp_integration for one integration's full Portkey-side config and list_mcp_servers for the servers under an integration.",
5077
5261
  MCP_INTEGRATIONS_TOOL_SCHEMAS.listMcpIntegrations,
5078
5262
  async (params) => {
5079
5263
  const result = await service.mcpIntegrations.listMcpIntegrations(params);
@@ -5097,7 +5281,7 @@ function registerMcpIntegrationsTools(server, service) {
5097
5281
  );
5098
5282
  server.tool(
5099
5283
  "create_mcp_integration",
5100
- "Create a new MCP integration in Portkey for connecting external MCP servers to your organization",
5284
+ "Create an MCP integration from an external server URL. Registers the Portkey-side connection and returns the new id and slug; if auth_type is headers, custom_headers are required, and you usually follow with create_mcp_server and capability updates.",
5101
5285
  MCP_INTEGRATIONS_TOOL_SCHEMAS.createMcpIntegration,
5102
5286
  async (params) => {
5103
5287
  if (params.auth_type === "headers" && (!params.custom_headers || Object.keys(params.custom_headers).length === 0)) {
@@ -5136,7 +5320,7 @@ function registerMcpIntegrationsTools(server, service) {
5136
5320
  );
5137
5321
  server.tool(
5138
5322
  "get_mcp_integration",
5139
- "Retrieve detailed information about a specific MCP integration by ID or slug",
5323
+ "Retrieve one MCP integration by id or slug. Returns the full Portkey-side config, including auth type, transport, and masked configuration keys; use get_mcp_integration_metadata for the server's self-reported metadata.",
5140
5324
  MCP_INTEGRATIONS_TOOL_SCHEMAS.getMcpIntegration,
5141
5325
  async (params) => {
5142
5326
  const integration = await service.mcpIntegrations.getMcpIntegration(
@@ -5154,7 +5338,7 @@ function registerMcpIntegrationsTools(server, service) {
5154
5338
  );
5155
5339
  server.tool(
5156
5340
  "update_mcp_integration",
5157
- "Update an existing MCP integration's name, description, URL, auth, or transport",
5341
+ "Update an MCP integration's name, description, URL, auth, or transport. Changes apply immediately and altering url or auth_type can break connected clients; use update_mcp_server when you only need to rename or re-describe a server.",
5158
5342
  MCP_INTEGRATIONS_TOOL_SCHEMAS.updateMcpIntegration,
5159
5343
  async (params) => {
5160
5344
  const { id, custom_headers, ...rest } = params;
@@ -5181,7 +5365,7 @@ function registerMcpIntegrationsTools(server, service) {
5181
5365
  );
5182
5366
  server.tool(
5183
5367
  "delete_mcp_integration",
5184
- "Delete an MCP integration. This action cannot be undone.",
5368
+ "Delete an MCP integration and all servers beneath it. This is irreversible, removes connected access immediately, and should only be used after confirming nothing depends on the integration.",
5185
5369
  MCP_INTEGRATIONS_TOOL_SCHEMAS.deleteMcpIntegration,
5186
5370
  async (params) => {
5187
5371
  await service.mcpIntegrations.deleteMcpIntegration(params.id);
@@ -5204,7 +5388,7 @@ function registerMcpIntegrationsTools(server, service) {
5204
5388
  );
5205
5389
  server.tool(
5206
5390
  "get_mcp_integration_metadata",
5207
- "Retrieve metadata for a specific MCP integration",
5391
+ "Retrieve the external MCP server's self-reported metadata for an integration. Returns name, version, protocol, capability flags, and sync status; use get_mcp_integration for the Portkey-side connection config.",
5208
5392
  MCP_INTEGRATIONS_TOOL_SCHEMAS.getMcpIntegrationMetadata,
5209
5393
  async (params) => {
5210
5394
  const metadata = await service.mcpIntegrations.getMcpIntegrationMetadata(
@@ -5226,7 +5410,7 @@ function registerMcpIntegrationsTools(server, service) {
5226
5410
  );
5227
5411
  server.tool(
5228
5412
  "list_mcp_integration_capabilities",
5229
- "List all capabilities (tools, resources, prompts) available on an MCP integration",
5413
+ "List capabilities exposed by the external MCP server for an integration. Returns total plus enabled-state entries so you can decide what to toggle; use before update_mcp_integration_capabilities when you need to compare the current surface.",
5230
5414
  MCP_INTEGRATIONS_TOOL_SCHEMAS.listMcpIntegrationCapabilities,
5231
5415
  async (params) => {
5232
5416
  const result = await service.mcpIntegrations.listMcpIntegrationCapabilities(params.id);
@@ -5246,7 +5430,7 @@ function registerMcpIntegrationsTools(server, service) {
5246
5430
  );
5247
5431
  server.tool(
5248
5432
  "update_mcp_integration_capabilities",
5249
- "Bulk enable or disable capabilities on an MCP integration",
5433
+ "Bulk enable or disable capabilities on an MCP integration. Changes take effect immediately for connected users and hide or expose the selected tools, resources, and prompts; use list_mcp_integration_capabilities first if you need the current state.",
5250
5434
  MCP_INTEGRATIONS_TOOL_SCHEMAS.updateMcpIntegrationCapabilities,
5251
5435
  async (params) => {
5252
5436
  await service.mcpIntegrations.updateMcpIntegrationCapabilities(
@@ -5274,7 +5458,7 @@ function registerMcpIntegrationsTools(server, service) {
5274
5458
  );
5275
5459
  server.tool(
5276
5460
  "list_mcp_integration_workspaces",
5277
- "List workspace access settings for an MCP integration",
5461
+ "List which workspaces can access an MCP integration. Returns the global access mode plus per-workspace enablement for audit or permission review; use before update_mcp_integration_workspaces.",
5278
5462
  MCP_INTEGRATIONS_TOOL_SCHEMAS.listMcpIntegrationWorkspaces,
5279
5463
  async (params) => {
5280
5464
  const result = await service.mcpIntegrations.listMcpIntegrationWorkspaces(
@@ -5302,7 +5486,7 @@ function registerMcpIntegrationsTools(server, service) {
5302
5486
  );
5303
5487
  server.tool(
5304
5488
  "update_mcp_integration_workspaces",
5305
- "Bulk update workspace access for an MCP integration",
5489
+ "Grant or revoke workspace access to an MCP integration in bulk. Changes take effect immediately for all users in the selected workspaces; use list_mcp_integration_workspaces first to review the current access state.",
5306
5490
  MCP_INTEGRATIONS_TOOL_SCHEMAS.updateMcpIntegrationWorkspaces,
5307
5491
  async (params) => {
5308
5492
  await service.mcpIntegrations.updateMcpIntegrationWorkspaces(params.id, {
@@ -5417,7 +5601,7 @@ function formatMcpServerUserAccess(user) {
5417
5601
  function registerMcpServersTools(server, service) {
5418
5602
  server.tool(
5419
5603
  "list_mcp_servers",
5420
- "List all MCP servers in your Portkey organization with optional pagination and workspace filtering",
5604
+ "List MCP servers in the organization. Returns paginated server records plus total for discovering server IDs; use get_mcp_server for one server's details and list_mcp_integrations for the parent integration.",
5421
5605
  MCP_SERVERS_TOOL_SCHEMAS.listMcpServers,
5422
5606
  async (params) => {
5423
5607
  const result = await service.mcpServers.listMcpServers(params);
@@ -5440,7 +5624,7 @@ function registerMcpServersTools(server, service) {
5440
5624
  );
5441
5625
  server.tool(
5442
5626
  "create_mcp_server",
5443
- "Register a new MCP server under an existing MCP integration",
5627
+ "Create an MCP server under an existing integration. Registers the server and returns the new id and slug; use list_mcp_integrations first to find the parent integration, then capabilities or access tools to configure it.",
5444
5628
  MCP_SERVERS_TOOL_SCHEMAS.createMcpServer,
5445
5629
  async (params) => {
5446
5630
  const result = await service.mcpServers.createMcpServer(params);
@@ -5464,7 +5648,7 @@ function registerMcpServersTools(server, service) {
5464
5648
  );
5465
5649
  server.tool(
5466
5650
  "get_mcp_server",
5467
- "Retrieve detailed information about a specific MCP server by ID or slug",
5651
+ "Retrieve one MCP server by id or slug. Returns server details including the parent integration, status, and created time; use get_mcp_server when you need the server record rather than the integration config.",
5468
5652
  MCP_SERVERS_TOOL_SCHEMAS.getMcpServer,
5469
5653
  async (params) => {
5470
5654
  const mcpServer = await service.mcpServers.getMcpServer(params.id);
@@ -5480,7 +5664,7 @@ function registerMcpServersTools(server, service) {
5480
5664
  );
5481
5665
  server.tool(
5482
5666
  "update_mcp_server",
5483
- "Update an existing MCP server's name or description",
5667
+ "Update an MCP server's name or description. Changes apply immediately, but URL and auth live on the parent integration, so use update_mcp_integration for those fields.",
5484
5668
  MCP_SERVERS_TOOL_SCHEMAS.updateMcpServer,
5485
5669
  async (params) => {
5486
5670
  const { id, ...data } = params;
@@ -5504,7 +5688,7 @@ function registerMcpServersTools(server, service) {
5504
5688
  );
5505
5689
  server.tool(
5506
5690
  "delete_mcp_server",
5507
- "Delete an MCP server. This action cannot be undone.",
5691
+ "Delete an MCP server instance. This is irreversible, removes connected users' access immediately, and should be used only after confirming no workflows depend on the server.",
5508
5692
  MCP_SERVERS_TOOL_SCHEMAS.deleteMcpServer,
5509
5693
  async (params) => {
5510
5694
  await service.mcpServers.deleteMcpServer(params.id);
@@ -5527,7 +5711,7 @@ function registerMcpServersTools(server, service) {
5527
5711
  );
5528
5712
  server.tool(
5529
5713
  "test_mcp_server",
5530
- "Test connectivity to an MCP server to verify it is reachable and responding",
5714
+ "Test connectivity to an MCP server. Sends a live check and returns success, response time, HTTP status, and any error; use this before changing configuration or when diagnosing reachability.",
5531
5715
  MCP_SERVERS_TOOL_SCHEMAS.testMcpServer,
5532
5716
  async (params) => {
5533
5717
  const result = await service.mcpServers.testMcpServer(params.id);
@@ -5543,7 +5727,7 @@ function registerMcpServersTools(server, service) {
5543
5727
  );
5544
5728
  server.tool(
5545
5729
  "list_mcp_server_capabilities",
5546
- "List all capabilities (tools, resources, prompts) exposed by an MCP server",
5730
+ "List capabilities exposed by an MCP server instance. Returns total plus the current tool, resource, and prompt surface; use this instead of the integration-level capability list when you need server-specific exposure.",
5547
5731
  MCP_SERVERS_TOOL_SCHEMAS.listMcpServerCapabilities,
5548
5732
  async (params) => {
5549
5733
  const result = await service.mcpServers.listMcpServerCapabilities(
@@ -5565,7 +5749,7 @@ function registerMcpServersTools(server, service) {
5565
5749
  );
5566
5750
  server.tool(
5567
5751
  "update_mcp_server_capabilities",
5568
- "Bulk enable or disable capabilities on an MCP server",
5752
+ "Enable or disable capabilities on an MCP server. Changes take effect immediately and override the integration-level settings for this server; use list_mcp_server_capabilities first to inspect the current surface.",
5569
5753
  MCP_SERVERS_TOOL_SCHEMAS.updateMcpServerCapabilities,
5570
5754
  async (params) => {
5571
5755
  await service.mcpServers.updateMcpServerCapabilities(params.id, {
@@ -5590,7 +5774,7 @@ function registerMcpServersTools(server, service) {
5590
5774
  );
5591
5775
  server.tool(
5592
5776
  "list_mcp_server_user_access",
5593
- "List user access settings for an MCP server",
5777
+ "List per-user access for an MCP server. Returns the default access mode, override flags, and connection status so you can audit who can use it; use before update_mcp_server_user_access.",
5594
5778
  MCP_SERVERS_TOOL_SCHEMAS.listMcpServerUserAccess,
5595
5779
  async (params) => {
5596
5780
  const result = await service.mcpServers.listMcpServerUserAccess(
@@ -5616,7 +5800,7 @@ function registerMcpServersTools(server, service) {
5616
5800
  );
5617
5801
  server.tool(
5618
5802
  "update_mcp_server_user_access",
5619
- "Bulk update user access for an MCP server",
5803
+ "Grant or revoke individual user access to an MCP server. Changes take effect immediately and override the default access setting for the selected users; use list_mcp_server_user_access first if you need the current state.",
5620
5804
  MCP_SERVERS_TOOL_SCHEMAS.updateMcpServerUserAccess,
5621
5805
  async (params) => {
5622
5806
  await service.mcpServers.updateMcpServerUserAccess(params.id, {
@@ -5681,7 +5865,7 @@ var PARTIALS_TOOL_SCHEMAS = {
5681
5865
  function registerPartialsTools(server, service) {
5682
5866
  server.tool(
5683
5867
  "create_prompt_partial",
5684
- "Create a new prompt partial (reusable text snippet) that can be included in prompts using mustache syntax like {{> partial_name}}",
5868
+ "Create a reusable prompt partial for inclusion with {{> partial_name}}. Use this for shared snippets or macros; returns the partial id, slug, and version id, and the new version stays inactive until published.",
5685
5869
  PARTIALS_TOOL_SCHEMAS.createPromptPartial,
5686
5870
  async (params) => {
5687
5871
  const result = await service.partials.createPromptPartial({
@@ -5711,7 +5895,7 @@ function registerPartialsTools(server, service) {
5711
5895
  );
5712
5896
  server.tool(
5713
5897
  "list_prompt_partials",
5714
- "List all prompt partials in your Portkey organization with optional filtering by collection",
5898
+ "List partials across collections, with optional collection filtering. Returns ids, slugs, names, collections, and status so you can choose a prompt_partial_id before get/update/delete.",
5715
5899
  PARTIALS_TOOL_SCHEMAS.listPromptPartials,
5716
5900
  async (params) => {
5717
5901
  const partials = await service.partials.listPromptPartials(params);
@@ -5742,7 +5926,7 @@ function registerPartialsTools(server, service) {
5742
5926
  );
5743
5927
  server.tool(
5744
5928
  "get_prompt_partial",
5745
- "Retrieve detailed information about a specific prompt partial including its content and version info",
5929
+ "Fetch a partial's content and current version details. Use this before embedding, updating, or checking what {{> partial_name}} resolves to; returns the stored string plus version metadata.",
5746
5930
  PARTIALS_TOOL_SCHEMAS.getPromptPartial,
5747
5931
  async (params) => {
5748
5932
  const partial = await service.partials.getPromptPartial(
@@ -5776,7 +5960,7 @@ function registerPartialsTools(server, service) {
5776
5960
  );
5777
5961
  server.tool(
5778
5962
  "update_prompt_partial",
5779
- "Update an existing prompt partial. A new version is created in archived status \u2014 use publish_partial to make it active.",
5963
+ "Create a new version of a partial by updating its content or metadata. Only provided fields change, and the new version stays inactive until publish_partial makes it current.",
5780
5964
  PARTIALS_TOOL_SCHEMAS.updatePromptPartial,
5781
5965
  async (params) => {
5782
5966
  const { prompt_partial_id, ...updateData } = params;
@@ -5803,7 +5987,7 @@ function registerPartialsTools(server, service) {
5803
5987
  );
5804
5988
  server.tool(
5805
5989
  "delete_prompt_partial",
5806
- "Delete a prompt partial by ID. This action cannot be undone.",
5990
+ "Delete a prompt partial by ID. This cannot be undone, and prompts that reference it with {{> name}} will fail to render until you replace the reference.",
5807
5991
  PARTIALS_TOOL_SCHEMAS.deletePromptPartial,
5808
5992
  async (params) => {
5809
5993
  await service.partials.deletePromptPartial(params.prompt_partial_id);
@@ -5826,7 +6010,7 @@ function registerPartialsTools(server, service) {
5826
6010
  );
5827
6011
  server.tool(
5828
6012
  "list_partial_versions",
5829
- "List all versions of a prompt partial to view its change history",
6013
+ "List all versions for one partial, including version numbers, descriptions, status, and timestamps. Use this when you need history or want to choose a version_id before publish_partial.",
5830
6014
  PARTIALS_TOOL_SCHEMAS.listPartialVersions,
5831
6015
  async (params) => {
5832
6016
  const versions = await service.partials.listPartialVersions(
@@ -5861,7 +6045,7 @@ function registerPartialsTools(server, service) {
5861
6045
  );
5862
6046
  server.tool(
5863
6047
  "publish_partial",
5864
- "Publish a specific version of a prompt partial, making it the default version",
6048
+ "Publish a specific partial version as the default version. This changes which content {{> partial_name}} resolves to and replaces the previously active version.",
5865
6049
  PARTIALS_TOOL_SCHEMAS.publishPartial,
5866
6050
  async (params) => {
5867
6051
  await service.partials.publishPartial(params.prompt_partial_id, {
@@ -5962,14 +6146,25 @@ function toPromptToolChoice(toolChoice) {
5962
6146
 
5963
6147
  // src/tools/prompts.tools.ts
5964
6148
  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");
6149
+ var PROMPT_TEMPLATE_CONTENT_BLOCK_SCHEMA = z15.object({
6150
+ type: z15.string().describe("Content block type"),
6151
+ text: z15.string().optional().describe("Text content for text-based blocks")
6152
+ }).passthrough().describe("Content block within a structured chat message");
6153
+ var PROMPT_TEMPLATE_MESSAGE_SCHEMA = z15.object({
6154
+ role: z15.enum(["system", "user", "assistant"]).describe("Message role in the chat template"),
6155
+ content: z15.array(PROMPT_TEMPLATE_CONTENT_BLOCK_SCHEMA).describe("Message content blocks")
6156
+ }).passthrough().describe("Structured chat message in a prompt template");
5965
6157
  var PROMPTS_TOOL_SCHEMAS = {
5966
6158
  createPrompt: {
5967
6159
  name: z15.string().describe("Display name for the prompt"),
5968
6160
  collection_id: z15.string().describe(
5969
6161
  "Collection ID to organize the prompt in (use list_collections to find)"
5970
6162
  ),
5971
- string: z15.string().describe(
5972
- `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.`
6163
+ string: z15.string().optional().describe(
6164
+ "Legacy prompt template string. Use plain text for single-message prompts, or a JSON-encoded messages array string for multi-message chat prompts."
6165
+ ),
6166
+ messages: z15.array(PROMPT_TEMPLATE_MESSAGE_SCHEMA).optional().describe(
6167
+ "Structured chat template alias. Serialized to the legacy string format before creation."
5973
6168
  ),
5974
6169
  parameters: z15.record(z15.string(), z15.unknown()).describe("Default values for template variables"),
5975
6170
  virtual_key: z15.string().describe("Virtual key slug for model access"),
@@ -6006,7 +6201,10 @@ var PROMPTS_TOOL_SCHEMAS = {
6006
6201
  name: z15.string().optional().describe("New display name for the prompt"),
6007
6202
  collection_id: z15.string().optional().describe("Move to a different collection"),
6008
6203
  string: z15.string().optional().describe(
6009
- "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."
6204
+ "Legacy prompt template string. Use plain text for single-message prompts, or a JSON-encoded messages array string for multi-message chat prompts."
6205
+ ),
6206
+ messages: z15.array(PROMPT_TEMPLATE_MESSAGE_SCHEMA).optional().describe(
6207
+ "Structured chat template alias for updates. Serialized to the legacy string format before the prompt is updated."
6010
6208
  ),
6011
6209
  parameters: z15.record(z15.string(), z15.unknown()).optional().describe("New default values for template variables"),
6012
6210
  model: z15.string().optional().describe("New model identifier"),
@@ -6052,7 +6250,12 @@ var PROMPTS_TOOL_SCHEMAS = {
6052
6250
  app: PromptAppIdentifierSchema,
6053
6251
  env: PromptEnvironmentIdentifierSchema,
6054
6252
  collection_id: z15.string().describe("Collection ID to search in and create under"),
6055
- string: z15.string().describe("Prompt template string with {{variable}} mustache syntax"),
6253
+ string: z15.string().optional().describe(
6254
+ "Legacy prompt template string with {{variable}} mustache syntax."
6255
+ ),
6256
+ messages: z15.array(PROMPT_TEMPLATE_MESSAGE_SCHEMA).optional().describe(
6257
+ "Structured chat template alias for migrations. Serialized to the legacy string format before the prompt is created or updated."
6258
+ ),
6056
6259
  parameters: z15.record(z15.string(), z15.unknown()).describe("Default values for template variables"),
6057
6260
  virtual_key: z15.string().describe("Virtual key slug for model access"),
6058
6261
  model: z15.string().optional().describe("Model identifier"),
@@ -6095,6 +6298,15 @@ var PROMPTS_TOOL_SCHEMAS = {
6095
6298
  )
6096
6299
  }
6097
6300
  };
6301
+ function normalizePromptTemplateString(params) {
6302
+ if (params.string !== void 0) {
6303
+ return params.string;
6304
+ }
6305
+ if (params.messages !== void 0) {
6306
+ return JSON.stringify(params.messages);
6307
+ }
6308
+ return void 0;
6309
+ }
6098
6310
  function extractPromptTemplateString(template) {
6099
6311
  const inner = typeof template === "object" && template !== null && "string" in template ? template.string : template;
6100
6312
  if (inner === void 0) {
@@ -6158,14 +6370,7 @@ function formatPromptListResponse(prompts, params) {
6158
6370
  function registerPromptsTools(server, service) {
6159
6371
  server.tool(
6160
6372
  "create_prompt",
6161
- `Create a new prompt template in Portkey. Supports both single-message and multi-message (chat) templates.
6162
-
6163
- IMPORTANT: The "string" parameter accepts TWO formats:
6164
- 1. Plain text: "Hello {{name}}, how can I help?"
6165
- 2. Multi-message JSON array (MUST be a JSON-encoded string):
6166
- '[{"role":"system","content":[{"type":"text","text":"You are a helpful assistant."}]},{"role":"user","content":[{"type":"text","text":"{{user_input}}"}]}]'
6167
-
6168
- Most production prompts use format #2 (multi-message). Use get_prompt to see examples of the format.`,
6373
+ "Create a new prompt template and initial version. Use this for first-time setup; use migrate_prompt for idempotent CI/CD flows. Accepts plain text or structured chat messages, creates a new version immediately, and returns the prompt id, slug, and version id. For multi-message chat prompts pass messages (preferred) or a JSON-encoded array as string.",
6169
6374
  PROMPTS_TOOL_SCHEMAS.createPrompt,
6170
6375
  async (params) => {
6171
6376
  if (!params.model && !params.ai_model_id && !params.finetune_id) {
@@ -6179,6 +6384,18 @@ Most production prompts use format #2 (multi-message). Use get_prompt to see exa
6179
6384
  isError: true
6180
6385
  };
6181
6386
  }
6387
+ const templateString = normalizePromptTemplateString(params);
6388
+ if (templateString === void 0) {
6389
+ return {
6390
+ content: [
6391
+ {
6392
+ type: "text",
6393
+ text: "Error creating prompt: Provide either string or messages"
6394
+ }
6395
+ ],
6396
+ isError: true
6397
+ };
6398
+ }
6182
6399
  if (params.dry_run) {
6183
6400
  return {
6184
6401
  content: [
@@ -6193,7 +6410,7 @@ Most production prompts use format #2 (multi-message). Use get_prompt to see exa
6193
6410
  name: params.name,
6194
6411
  collection_id: params.collection_id,
6195
6412
  model: params.model,
6196
- template_length: params.string.length,
6413
+ template_length: templateString.length,
6197
6414
  parameter_count: Object.keys(params.parameters ?? {}).length
6198
6415
  }
6199
6416
  },
@@ -6207,17 +6424,17 @@ Most production prompts use format #2 (multi-message). Use get_prompt to see exa
6207
6424
  const result = await service.prompts.createPrompt({
6208
6425
  name: params.name,
6209
6426
  collection_id: params.collection_id,
6210
- string: params.string,
6427
+ string: templateString,
6211
6428
  parameters: params.parameters,
6212
6429
  virtual_key: params.virtual_key,
6213
- model: params.model,
6214
- ai_model_id: params.ai_model_id,
6215
- finetune_id: params.finetune_id,
6216
- version_description: params.version_description,
6217
- template_metadata: params.template_metadata,
6218
- functions: params.functions,
6219
- tools: params.tools,
6220
- tool_choice: toPromptToolChoice(params.tool_choice)
6430
+ ...params.model !== void 0 ? { model: params.model } : {},
6431
+ ...params.ai_model_id !== void 0 ? { ai_model_id: params.ai_model_id } : {},
6432
+ ...params.finetune_id !== void 0 ? { finetune_id: params.finetune_id } : {},
6433
+ ...params.version_description !== void 0 ? { version_description: params.version_description } : {},
6434
+ ...params.template_metadata !== void 0 ? { template_metadata: params.template_metadata } : {},
6435
+ ...params.functions !== void 0 ? { functions: params.functions } : {},
6436
+ ...params.tools !== void 0 ? { tools: params.tools } : {},
6437
+ ...params.tool_choice !== void 0 ? { tool_choice: toPromptToolChoice(params.tool_choice) } : {}
6221
6438
  });
6222
6439
  return {
6223
6440
  content: [
@@ -6240,7 +6457,7 @@ Most production prompts use format #2 (multi-message). Use get_prompt to see exa
6240
6457
  );
6241
6458
  server.tool(
6242
6459
  "list_prompts",
6243
- "List all prompts in your Portkey organization with optional filtering by collection, workspace, or search query",
6460
+ "List prompts across the workspace, with optional collection, workspace, or search filters. Returns a paginated summary with id, name, slug, model, and status so you can choose a prompt_id before get_prompt, update_prompt, or render_prompt.",
6244
6461
  PROMPTS_TOOL_SCHEMAS.listPrompts,
6245
6462
  async (params) => {
6246
6463
  const prompts = await service.prompts.listPrompts(params);
@@ -6260,12 +6477,7 @@ Most production prompts use format #2 (multi-message). Use get_prompt to see exa
6260
6477
  );
6261
6478
  server.tool(
6262
6479
  "get_prompt",
6263
- `Retrieve detailed information about a specific prompt including its template, parameters, and version history.
6264
-
6265
- The template field shows the raw "string" value stored in Portkey:
6266
- - If it starts with "[", it is a JSON-encoded messages array (multi-message prompt with roles).
6267
- - Otherwise it is a plain string template.
6268
- When updating a prompt, pass the same format back in the "string" field of update_prompt.`,
6480
+ "Fetch a prompt's full definition, active version, and version history. Use this before updating, publishing, rendering, or copying a prompt when you need the stored template and metadata. For multi-message chat prompts pass messages (preferred) or a JSON-encoded array as string.",
6269
6481
  PROMPTS_TOOL_SCHEMAS.getPrompt,
6270
6482
  async (params) => {
6271
6483
  const prompt = await service.prompts.getPrompt(params.prompt_id);
@@ -6327,17 +6539,14 @@ When updating a prompt, pass the same format back in the "string" field of updat
6327
6539
  );
6328
6540
  server.tool(
6329
6541
  "update_prompt",
6330
- `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.
6331
-
6332
- IMPORTANT: The "string" parameter accepts the same two formats as create_prompt:
6333
- 1. Plain text: "Hello {{name}}"
6334
- 2. Multi-message JSON array (MUST be a JSON-encoded string):
6335
- '[{"role":"system","content":[{"type":"text","text":"..."}]},{"role":"user","content":[{"type":"text","text":"{{input}}"}]}]'
6336
-
6337
- 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.`,
6542
+ "Update an existing prompt and create a new archived version. Only provided fields change, and publish_prompt is what makes the new version active. For multi-message chat prompts pass messages (preferred) or a JSON-encoded array as string.",
6338
6543
  PROMPTS_TOOL_SCHEMAS.updatePrompt,
6339
6544
  async (params) => {
6340
- const { prompt_id, dry_run, ...updateData } = params;
6545
+ const { prompt_id, dry_run, messages, ...updateData } = params;
6546
+ const templateString = normalizePromptTemplateString({
6547
+ string: updateData.string,
6548
+ messages
6549
+ });
6341
6550
  if (dry_run) {
6342
6551
  const current = await service.prompts.getPrompt(prompt_id);
6343
6552
  return {
@@ -6362,8 +6571,17 @@ Use get_prompt first to see the current format, then pass the same format back.
6362
6571
  };
6363
6572
  }
6364
6573
  const result = await service.prompts.updatePrompt(prompt_id, {
6365
- ...updateData,
6366
- tool_choice: toPromptToolChoice(updateData.tool_choice)
6574
+ ...updateData.name !== void 0 ? { name: updateData.name } : {},
6575
+ ...updateData.collection_id !== void 0 ? { collection_id: updateData.collection_id } : {},
6576
+ ...templateString !== void 0 ? { string: templateString } : {},
6577
+ ...updateData.parameters !== void 0 ? { parameters: updateData.parameters } : {},
6578
+ ...updateData.model !== void 0 ? { model: updateData.model } : {},
6579
+ ...updateData.virtual_key !== void 0 ? { virtual_key: updateData.virtual_key } : {},
6580
+ ...updateData.version_description !== void 0 ? { version_description: updateData.version_description } : {},
6581
+ ...updateData.template_metadata !== void 0 ? { template_metadata: updateData.template_metadata } : {},
6582
+ ...updateData.functions !== void 0 ? { functions: updateData.functions } : {},
6583
+ ...updateData.tools !== void 0 ? { tools: updateData.tools } : {},
6584
+ ...updateData.tool_choice !== void 0 ? { tool_choice: toPromptToolChoice(updateData.tool_choice) } : {}
6367
6585
  });
6368
6586
  return {
6369
6587
  content: [
@@ -6386,7 +6604,7 @@ Use get_prompt first to see the current format, then pass the same format back.
6386
6604
  );
6387
6605
  server.tool(
6388
6606
  "delete_prompt",
6389
- "Delete a prompt by its ID. This action cannot be undone and will remove the prompt and all its versions.",
6607
+ "Delete a prompt and all its versions by id. This cannot be undone, immediately breaks callers using the slug, and should only be used after checking list_prompt_versions or confirming you do not need an audit trail.",
6390
6608
  PROMPTS_TOOL_SCHEMAS.deletePrompt,
6391
6609
  async (params) => {
6392
6610
  await service.prompts.deletePrompt(params.prompt_id);
@@ -6409,7 +6627,7 @@ Use get_prompt first to see the current format, then pass the same format back.
6409
6627
  );
6410
6628
  server.tool(
6411
6629
  "publish_prompt",
6412
- "Publish a specific version of a prompt, making it the default version that will be used when the prompt is called. This is useful for promoting a tested version to production.",
6630
+ "Publish a specific version of a prompt as the active default. Use list_prompt_versions to choose the version and update_prompt when you need to create new content before promoting it.",
6413
6631
  PROMPTS_TOOL_SCHEMAS.publishPrompt,
6414
6632
  async (params) => {
6415
6633
  await service.prompts.publishPrompt(params.prompt_id, {
@@ -6436,7 +6654,7 @@ Use get_prompt first to see the current format, then pass the same format back.
6436
6654
  );
6437
6655
  server.tool(
6438
6656
  "list_prompt_versions",
6439
- "List all versions of a specific prompt with their details, including version number, description, template content, and creation date.",
6657
+ "List all versions of one prompt, including version number, description, status, label, and a short template preview. Use this for history or to choose a version_id before publish_prompt or update_prompt_version.",
6440
6658
  PROMPTS_TOOL_SCHEMAS.listPromptVersions,
6441
6659
  async (params) => {
6442
6660
  const versions = await service.prompts.listPromptVersions(
@@ -6474,7 +6692,7 @@ Use get_prompt first to see the current format, then pass the same format back.
6474
6692
  );
6475
6693
  server.tool(
6476
6694
  "render_prompt",
6477
- "Render a prompt template by substituting variables, returning the final messages without executing",
6695
+ "Render a prompt by substituting variables and returning the final messages without calling the model. Use this to verify template output before a completion; run_prompt_completion is the tool that actually invokes the model.",
6478
6696
  PROMPTS_TOOL_SCHEMAS.renderPrompt,
6479
6697
  async (params) => {
6480
6698
  const result = await service.prompts.renderPrompt(params.prompt_id, {
@@ -6506,7 +6724,7 @@ Use get_prompt first to see the current format, then pass the same format back.
6506
6724
  );
6507
6725
  server.tool(
6508
6726
  "run_prompt_completion",
6509
- "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.",
6727
+ "Execute a prompt against the configured model and return the completion. This makes a billable model call, so use render_prompt first when you want to check the template and validate_completion_metadata when billing fields are uncertain.",
6510
6728
  PROMPTS_TOOL_SCHEMAS.runPromptCompletion,
6511
6729
  async (params) => {
6512
6730
  const result = await service.prompts.runPromptCompletion(
@@ -6545,24 +6763,36 @@ Use get_prompt first to see the current format, then pass the same format back.
6545
6763
  );
6546
6764
  server.tool(
6547
6765
  "migrate_prompt",
6548
- "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.",
6766
+ "Create or update a prompt in one idempotent step for CI/CD and prompt-as-code flows. Finds existing prompts by name within the collection, stores app/env in template_metadata, and supports dry_run for safe preflight checks.",
6549
6767
  PROMPTS_TOOL_SCHEMAS.migratePrompt,
6550
6768
  async (params) => {
6769
+ const templateString = normalizePromptTemplateString(params);
6770
+ if (templateString === void 0) {
6771
+ return {
6772
+ content: [
6773
+ {
6774
+ type: "text",
6775
+ text: "Error migrating prompt: Provide either string or messages"
6776
+ }
6777
+ ],
6778
+ isError: true
6779
+ };
6780
+ }
6551
6781
  const result = await service.prompts.migratePrompt({
6552
6782
  name: params.name,
6553
6783
  app: params.app,
6554
6784
  env: params.env,
6555
6785
  collection_id: params.collection_id,
6556
- string: params.string,
6786
+ string: templateString,
6557
6787
  parameters: params.parameters,
6558
6788
  virtual_key: params.virtual_key,
6559
- model: params.model,
6560
- version_description: params.version_description,
6561
- template_metadata: params.template_metadata,
6562
- functions: params.functions,
6563
- tools: params.tools,
6564
- tool_choice: toPromptToolChoice(params.tool_choice),
6565
- dry_run: params.dry_run
6789
+ ...params.model !== void 0 ? { model: params.model } : {},
6790
+ ...params.version_description !== void 0 ? { version_description: params.version_description } : {},
6791
+ ...params.template_metadata !== void 0 ? { template_metadata: params.template_metadata } : {},
6792
+ ...params.functions !== void 0 ? { functions: params.functions } : {},
6793
+ ...params.tools !== void 0 ? { tools: params.tools } : {},
6794
+ ...params.tool_choice !== void 0 ? { tool_choice: toPromptToolChoice(params.tool_choice) } : {},
6795
+ ...params.dry_run !== void 0 ? { dry_run: params.dry_run } : {}
6566
6796
  });
6567
6797
  return {
6568
6798
  content: [
@@ -6587,7 +6817,7 @@ Use get_prompt first to see the current format, then pass the same format back.
6587
6817
  );
6588
6818
  server.tool(
6589
6819
  "promote_prompt",
6590
- "Promote a prompt from one environment to another (e.g., staging -> prod). Copies the current version to the target environment. If the target prompt already exists it is updated with a new version; otherwise a new prompt is created.",
6820
+ "Copy a prompt from one environment to another and create or update the target automatically. Use this for staged releases when you want the target prompt synchronized without manual edits, and it returns both source and target version ids.",
6591
6821
  PROMPTS_TOOL_SCHEMAS.promotePrompt,
6592
6822
  async (params) => {
6593
6823
  const result = await service.prompts.promotePrompt({
@@ -6625,7 +6855,7 @@ Use get_prompt first to see the current format, then pass the same format back.
6625
6855
  );
6626
6856
  server.tool(
6627
6857
  "validate_completion_metadata",
6628
- "Validate billing metadata before running a completion. Checks for required fields (client_id, app, env) and valid values.",
6858
+ "Preflight billing metadata before run_prompt_completion. Validates required fields and values without making changes, so you can catch attribution errors before paying for the call.",
6629
6859
  PROMPTS_TOOL_SCHEMAS.validateCompletionMetadata,
6630
6860
  async (params) => {
6631
6861
  const result = service.prompts.validateBillingMetadata(params);
@@ -6650,7 +6880,7 @@ Use get_prompt first to see the current format, then pass the same format back.
6650
6880
  );
6651
6881
  server.tool(
6652
6882
  "get_prompt_version",
6653
- "Retrieve a specific version of a prompt by its version ID",
6883
+ "Retrieve a specific prompt version by its version UUID. Use list_prompt_versions to find the id first; returns the template, parameters, and model config for that version.",
6654
6884
  PROMPTS_TOOL_SCHEMAS.getPromptVersion,
6655
6885
  async (params) => {
6656
6886
  const version = await service.prompts.getPromptVersion(
@@ -6669,7 +6899,7 @@ Use get_prompt first to see the current format, then pass the same format back.
6669
6899
  );
6670
6900
  server.tool(
6671
6901
  "update_prompt_version",
6672
- "Update a specific prompt version, e.g. to assign or remove a label",
6902
+ "Update a specific prompt version's label assignment. This only assigns or removes a label, and null clears the label after you look up ids with list_prompt_labels.",
6673
6903
  PROMPTS_TOOL_SCHEMAS.updatePromptVersion,
6674
6904
  async (params) => {
6675
6905
  if (params.label_id === void 0) {
@@ -6777,7 +7007,7 @@ var PROVIDERS_TOOL_SCHEMAS = {
6777
7007
  function registerProvidersTools(server, service) {
6778
7008
  server.tool(
6779
7009
  "list_providers",
6780
- "List all providers in your Portkey organization with optional pagination and workspace filtering",
7010
+ "List workspace-scoped provider instances and their limits or status. Use this to find provider slugs for workspace-level updates; use list_integrations for the org-level source connection. Returns total plus provider name, slug, integration, status, limits, expiration, and reset flags.",
6781
7011
  PROVIDERS_TOOL_SCHEMAS.listProviders,
6782
7012
  async (params) => {
6783
7013
  const providers = await service.providers.listProviders({
@@ -6823,7 +7053,7 @@ function registerProvidersTools(server, service) {
6823
7053
  );
6824
7054
  server.tool(
6825
7055
  "create_provider",
6826
- "Create a new provider configuration in Portkey. Providers define integrations with AI model providers like OpenAI, Anthropic, etc.",
7056
+ "Create a workspace provider backed by an org integration. The provider inherits the integration key, but its limits and expiration are enforced independently for that workspace. Returns the new provider id and slug.",
6827
7057
  PROVIDERS_TOOL_SCHEMAS.createProvider,
6828
7058
  async (params) => {
6829
7059
  const result = await service.providers.createProvider({
@@ -6864,7 +7094,7 @@ function registerProvidersTools(server, service) {
6864
7094
  );
6865
7095
  server.tool(
6866
7096
  "get_provider",
6867
- "Retrieve detailed information about a specific provider by its slug",
7097
+ "Fetch one provider by slug, including limits, rate settings, expiration, and reset status. Use this to check consumption or audit configuration before updating.",
6868
7098
  PROVIDERS_TOOL_SCHEMAS.getProvider,
6869
7099
  async (params) => {
6870
7100
  const provider = await service.providers.getProvider(
@@ -6906,7 +7136,7 @@ function registerProvidersTools(server, service) {
6906
7136
  );
6907
7137
  server.tool(
6908
7138
  "update_provider",
6909
- "Update an existing provider's name, note, limits, or expiration",
7139
+ "Update a provider's metadata, limits, or expiration. reset_usage clears accumulated usage counters immediately, so use it only when you intend to reset quota tracking. Returns the updated provider id and slug.",
6910
7140
  PROVIDERS_TOOL_SCHEMAS.updateProvider,
6911
7141
  async (params) => {
6912
7142
  const result = await service.providers.updateProvider(
@@ -6949,7 +7179,7 @@ function registerProvidersTools(server, service) {
6949
7179
  );
6950
7180
  server.tool(
6951
7181
  "delete_provider",
6952
- "Delete a provider by slug. This action cannot be undone.",
7182
+ "Delete a workspace provider by slug. This is irreversible and will break prompts, configs, and virtual keys that reference it; use delete_integration for the org source instead. Returns success after the provider is removed.",
6953
7183
  PROVIDERS_TOOL_SCHEMAS.deleteProvider,
6954
7184
  async (params) => {
6955
7185
  await service.providers.deleteProvider(params.slug, params.workspace_id);
@@ -6996,15 +7226,12 @@ var TRACING_TOOL_SCHEMAS = {
6996
7226
  ),
6997
7227
  weight: z17.coerce.number().positive().optional().describe("New weighting factor for the feedback"),
6998
7228
  metadata: z17.record(z17.string(), z17.unknown()).optional().describe("New or updated custom metadata for the feedback")
6999
- },
7000
- getTrace: {
7001
- id: z17.string().describe("The unique identifier of the trace to retrieve")
7002
7229
  }
7003
7230
  };
7004
7231
  function registerTracingTools(server, service) {
7005
7232
  server.tool(
7006
7233
  "create_feedback",
7007
- "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.",
7234
+ "Create feedback for a trace or request. Writes a new feedback record linked by trace_id, returns the created feedback IDs and status, and takes effect immediately; use update_feedback when correcting an existing record.",
7008
7235
  TRACING_TOOL_SCHEMAS.createFeedback,
7009
7236
  async (params) => {
7010
7237
  const result = await service.tracing.createFeedback({
@@ -7033,7 +7260,7 @@ function registerTracingTools(server, service) {
7033
7260
  );
7034
7261
  server.tool(
7035
7262
  "update_feedback",
7036
- "Update existing feedback by ID. Allows modifying the feedback value, weight, or metadata after initial creation.",
7263
+ "Update an existing feedback record by ID. Returns the updated status and feedback IDs, changes only value, weight, and metadata, and leaves the trace linkage immutable; use create_feedback only for a new record.",
7037
7264
  TRACING_TOOL_SCHEMAS.updateFeedback,
7038
7265
  async (params) => {
7039
7266
  const result = await service.tracing.updateFeedback(params.id, {
@@ -7059,51 +7286,6 @@ function registerTracingTools(server, service) {
7059
7286
  };
7060
7287
  }
7061
7288
  );
7062
- server.tool(
7063
- "get_trace",
7064
- "Retrieve detailed information about a specific trace by ID. Returns full request/response data, all spans, metadata, cost, token usage, and any associated feedback.",
7065
- TRACING_TOOL_SCHEMAS.getTrace,
7066
- async (params) => {
7067
- const result = await service.tracing.getTrace(params.id);
7068
- const trace = result.data;
7069
- return {
7070
- content: [
7071
- {
7072
- type: "text",
7073
- text: JSON.stringify(
7074
- {
7075
- success: result.success,
7076
- trace: {
7077
- id: trace.id,
7078
- trace_id: trace.trace_id,
7079
- request: trace.request,
7080
- response: trace.response,
7081
- metadata: trace.metadata,
7082
- workspace_id: trace.workspace_id,
7083
- organisation_id: trace.organisation_id,
7084
- cost: trace.cost,
7085
- tokens: trace.tokens,
7086
- spans: trace.spans?.map((span) => ({
7087
- span_id: span.span_id,
7088
- span_name: span.span_name,
7089
- parent_span_id: span.parent_span_id,
7090
- start_time: span.start_time,
7091
- end_time: span.end_time,
7092
- status: span.status,
7093
- attributes: span.attributes
7094
- })),
7095
- feedback: trace.feedback,
7096
- created_at: trace.created_at
7097
- }
7098
- },
7099
- null,
7100
- 2
7101
- )
7102
- }
7103
- ]
7104
- };
7105
- }
7106
- );
7107
7289
  }
7108
7290
 
7109
7291
  // src/tools/users.tools.ts
@@ -7207,7 +7389,7 @@ function formatUserAnalyticsGroup(group) {
7207
7389
  function registerUsersTools(server, service) {
7208
7390
  server.tool(
7209
7391
  "list_all_users",
7210
- "List all users in your Portkey organization, including their roles and account details",
7392
+ "List accepted org users with id, name, email, role, and timestamps. Use this to find a user_id before get_user, update_user, delete_user, or add_workspace_member; use list_user_invites for pending invitations.",
7211
7393
  USERS_TOOL_SCHEMAS.listAllUsers,
7212
7394
  async () => {
7213
7395
  const users = await service.users.listUsers();
@@ -7230,7 +7412,7 @@ function registerUsersTools(server, service) {
7230
7412
  );
7231
7413
  server.tool(
7232
7414
  "invite_user",
7233
- "Invite a new user to your Portkey organization with specific workspace access and API key permissions. After the invite is accepted, use add_workspace_member to assign workspace roles.",
7415
+ "Invite a new org user and optionally provision workspace access and an API key in one call. Workspace assignments apply only after acceptance; use add_workspace_member or update_workspace_member later for follow-up changes.",
7234
7416
  USERS_TOOL_SCHEMAS.inviteUser,
7235
7417
  async (params) => {
7236
7418
  const result = await service.users.inviteUser(params);
@@ -7254,7 +7436,7 @@ function registerUsersTools(server, service) {
7254
7436
  );
7255
7437
  server.tool(
7256
7438
  "get_user_stats",
7257
- "Retrieve detailed analytics data about user activity within a specified time range, including request counts and costs",
7439
+ "Return per-user request and cost analytics for a required time range. This is usage-by-user, not population metrics; use get_users_analytics for active-user or cohort trends.",
7258
7440
  USERS_TOOL_SCHEMAS.getUserStats,
7259
7441
  async (params) => {
7260
7442
  const stats = await service.users.getUserGroupedData(params);
@@ -7277,7 +7459,7 @@ function registerUsersTools(server, service) {
7277
7459
  );
7278
7460
  server.tool(
7279
7461
  "get_user",
7280
- "Retrieve detailed information about a specific user by their ID",
7462
+ "Get one accepted user by id and return their profile, role, and timestamps. Use list_all_users to find the id if you only have a name or email, and get_user_invite for pending invitations.",
7281
7463
  USERS_TOOL_SCHEMAS.getUser,
7282
7464
  async (params) => {
7283
7465
  const user = await service.users.getUser(params.user_id);
@@ -7293,7 +7475,7 @@ function registerUsersTools(server, service) {
7293
7475
  );
7294
7476
  server.tool(
7295
7477
  "update_user",
7296
- "Update a user's profile information including name and organization role",
7478
+ "Update a user's first name, last name, or organization role by id. Email and workspace roles are not editable here; use update_workspace_member for workspace membership changes.",
7297
7479
  USERS_TOOL_SCHEMAS.updateUser,
7298
7480
  async (params) => {
7299
7481
  const { user_id, ...updateData } = params;
@@ -7317,7 +7499,7 @@ function registerUsersTools(server, service) {
7317
7499
  );
7318
7500
  server.tool(
7319
7501
  "delete_user",
7320
- "Remove a user from your Portkey organization. Permanently removes the user and all their org/workspace memberships. Cannot be undone.",
7502
+ "Delete a user from the org by id. This is permanent, removes org and workspace memberships, revokes API keys, and ends active sessions; use delete_user_invite for pending invites instead.",
7321
7503
  USERS_TOOL_SCHEMAS.deleteUser,
7322
7504
  async (params) => {
7323
7505
  await service.users.deleteUser(params.user_id);
@@ -7340,7 +7522,7 @@ function registerUsersTools(server, service) {
7340
7522
  );
7341
7523
  server.tool(
7342
7524
  "list_user_invites",
7343
- "List all pending and sent user invitations in your Portkey organization",
7525
+ "List pending and sent invitations with id, email, role, status, and expiry. Use this to check invite state; use list_all_users for users who already accepted.",
7344
7526
  USERS_TOOL_SCHEMAS.listUserInvites,
7345
7527
  async () => {
7346
7528
  const invites = await service.users.listUserInvites();
@@ -7363,7 +7545,7 @@ function registerUsersTools(server, service) {
7363
7545
  );
7364
7546
  server.tool(
7365
7547
  "get_user_invite",
7366
- "Retrieve details about a specific user invitation",
7548
+ "Get one invitation by invite id and return its email, role, status, and expiry. Use this for pending invites only; use get_user for accepted users.",
7367
7549
  USERS_TOOL_SCHEMAS.getUserInvite,
7368
7550
  async (params) => {
7369
7551
  const invite = await service.users.getUserInvite(params.invite_id);
@@ -7379,7 +7561,7 @@ function registerUsersTools(server, service) {
7379
7561
  );
7380
7562
  server.tool(
7381
7563
  "delete_user_invite",
7382
- "Cancel and delete a pending user invitation",
7564
+ "Delete a pending invite and revoke its invite link. This does not affect existing users; use delete_user for full user removal.",
7383
7565
  USERS_TOOL_SCHEMAS.deleteUserInvite,
7384
7566
  async (params) => {
7385
7567
  await service.users.deleteUserInvite(params.invite_id);
@@ -7402,7 +7584,7 @@ function registerUsersTools(server, service) {
7402
7584
  );
7403
7585
  server.tool(
7404
7586
  "resend_user_invite",
7405
- "Resend an invitation email to a pending user",
7587
+ "Resend the email for a pending invite that has not been accepted. The invite must still exist; use get_user_invite first if you are unsure.",
7406
7588
  USERS_TOOL_SCHEMAS.resendUserInvite,
7407
7589
  async (params) => {
7408
7590
  await service.users.resendUserInvite(params.invite_id);
@@ -7532,7 +7714,7 @@ function formatWorkspaceDetail(workspace) {
7532
7714
  function registerWorkspacesTools(server, service) {
7533
7715
  server.tool(
7534
7716
  "list_workspaces",
7535
- "Retrieve all workspaces in your Portkey organization, including their configurations and metadata",
7717
+ "List workspaces with id, name, slug, default settings, and timestamps. Use this to find a workspace_id before get_workspace, update_workspace, add_workspace_member, or remove_workspace_member.",
7536
7718
  WORKSPACES_TOOL_SCHEMAS.listWorkspaces,
7537
7719
  async (params) => {
7538
7720
  const workspaces = await service.workspaces.listWorkspaces(params);
@@ -7555,7 +7737,7 @@ function registerWorkspacesTools(server, service) {
7555
7737
  );
7556
7738
  server.tool(
7557
7739
  "get_workspace",
7558
- "Retrieve detailed information about a specific workspace, including its configuration, metadata, and user access details",
7740
+ "Get one workspace by id and return its full details, including defaults and the complete member list. Use this when you need membership detail; use list_workspaces for an overview.",
7559
7741
  WORKSPACES_TOOL_SCHEMAS.getWorkspace,
7560
7742
  async (params) => {
7561
7743
  const workspace = await service.workspaces.getWorkspace(
@@ -7573,7 +7755,7 @@ function registerWorkspacesTools(server, service) {
7573
7755
  );
7574
7756
  server.tool(
7575
7757
  "create_workspace",
7576
- "Create a new workspace in your Portkey organization",
7758
+ "Create a workspace to isolate resources, API keys, and team members. If slug is omitted it is auto-generated from the name; returns the new workspace id, name, and slug.",
7577
7759
  WORKSPACES_TOOL_SCHEMAS.createWorkspace,
7578
7760
  async (params) => {
7579
7761
  const workspace = await service.workspaces.createWorkspace({
@@ -7604,7 +7786,7 @@ function registerWorkspacesTools(server, service) {
7604
7786
  );
7605
7787
  server.tool(
7606
7788
  "update_workspace",
7607
- "Update an existing workspace's settings and metadata",
7789
+ "Update a workspace's name, slug, description, default flag, or metadata by id. Only provided fields change; changing the slug can break URLs and other references.",
7608
7790
  WORKSPACES_TOOL_SCHEMAS.updateWorkspace,
7609
7791
  async (params) => {
7610
7792
  const { workspace_id, is_default, metadata, ...rest } = params;
@@ -7634,7 +7816,7 @@ function registerWorkspacesTools(server, service) {
7634
7816
  );
7635
7817
  server.tool(
7636
7818
  "delete_workspace",
7637
- "Delete a workspace from your organization. Permanently deletes the workspace and all its members, configs, API keys, and resources. Cannot be undone.",
7819
+ "Delete a workspace by id. This is permanent and removes the workspace, its members, configs, API keys, and resources.",
7638
7820
  WORKSPACES_TOOL_SCHEMAS.deleteWorkspace,
7639
7821
  async (params) => {
7640
7822
  await service.workspaces.deleteWorkspace(params.workspace_id);
@@ -7657,7 +7839,7 @@ function registerWorkspacesTools(server, service) {
7657
7839
  );
7658
7840
  server.tool(
7659
7841
  "add_workspace_member",
7660
- "Add a user to a workspace with a specific role",
7842
+ "Add an existing org user to a workspace with a role. Requires a UUID user_id; use list_all_users to find it, and invite_user first if the person is not yet in the org.",
7661
7843
  WORKSPACES_TOOL_SCHEMAS.addWorkspaceMember,
7662
7844
  async (params) => {
7663
7845
  const member = await service.workspaces.addWorkspaceMember(
@@ -7686,7 +7868,7 @@ function registerWorkspacesTools(server, service) {
7686
7868
  );
7687
7869
  server.tool(
7688
7870
  "list_workspace_members",
7689
- "List all members of a workspace with their roles",
7871
+ "List every member in a workspace with organization role, workspace role, status, and timestamps. Use this to find a user_id before get_workspace_member, update_workspace_member, or remove_workspace_member.",
7690
7872
  WORKSPACES_TOOL_SCHEMAS.listWorkspaceMembers,
7691
7873
  async (params) => {
7692
7874
  const members = await service.workspaces.listWorkspaceMembers(
@@ -7711,7 +7893,7 @@ function registerWorkspacesTools(server, service) {
7711
7893
  );
7712
7894
  server.tool(
7713
7895
  "get_workspace_member",
7714
- "Get details about a specific member of a workspace",
7896
+ "Get one workspace member by workspace_id and user_id. Use this when you already know both IDs; use list_workspace_members to browse the full roster.",
7715
7897
  WORKSPACES_TOOL_SCHEMAS.getWorkspaceMember,
7716
7898
  async (params) => {
7717
7899
  const member = await service.workspaces.getWorkspaceMember(
@@ -7730,7 +7912,7 @@ function registerWorkspacesTools(server, service) {
7730
7912
  );
7731
7913
  server.tool(
7732
7914
  "update_workspace_member",
7733
- "Update a member's role in a workspace",
7915
+ "Update a workspace member's role by workspace_id and user_id. Only the role changes here; use list_workspace_members or get_workspace_member to confirm the current assignment first.",
7734
7916
  WORKSPACES_TOOL_SCHEMAS.updateWorkspaceMember,
7735
7917
  async (params) => {
7736
7918
  const member = await service.workspaces.updateWorkspaceMember(
@@ -7759,7 +7941,7 @@ function registerWorkspacesTools(server, service) {
7759
7941
  );
7760
7942
  server.tool(
7761
7943
  "remove_workspace_member",
7762
- "Remove a user from a workspace",
7944
+ "Remove a user from a workspace and revoke workspace access. This does not delete the user from the organization; use delete_user for full removal.",
7763
7945
  WORKSPACES_TOOL_SCHEMAS.removeWorkspaceMember,
7764
7946
  async (params) => {
7765
7947
  await service.workspaces.removeWorkspaceMember(
@@ -7840,6 +8022,37 @@ var DESTRUCTIVE_TOOL_PREFIXES = [
7840
8022
  "cancel_",
7841
8023
  "reset_"
7842
8024
  ];
8025
+ var ENTERPRISE_GATED_TOOL_NAMES = /* @__PURE__ */ new Set([
8026
+ "get_cost_analytics",
8027
+ "get_request_analytics",
8028
+ "get_token_analytics",
8029
+ "get_latency_analytics",
8030
+ "get_error_analytics",
8031
+ "get_error_rate_analytics",
8032
+ "get_cache_hit_latency",
8033
+ "get_cache_hit_rate",
8034
+ "get_users_analytics",
8035
+ "get_error_stacks_analytics",
8036
+ "get_error_status_codes_analytics",
8037
+ "get_user_requests_analytics",
8038
+ "get_rescued_requests_analytics",
8039
+ "get_feedback_analytics",
8040
+ "get_feedback_models_analytics",
8041
+ "get_feedback_scores_analytics",
8042
+ "get_feedback_weighted_analytics",
8043
+ "get_analytics_group_users",
8044
+ "get_analytics_group_models",
8045
+ "get_analytics_group_metadata",
8046
+ "list_audit_logs",
8047
+ "get_integration",
8048
+ "list_integration_models",
8049
+ "list_integration_workspaces",
8050
+ "list_all_users",
8051
+ "get_user",
8052
+ "list_user_invites",
8053
+ "get_user_stats"
8054
+ ]);
8055
+ var ENTERPRISE_GATED_DESCRIPTION_NOTE = "Enterprise-gated. Returns 403 on non-Enterprise Portkey plans.";
7843
8056
  function isToolAnnotationsLike(value) {
7844
8057
  if (!isRecord2(value)) {
7845
8058
  return false;
@@ -7888,6 +8101,15 @@ function inferToolAnnotations(toolName) {
7888
8101
  openWorldHint: true
7889
8102
  };
7890
8103
  }
8104
+ function augmentToolDescription(toolName, description) {
8105
+ if (!description || !ENTERPRISE_GATED_TOOL_NAMES.has(toolName)) {
8106
+ return description;
8107
+ }
8108
+ if (description.includes(ENTERPRISE_GATED_DESCRIPTION_NOTE)) {
8109
+ return description;
8110
+ }
8111
+ return `${description} ${ENTERPRISE_GATED_DESCRIPTION_NOTE}`;
8112
+ }
7891
8113
  function getToolErrorMessage(error) {
7892
8114
  if (error instanceof Error && error.message) {
7893
8115
  return error.message;
@@ -7992,6 +8214,7 @@ function buildToolRegistration(name, rest) {
7992
8214
  if (typeof args[0] === "string") {
7993
8215
  description = args.shift();
7994
8216
  }
8217
+ description = augmentToolDescription(name, description);
7995
8218
  let inputSchema;
7996
8219
  let annotations = inferredAnnotations;
7997
8220
  if (args.length === 1) {
@@ -8637,7 +8860,27 @@ function readPackageVersion() {
8637
8860
  return "0.0.0";
8638
8861
  }
8639
8862
  var PACKAGE_VERSION = readPackageVersion();
8640
- 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.";
8863
+ 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.";
8864
+ function parseConfiguredToolDomains(rawValue = process.env.PORTKEY_TOOL_DOMAINS?.trim() || process.env.MCP_TOOL_DOMAINS?.trim()) {
8865
+ if (!rawValue) {
8866
+ return void 0;
8867
+ }
8868
+ const requestedDomains = rawValue.split(",").map((value) => value.trim().toLowerCase()).filter((value) => value.length > 0);
8869
+ if (requestedDomains.length === 0) {
8870
+ throw new Error(
8871
+ `Invalid PORTKEY_TOOL_DOMAINS value. Expected one or more domains from: ${TOOL_DOMAIN_NAMES.join(", ")}`
8872
+ );
8873
+ }
8874
+ const invalidDomains = requestedDomains.filter(
8875
+ (value) => !isToolDomain(value)
8876
+ );
8877
+ if (invalidDomains.length > 0) {
8878
+ throw new Error(
8879
+ `Unknown tool domains in PORTKEY_TOOL_DOMAINS: ${invalidDomains.join(", ")}. Valid domains: ${TOOL_DOMAIN_NAMES.join(", ")}`
8880
+ );
8881
+ }
8882
+ return normalizeToolDomains(requestedDomains);
8883
+ }
8641
8884
  function createMcpServer(options = {}) {
8642
8885
  const service = getSharedPortkeyService();
8643
8886
  const server = new McpServer(
@@ -8652,7 +8895,9 @@ function createMcpServer(options = {}) {
8652
8895
  instructions: SERVER_INSTRUCTIONS
8653
8896
  }
8654
8897
  );
8655
- registerAllTools(server, service, { domains: options.toolDomains });
8898
+ registerAllTools(server, service, {
8899
+ domains: options.toolDomains ?? parseConfiguredToolDomains()
8900
+ });
8656
8901
  return {
8657
8902
  server,
8658
8903
  service