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/index.js CHANGED
@@ -1438,9 +1438,6 @@ var TracingService = class extends BaseService {
1438
1438
  data
1439
1439
  );
1440
1440
  }
1441
- async getTrace(id) {
1442
- return this.get(`/logs/${this.encodePathSegment(id)}`);
1443
- }
1444
1441
  };
1445
1442
 
1446
1443
  // src/services/users.service.ts
@@ -1674,23 +1671,99 @@ var baseAnalyticsSchema = {
1674
1671
  prompt_token_max: z.coerce.number().positive().optional().describe("Maximum number of prompt tokens"),
1675
1672
  completion_token_min: z.coerce.number().positive().optional().describe("Minimum number of completion tokens"),
1676
1673
  completion_token_max: z.coerce.number().positive().optional().describe("Maximum number of completion tokens"),
1677
- status_code: z.string().optional().describe("Filter by specific HTTP status codes (comma-separated)"),
1674
+ status_code: z.string().optional().describe(
1675
+ "Legacy Portkey query param for HTTP status codes. Comma-separated string; prefer status_codes for structured inputs."
1676
+ ),
1678
1677
  weighted_feedback_min: z.coerce.number().min(-10).max(10).optional().describe("Minimum weighted feedback score (-10 to 10)"),
1679
1678
  weighted_feedback_max: z.coerce.number().min(-10).max(10).optional().describe("Maximum weighted feedback score (-10 to 10)"),
1680
- virtual_keys: z.string().optional().describe("Filter by specific virtual key slugs (comma-separated)"),
1681
- configs: z.string().optional().describe("Filter by specific config slugs (comma-separated)"),
1679
+ virtual_keys: z.string().optional().describe(
1680
+ "Legacy Portkey query param for virtual key slugs. Comma-separated string; prefer virtual_key_slugs for structured inputs."
1681
+ ),
1682
+ configs: z.string().optional().describe(
1683
+ "Legacy Portkey query param for config slugs. Comma-separated string; prefer config_slugs for structured inputs."
1684
+ ),
1685
+ status_codes: z.array(z.string()).optional().describe(
1686
+ "Structured alias for status_code. Use an array of HTTP status codes; normalized to the legacy comma-separated Portkey query param."
1687
+ ),
1688
+ virtual_key_slugs: z.array(z.string()).optional().describe(
1689
+ "Structured alias for virtual_keys. Use an array of virtual key slugs; normalized to the legacy comma-separated Portkey query param."
1690
+ ),
1691
+ config_slugs: z.array(z.string()).optional().describe(
1692
+ "Structured alias for configs. Use an array of config slugs; normalized to the legacy comma-separated Portkey query param."
1693
+ ),
1682
1694
  workspace_slug: z.string().optional().describe("Filter by specific workspace"),
1683
- api_key_ids: z.string().optional().describe("Filter by specific API key UUIDs (comma-separated)"),
1695
+ api_key_ids: z.preprocess((value) => {
1696
+ if (value == null) {
1697
+ return value;
1698
+ }
1699
+ if (Array.isArray(value)) {
1700
+ return value.map((item) => String(item)).join(",");
1701
+ }
1702
+ return value;
1703
+ }, z.string().optional()).describe(
1704
+ "Legacy Portkey query param for API key UUIDs. Comma-separated string; request_analytics also accepts an array and normalizes it to this form."
1705
+ ),
1684
1706
  metadata: z.string().optional().describe(
1685
- `Stringified JSON object for metadata filtering, e.g. '{"env":"prod","app":"myapp"}'.`
1707
+ `Legacy Portkey query param for metadata filtering. Stringified JSON object, e.g. '{"env":"prod","app":"myapp"}'; prefer metadata_filter for structured inputs.`
1686
1708
  ),
1687
1709
  ai_org_model: z.string().optional().describe(
1688
- "Filter by provider and model, format: 'provider__model' with double underscore, e.g. 'openai__gpt-4' or 'anthropic__claude-3-opus'. Comma-separated for multiple."
1710
+ "Legacy Portkey query param for provider/model pairs. Format: 'provider__model' with double underscore, e.g. 'openai__gpt-4' or 'anthropic__claude-3-opus'. Comma-separated string; prefer provider_models for structured inputs."
1711
+ ),
1712
+ provider_models: z.array(z.string()).optional().describe(
1713
+ "Structured alias for ai_org_model. Use provider__model strings in an array; normalized to the legacy comma-separated Portkey query param."
1714
+ ),
1715
+ trace_id: z.string().optional().describe(
1716
+ "Legacy Portkey query param for trace IDs. Comma-separated string; prefer trace_ids for structured inputs."
1717
+ ),
1718
+ trace_ids: z.array(z.string()).optional().describe(
1719
+ "Structured alias for trace_id. Use an array of trace IDs; normalized to the legacy comma-separated Portkey query param."
1720
+ ),
1721
+ span_id: z.string().optional().describe(
1722
+ "Legacy Portkey query param for span IDs. Comma-separated string; prefer span_ids for structured inputs."
1723
+ ),
1724
+ span_ids: z.array(z.string()).optional().describe(
1725
+ "Structured alias for span_id. Use an array of span IDs; normalized to the legacy comma-separated Portkey query param."
1726
+ ),
1727
+ metadata_filter: z.record(z.string(), z.unknown()).optional().describe(
1728
+ "Structured alias for metadata. Use an object such as { env: 'prod' }; normalized to a JSON string before the request is sent."
1689
1729
  ),
1690
- trace_id: z.string().optional().describe("Filter by trace IDs (comma-separated)"),
1691
- span_id: z.string().optional().describe("Filter by span IDs (comma-separated)"),
1692
1730
  prompt_slug: z.string().optional().describe("Filter by prompt slug")
1693
1731
  };
1732
+ var requestAnalyticsSchema = {
1733
+ ...baseAnalyticsSchema,
1734
+ status_codes: z.array(z.string()).optional().describe(
1735
+ "Structured alias for status_code. Use an array of HTTP status codes; normalized to the legacy comma-separated Portkey query param."
1736
+ ),
1737
+ virtual_key_slugs: z.array(z.string()).optional().describe(
1738
+ "Structured alias for virtual_keys. Use an array of virtual key slugs; normalized to the legacy comma-separated Portkey query param."
1739
+ ),
1740
+ config_slugs: z.array(z.string()).optional().describe(
1741
+ "Structured alias for configs. Use an array of config slugs; normalized to the legacy comma-separated Portkey query param."
1742
+ ),
1743
+ api_key_ids: z.preprocess((value) => {
1744
+ if (value == null) {
1745
+ return value;
1746
+ }
1747
+ if (Array.isArray(value)) {
1748
+ return value.map((item) => String(item)).join(",");
1749
+ }
1750
+ return value;
1751
+ }, z.string().optional()).describe(
1752
+ "API key UUIDs. Accepts the legacy comma-separated string or a structured array; normalized to the legacy Portkey query param before the request is sent."
1753
+ ),
1754
+ trace_ids: z.array(z.string()).optional().describe(
1755
+ "Structured alias for trace_id. Use an array of trace IDs; normalized to the legacy comma-separated Portkey query param."
1756
+ ),
1757
+ span_ids: z.array(z.string()).optional().describe(
1758
+ "Structured alias for span_id. Use an array of span IDs; normalized to the legacy comma-separated Portkey query param."
1759
+ ),
1760
+ provider_models: z.array(z.string()).optional().describe(
1761
+ "Structured alias for ai_org_model. Use provider__model strings in an array; normalized to the legacy comma-separated Portkey query param."
1762
+ ),
1763
+ metadata_filter: z.record(z.string(), z.unknown()).optional().describe(
1764
+ "Structured alias for metadata. Use an object such as { env: 'prod' }; normalized to a JSON string before the request is sent."
1765
+ )
1766
+ };
1694
1767
  var paginatedAnalyticsSchema = {
1695
1768
  ...baseAnalyticsSchema,
1696
1769
  current_page: z.coerce.number().positive().optional().describe("Page number for pagination"),
@@ -1717,13 +1790,88 @@ function formatGroupedAnalytics(analytics, groupLabel) {
1717
1790
  [groupLabel]: analytics.data
1718
1791
  };
1719
1792
  }
1793
+ function normalizeCommaSeparatedParam(value) {
1794
+ if (value == null) {
1795
+ return void 0;
1796
+ }
1797
+ if (Array.isArray(value)) {
1798
+ return value.map((item) => String(item)).join(",");
1799
+ }
1800
+ if (typeof value === "string") {
1801
+ return value;
1802
+ }
1803
+ return void 0;
1804
+ }
1805
+ function normalizeMetadataFilter(value) {
1806
+ if (value == null) {
1807
+ return void 0;
1808
+ }
1809
+ if (typeof value === "string") {
1810
+ return value;
1811
+ }
1812
+ if (typeof value === "object") {
1813
+ return JSON.stringify(value);
1814
+ }
1815
+ return void 0;
1816
+ }
1817
+ function normalizeAnalyticsParams(params) {
1818
+ const {
1819
+ status_codes,
1820
+ virtual_key_slugs,
1821
+ config_slugs,
1822
+ api_key_ids,
1823
+ trace_ids,
1824
+ span_ids,
1825
+ provider_models,
1826
+ metadata_filter,
1827
+ ...legacyParams
1828
+ } = params;
1829
+ const normalizedParams = {
1830
+ ...legacyParams
1831
+ };
1832
+ const statusCode = normalizeCommaSeparatedParam(status_codes) ?? normalizeCommaSeparatedParam(legacyParams.status_code);
1833
+ if (statusCode !== void 0) {
1834
+ normalizedParams.status_code = statusCode;
1835
+ }
1836
+ const virtualKeys = normalizeCommaSeparatedParam(virtual_key_slugs) ?? normalizeCommaSeparatedParam(legacyParams.virtual_keys);
1837
+ if (virtualKeys !== void 0) {
1838
+ normalizedParams.virtual_keys = virtualKeys;
1839
+ }
1840
+ const configs = normalizeCommaSeparatedParam(config_slugs) ?? normalizeCommaSeparatedParam(legacyParams.configs);
1841
+ if (configs !== void 0) {
1842
+ normalizedParams.configs = configs;
1843
+ }
1844
+ const apiKeyIds = normalizeCommaSeparatedParam(api_key_ids) ?? normalizeCommaSeparatedParam(legacyParams.api_key_ids);
1845
+ if (apiKeyIds !== void 0) {
1846
+ normalizedParams.api_key_ids = apiKeyIds;
1847
+ }
1848
+ const metadata = normalizeMetadataFilter(metadata_filter) ?? normalizeMetadataFilter(legacyParams.metadata);
1849
+ if (metadata !== void 0) {
1850
+ normalizedParams.metadata = metadata;
1851
+ }
1852
+ const providerModels = normalizeCommaSeparatedParam(provider_models) ?? normalizeCommaSeparatedParam(legacyParams.ai_org_model);
1853
+ if (providerModels !== void 0) {
1854
+ normalizedParams.ai_org_model = providerModels;
1855
+ }
1856
+ const traceId = normalizeCommaSeparatedParam(trace_ids) ?? normalizeCommaSeparatedParam(legacyParams.trace_id);
1857
+ if (traceId !== void 0) {
1858
+ normalizedParams.trace_id = traceId;
1859
+ }
1860
+ const spanId = normalizeCommaSeparatedParam(span_ids) ?? normalizeCommaSeparatedParam(legacyParams.span_id);
1861
+ if (spanId !== void 0) {
1862
+ normalizedParams.span_id = spanId;
1863
+ }
1864
+ return normalizedParams;
1865
+ }
1720
1866
  function registerAnalyticsTools(server, service) {
1721
1867
  server.tool(
1722
1868
  "get_cost_analytics",
1723
- "Retrieve detailed cost analytics data over time, including total costs and averages per request",
1869
+ "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.",
1724
1870
  baseAnalyticsSchema,
1725
1871
  async (params) => {
1726
- const analytics = await service.analytics.getCostAnalytics(params);
1872
+ const analytics = await service.analytics.getCostAnalytics(
1873
+ normalizeAnalyticsParams(params)
1874
+ );
1727
1875
  const dataPoints = analytics.data_points.map((point) => ({
1728
1876
  timestamp: point.timestamp,
1729
1877
  total_cost: point.total,
@@ -1751,10 +1899,12 @@ function registerAnalyticsTools(server, service) {
1751
1899
  );
1752
1900
  server.tool(
1753
1901
  "get_request_analytics",
1754
- "Retrieve request analytics as time-series data, showing total, successful, and failed requests over time",
1755
- baseAnalyticsSchema,
1902
+ "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.",
1903
+ requestAnalyticsSchema,
1756
1904
  async (params) => {
1757
- const analytics = await service.analytics.getRequestAnalytics(params);
1905
+ const analytics = await service.analytics.getRequestAnalytics(
1906
+ normalizeAnalyticsParams(params)
1907
+ );
1758
1908
  const dataPoints = analytics.data_points.map((point) => ({
1759
1909
  timestamp: point.timestamp,
1760
1910
  total: point.total,
@@ -1784,10 +1934,12 @@ function registerAnalyticsTools(server, service) {
1784
1934
  );
1785
1935
  server.tool(
1786
1936
  "get_token_analytics",
1787
- "Retrieve token usage analytics as time-series data, showing total, prompt, and completion tokens over time",
1937
+ "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.",
1788
1938
  baseAnalyticsSchema,
1789
1939
  async (params) => {
1790
- const analytics = await service.analytics.getTokenAnalytics(params);
1940
+ const analytics = await service.analytics.getTokenAnalytics(
1941
+ normalizeAnalyticsParams(params)
1942
+ );
1791
1943
  const dataPoints = analytics.data_points.map((point) => ({
1792
1944
  timestamp: point.timestamp,
1793
1945
  total: point.total,
@@ -1817,10 +1969,12 @@ function registerAnalyticsTools(server, service) {
1817
1969
  );
1818
1970
  server.tool(
1819
1971
  "get_latency_analytics",
1820
- "Retrieve latency analytics as time-series data, showing average, p50, p90, and p99 latency percentiles over time",
1972
+ "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.",
1821
1973
  baseAnalyticsSchema,
1822
1974
  async (params) => {
1823
- const analytics = await service.analytics.getLatencyAnalytics(params);
1975
+ const analytics = await service.analytics.getLatencyAnalytics(
1976
+ normalizeAnalyticsParams(params)
1977
+ );
1824
1978
  const dataPoints = analytics.data_points.map((point) => ({
1825
1979
  timestamp: point.timestamp,
1826
1980
  avg: point.avg,
@@ -1852,10 +2006,12 @@ function registerAnalyticsTools(server, service) {
1852
2006
  );
1853
2007
  server.tool(
1854
2008
  "get_error_analytics",
1855
- "Retrieve error count analytics as time-series data, showing total error counts over time",
2009
+ "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.",
1856
2010
  baseAnalyticsSchema,
1857
2011
  async (params) => {
1858
- const analytics = await service.analytics.getErrorAnalytics(params);
2012
+ const analytics = await service.analytics.getErrorAnalytics(
2013
+ normalizeAnalyticsParams(params)
2014
+ );
1859
2015
  const dataPoints = analytics.data_points.map((point) => ({
1860
2016
  timestamp: point.timestamp,
1861
2017
  total_errors: point.total
@@ -1881,10 +2037,12 @@ function registerAnalyticsTools(server, service) {
1881
2037
  );
1882
2038
  server.tool(
1883
2039
  "get_error_rate_analytics",
1884
- "Retrieve error rate analytics as time-series data, showing the percentage of failed requests over time",
2040
+ "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.",
1885
2041
  baseAnalyticsSchema,
1886
2042
  async (params) => {
1887
- const analytics = await service.analytics.getErrorRateAnalytics(params);
2043
+ const analytics = await service.analytics.getErrorRateAnalytics(
2044
+ normalizeAnalyticsParams(params)
2045
+ );
1888
2046
  const dataPoints = analytics.data_points.map((point) => ({
1889
2047
  timestamp: point.timestamp,
1890
2048
  error_rate_percent: point.rate
@@ -1910,10 +2068,12 @@ function registerAnalyticsTools(server, service) {
1910
2068
  );
1911
2069
  server.tool(
1912
2070
  "get_cache_hit_latency",
1913
- "Retrieve cache hit latency analytics as time-series data, showing total and average latency for cache hits over time",
2071
+ "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.",
1914
2072
  baseAnalyticsSchema,
1915
2073
  async (params) => {
1916
- const analytics = await service.analytics.getCacheHitLatency(params);
2074
+ const analytics = await service.analytics.getCacheHitLatency(
2075
+ normalizeAnalyticsParams(params)
2076
+ );
1917
2077
  const dataPoints = analytics.data_points.map((point) => ({
1918
2078
  timestamp: point.timestamp,
1919
2079
  total: point.total,
@@ -1941,10 +2101,12 @@ function registerAnalyticsTools(server, service) {
1941
2101
  );
1942
2102
  server.tool(
1943
2103
  "get_cache_hit_rate",
1944
- "Retrieve cache hit rate analytics as time-series data, showing hit rate percentage, total hits, and misses over time",
2104
+ "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.",
1945
2105
  baseAnalyticsSchema,
1946
2106
  async (params) => {
1947
- const analytics = await service.analytics.getCacheHitRate(params);
2107
+ const analytics = await service.analytics.getCacheHitRate(
2108
+ normalizeAnalyticsParams(params)
2109
+ );
1948
2110
  const dataPoints = analytics.data_points.map((point) => ({
1949
2111
  timestamp: point.timestamp,
1950
2112
  rate: point.rate,
@@ -1974,10 +2136,12 @@ function registerAnalyticsTools(server, service) {
1974
2136
  );
1975
2137
  server.tool(
1976
2138
  "get_users_analytics",
1977
- "Retrieve user activity analytics over time, showing active and new user counts",
2139
+ "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.",
1978
2140
  baseAnalyticsSchema,
1979
2141
  async (params) => {
1980
- const analytics = await service.analytics.getUsersAnalytics(params);
2142
+ const analytics = await service.analytics.getUsersAnalytics(
2143
+ normalizeAnalyticsParams(params)
2144
+ );
1981
2145
  const dataPoints = analytics.data_points.map((point) => ({
1982
2146
  timestamp: point.timestamp,
1983
2147
  active_users: point.active_users,
@@ -2005,10 +2169,12 @@ function registerAnalyticsTools(server, service) {
2005
2169
  );
2006
2170
  server.tool(
2007
2171
  "get_error_stacks_analytics",
2008
- "Retrieve error analytics broken down by status code stacks over time",
2172
+ "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.",
2009
2173
  baseAnalyticsSchema,
2010
2174
  async (params) => {
2011
- const analytics = await service.analytics.getErrorStacksAnalytics(params);
2175
+ const analytics = await service.analytics.getErrorStacksAnalytics(
2176
+ normalizeAnalyticsParams(params)
2177
+ );
2012
2178
  return {
2013
2179
  content: [
2014
2180
  {
@@ -2025,10 +2191,12 @@ function registerAnalyticsTools(server, service) {
2025
2191
  );
2026
2192
  server.tool(
2027
2193
  "get_error_status_codes_analytics",
2028
- "Retrieve unique error status code distribution analytics over time",
2194
+ "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.",
2029
2195
  baseAnalyticsSchema,
2030
2196
  async (params) => {
2031
- const analytics = await service.analytics.getErrorStatusCodesAnalytics(params);
2197
+ const analytics = await service.analytics.getErrorStatusCodesAnalytics(
2198
+ normalizeAnalyticsParams(params)
2199
+ );
2032
2200
  return {
2033
2201
  content: [
2034
2202
  {
@@ -2045,10 +2213,12 @@ function registerAnalyticsTools(server, service) {
2045
2213
  );
2046
2214
  server.tool(
2047
2215
  "get_user_requests_analytics",
2048
- "Retrieve per-user request count analytics over time",
2216
+ "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.",
2049
2217
  baseAnalyticsSchema,
2050
2218
  async (params) => {
2051
- const analytics = await service.analytics.getUserRequestsAnalytics(params);
2219
+ const analytics = await service.analytics.getUserRequestsAnalytics(
2220
+ normalizeAnalyticsParams(params)
2221
+ );
2052
2222
  return {
2053
2223
  content: [
2054
2224
  {
@@ -2065,10 +2235,12 @@ function registerAnalyticsTools(server, service) {
2065
2235
  );
2066
2236
  server.tool(
2067
2237
  "get_rescued_requests_analytics",
2068
- "Retrieve analytics for requests rescued by retry or fallback strategies over time",
2238
+ "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.",
2069
2239
  baseAnalyticsSchema,
2070
2240
  async (params) => {
2071
- const analytics = await service.analytics.getRescuedRequestsAnalytics(params);
2241
+ const analytics = await service.analytics.getRescuedRequestsAnalytics(
2242
+ normalizeAnalyticsParams(params)
2243
+ );
2072
2244
  return {
2073
2245
  content: [
2074
2246
  {
@@ -2085,10 +2257,12 @@ function registerAnalyticsTools(server, service) {
2085
2257
  );
2086
2258
  server.tool(
2087
2259
  "get_feedback_analytics",
2088
- "Retrieve feedback submission analytics over time",
2260
+ "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.",
2089
2261
  baseAnalyticsSchema,
2090
2262
  async (params) => {
2091
- const analytics = await service.analytics.getFeedbackAnalytics(params);
2263
+ const analytics = await service.analytics.getFeedbackAnalytics(
2264
+ normalizeAnalyticsParams(params)
2265
+ );
2092
2266
  return {
2093
2267
  content: [
2094
2268
  {
@@ -2105,10 +2279,12 @@ function registerAnalyticsTools(server, service) {
2105
2279
  );
2106
2280
  server.tool(
2107
2281
  "get_feedback_models_analytics",
2108
- "Retrieve feedback analytics grouped by AI model over time",
2282
+ "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.",
2109
2283
  baseAnalyticsSchema,
2110
2284
  async (params) => {
2111
- const analytics = await service.analytics.getFeedbackModelsAnalytics(params);
2285
+ const analytics = await service.analytics.getFeedbackModelsAnalytics(
2286
+ normalizeAnalyticsParams(params)
2287
+ );
2112
2288
  return {
2113
2289
  content: [
2114
2290
  {
@@ -2125,10 +2301,12 @@ function registerAnalyticsTools(server, service) {
2125
2301
  );
2126
2302
  server.tool(
2127
2303
  "get_feedback_scores_analytics",
2128
- "Retrieve feedback score distribution analytics over time",
2304
+ "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.",
2129
2305
  baseAnalyticsSchema,
2130
2306
  async (params) => {
2131
- const analytics = await service.analytics.getFeedbackScoresAnalytics(params);
2307
+ const analytics = await service.analytics.getFeedbackScoresAnalytics(
2308
+ normalizeAnalyticsParams(params)
2309
+ );
2132
2310
  return {
2133
2311
  content: [
2134
2312
  {
@@ -2145,10 +2323,12 @@ function registerAnalyticsTools(server, service) {
2145
2323
  );
2146
2324
  server.tool(
2147
2325
  "get_feedback_weighted_analytics",
2148
- "Retrieve weighted feedback analytics over time",
2326
+ "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.",
2149
2327
  baseAnalyticsSchema,
2150
2328
  async (params) => {
2151
- const analytics = await service.analytics.getFeedbackWeightedAnalytics(params);
2329
+ const analytics = await service.analytics.getFeedbackWeightedAnalytics(
2330
+ normalizeAnalyticsParams(params)
2331
+ );
2152
2332
  return {
2153
2333
  content: [
2154
2334
  {
@@ -2165,10 +2345,12 @@ function registerAnalyticsTools(server, service) {
2165
2345
  );
2166
2346
  server.tool(
2167
2347
  "get_analytics_group_users",
2168
- "Retrieve analytics data grouped by user with pagination",
2348
+ "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.",
2169
2349
  paginatedAnalyticsSchema,
2170
2350
  async (params) => {
2171
- const analytics = await service.analytics.getAnalyticsGroupUsers(params);
2351
+ const analytics = await service.analytics.getAnalyticsGroupUsers(
2352
+ normalizeAnalyticsParams(params)
2353
+ );
2172
2354
  return {
2173
2355
  content: [
2174
2356
  {
@@ -2185,10 +2367,12 @@ function registerAnalyticsTools(server, service) {
2185
2367
  );
2186
2368
  server.tool(
2187
2369
  "get_analytics_group_models",
2188
- "Retrieve analytics data grouped by AI model with pagination",
2370
+ "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.",
2189
2371
  paginatedAnalyticsSchema,
2190
2372
  async (params) => {
2191
- const analytics = await service.analytics.getAnalyticsGroupModels(params);
2373
+ const analytics = await service.analytics.getAnalyticsGroupModels(
2374
+ normalizeAnalyticsParams(params)
2375
+ );
2192
2376
  return {
2193
2377
  content: [
2194
2378
  {
@@ -2205,13 +2389,13 @@ function registerAnalyticsTools(server, service) {
2205
2389
  );
2206
2390
  server.tool(
2207
2391
  "get_analytics_group_metadata",
2208
- "Retrieve analytics data grouped by a specific metadata key with pagination",
2392
+ "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.",
2209
2393
  analyticsGroupMetadataSchema,
2210
2394
  async (params) => {
2211
2395
  const { metadata_key, ...analyticsParams } = params;
2212
2396
  const analytics = await service.analytics.getAnalyticsGroupMetadata(
2213
2397
  metadata_key,
2214
- analyticsParams
2398
+ normalizeAnalyticsParams(analyticsParams)
2215
2399
  );
2216
2400
  return {
2217
2401
  content: [
@@ -2255,7 +2439,7 @@ var AUDIT_TOOL_SCHEMAS = {
2255
2439
  function registerAuditTools(server, service) {
2256
2440
  server.tool(
2257
2441
  "list_audit_logs",
2258
- "Retrieve audit logs for your Portkey organization. Audit logs track all administrative actions including user management, configuration changes, and access events. Supports filtering by time range, actor, action type, and resource.",
2442
+ "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.",
2259
2443
  AUDIT_TOOL_SCHEMAS.listAuditLogs,
2260
2444
  async (params) => {
2261
2445
  const result = await service.audit.listAuditLogs({
@@ -2335,7 +2519,7 @@ var COLLECTIONS_TOOL_SCHEMAS = {
2335
2519
  function registerCollectionsTools(server, service) {
2336
2520
  server.tool(
2337
2521
  "list_collections",
2338
- "List all prompt collections in your Portkey organization. Collections group prompts by app (e.g., hourlink, apizone, research-pilot).",
2522
+ "List 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.",
2339
2523
  COLLECTIONS_TOOL_SCHEMAS.listCollections,
2340
2524
  async (params) => {
2341
2525
  const collections = await service.collections.listCollections(params);
@@ -2365,7 +2549,7 @@ function registerCollectionsTools(server, service) {
2365
2549
  );
2366
2550
  server.tool(
2367
2551
  "create_collection",
2368
- "Create a new prompt collection for organizing prompts by app. Use one collection per app (hourlink, apizone, research-pilot).",
2552
+ "Create a new prompt collection for organizing prompts by app. Use this when you need a new namespace before create_prompt; returns the collection id and slug, and does not move any prompts.",
2369
2553
  COLLECTIONS_TOOL_SCHEMAS.createCollection,
2370
2554
  async (params) => {
2371
2555
  const result = await service.collections.createCollection(params);
@@ -2389,7 +2573,7 @@ function registerCollectionsTools(server, service) {
2389
2573
  );
2390
2574
  server.tool(
2391
2575
  "get_collection",
2392
- "Retrieve detailed information about a specific collection",
2576
+ "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.",
2393
2577
  COLLECTIONS_TOOL_SCHEMAS.getCollection,
2394
2578
  async (params) => {
2395
2579
  const collection = await service.collections.getCollection(
@@ -2418,7 +2602,7 @@ function registerCollectionsTools(server, service) {
2418
2602
  );
2419
2603
  server.tool(
2420
2604
  "update_collection",
2421
- "Update a collection's name or description",
2605
+ "Update a collection's name or description only. This does not move prompts or change membership, so use it for metadata changes rather than reorganization.",
2422
2606
  COLLECTIONS_TOOL_SCHEMAS.updateCollection,
2423
2607
  async (params) => {
2424
2608
  await service.collections.updateCollection(params.collection_id, {
@@ -2444,7 +2628,7 @@ function registerCollectionsTools(server, service) {
2444
2628
  );
2445
2629
  server.tool(
2446
2630
  "delete_collection",
2447
- "Delete a collection by ID. This action cannot be undone. Prompts in this collection will become orphaned.",
2631
+ "Delete a prompt collection by ID. This cannot be undone; prompts stay in the workspace but lose their collection grouping, so reassign them first if organization matters.",
2448
2632
  COLLECTIONS_TOOL_SCHEMAS.deleteCollection,
2449
2633
  async (params) => {
2450
2634
  const result = await service.collections.deleteCollection(
@@ -2542,7 +2726,7 @@ function hasConfigSettings(config) {
2542
2726
  function registerConfigsTools(server, service) {
2543
2727
  server.tool(
2544
2728
  "list_configs",
2545
- "Retrieve all configurations in your Portkey organization, including their status and workspace associations",
2729
+ "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.",
2546
2730
  CONFIGS_TOOL_SCHEMAS.listConfigs,
2547
2731
  async () => {
2548
2732
  const configs = await service.configs.listConfigs();
@@ -2576,7 +2760,7 @@ function registerConfigsTools(server, service) {
2576
2760
  );
2577
2761
  server.tool(
2578
2762
  "get_config",
2579
- "Retrieve detailed information about a specific configuration, including cache settings, retry policies, and routing strategy",
2763
+ "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.",
2580
2764
  CONFIGS_TOOL_SCHEMAS.getConfig,
2581
2765
  async (params) => {
2582
2766
  const response = await service.configs.getConfig(params.slug);
@@ -2620,7 +2804,7 @@ function registerConfigsTools(server, service) {
2620
2804
  );
2621
2805
  server.tool(
2622
2806
  "create_config",
2623
- "Create a new configuration with cache, retry, and routing settings. At least one setting is required: cache (cache_mode/cache_max_age), retry (retry_attempts/retry_on_status_codes), strategy_mode, or targets.",
2807
+ "Create a 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.",
2624
2808
  CONFIGS_TOOL_SCHEMAS.createConfig,
2625
2809
  async (params) => {
2626
2810
  const config = buildConfigPayload(params);
@@ -2660,7 +2844,7 @@ function registerConfigsTools(server, service) {
2660
2844
  );
2661
2845
  server.tool(
2662
2846
  "update_config",
2663
- "Update an existing configuration's cache, retry, or routing settings",
2847
+ "Update 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.",
2664
2848
  CONFIGS_TOOL_SCHEMAS.updateConfig,
2665
2849
  async (params) => {
2666
2850
  const config = buildConfigPayload(params);
@@ -2695,7 +2879,7 @@ function registerConfigsTools(server, service) {
2695
2879
  );
2696
2880
  server.tool(
2697
2881
  "delete_config",
2698
- "Delete a configuration by slug. This action cannot be undone.",
2882
+ "Delete a config by slug. This is permanent, removes all versions, and breaks anything still pointing at that slug; check list_config_versions first.",
2699
2883
  CONFIGS_TOOL_SCHEMAS.deleteConfig,
2700
2884
  async (params) => {
2701
2885
  const result = await service.configs.deleteConfig(params.slug);
@@ -2718,7 +2902,7 @@ function registerConfigsTools(server, service) {
2718
2902
  );
2719
2903
  server.tool(
2720
2904
  "list_config_versions",
2721
- "List all versions of a configuration to view its change history",
2905
+ "List 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.",
2722
2906
  CONFIGS_TOOL_SCHEMAS.listConfigVersions,
2723
2907
  async (params) => {
2724
2908
  const result = await service.configs.listConfigVersions(params.slug);
@@ -2800,7 +2984,7 @@ var GUARDRAILS_TOOL_SCHEMAS = {
2800
2984
  function registerGuardrailsTools(server, service) {
2801
2985
  server.tool(
2802
2986
  "list_guardrails",
2803
- "List all guardrails in your Portkey organization with optional filtering by workspace or organization",
2987
+ "List 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.",
2804
2988
  GUARDRAILS_TOOL_SCHEMAS.listGuardrails,
2805
2989
  async (params) => {
2806
2990
  const result = await service.guardrails.listGuardrails(params);
@@ -2834,7 +3018,7 @@ function registerGuardrailsTools(server, service) {
2834
3018
  );
2835
3019
  server.tool(
2836
3020
  "get_guardrail",
2837
- "Retrieve detailed information about a specific guardrail, including its checks and actions configuration",
3021
+ "Fetch one guardrail with its full checks and actions. Use this before updating rules or when you need the exact enforcement policy.",
2838
3022
  GUARDRAILS_TOOL_SCHEMAS.getGuardrail,
2839
3023
  async (params) => {
2840
3024
  const guardrail = await service.guardrails.getGuardrail(
@@ -2869,7 +3053,7 @@ function registerGuardrailsTools(server, service) {
2869
3053
  );
2870
3054
  server.tool(
2871
3055
  "create_guardrail",
2872
- "Create a new guardrail with specified checks and actions for content moderation and security. checks is an array of check objects with id (e.g. 'default.jwt', 'default.pii'), optional name, is_enabled boolean, and parameters object.",
3056
+ "Create a 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.",
2873
3057
  GUARDRAILS_TOOL_SCHEMAS.createGuardrail,
2874
3058
  async (params) => {
2875
3059
  const result = await service.guardrails.createGuardrail({
@@ -2900,7 +3084,7 @@ function registerGuardrailsTools(server, service) {
2900
3084
  );
2901
3085
  server.tool(
2902
3086
  "update_guardrail",
2903
- "Update an existing guardrail's name, checks, or actions configuration",
3087
+ "Update a guardrail's name, checks, or actions. This creates a new version, so configs keep pointing at the latest policy after the change.",
2904
3088
  GUARDRAILS_TOOL_SCHEMAS.updateGuardrail,
2905
3089
  async (params) => {
2906
3090
  const updateData = {};
@@ -2938,7 +3122,7 @@ function registerGuardrailsTools(server, service) {
2938
3122
  );
2939
3123
  server.tool(
2940
3124
  "delete_guardrail",
2941
- "Delete a guardrail by its ID or slug. This action cannot be undone.",
3125
+ "Delete a guardrail by id or slug. This is irreversible and removes the check from any configs that reference it, so review dependent configs first.",
2942
3126
  GUARDRAILS_TOOL_SCHEMAS.deleteGuardrail,
2943
3127
  async (params) => {
2944
3128
  const result = await service.guardrails.deleteGuardrail(
@@ -3101,7 +3285,7 @@ var INTEGRATIONS_TOOL_SCHEMAS = {
3101
3285
  function registerIntegrationsTools(server, service) {
3102
3286
  server.tool(
3103
3287
  "list_integrations",
3104
- "List all integrations in your Portkey organization with optional filtering by workspace or type",
3288
+ "List org-level 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.",
3105
3289
  INTEGRATIONS_TOOL_SCHEMAS.listIntegrations,
3106
3290
  async (params) => {
3107
3291
  const integrations = await service.integrations.listIntegrations({
@@ -3139,7 +3323,7 @@ function registerIntegrationsTools(server, service) {
3139
3323
  );
3140
3324
  server.tool(
3141
3325
  "create_integration",
3142
- "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.",
3326
+ "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.",
3143
3327
  INTEGRATIONS_TOOL_SCHEMAS.createIntegration,
3144
3328
  async (params) => {
3145
3329
  const configurations = {};
@@ -3187,7 +3371,7 @@ function registerIntegrationsTools(server, service) {
3187
3371
  );
3188
3372
  server.tool(
3189
3373
  "get_integration",
3190
- "Retrieve detailed information about a specific integration by its slug",
3374
+ "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.",
3191
3375
  INTEGRATIONS_TOOL_SCHEMAS.getIntegration,
3192
3376
  async (params) => {
3193
3377
  const integration = await service.integrations.getIntegration(
@@ -3224,7 +3408,7 @@ function registerIntegrationsTools(server, service) {
3224
3408
  );
3225
3409
  server.tool(
3226
3410
  "update_integration",
3227
- "Update an existing integration's name, API key, description, or provider-specific configurations",
3411
+ "Update an integration's name, key, or provider-specific config. Key and config changes take effect immediately and can disrupt dependent providers or live requests.",
3228
3412
  INTEGRATIONS_TOOL_SCHEMAS.updateIntegration,
3229
3413
  async (params) => {
3230
3414
  const configurations = {};
@@ -3271,7 +3455,7 @@ function registerIntegrationsTools(server, service) {
3271
3455
  );
3272
3456
  server.tool(
3273
3457
  "delete_integration",
3274
- "Delete an integration by slug. This action cannot be undone.",
3458
+ "Delete an integration by slug. This is irreversible and stops the org-level connection, which will break dependent virtual keys, providers, and workspace access.",
3275
3459
  INTEGRATIONS_TOOL_SCHEMAS.deleteIntegration,
3276
3460
  async (params) => {
3277
3461
  const result = await service.integrations.deleteIntegration(params.slug);
@@ -3294,7 +3478,7 @@ function registerIntegrationsTools(server, service) {
3294
3478
  );
3295
3479
  server.tool(
3296
3480
  "list_integration_models",
3297
- "List all models available for a specific integration with their enabled status",
3481
+ "List 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.",
3298
3482
  INTEGRATIONS_TOOL_SCHEMAS.listIntegrationModels,
3299
3483
  async (params) => {
3300
3484
  const models = await service.integrations.listIntegrationModels(
@@ -3332,7 +3516,7 @@ function registerIntegrationsTools(server, service) {
3332
3516
  );
3333
3517
  server.tool(
3334
3518
  "update_integration_models",
3335
- "Update model access settings for an integration - enable/disable models or add custom models",
3519
+ "Enable, disable, 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.",
3336
3520
  INTEGRATIONS_TOOL_SCHEMAS.updateIntegrationModels,
3337
3521
  async (params) => {
3338
3522
  const result = await service.integrations.updateIntegrationModels(
@@ -3361,7 +3545,7 @@ function registerIntegrationsTools(server, service) {
3361
3545
  );
3362
3546
  server.tool(
3363
3547
  "delete_integration_model",
3364
- "Delete a specific custom model from an integration",
3548
+ "Delete a 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.",
3365
3549
  INTEGRATIONS_TOOL_SCHEMAS.deleteIntegrationModel,
3366
3550
  async (params) => {
3367
3551
  const result = await service.integrations.deleteIntegrationModel(
@@ -3387,7 +3571,7 @@ function registerIntegrationsTools(server, service) {
3387
3571
  );
3388
3572
  server.tool(
3389
3573
  "list_integration_workspaces",
3390
- "List all workspaces that have access to a specific integration",
3574
+ "List 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.",
3391
3575
  INTEGRATIONS_TOOL_SCHEMAS.listIntegrationWorkspaces,
3392
3576
  async (params) => {
3393
3577
  const workspaces = await service.integrations.listIntegrationWorkspaces(
@@ -3426,7 +3610,7 @@ function registerIntegrationsTools(server, service) {
3426
3610
  );
3427
3611
  server.tool(
3428
3612
  "update_integration_workspaces",
3429
- "Update workspace access settings for an integration - enable/disable workspace access and configure limits",
3613
+ "Control which workspaces can use an integration and set per-workspace limits. Access changes and new limits apply to downstream usage immediately. Returns success and the number of workspaces updated.",
3430
3614
  INTEGRATIONS_TOOL_SCHEMAS.updateIntegrationWorkspaces,
3431
3615
  async (params) => {
3432
3616
  const result = await service.integrations.updateIntegrationWorkspaces(
@@ -3554,7 +3738,7 @@ var KEYS_TOOL_SCHEMAS = {
3554
3738
  function registerKeysTools(server, service) {
3555
3739
  server.tool(
3556
3740
  "list_virtual_keys",
3557
- "Retrieve all virtual keys in your Portkey organization, including their usage limits, rate limits, and status",
3741
+ "List 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.",
3558
3742
  KEYS_TOOL_SCHEMAS.listVirtualKeys,
3559
3743
  async () => {
3560
3744
  const virtualKeys = await service.keys.listVirtualKeys();
@@ -3595,7 +3779,7 @@ function registerKeysTools(server, service) {
3595
3779
  );
3596
3780
  server.tool(
3597
3781
  "create_virtual_key",
3598
- "Create a new virtual key for a provider (e.g., openai, anthropic). Virtual keys securely store provider API keys.",
3782
+ "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.",
3599
3783
  KEYS_TOOL_SCHEMAS.createVirtualKey,
3600
3784
  async (params) => {
3601
3785
  const result = await service.keys.createVirtualKey({
@@ -3634,7 +3818,7 @@ function registerKeysTools(server, service) {
3634
3818
  );
3635
3819
  server.tool(
3636
3820
  "get_virtual_key",
3637
- "Retrieve detailed information about a specific virtual key by its slug",
3821
+ "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.",
3638
3822
  KEYS_TOOL_SCHEMAS.getVirtualKey,
3639
3823
  async (params) => {
3640
3824
  const virtualKey = await service.keys.getVirtualKey(params.slug);
@@ -3672,7 +3856,7 @@ function registerKeysTools(server, service) {
3672
3856
  );
3673
3857
  server.tool(
3674
3858
  "update_virtual_key",
3675
- "Update an existing virtual key's name, API key, note, or limits",
3859
+ "Update 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.",
3676
3860
  KEYS_TOOL_SCHEMAS.updateVirtualKey,
3677
3861
  async (params) => {
3678
3862
  const result = await service.keys.updateVirtualKey(params.slug, {
@@ -3706,7 +3890,7 @@ function registerKeysTools(server, service) {
3706
3890
  );
3707
3891
  server.tool(
3708
3892
  "delete_virtual_key",
3709
- "Delete a virtual key by slug. This action cannot be undone.",
3893
+ "Delete a virtual key by slug. This is irreversible and will break prompts and configs that reference the slug, so confirm no active dependencies first. Returns success after removal.",
3710
3894
  KEYS_TOOL_SCHEMAS.deleteVirtualKey,
3711
3895
  async (params) => {
3712
3896
  const result = await service.keys.deleteVirtualKey(params.slug);
@@ -3729,7 +3913,7 @@ function registerKeysTools(server, service) {
3729
3913
  );
3730
3914
  server.tool(
3731
3915
  "create_api_key",
3732
- "Create a new Portkey API key for authentication. Organisation-level keys provide full access, workspace keys are scoped. Scopes control read/write permissions to specific resources (logs, analytics, prompts, etc.).",
3916
+ "Create a 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.",
3733
3917
  KEYS_TOOL_SCHEMAS.createApiKey,
3734
3918
  async (params) => {
3735
3919
  if (params.type === "workspace" && !params.workspace_id) {
@@ -3800,7 +3984,7 @@ function registerKeysTools(server, service) {
3800
3984
  );
3801
3985
  server.tool(
3802
3986
  "list_api_keys",
3803
- "List all API keys in your Portkey organization with optional pagination and workspace filtering",
3987
+ "List Portkey API keys 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.",
3804
3988
  KEYS_TOOL_SCHEMAS.listApiKeys,
3805
3989
  async (params) => {
3806
3990
  const apiKeys = await service.keys.listApiKeys({
@@ -3853,7 +4037,7 @@ function registerKeysTools(server, service) {
3853
4037
  );
3854
4038
  server.tool(
3855
4039
  "get_api_key",
3856
- "Retrieve detailed information about a specific API key by its UUID",
4040
+ "Fetch one API key by UUID without revealing the secret. Use this to inspect scopes, defaults, limits, expiration, and reset state before changing access.",
3857
4041
  KEYS_TOOL_SCHEMAS.getApiKey,
3858
4042
  async (params) => {
3859
4043
  const apiKey = await service.keys.getApiKey(params.id);
@@ -3900,7 +4084,7 @@ function registerKeysTools(server, service) {
3900
4084
  );
3901
4085
  server.tool(
3902
4086
  "update_api_key",
3903
- "Update an existing API key's name, description, scopes, or limits",
4087
+ "Update an 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.",
3904
4088
  KEYS_TOOL_SCHEMAS.updateApiKey,
3905
4089
  async (params) => {
3906
4090
  const result = await service.keys.updateApiKey(params.id, {
@@ -3938,7 +4122,7 @@ function registerKeysTools(server, service) {
3938
4122
  );
3939
4123
  server.tool(
3940
4124
  "delete_api_key",
3941
- "Delete an API key by UUID. This action cannot be undone.",
4125
+ "Delete an API key by UUID. This cannot be undone, revokes access immediately, and can break active sessions using the key. Returns success after revocation.",
3942
4126
  KEYS_TOOL_SCHEMAS.deleteApiKey,
3943
4127
  async (params) => {
3944
4128
  const result = await service.keys.deleteApiKey(params.id);
@@ -3998,7 +4182,7 @@ var LABELS_TOOL_SCHEMAS = {
3998
4182
  function registerLabelsTools(server, service) {
3999
4183
  server.tool(
4000
4184
  "create_prompt_label",
4001
- "Create a new prompt label to categorize and organize prompts. Labels can be color-coded and scoped to workspaces or organizations.",
4185
+ "Create a 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.",
4002
4186
  LABELS_TOOL_SCHEMAS.createPromptLabel,
4003
4187
  async (params) => {
4004
4188
  if (!params.organisation_id && !params.workspace_id) {
@@ -4038,7 +4222,7 @@ function registerLabelsTools(server, service) {
4038
4222
  );
4039
4223
  server.tool(
4040
4224
  "list_prompt_labels",
4041
- "List all prompt labels in your Portkey organization with optional filtering by workspace, organisation, or search query",
4225
+ "List 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.",
4042
4226
  LABELS_TOOL_SCHEMAS.listPromptLabels,
4043
4227
  async (params) => {
4044
4228
  const result = await service.labels.listLabels(params);
@@ -4070,7 +4254,7 @@ function registerLabelsTools(server, service) {
4070
4254
  );
4071
4255
  server.tool(
4072
4256
  "get_prompt_label",
4073
- "Retrieve detailed information about a specific prompt label",
4257
+ "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.",
4074
4258
  LABELS_TOOL_SCHEMAS.getPromptLabel,
4075
4259
  async (params) => {
4076
4260
  const label = await service.labels.getLabel(params.label_id, {
@@ -4104,7 +4288,7 @@ function registerLabelsTools(server, service) {
4104
4288
  );
4105
4289
  server.tool(
4106
4290
  "update_prompt_label",
4107
- "Update an existing prompt label's name, description, or color",
4291
+ "Update a prompt label's name, description, or color only. This changes the label definition, not existing prompt-version assignments or history.",
4108
4292
  LABELS_TOOL_SCHEMAS.updatePromptLabel,
4109
4293
  async (params) => {
4110
4294
  const { label_id, ...updateData } = params;
@@ -4128,7 +4312,7 @@ function registerLabelsTools(server, service) {
4128
4312
  );
4129
4313
  server.tool(
4130
4314
  "delete_prompt_label",
4131
- "Delete a prompt label by ID. This action cannot be undone.",
4315
+ "Delete a prompt label by ID. This cannot be undone; versions carrying the label lose it, and any workflow resolving by that label will need a replacement.",
4132
4316
  LABELS_TOOL_SCHEMAS.deletePromptLabel,
4133
4317
  async (params) => {
4134
4318
  await service.labels.deleteLabel(params.label_id);
@@ -4280,7 +4464,7 @@ function formatUsageLimitEntity(entity) {
4280
4464
  function registerLimitsTools(server, service) {
4281
4465
  server.tool(
4282
4466
  "list_rate_limits",
4283
- "Retrieve all rate limits in your Portkey organization. Rate limits control how many requests or tokens can be consumed per time unit (rpm/rph/rpd).",
4467
+ "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.",
4284
4468
  LIMITS_TOOL_SCHEMAS.listRateLimits,
4285
4469
  async (params) => {
4286
4470
  const result = await service.limits.listRateLimits(params.workspace_id);
@@ -4303,7 +4487,7 @@ function registerLimitsTools(server, service) {
4303
4487
  );
4304
4488
  server.tool(
4305
4489
  "get_rate_limit",
4306
- "Retrieve detailed information about a specific rate limit by its ID",
4490
+ "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.",
4307
4491
  LIMITS_TOOL_SCHEMAS.getRateLimit,
4308
4492
  async (params) => {
4309
4493
  const result = await service.limits.getRateLimit(params.id);
@@ -4319,7 +4503,7 @@ function registerLimitsTools(server, service) {
4319
4503
  );
4320
4504
  server.tool(
4321
4505
  "create_rate_limit",
4322
- "Create a new rate limit policy to control request/token consumption per time unit. Requires conditions to match against and group_by to specify how limits are applied.",
4506
+ "Create a 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.",
4323
4507
  LIMITS_TOOL_SCHEMAS.createRateLimit,
4324
4508
  async (params) => {
4325
4509
  const result = await service.limits.createRateLimit({
@@ -4351,7 +4535,7 @@ function registerLimitsTools(server, service) {
4351
4535
  );
4352
4536
  server.tool(
4353
4537
  "update_rate_limit",
4354
- "Update an existing rate limit's name, unit, or value",
4538
+ "Update 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.",
4355
4539
  LIMITS_TOOL_SCHEMAS.updateRateLimit,
4356
4540
  async (params) => {
4357
4541
  const result = await service.limits.updateRateLimit(params.id, {
@@ -4378,7 +4562,7 @@ function registerLimitsTools(server, service) {
4378
4562
  );
4379
4563
  server.tool(
4380
4564
  "delete_rate_limit",
4381
- "Delete a rate limit by ID. This action cannot be undone.",
4565
+ "Delete a rate limit by id. This is permanent and removes throttling immediately; review dependent configs and virtual keys before deleting.",
4382
4566
  LIMITS_TOOL_SCHEMAS.deleteRateLimit,
4383
4567
  async (params) => {
4384
4568
  await service.limits.deleteRateLimit(params.id);
@@ -4401,7 +4585,7 @@ function registerLimitsTools(server, service) {
4401
4585
  );
4402
4586
  server.tool(
4403
4587
  "list_usage_limits",
4404
- "Retrieve all usage limits in your Portkey organization. Usage limits control how much cost or tokens can be consumed, with optional periodic resets.",
4588
+ "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.",
4405
4589
  LIMITS_TOOL_SCHEMAS.listUsageLimits,
4406
4590
  async (params) => {
4407
4591
  const result = await service.limits.listUsageLimits(params.workspace_id);
@@ -4424,7 +4608,7 @@ function registerLimitsTools(server, service) {
4424
4608
  );
4425
4609
  server.tool(
4426
4610
  "get_usage_limit",
4427
- "Retrieve detailed information about a specific usage limit by its ID",
4611
+ "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.",
4428
4612
  LIMITS_TOOL_SCHEMAS.getUsageLimit,
4429
4613
  async (params) => {
4430
4614
  const result = await service.limits.getUsageLimit(params.id);
@@ -4440,7 +4624,7 @@ function registerLimitsTools(server, service) {
4440
4624
  );
4441
4625
  server.tool(
4442
4626
  "create_usage_limit",
4443
- "Create a new usage limit policy to control cost or token consumption. Requires conditions to match against and group_by to specify how limits are applied.",
4627
+ "Create a 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.",
4444
4628
  LIMITS_TOOL_SCHEMAS.createUsageLimit,
4445
4629
  async (params) => {
4446
4630
  const result = await service.limits.createUsageLimit({
@@ -4473,7 +4657,7 @@ function registerLimitsTools(server, service) {
4473
4657
  );
4474
4658
  server.tool(
4475
4659
  "update_usage_limit",
4476
- "Update an existing usage limit's configuration",
4660
+ "Update a usage limit's name, credit_limit, alert_threshold, reset schedule, or reset target by id. Conditions and group_by are immutable after creation.",
4477
4661
  LIMITS_TOOL_SCHEMAS.updateUsageLimit,
4478
4662
  async (params) => {
4479
4663
  const result = await service.limits.updateUsageLimit(params.id, {
@@ -4502,7 +4686,7 @@ function registerLimitsTools(server, service) {
4502
4686
  );
4503
4687
  server.tool(
4504
4688
  "delete_usage_limit",
4505
- "Delete a usage limit by ID. This action cannot be undone.",
4689
+ "Delete a usage limit by id. This is permanent, removes the budget immediately, and clears tracked usage state; check list_usage_limit_entities first if you need impact.",
4506
4690
  LIMITS_TOOL_SCHEMAS.deleteUsageLimit,
4507
4691
  async (params) => {
4508
4692
  await service.limits.deleteUsageLimit(params.id);
@@ -4525,7 +4709,7 @@ function registerLimitsTools(server, service) {
4525
4709
  );
4526
4710
  server.tool(
4527
4711
  "list_usage_limit_entities",
4528
- "List all entities tracked against a usage limit policy, showing current usage per entity",
4712
+ "List 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.",
4529
4713
  LIMITS_TOOL_SCHEMAS.listUsageLimitEntities,
4530
4714
  async (params) => {
4531
4715
  const result = await service.limits.listUsageLimitEntities(
@@ -4550,7 +4734,7 @@ function registerLimitsTools(server, service) {
4550
4734
  );
4551
4735
  server.tool(
4552
4736
  "reset_usage_limit_entity",
4553
- "Reset accumulated usage for a specific entity on a usage limit policy",
4737
+ "Reset 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.",
4554
4738
  LIMITS_TOOL_SCHEMAS.resetUsageLimitEntity,
4555
4739
  async (params) => {
4556
4740
  await service.limits.resetUsageLimitEntity(
@@ -4667,7 +4851,7 @@ var LOGGING_TOOL_SCHEMAS = {
4667
4851
  function registerLoggingTools(server, service) {
4668
4852
  server.tool(
4669
4853
  "insert_log",
4670
- "Insert a log entry (or multiple entries) into Portkey for tracking AI requests and responses. request_provider must match a configured integration (e.g. 'openai', 'anthropic'). Use metadata_span_id and metadata_parent_span_id to create trace hierarchies.",
4854
+ "Insert 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.",
4671
4855
  LOGGING_TOOL_SCHEMAS.insertLog,
4672
4856
  async (params) => {
4673
4857
  const entry = {
@@ -4715,7 +4899,7 @@ function registerLoggingTools(server, service) {
4715
4899
  );
4716
4900
  server.tool(
4717
4901
  "create_log_export",
4718
- "Create a new log export job to export logs matching specified filters. time_min/time_max accept ISO 8601 format ('2024-01-01T00:00:00Z'). requested_fields selects which columns to include.",
4902
+ "Create a 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.",
4719
4903
  LOGGING_TOOL_SCHEMAS.createLogExport,
4720
4904
  async (params) => {
4721
4905
  const result = await service.logging.createLogExport({
@@ -4753,7 +4937,7 @@ function registerLoggingTools(server, service) {
4753
4937
  );
4754
4938
  server.tool(
4755
4939
  "list_log_exports",
4756
- "List all log export jobs for a workspace",
4940
+ "List 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.",
4757
4941
  LOGGING_TOOL_SCHEMAS.listLogExports,
4758
4942
  async (params) => {
4759
4943
  const result = await service.logging.listLogExports({
@@ -4788,7 +4972,7 @@ function registerLoggingTools(server, service) {
4788
4972
  );
4789
4973
  server.tool(
4790
4974
  "get_log_export",
4791
- "Get details of a specific log export by its ID",
4975
+ "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.",
4792
4976
  LOGGING_TOOL_SCHEMAS.getLogExport,
4793
4977
  async (params) => {
4794
4978
  const result = await service.logging.getLogExport(params.export_id);
@@ -4819,7 +5003,7 @@ function registerLoggingTools(server, service) {
4819
5003
  );
4820
5004
  server.tool(
4821
5005
  "start_log_export",
4822
- "Start a log export job that was previously created",
5006
+ "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.",
4823
5007
  LOGGING_TOOL_SCHEMAS.startLogExport,
4824
5008
  async (params) => {
4825
5009
  const result = await service.logging.startLogExport(params.export_id);
@@ -4843,7 +5027,7 @@ function registerLoggingTools(server, service) {
4843
5027
  );
4844
5028
  server.tool(
4845
5029
  "cancel_log_export",
4846
- "Cancel a running log export job",
5030
+ "Cancel a pending or running log export job. This permanently stops that export, so create a new log export if you need the same data again.",
4847
5031
  LOGGING_TOOL_SCHEMAS.cancelLogExport,
4848
5032
  async (params) => {
4849
5033
  const result = await service.logging.cancelLogExport(params.export_id);
@@ -4867,7 +5051,7 @@ function registerLoggingTools(server, service) {
4867
5051
  );
4868
5052
  server.tool(
4869
5053
  "download_log_export",
4870
- "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.",
5054
+ "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.",
4871
5055
  LOGGING_TOOL_SCHEMAS.downloadLogExport,
4872
5056
  async (params) => {
4873
5057
  const result = await service.logging.downloadLogExport(params.export_id);
@@ -4891,7 +5075,7 @@ function registerLoggingTools(server, service) {
4891
5075
  );
4892
5076
  server.tool(
4893
5077
  "update_log_export",
4894
- "Update an existing log export configuration. Only time_of_generation_max, requested_fields, and workspace_id can be modified after creation.",
5078
+ "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.",
4895
5079
  LOGGING_TOOL_SCHEMAS.updateLogExport,
4896
5080
  async (params) => {
4897
5081
  const updateData = {};
@@ -5058,7 +5242,7 @@ function formatMcpIntegrationWorkspace(workspace) {
5058
5242
  function registerMcpIntegrationsTools(server, service) {
5059
5243
  server.tool(
5060
5244
  "list_mcp_integrations",
5061
- "List all MCP integrations in your Portkey organization with optional pagination and workspace filtering",
5245
+ "List 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.",
5062
5246
  MCP_INTEGRATIONS_TOOL_SCHEMAS.listMcpIntegrations,
5063
5247
  async (params) => {
5064
5248
  const result = await service.mcpIntegrations.listMcpIntegrations(params);
@@ -5082,7 +5266,7 @@ function registerMcpIntegrationsTools(server, service) {
5082
5266
  );
5083
5267
  server.tool(
5084
5268
  "create_mcp_integration",
5085
- "Create a new MCP integration in Portkey for connecting external MCP servers to your organization",
5269
+ "Create 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.",
5086
5270
  MCP_INTEGRATIONS_TOOL_SCHEMAS.createMcpIntegration,
5087
5271
  async (params) => {
5088
5272
  if (params.auth_type === "headers" && (!params.custom_headers || Object.keys(params.custom_headers).length === 0)) {
@@ -5121,7 +5305,7 @@ function registerMcpIntegrationsTools(server, service) {
5121
5305
  );
5122
5306
  server.tool(
5123
5307
  "get_mcp_integration",
5124
- "Retrieve detailed information about a specific MCP integration by ID or slug",
5308
+ "Retrieve 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.",
5125
5309
  MCP_INTEGRATIONS_TOOL_SCHEMAS.getMcpIntegration,
5126
5310
  async (params) => {
5127
5311
  const integration = await service.mcpIntegrations.getMcpIntegration(
@@ -5139,7 +5323,7 @@ function registerMcpIntegrationsTools(server, service) {
5139
5323
  );
5140
5324
  server.tool(
5141
5325
  "update_mcp_integration",
5142
- "Update an existing MCP integration's name, description, URL, auth, or transport",
5326
+ "Update an 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.",
5143
5327
  MCP_INTEGRATIONS_TOOL_SCHEMAS.updateMcpIntegration,
5144
5328
  async (params) => {
5145
5329
  const { id, custom_headers, ...rest } = params;
@@ -5166,7 +5350,7 @@ function registerMcpIntegrationsTools(server, service) {
5166
5350
  );
5167
5351
  server.tool(
5168
5352
  "delete_mcp_integration",
5169
- "Delete an MCP integration. This action cannot be undone.",
5353
+ "Delete an MCP integration and all servers beneath it. This is irreversible, removes connected access immediately, and should only be used after confirming nothing depends on the integration.",
5170
5354
  MCP_INTEGRATIONS_TOOL_SCHEMAS.deleteMcpIntegration,
5171
5355
  async (params) => {
5172
5356
  await service.mcpIntegrations.deleteMcpIntegration(params.id);
@@ -5189,7 +5373,7 @@ function registerMcpIntegrationsTools(server, service) {
5189
5373
  );
5190
5374
  server.tool(
5191
5375
  "get_mcp_integration_metadata",
5192
- "Retrieve metadata for a specific MCP integration",
5376
+ "Retrieve 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.",
5193
5377
  MCP_INTEGRATIONS_TOOL_SCHEMAS.getMcpIntegrationMetadata,
5194
5378
  async (params) => {
5195
5379
  const metadata = await service.mcpIntegrations.getMcpIntegrationMetadata(
@@ -5211,7 +5395,7 @@ function registerMcpIntegrationsTools(server, service) {
5211
5395
  );
5212
5396
  server.tool(
5213
5397
  "list_mcp_integration_capabilities",
5214
- "List all capabilities (tools, resources, prompts) available on an MCP integration",
5398
+ "List 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.",
5215
5399
  MCP_INTEGRATIONS_TOOL_SCHEMAS.listMcpIntegrationCapabilities,
5216
5400
  async (params) => {
5217
5401
  const result = await service.mcpIntegrations.listMcpIntegrationCapabilities(params.id);
@@ -5231,7 +5415,7 @@ function registerMcpIntegrationsTools(server, service) {
5231
5415
  );
5232
5416
  server.tool(
5233
5417
  "update_mcp_integration_capabilities",
5234
- "Bulk enable or disable capabilities on an MCP integration",
5418
+ "Bulk enable or disable capabilities on an MCP integration. 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.",
5235
5419
  MCP_INTEGRATIONS_TOOL_SCHEMAS.updateMcpIntegrationCapabilities,
5236
5420
  async (params) => {
5237
5421
  await service.mcpIntegrations.updateMcpIntegrationCapabilities(
@@ -5259,7 +5443,7 @@ function registerMcpIntegrationsTools(server, service) {
5259
5443
  );
5260
5444
  server.tool(
5261
5445
  "list_mcp_integration_workspaces",
5262
- "List workspace access settings for an MCP integration",
5446
+ "List which workspaces 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.",
5263
5447
  MCP_INTEGRATIONS_TOOL_SCHEMAS.listMcpIntegrationWorkspaces,
5264
5448
  async (params) => {
5265
5449
  const result = await service.mcpIntegrations.listMcpIntegrationWorkspaces(
@@ -5287,7 +5471,7 @@ function registerMcpIntegrationsTools(server, service) {
5287
5471
  );
5288
5472
  server.tool(
5289
5473
  "update_mcp_integration_workspaces",
5290
- "Bulk update workspace access for an MCP integration",
5474
+ "Grant or revoke workspace access to an MCP integration in bulk. Changes take effect immediately for all users in the selected workspaces; use list_mcp_integration_workspaces first to review the current access state.",
5291
5475
  MCP_INTEGRATIONS_TOOL_SCHEMAS.updateMcpIntegrationWorkspaces,
5292
5476
  async (params) => {
5293
5477
  await service.mcpIntegrations.updateMcpIntegrationWorkspaces(params.id, {
@@ -5402,7 +5586,7 @@ function formatMcpServerUserAccess(user) {
5402
5586
  function registerMcpServersTools(server, service) {
5403
5587
  server.tool(
5404
5588
  "list_mcp_servers",
5405
- "List all MCP servers in your Portkey organization with optional pagination and workspace filtering",
5589
+ "List 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.",
5406
5590
  MCP_SERVERS_TOOL_SCHEMAS.listMcpServers,
5407
5591
  async (params) => {
5408
5592
  const result = await service.mcpServers.listMcpServers(params);
@@ -5425,7 +5609,7 @@ function registerMcpServersTools(server, service) {
5425
5609
  );
5426
5610
  server.tool(
5427
5611
  "create_mcp_server",
5428
- "Register a new MCP server under an existing MCP integration",
5612
+ "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.",
5429
5613
  MCP_SERVERS_TOOL_SCHEMAS.createMcpServer,
5430
5614
  async (params) => {
5431
5615
  const result = await service.mcpServers.createMcpServer(params);
@@ -5449,7 +5633,7 @@ function registerMcpServersTools(server, service) {
5449
5633
  );
5450
5634
  server.tool(
5451
5635
  "get_mcp_server",
5452
- "Retrieve detailed information about a specific MCP server by ID or slug",
5636
+ "Retrieve 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.",
5453
5637
  MCP_SERVERS_TOOL_SCHEMAS.getMcpServer,
5454
5638
  async (params) => {
5455
5639
  const mcpServer = await service.mcpServers.getMcpServer(params.id);
@@ -5465,7 +5649,7 @@ function registerMcpServersTools(server, service) {
5465
5649
  );
5466
5650
  server.tool(
5467
5651
  "update_mcp_server",
5468
- "Update an existing MCP server's name or description",
5652
+ "Update an 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.",
5469
5653
  MCP_SERVERS_TOOL_SCHEMAS.updateMcpServer,
5470
5654
  async (params) => {
5471
5655
  const { id, ...data } = params;
@@ -5489,7 +5673,7 @@ function registerMcpServersTools(server, service) {
5489
5673
  );
5490
5674
  server.tool(
5491
5675
  "delete_mcp_server",
5492
- "Delete an MCP server. This action cannot be undone.",
5676
+ "Delete an MCP server instance. This is irreversible, removes connected users' access immediately, and should be used only after confirming no workflows depend on the server.",
5493
5677
  MCP_SERVERS_TOOL_SCHEMAS.deleteMcpServer,
5494
5678
  async (params) => {
5495
5679
  await service.mcpServers.deleteMcpServer(params.id);
@@ -5512,7 +5696,7 @@ function registerMcpServersTools(server, service) {
5512
5696
  );
5513
5697
  server.tool(
5514
5698
  "test_mcp_server",
5515
- "Test connectivity to an MCP server to verify it is reachable and responding",
5699
+ "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.",
5516
5700
  MCP_SERVERS_TOOL_SCHEMAS.testMcpServer,
5517
5701
  async (params) => {
5518
5702
  const result = await service.mcpServers.testMcpServer(params.id);
@@ -5528,7 +5712,7 @@ function registerMcpServersTools(server, service) {
5528
5712
  );
5529
5713
  server.tool(
5530
5714
  "list_mcp_server_capabilities",
5531
- "List all capabilities (tools, resources, prompts) exposed by an MCP server",
5715
+ "List 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.",
5532
5716
  MCP_SERVERS_TOOL_SCHEMAS.listMcpServerCapabilities,
5533
5717
  async (params) => {
5534
5718
  const result = await service.mcpServers.listMcpServerCapabilities(
@@ -5550,7 +5734,7 @@ function registerMcpServersTools(server, service) {
5550
5734
  );
5551
5735
  server.tool(
5552
5736
  "update_mcp_server_capabilities",
5553
- "Bulk enable or disable capabilities on an MCP server",
5737
+ "Enable or disable 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.",
5554
5738
  MCP_SERVERS_TOOL_SCHEMAS.updateMcpServerCapabilities,
5555
5739
  async (params) => {
5556
5740
  await service.mcpServers.updateMcpServerCapabilities(params.id, {
@@ -5575,7 +5759,7 @@ function registerMcpServersTools(server, service) {
5575
5759
  );
5576
5760
  server.tool(
5577
5761
  "list_mcp_server_user_access",
5578
- "List user access settings for an MCP server",
5762
+ "List per-user access 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.",
5579
5763
  MCP_SERVERS_TOOL_SCHEMAS.listMcpServerUserAccess,
5580
5764
  async (params) => {
5581
5765
  const result = await service.mcpServers.listMcpServerUserAccess(
@@ -5601,7 +5785,7 @@ function registerMcpServersTools(server, service) {
5601
5785
  );
5602
5786
  server.tool(
5603
5787
  "update_mcp_server_user_access",
5604
- "Bulk update user access for an MCP server",
5788
+ "Grant or revoke individual user access to an MCP server. 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.",
5605
5789
  MCP_SERVERS_TOOL_SCHEMAS.updateMcpServerUserAccess,
5606
5790
  async (params) => {
5607
5791
  await service.mcpServers.updateMcpServerUserAccess(params.id, {
@@ -5666,7 +5850,7 @@ var PARTIALS_TOOL_SCHEMAS = {
5666
5850
  function registerPartialsTools(server, service) {
5667
5851
  server.tool(
5668
5852
  "create_prompt_partial",
5669
- "Create a new prompt partial (reusable text snippet) that can be included in prompts using mustache syntax like {{> partial_name}}",
5853
+ "Create a 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.",
5670
5854
  PARTIALS_TOOL_SCHEMAS.createPromptPartial,
5671
5855
  async (params) => {
5672
5856
  const result = await service.partials.createPromptPartial({
@@ -5696,7 +5880,7 @@ function registerPartialsTools(server, service) {
5696
5880
  );
5697
5881
  server.tool(
5698
5882
  "list_prompt_partials",
5699
- "List all prompt partials in your Portkey organization with optional filtering by collection",
5883
+ "List 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.",
5700
5884
  PARTIALS_TOOL_SCHEMAS.listPromptPartials,
5701
5885
  async (params) => {
5702
5886
  const partials = await service.partials.listPromptPartials(params);
@@ -5727,7 +5911,7 @@ function registerPartialsTools(server, service) {
5727
5911
  );
5728
5912
  server.tool(
5729
5913
  "get_prompt_partial",
5730
- "Retrieve detailed information about a specific prompt partial including its content and version info",
5914
+ "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.",
5731
5915
  PARTIALS_TOOL_SCHEMAS.getPromptPartial,
5732
5916
  async (params) => {
5733
5917
  const partial = await service.partials.getPromptPartial(
@@ -5761,7 +5945,7 @@ function registerPartialsTools(server, service) {
5761
5945
  );
5762
5946
  server.tool(
5763
5947
  "update_prompt_partial",
5764
- "Update an existing prompt partial. A new version is created in archived status \u2014 use publish_partial to make it active.",
5948
+ "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.",
5765
5949
  PARTIALS_TOOL_SCHEMAS.updatePromptPartial,
5766
5950
  async (params) => {
5767
5951
  const { prompt_partial_id, ...updateData } = params;
@@ -5788,7 +5972,7 @@ function registerPartialsTools(server, service) {
5788
5972
  );
5789
5973
  server.tool(
5790
5974
  "delete_prompt_partial",
5791
- "Delete a prompt partial by ID. This action cannot be undone.",
5975
+ "Delete a prompt partial by ID. This cannot be undone, and prompts that reference it with {{> name}} will fail to render until you replace the reference.",
5792
5976
  PARTIALS_TOOL_SCHEMAS.deletePromptPartial,
5793
5977
  async (params) => {
5794
5978
  await service.partials.deletePromptPartial(params.prompt_partial_id);
@@ -5811,7 +5995,7 @@ function registerPartialsTools(server, service) {
5811
5995
  );
5812
5996
  server.tool(
5813
5997
  "list_partial_versions",
5814
- "List all versions of a prompt partial to view its change history",
5998
+ "List all versions 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.",
5815
5999
  PARTIALS_TOOL_SCHEMAS.listPartialVersions,
5816
6000
  async (params) => {
5817
6001
  const versions = await service.partials.listPartialVersions(
@@ -5846,7 +6030,7 @@ function registerPartialsTools(server, service) {
5846
6030
  );
5847
6031
  server.tool(
5848
6032
  "publish_partial",
5849
- "Publish a specific version of a prompt partial, making it the default version",
6033
+ "Publish a specific partial version as the default version. This changes which content {{> partial_name}} resolves to and replaces the previously active version.",
5850
6034
  PARTIALS_TOOL_SCHEMAS.publishPartial,
5851
6035
  async (params) => {
5852
6036
  await service.partials.publishPartial(params.prompt_partial_id, {
@@ -5947,14 +6131,25 @@ function toPromptToolChoice(toolChoice) {
5947
6131
 
5948
6132
  // src/tools/prompts.tools.ts
5949
6133
  var PROMPT_VARIABLES_SCHEMA = z15.record(z15.string(), z15.union([z15.string(), z15.coerce.number(), z15.boolean()])).describe("Variable values to substitute into the template");
6134
+ var PROMPT_TEMPLATE_CONTENT_BLOCK_SCHEMA = z15.object({
6135
+ type: z15.string().describe("Content block type"),
6136
+ text: z15.string().optional().describe("Text content for text-based blocks")
6137
+ }).passthrough().describe("Content block within a structured chat message");
6138
+ var PROMPT_TEMPLATE_MESSAGE_SCHEMA = z15.object({
6139
+ role: z15.enum(["system", "user", "assistant"]).describe("Message role in the chat template"),
6140
+ content: z15.array(PROMPT_TEMPLATE_CONTENT_BLOCK_SCHEMA).describe("Message content blocks")
6141
+ }).passthrough().describe("Structured chat message in a prompt template");
5950
6142
  var PROMPTS_TOOL_SCHEMAS = {
5951
6143
  createPrompt: {
5952
6144
  name: z15.string().describe("Display name for the prompt"),
5953
6145
  collection_id: z15.string().describe(
5954
6146
  "Collection ID to organize the prompt in (use list_collections to find)"
5955
6147
  ),
5956
- string: z15.string().describe(
5957
- `The prompt template. Plain text OR a JSON-encoded messages array string for multi-message chat prompts: '[{"role":"system","content":[{"type":"text","text":"..."}]},{"role":"user","content":[{"type":"text","text":"{{input}}"}]}]'. Use get_prompt on an existing prompt to see the exact format.`
6148
+ string: z15.string().optional().describe(
6149
+ "Legacy prompt template string. Use plain text for single-message prompts, or a JSON-encoded messages array string for multi-message chat prompts."
6150
+ ),
6151
+ messages: z15.array(PROMPT_TEMPLATE_MESSAGE_SCHEMA).optional().describe(
6152
+ "Structured chat template alias. Serialized to the legacy string format before creation."
5958
6153
  ),
5959
6154
  parameters: z15.record(z15.string(), z15.unknown()).describe("Default values for template variables"),
5960
6155
  virtual_key: z15.string().describe("Virtual key slug for model access"),
@@ -5991,7 +6186,10 @@ var PROMPTS_TOOL_SCHEMAS = {
5991
6186
  name: z15.string().optional().describe("New display name for the prompt"),
5992
6187
  collection_id: z15.string().optional().describe("Move to a different collection"),
5993
6188
  string: z15.string().optional().describe(
5994
- "Updated prompt template. Plain text OR a JSON-encoded messages array string for multi-message chat prompts. Use get_prompt to see the current format before updating."
6189
+ "Legacy prompt template string. Use plain text for single-message prompts, or a JSON-encoded messages array string for multi-message chat prompts."
6190
+ ),
6191
+ messages: z15.array(PROMPT_TEMPLATE_MESSAGE_SCHEMA).optional().describe(
6192
+ "Structured chat template alias for updates. Serialized to the legacy string format before the prompt is updated."
5995
6193
  ),
5996
6194
  parameters: z15.record(z15.string(), z15.unknown()).optional().describe("New default values for template variables"),
5997
6195
  model: z15.string().optional().describe("New model identifier"),
@@ -6037,7 +6235,12 @@ var PROMPTS_TOOL_SCHEMAS = {
6037
6235
  app: PromptAppIdentifierSchema,
6038
6236
  env: PromptEnvironmentIdentifierSchema,
6039
6237
  collection_id: z15.string().describe("Collection ID to search in and create under"),
6040
- string: z15.string().describe("Prompt template string with {{variable}} mustache syntax"),
6238
+ string: z15.string().optional().describe(
6239
+ "Legacy prompt template string with {{variable}} mustache syntax."
6240
+ ),
6241
+ messages: z15.array(PROMPT_TEMPLATE_MESSAGE_SCHEMA).optional().describe(
6242
+ "Structured chat template alias for migrations. Serialized to the legacy string format before the prompt is created or updated."
6243
+ ),
6041
6244
  parameters: z15.record(z15.string(), z15.unknown()).describe("Default values for template variables"),
6042
6245
  virtual_key: z15.string().describe("Virtual key slug for model access"),
6043
6246
  model: z15.string().optional().describe("Model identifier"),
@@ -6080,6 +6283,15 @@ var PROMPTS_TOOL_SCHEMAS = {
6080
6283
  )
6081
6284
  }
6082
6285
  };
6286
+ function normalizePromptTemplateString(params) {
6287
+ if (params.string !== void 0) {
6288
+ return params.string;
6289
+ }
6290
+ if (params.messages !== void 0) {
6291
+ return JSON.stringify(params.messages);
6292
+ }
6293
+ return void 0;
6294
+ }
6083
6295
  function extractPromptTemplateString(template) {
6084
6296
  const inner = typeof template === "object" && template !== null && "string" in template ? template.string : template;
6085
6297
  if (inner === void 0) {
@@ -6143,14 +6355,7 @@ function formatPromptListResponse(prompts, params) {
6143
6355
  function registerPromptsTools(server, service) {
6144
6356
  server.tool(
6145
6357
  "create_prompt",
6146
- `Create a new prompt template in Portkey. Supports both single-message and multi-message (chat) templates.
6147
-
6148
- IMPORTANT: The "string" parameter accepts TWO formats:
6149
- 1. Plain text: "Hello {{name}}, how can I help?"
6150
- 2. Multi-message JSON array (MUST be a JSON-encoded string):
6151
- '[{"role":"system","content":[{"type":"text","text":"You are a helpful assistant."}]},{"role":"user","content":[{"type":"text","text":"{{user_input}}"}]}]'
6152
-
6153
- Most production prompts use format #2 (multi-message). Use get_prompt to see examples of the format.`,
6358
+ "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.",
6154
6359
  PROMPTS_TOOL_SCHEMAS.createPrompt,
6155
6360
  async (params) => {
6156
6361
  if (!params.model && !params.ai_model_id && !params.finetune_id) {
@@ -6164,6 +6369,18 @@ Most production prompts use format #2 (multi-message). Use get_prompt to see exa
6164
6369
  isError: true
6165
6370
  };
6166
6371
  }
6372
+ const templateString = normalizePromptTemplateString(params);
6373
+ if (templateString === void 0) {
6374
+ return {
6375
+ content: [
6376
+ {
6377
+ type: "text",
6378
+ text: "Error creating prompt: Provide either string or messages"
6379
+ }
6380
+ ],
6381
+ isError: true
6382
+ };
6383
+ }
6167
6384
  if (params.dry_run) {
6168
6385
  return {
6169
6386
  content: [
@@ -6178,7 +6395,7 @@ Most production prompts use format #2 (multi-message). Use get_prompt to see exa
6178
6395
  name: params.name,
6179
6396
  collection_id: params.collection_id,
6180
6397
  model: params.model,
6181
- template_length: params.string.length,
6398
+ template_length: templateString.length,
6182
6399
  parameter_count: Object.keys(params.parameters ?? {}).length
6183
6400
  }
6184
6401
  },
@@ -6192,17 +6409,17 @@ Most production prompts use format #2 (multi-message). Use get_prompt to see exa
6192
6409
  const result = await service.prompts.createPrompt({
6193
6410
  name: params.name,
6194
6411
  collection_id: params.collection_id,
6195
- string: params.string,
6412
+ string: templateString,
6196
6413
  parameters: params.parameters,
6197
6414
  virtual_key: params.virtual_key,
6198
- model: params.model,
6199
- ai_model_id: params.ai_model_id,
6200
- finetune_id: params.finetune_id,
6201
- version_description: params.version_description,
6202
- template_metadata: params.template_metadata,
6203
- functions: params.functions,
6204
- tools: params.tools,
6205
- tool_choice: toPromptToolChoice(params.tool_choice)
6415
+ ...params.model !== void 0 ? { model: params.model } : {},
6416
+ ...params.ai_model_id !== void 0 ? { ai_model_id: params.ai_model_id } : {},
6417
+ ...params.finetune_id !== void 0 ? { finetune_id: params.finetune_id } : {},
6418
+ ...params.version_description !== void 0 ? { version_description: params.version_description } : {},
6419
+ ...params.template_metadata !== void 0 ? { template_metadata: params.template_metadata } : {},
6420
+ ...params.functions !== void 0 ? { functions: params.functions } : {},
6421
+ ...params.tools !== void 0 ? { tools: params.tools } : {},
6422
+ ...params.tool_choice !== void 0 ? { tool_choice: toPromptToolChoice(params.tool_choice) } : {}
6206
6423
  });
6207
6424
  return {
6208
6425
  content: [
@@ -6225,7 +6442,7 @@ Most production prompts use format #2 (multi-message). Use get_prompt to see exa
6225
6442
  );
6226
6443
  server.tool(
6227
6444
  "list_prompts",
6228
- "List all prompts in your Portkey organization with optional filtering by collection, workspace, or search query",
6445
+ "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.",
6229
6446
  PROMPTS_TOOL_SCHEMAS.listPrompts,
6230
6447
  async (params) => {
6231
6448
  const prompts = await service.prompts.listPrompts(params);
@@ -6245,12 +6462,7 @@ Most production prompts use format #2 (multi-message). Use get_prompt to see exa
6245
6462
  );
6246
6463
  server.tool(
6247
6464
  "get_prompt",
6248
- `Retrieve detailed information about a specific prompt including its template, parameters, and version history.
6249
-
6250
- The template field shows the raw "string" value stored in Portkey:
6251
- - If it starts with "[", it is a JSON-encoded messages array (multi-message prompt with roles).
6252
- - Otherwise it is a plain string template.
6253
- When updating a prompt, pass the same format back in the "string" field of update_prompt.`,
6465
+ "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.",
6254
6466
  PROMPTS_TOOL_SCHEMAS.getPrompt,
6255
6467
  async (params) => {
6256
6468
  const prompt = await service.prompts.getPrompt(params.prompt_id);
@@ -6312,17 +6524,14 @@ When updating a prompt, pass the same format back in the "string" field of updat
6312
6524
  );
6313
6525
  server.tool(
6314
6526
  "update_prompt",
6315
- `Update an existing prompt template. Creates a new version. Uses patch mode \u2014 only provided fields are updated, others are kept from the current version.
6316
-
6317
- IMPORTANT: The "string" parameter accepts the same two formats as create_prompt:
6318
- 1. Plain text: "Hello {{name}}"
6319
- 2. Multi-message JSON array (MUST be a JSON-encoded string):
6320
- '[{"role":"system","content":[{"type":"text","text":"..."}]},{"role":"user","content":[{"type":"text","text":"{{input}}"}]}]'
6321
-
6322
- Use get_prompt first to see the current format, then pass the same format back. New versions are created in "archived" status \u2014 use publish_prompt to make active.`,
6527
+ "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.",
6323
6528
  PROMPTS_TOOL_SCHEMAS.updatePrompt,
6324
6529
  async (params) => {
6325
- const { prompt_id, dry_run, ...updateData } = params;
6530
+ const { prompt_id, dry_run, messages, ...updateData } = params;
6531
+ const templateString = normalizePromptTemplateString({
6532
+ string: updateData.string,
6533
+ messages
6534
+ });
6326
6535
  if (dry_run) {
6327
6536
  const current = await service.prompts.getPrompt(prompt_id);
6328
6537
  return {
@@ -6347,8 +6556,17 @@ Use get_prompt first to see the current format, then pass the same format back.
6347
6556
  };
6348
6557
  }
6349
6558
  const result = await service.prompts.updatePrompt(prompt_id, {
6350
- ...updateData,
6351
- tool_choice: toPromptToolChoice(updateData.tool_choice)
6559
+ ...updateData.name !== void 0 ? { name: updateData.name } : {},
6560
+ ...updateData.collection_id !== void 0 ? { collection_id: updateData.collection_id } : {},
6561
+ ...templateString !== void 0 ? { string: templateString } : {},
6562
+ ...updateData.parameters !== void 0 ? { parameters: updateData.parameters } : {},
6563
+ ...updateData.model !== void 0 ? { model: updateData.model } : {},
6564
+ ...updateData.virtual_key !== void 0 ? { virtual_key: updateData.virtual_key } : {},
6565
+ ...updateData.version_description !== void 0 ? { version_description: updateData.version_description } : {},
6566
+ ...updateData.template_metadata !== void 0 ? { template_metadata: updateData.template_metadata } : {},
6567
+ ...updateData.functions !== void 0 ? { functions: updateData.functions } : {},
6568
+ ...updateData.tools !== void 0 ? { tools: updateData.tools } : {},
6569
+ ...updateData.tool_choice !== void 0 ? { tool_choice: toPromptToolChoice(updateData.tool_choice) } : {}
6352
6570
  });
6353
6571
  return {
6354
6572
  content: [
@@ -6371,7 +6589,7 @@ Use get_prompt first to see the current format, then pass the same format back.
6371
6589
  );
6372
6590
  server.tool(
6373
6591
  "delete_prompt",
6374
- "Delete a prompt by its ID. This action cannot be undone and will remove the prompt and all its versions.",
6592
+ "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.",
6375
6593
  PROMPTS_TOOL_SCHEMAS.deletePrompt,
6376
6594
  async (params) => {
6377
6595
  await service.prompts.deletePrompt(params.prompt_id);
@@ -6394,7 +6612,7 @@ Use get_prompt first to see the current format, then pass the same format back.
6394
6612
  );
6395
6613
  server.tool(
6396
6614
  "publish_prompt",
6397
- "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.",
6615
+ "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.",
6398
6616
  PROMPTS_TOOL_SCHEMAS.publishPrompt,
6399
6617
  async (params) => {
6400
6618
  await service.prompts.publishPrompt(params.prompt_id, {
@@ -6421,7 +6639,7 @@ Use get_prompt first to see the current format, then pass the same format back.
6421
6639
  );
6422
6640
  server.tool(
6423
6641
  "list_prompt_versions",
6424
- "List all versions of a specific prompt with their details, including version number, description, template content, and creation date.",
6642
+ "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.",
6425
6643
  PROMPTS_TOOL_SCHEMAS.listPromptVersions,
6426
6644
  async (params) => {
6427
6645
  const versions = await service.prompts.listPromptVersions(
@@ -6459,7 +6677,7 @@ Use get_prompt first to see the current format, then pass the same format back.
6459
6677
  );
6460
6678
  server.tool(
6461
6679
  "render_prompt",
6462
- "Render a prompt template by substituting variables, returning the final messages without executing",
6680
+ "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.",
6463
6681
  PROMPTS_TOOL_SCHEMAS.renderPrompt,
6464
6682
  async (params) => {
6465
6683
  const result = await service.prompts.renderPrompt(params.prompt_id, {
@@ -6491,7 +6709,7 @@ Use get_prompt first to see the current format, then pass the same format back.
6491
6709
  );
6492
6710
  server.tool(
6493
6711
  "run_prompt_completion",
6494
- "Execute a prompt template with variables and get the model completion response. REQUIRES billing metadata (client_id, app, env). Use validate_completion_metadata first if uncertain.",
6712
+ "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.",
6495
6713
  PROMPTS_TOOL_SCHEMAS.runPromptCompletion,
6496
6714
  async (params) => {
6497
6715
  const result = await service.prompts.runPromptCompletion(
@@ -6530,24 +6748,36 @@ Use get_prompt first to see the current format, then pass the same format back.
6530
6748
  );
6531
6749
  server.tool(
6532
6750
  "migrate_prompt",
6533
- "Create or update a prompt based on whether it exists. Useful for CI/CD and prompt-as-code workflows. Finds existing prompts by name within the collection. The app and env values are added to template_metadata automatically.",
6751
+ "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.",
6534
6752
  PROMPTS_TOOL_SCHEMAS.migratePrompt,
6535
6753
  async (params) => {
6754
+ const templateString = normalizePromptTemplateString(params);
6755
+ if (templateString === void 0) {
6756
+ return {
6757
+ content: [
6758
+ {
6759
+ type: "text",
6760
+ text: "Error migrating prompt: Provide either string or messages"
6761
+ }
6762
+ ],
6763
+ isError: true
6764
+ };
6765
+ }
6536
6766
  const result = await service.prompts.migratePrompt({
6537
6767
  name: params.name,
6538
6768
  app: params.app,
6539
6769
  env: params.env,
6540
6770
  collection_id: params.collection_id,
6541
- string: params.string,
6771
+ string: templateString,
6542
6772
  parameters: params.parameters,
6543
6773
  virtual_key: params.virtual_key,
6544
- model: params.model,
6545
- version_description: params.version_description,
6546
- template_metadata: params.template_metadata,
6547
- functions: params.functions,
6548
- tools: params.tools,
6549
- tool_choice: toPromptToolChoice(params.tool_choice),
6550
- dry_run: params.dry_run
6774
+ ...params.model !== void 0 ? { model: params.model } : {},
6775
+ ...params.version_description !== void 0 ? { version_description: params.version_description } : {},
6776
+ ...params.template_metadata !== void 0 ? { template_metadata: params.template_metadata } : {},
6777
+ ...params.functions !== void 0 ? { functions: params.functions } : {},
6778
+ ...params.tools !== void 0 ? { tools: params.tools } : {},
6779
+ ...params.tool_choice !== void 0 ? { tool_choice: toPromptToolChoice(params.tool_choice) } : {},
6780
+ ...params.dry_run !== void 0 ? { dry_run: params.dry_run } : {}
6551
6781
  });
6552
6782
  return {
6553
6783
  content: [
@@ -6572,7 +6802,7 @@ Use get_prompt first to see the current format, then pass the same format back.
6572
6802
  );
6573
6803
  server.tool(
6574
6804
  "promote_prompt",
6575
- "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.",
6805
+ "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.",
6576
6806
  PROMPTS_TOOL_SCHEMAS.promotePrompt,
6577
6807
  async (params) => {
6578
6808
  const result = await service.prompts.promotePrompt({
@@ -6610,7 +6840,7 @@ Use get_prompt first to see the current format, then pass the same format back.
6610
6840
  );
6611
6841
  server.tool(
6612
6842
  "validate_completion_metadata",
6613
- "Validate billing metadata before running a completion. Checks for required fields (client_id, app, env) and valid values.",
6843
+ "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.",
6614
6844
  PROMPTS_TOOL_SCHEMAS.validateCompletionMetadata,
6615
6845
  async (params) => {
6616
6846
  const result = service.prompts.validateBillingMetadata(params);
@@ -6635,7 +6865,7 @@ Use get_prompt first to see the current format, then pass the same format back.
6635
6865
  );
6636
6866
  server.tool(
6637
6867
  "get_prompt_version",
6638
- "Retrieve a specific version of a prompt by its version ID",
6868
+ "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.",
6639
6869
  PROMPTS_TOOL_SCHEMAS.getPromptVersion,
6640
6870
  async (params) => {
6641
6871
  const version = await service.prompts.getPromptVersion(
@@ -6654,7 +6884,7 @@ Use get_prompt first to see the current format, then pass the same format back.
6654
6884
  );
6655
6885
  server.tool(
6656
6886
  "update_prompt_version",
6657
- "Update a specific prompt version, e.g. to assign or remove a label",
6887
+ "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.",
6658
6888
  PROMPTS_TOOL_SCHEMAS.updatePromptVersion,
6659
6889
  async (params) => {
6660
6890
  if (params.label_id === void 0) {
@@ -6762,7 +6992,7 @@ var PROVIDERS_TOOL_SCHEMAS = {
6762
6992
  function registerProvidersTools(server, service) {
6763
6993
  server.tool(
6764
6994
  "list_providers",
6765
- "List all providers in your Portkey organization with optional pagination and workspace filtering",
6995
+ "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.",
6766
6996
  PROVIDERS_TOOL_SCHEMAS.listProviders,
6767
6997
  async (params) => {
6768
6998
  const providers = await service.providers.listProviders({
@@ -6808,7 +7038,7 @@ function registerProvidersTools(server, service) {
6808
7038
  );
6809
7039
  server.tool(
6810
7040
  "create_provider",
6811
- "Create a new provider configuration in Portkey. Providers define integrations with AI model providers like OpenAI, Anthropic, etc.",
7041
+ "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.",
6812
7042
  PROVIDERS_TOOL_SCHEMAS.createProvider,
6813
7043
  async (params) => {
6814
7044
  const result = await service.providers.createProvider({
@@ -6849,7 +7079,7 @@ function registerProvidersTools(server, service) {
6849
7079
  );
6850
7080
  server.tool(
6851
7081
  "get_provider",
6852
- "Retrieve detailed information about a specific provider by its slug",
7082
+ "Fetch one provider by slug, including limits, rate settings, expiration, and reset status. Use this to check consumption or audit configuration before updating.",
6853
7083
  PROVIDERS_TOOL_SCHEMAS.getProvider,
6854
7084
  async (params) => {
6855
7085
  const provider = await service.providers.getProvider(
@@ -6891,7 +7121,7 @@ function registerProvidersTools(server, service) {
6891
7121
  );
6892
7122
  server.tool(
6893
7123
  "update_provider",
6894
- "Update an existing provider's name, note, limits, or expiration",
7124
+ "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.",
6895
7125
  PROVIDERS_TOOL_SCHEMAS.updateProvider,
6896
7126
  async (params) => {
6897
7127
  const result = await service.providers.updateProvider(
@@ -6934,7 +7164,7 @@ function registerProvidersTools(server, service) {
6934
7164
  );
6935
7165
  server.tool(
6936
7166
  "delete_provider",
6937
- "Delete a provider by slug. This action cannot be undone.",
7167
+ "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.",
6938
7168
  PROVIDERS_TOOL_SCHEMAS.deleteProvider,
6939
7169
  async (params) => {
6940
7170
  await service.providers.deleteProvider(params.slug, params.workspace_id);
@@ -6981,15 +7211,12 @@ var TRACING_TOOL_SCHEMAS = {
6981
7211
  ),
6982
7212
  weight: z17.coerce.number().positive().optional().describe("New weighting factor for the feedback"),
6983
7213
  metadata: z17.record(z17.string(), z17.unknown()).optional().describe("New or updated custom metadata for the feedback")
6984
- },
6985
- getTrace: {
6986
- id: z17.string().describe("The unique identifier of the trace to retrieve")
6987
7214
  }
6988
7215
  };
6989
7216
  function registerTracingTools(server, service) {
6990
7217
  server.tool(
6991
7218
  "create_feedback",
6992
- "Create feedback for a specific trace/request. Use this to capture user feedback (thumbs up/down, ratings) on AI generations. Feedback is linked via trace_id and can include custom metadata for analysis.",
7219
+ "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.",
6993
7220
  TRACING_TOOL_SCHEMAS.createFeedback,
6994
7221
  async (params) => {
6995
7222
  const result = await service.tracing.createFeedback({
@@ -7018,7 +7245,7 @@ function registerTracingTools(server, service) {
7018
7245
  );
7019
7246
  server.tool(
7020
7247
  "update_feedback",
7021
- "Update existing feedback by ID. Allows modifying the feedback value, weight, or metadata after initial creation.",
7248
+ "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.",
7022
7249
  TRACING_TOOL_SCHEMAS.updateFeedback,
7023
7250
  async (params) => {
7024
7251
  const result = await service.tracing.updateFeedback(params.id, {
@@ -7044,51 +7271,6 @@ function registerTracingTools(server, service) {
7044
7271
  };
7045
7272
  }
7046
7273
  );
7047
- server.tool(
7048
- "get_trace",
7049
- "Retrieve detailed information about a specific trace by ID. Returns full request/response data, all spans, metadata, cost, token usage, and any associated feedback.",
7050
- TRACING_TOOL_SCHEMAS.getTrace,
7051
- async (params) => {
7052
- const result = await service.tracing.getTrace(params.id);
7053
- const trace = result.data;
7054
- return {
7055
- content: [
7056
- {
7057
- type: "text",
7058
- text: JSON.stringify(
7059
- {
7060
- success: result.success,
7061
- trace: {
7062
- id: trace.id,
7063
- trace_id: trace.trace_id,
7064
- request: trace.request,
7065
- response: trace.response,
7066
- metadata: trace.metadata,
7067
- workspace_id: trace.workspace_id,
7068
- organisation_id: trace.organisation_id,
7069
- cost: trace.cost,
7070
- tokens: trace.tokens,
7071
- spans: trace.spans?.map((span) => ({
7072
- span_id: span.span_id,
7073
- span_name: span.span_name,
7074
- parent_span_id: span.parent_span_id,
7075
- start_time: span.start_time,
7076
- end_time: span.end_time,
7077
- status: span.status,
7078
- attributes: span.attributes
7079
- })),
7080
- feedback: trace.feedback,
7081
- created_at: trace.created_at
7082
- }
7083
- },
7084
- null,
7085
- 2
7086
- )
7087
- }
7088
- ]
7089
- };
7090
- }
7091
- );
7092
7274
  }
7093
7275
 
7094
7276
  // src/tools/users.tools.ts
@@ -7192,7 +7374,7 @@ function formatUserAnalyticsGroup(group) {
7192
7374
  function registerUsersTools(server, service) {
7193
7375
  server.tool(
7194
7376
  "list_all_users",
7195
- "List all users in your Portkey organization, including their roles and account details",
7377
+ "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.",
7196
7378
  USERS_TOOL_SCHEMAS.listAllUsers,
7197
7379
  async () => {
7198
7380
  const users = await service.users.listUsers();
@@ -7215,7 +7397,7 @@ function registerUsersTools(server, service) {
7215
7397
  );
7216
7398
  server.tool(
7217
7399
  "invite_user",
7218
- "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.",
7400
+ "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.",
7219
7401
  USERS_TOOL_SCHEMAS.inviteUser,
7220
7402
  async (params) => {
7221
7403
  const result = await service.users.inviteUser(params);
@@ -7239,7 +7421,7 @@ function registerUsersTools(server, service) {
7239
7421
  );
7240
7422
  server.tool(
7241
7423
  "get_user_stats",
7242
- "Retrieve detailed analytics data about user activity within a specified time range, including request counts and costs",
7424
+ "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.",
7243
7425
  USERS_TOOL_SCHEMAS.getUserStats,
7244
7426
  async (params) => {
7245
7427
  const stats = await service.users.getUserGroupedData(params);
@@ -7262,7 +7444,7 @@ function registerUsersTools(server, service) {
7262
7444
  );
7263
7445
  server.tool(
7264
7446
  "get_user",
7265
- "Retrieve detailed information about a specific user by their ID",
7447
+ "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.",
7266
7448
  USERS_TOOL_SCHEMAS.getUser,
7267
7449
  async (params) => {
7268
7450
  const user = await service.users.getUser(params.user_id);
@@ -7278,7 +7460,7 @@ function registerUsersTools(server, service) {
7278
7460
  );
7279
7461
  server.tool(
7280
7462
  "update_user",
7281
- "Update a user's profile information including name and organization role",
7463
+ "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.",
7282
7464
  USERS_TOOL_SCHEMAS.updateUser,
7283
7465
  async (params) => {
7284
7466
  const { user_id, ...updateData } = params;
@@ -7302,7 +7484,7 @@ function registerUsersTools(server, service) {
7302
7484
  );
7303
7485
  server.tool(
7304
7486
  "delete_user",
7305
- "Remove a user from your Portkey organization. Permanently removes the user and all their org/workspace memberships. Cannot be undone.",
7487
+ "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.",
7306
7488
  USERS_TOOL_SCHEMAS.deleteUser,
7307
7489
  async (params) => {
7308
7490
  await service.users.deleteUser(params.user_id);
@@ -7325,7 +7507,7 @@ function registerUsersTools(server, service) {
7325
7507
  );
7326
7508
  server.tool(
7327
7509
  "list_user_invites",
7328
- "List all pending and sent user invitations in your Portkey organization",
7510
+ "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.",
7329
7511
  USERS_TOOL_SCHEMAS.listUserInvites,
7330
7512
  async () => {
7331
7513
  const invites = await service.users.listUserInvites();
@@ -7348,7 +7530,7 @@ function registerUsersTools(server, service) {
7348
7530
  );
7349
7531
  server.tool(
7350
7532
  "get_user_invite",
7351
- "Retrieve details about a specific user invitation",
7533
+ "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.",
7352
7534
  USERS_TOOL_SCHEMAS.getUserInvite,
7353
7535
  async (params) => {
7354
7536
  const invite = await service.users.getUserInvite(params.invite_id);
@@ -7364,7 +7546,7 @@ function registerUsersTools(server, service) {
7364
7546
  );
7365
7547
  server.tool(
7366
7548
  "delete_user_invite",
7367
- "Cancel and delete a pending user invitation",
7549
+ "Delete a pending invite and revoke its invite link. This does not affect existing users; use delete_user for full user removal.",
7368
7550
  USERS_TOOL_SCHEMAS.deleteUserInvite,
7369
7551
  async (params) => {
7370
7552
  await service.users.deleteUserInvite(params.invite_id);
@@ -7387,7 +7569,7 @@ function registerUsersTools(server, service) {
7387
7569
  );
7388
7570
  server.tool(
7389
7571
  "resend_user_invite",
7390
- "Resend an invitation email to a pending user",
7572
+ "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.",
7391
7573
  USERS_TOOL_SCHEMAS.resendUserInvite,
7392
7574
  async (params) => {
7393
7575
  await service.users.resendUserInvite(params.invite_id);
@@ -7517,7 +7699,7 @@ function formatWorkspaceDetail(workspace) {
7517
7699
  function registerWorkspacesTools(server, service) {
7518
7700
  server.tool(
7519
7701
  "list_workspaces",
7520
- "Retrieve all workspaces in your Portkey organization, including their configurations and metadata",
7702
+ "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.",
7521
7703
  WORKSPACES_TOOL_SCHEMAS.listWorkspaces,
7522
7704
  async (params) => {
7523
7705
  const workspaces = await service.workspaces.listWorkspaces(params);
@@ -7540,7 +7722,7 @@ function registerWorkspacesTools(server, service) {
7540
7722
  );
7541
7723
  server.tool(
7542
7724
  "get_workspace",
7543
- "Retrieve detailed information about a specific workspace, including its configuration, metadata, and user access details",
7725
+ "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.",
7544
7726
  WORKSPACES_TOOL_SCHEMAS.getWorkspace,
7545
7727
  async (params) => {
7546
7728
  const workspace = await service.workspaces.getWorkspace(
@@ -7558,7 +7740,7 @@ function registerWorkspacesTools(server, service) {
7558
7740
  );
7559
7741
  server.tool(
7560
7742
  "create_workspace",
7561
- "Create a new workspace in your Portkey organization",
7743
+ "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.",
7562
7744
  WORKSPACES_TOOL_SCHEMAS.createWorkspace,
7563
7745
  async (params) => {
7564
7746
  const workspace = await service.workspaces.createWorkspace({
@@ -7589,7 +7771,7 @@ function registerWorkspacesTools(server, service) {
7589
7771
  );
7590
7772
  server.tool(
7591
7773
  "update_workspace",
7592
- "Update an existing workspace's settings and metadata",
7774
+ "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.",
7593
7775
  WORKSPACES_TOOL_SCHEMAS.updateWorkspace,
7594
7776
  async (params) => {
7595
7777
  const { workspace_id, is_default, metadata, ...rest } = params;
@@ -7619,7 +7801,7 @@ function registerWorkspacesTools(server, service) {
7619
7801
  );
7620
7802
  server.tool(
7621
7803
  "delete_workspace",
7622
- "Delete a workspace from your organization. Permanently deletes the workspace and all its members, configs, API keys, and resources. Cannot be undone.",
7804
+ "Delete a workspace by id. This is permanent and removes the workspace, its members, configs, API keys, and resources.",
7623
7805
  WORKSPACES_TOOL_SCHEMAS.deleteWorkspace,
7624
7806
  async (params) => {
7625
7807
  await service.workspaces.deleteWorkspace(params.workspace_id);
@@ -7642,7 +7824,7 @@ function registerWorkspacesTools(server, service) {
7642
7824
  );
7643
7825
  server.tool(
7644
7826
  "add_workspace_member",
7645
- "Add a user to a workspace with a specific role",
7827
+ "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.",
7646
7828
  WORKSPACES_TOOL_SCHEMAS.addWorkspaceMember,
7647
7829
  async (params) => {
7648
7830
  const member = await service.workspaces.addWorkspaceMember(
@@ -7671,7 +7853,7 @@ function registerWorkspacesTools(server, service) {
7671
7853
  );
7672
7854
  server.tool(
7673
7855
  "list_workspace_members",
7674
- "List all members of a workspace with their roles",
7856
+ "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.",
7675
7857
  WORKSPACES_TOOL_SCHEMAS.listWorkspaceMembers,
7676
7858
  async (params) => {
7677
7859
  const members = await service.workspaces.listWorkspaceMembers(
@@ -7696,7 +7878,7 @@ function registerWorkspacesTools(server, service) {
7696
7878
  );
7697
7879
  server.tool(
7698
7880
  "get_workspace_member",
7699
- "Get details about a specific member of a workspace",
7881
+ "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.",
7700
7882
  WORKSPACES_TOOL_SCHEMAS.getWorkspaceMember,
7701
7883
  async (params) => {
7702
7884
  const member = await service.workspaces.getWorkspaceMember(
@@ -7715,7 +7897,7 @@ function registerWorkspacesTools(server, service) {
7715
7897
  );
7716
7898
  server.tool(
7717
7899
  "update_workspace_member",
7718
- "Update a member's role in a workspace",
7900
+ "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.",
7719
7901
  WORKSPACES_TOOL_SCHEMAS.updateWorkspaceMember,
7720
7902
  async (params) => {
7721
7903
  const member = await service.workspaces.updateWorkspaceMember(
@@ -7744,7 +7926,7 @@ function registerWorkspacesTools(server, service) {
7744
7926
  );
7745
7927
  server.tool(
7746
7928
  "remove_workspace_member",
7747
- "Remove a user from a workspace",
7929
+ "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.",
7748
7930
  WORKSPACES_TOOL_SCHEMAS.removeWorkspaceMember,
7749
7931
  async (params) => {
7750
7932
  await service.workspaces.removeWorkspaceMember(
@@ -7795,6 +7977,9 @@ var TOOL_DOMAIN_NAMES = TOOL_DOMAIN_REGISTRARS.map(
7795
7977
  ([domain]) => domain
7796
7978
  );
7797
7979
  var TOOL_DOMAIN_NAME_SET = new Set(TOOL_DOMAIN_NAMES);
7980
+ function isToolDomain(value) {
7981
+ return TOOL_DOMAIN_NAME_SET.has(value);
7982
+ }
7798
7983
  function normalizeToolDomains(domains) {
7799
7984
  const selectedDomains = new Set(domains);
7800
7985
  return TOOL_DOMAIN_REGISTRARS.filter(
@@ -7822,6 +8007,37 @@ var DESTRUCTIVE_TOOL_PREFIXES = [
7822
8007
  "cancel_",
7823
8008
  "reset_"
7824
8009
  ];
8010
+ var ENTERPRISE_GATED_TOOL_NAMES = /* @__PURE__ */ new Set([
8011
+ "get_cost_analytics",
8012
+ "get_request_analytics",
8013
+ "get_token_analytics",
8014
+ "get_latency_analytics",
8015
+ "get_error_analytics",
8016
+ "get_error_rate_analytics",
8017
+ "get_cache_hit_latency",
8018
+ "get_cache_hit_rate",
8019
+ "get_users_analytics",
8020
+ "get_error_stacks_analytics",
8021
+ "get_error_status_codes_analytics",
8022
+ "get_user_requests_analytics",
8023
+ "get_rescued_requests_analytics",
8024
+ "get_feedback_analytics",
8025
+ "get_feedback_models_analytics",
8026
+ "get_feedback_scores_analytics",
8027
+ "get_feedback_weighted_analytics",
8028
+ "get_analytics_group_users",
8029
+ "get_analytics_group_models",
8030
+ "get_analytics_group_metadata",
8031
+ "list_audit_logs",
8032
+ "get_integration",
8033
+ "list_integration_models",
8034
+ "list_integration_workspaces",
8035
+ "list_all_users",
8036
+ "get_user",
8037
+ "list_user_invites",
8038
+ "get_user_stats"
8039
+ ]);
8040
+ var ENTERPRISE_GATED_DESCRIPTION_NOTE = "Enterprise-gated. Returns 403 on non-Enterprise Portkey plans.";
7825
8041
  function isToolAnnotationsLike(value) {
7826
8042
  if (!isRecord2(value)) {
7827
8043
  return false;
@@ -7870,6 +8086,15 @@ function inferToolAnnotations(toolName) {
7870
8086
  openWorldHint: true
7871
8087
  };
7872
8088
  }
8089
+ function augmentToolDescription(toolName, description) {
8090
+ if (!description || !ENTERPRISE_GATED_TOOL_NAMES.has(toolName)) {
8091
+ return description;
8092
+ }
8093
+ if (description.includes(ENTERPRISE_GATED_DESCRIPTION_NOTE)) {
8094
+ return description;
8095
+ }
8096
+ return `${description} ${ENTERPRISE_GATED_DESCRIPTION_NOTE}`;
8097
+ }
7873
8098
  function getToolErrorMessage(error) {
7874
8099
  if (error instanceof Error && error.message) {
7875
8100
  return error.message;
@@ -7974,6 +8199,7 @@ function buildToolRegistration(name, rest) {
7974
8199
  if (typeof args[0] === "string") {
7975
8200
  description = args.shift();
7976
8201
  }
8202
+ description = augmentToolDescription(name, description);
7977
8203
  let inputSchema;
7978
8204
  let annotations = inferredAnnotations;
7979
8205
  if (args.length === 1) {
@@ -8081,7 +8307,27 @@ function readPackageVersion() {
8081
8307
  return "0.0.0";
8082
8308
  }
8083
8309
  var PACKAGE_VERSION = readPackageVersion();
8084
- var SERVER_INSTRUCTIONS = "Portkey Admin API server. Use list_* tools for discovery and get_* tools for details. Analytics tools require time_of_generation_min/max. Prompt workflows: create_prompt -> publish_prompt. Always validate_completion_metadata before run_prompt_completion.";
8310
+ 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.";
8311
+ function parseConfiguredToolDomains(rawValue = process.env.PORTKEY_TOOL_DOMAINS?.trim() || process.env.MCP_TOOL_DOMAINS?.trim()) {
8312
+ if (!rawValue) {
8313
+ return void 0;
8314
+ }
8315
+ const requestedDomains = rawValue.split(",").map((value) => value.trim().toLowerCase()).filter((value) => value.length > 0);
8316
+ if (requestedDomains.length === 0) {
8317
+ throw new Error(
8318
+ `Invalid PORTKEY_TOOL_DOMAINS value. Expected one or more domains from: ${TOOL_DOMAIN_NAMES.join(", ")}`
8319
+ );
8320
+ }
8321
+ const invalidDomains = requestedDomains.filter(
8322
+ (value) => !isToolDomain(value)
8323
+ );
8324
+ if (invalidDomains.length > 0) {
8325
+ throw new Error(
8326
+ `Unknown tool domains in PORTKEY_TOOL_DOMAINS: ${invalidDomains.join(", ")}. Valid domains: ${TOOL_DOMAIN_NAMES.join(", ")}`
8327
+ );
8328
+ }
8329
+ return normalizeToolDomains(requestedDomains);
8330
+ }
8085
8331
  function createMcpServer(options = {}) {
8086
8332
  const service = getSharedPortkeyService();
8087
8333
  const server = new McpServer(
@@ -8096,7 +8342,9 @@ function createMcpServer(options = {}) {
8096
8342
  instructions: SERVER_INSTRUCTIONS
8097
8343
  }
8098
8344
  );
8099
- registerAllTools(server, service, { domains: options.toolDomains });
8345
+ registerAllTools(server, service, {
8346
+ domains: options.toolDomains ?? parseConfiguredToolDomains()
8347
+ });
8100
8348
  return {
8101
8349
  server,
8102
8350
  service