@runpod/mcp-server 4.5.0 → 4.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/stdio.cjs CHANGED
@@ -47,7 +47,7 @@ function authedGraphqlBase(env) {
47
47
  return pick(env.RUNPOD_AUTHED_GRAPHQL_URL, "https://api.runpod.io/graphql");
48
48
  }
49
49
  function hostedMcpBase(env) {
50
- return pick(env.RUNPOD_MCP_URL, "https://mcp.getrunpod.io");
50
+ return pick(env.RUNPOD_MCP_URL, "https://mcp.runpod.io");
51
51
  }
52
52
  var init_hosts = __esm({
53
53
  "src/_shared/hosts.ts"() {
@@ -1183,7 +1183,7 @@ var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
1183
1183
 
1184
1184
  // src/server.ts
1185
1185
  var SERVER_NAME = "Runpod API Server";
1186
- var SERVER_VERSION = true ? "4.5.0" : "dev";
1186
+ var SERVER_VERSION = true ? "4.7.0" : "dev";
1187
1187
 
1188
1188
  // src/specgen/server.ts
1189
1189
  var import_server3 = require("@modelcontextprotocol/sdk/server/index.js");
@@ -1513,6 +1513,7 @@ var generatedTools = [
1513
1513
  title: "Create cluster",
1514
1514
  operationId: "createCluster",
1515
1515
  description: "Create an instant cluster (multiple pods with high-speed interconnect). BILLABLE from creation for every pod in the cluster: it rents compute.podCount identical pods at once, each with compute.gpuCountPerPod GPUs of compute.gpuTypeId \u2014 state the hourly price for the total GPU count (podCount * gpuCountPerPod, priced from the catalog tools) and create only after the user's explicit go on that quoted shape and total hourly price. Verify GPU stock first via the catalog tools. The compute shape and type are fixed at creation; only the name can be changed later. The container configuration applies to every pod, and templateId is the only private-image path \u2014 a bare registry property is rejected. Delete with delete-cluster when finished.",
1516
+ directoryDescription: "Create an Instant Cluster: compute.podCount identical Pods joined by a high-speed interconnect, each with compute.gpuCountPerPod GPUs of compute.gpuTypeId. Billable from creation for every Pod in the cluster, at the GPU type's hourly price times the total GPU count. The compute shape and type are fixed at creation; only the name can change later. The container configuration applies to every Pod, and templateId is the only way to use a private image; a bare registry property is rejected.",
1516
1517
  method: "POST",
1517
1518
  path: "/v2/clusters",
1518
1519
  params: [],
@@ -1528,7 +1529,8 @@ var generatedTools = [
1528
1529
  type: "object",
1529
1530
  properties: {
1530
1531
  body: {
1531
- $ref: "#/$defs/CreateClusterRequest"
1532
+ $ref: "#/$defs/CreateClusterRequest",
1533
+ type: "object"
1532
1534
  }
1533
1535
  },
1534
1536
  required: ["body"],
@@ -1577,7 +1579,7 @@ var generatedTools = [
1577
1579
  description: "Environment variables as key-value pairs",
1578
1580
  examples: [
1579
1581
  {
1580
- JUPYTER_PASSWORD: "hunter2"
1582
+ JUPYTER_PASSWORD: "changeme"
1581
1583
  }
1582
1584
  ]
1583
1585
  },
@@ -1765,7 +1767,8 @@ var generatedTools = [
1765
1767
  type: "object",
1766
1768
  properties: {
1767
1769
  body: {
1768
- $ref: "#/$defs/CreateDelegationRequest"
1770
+ $ref: "#/$defs/CreateDelegationRequest",
1771
+ type: "object"
1769
1772
  }
1770
1773
  },
1771
1774
  required: ["body"],
@@ -1779,7 +1782,7 @@ var generatedTools = [
1779
1782
  type: "string",
1780
1783
  description: "ECR resource ARN",
1781
1784
  examples: [
1782
- "arn:aws:ecr:us-east-2:418399314813:repository/runpod/deployment"
1785
+ "arn:aws:ecr:us-east-2:123456789012:repository/runpod/deployment"
1783
1786
  ]
1784
1787
  },
1785
1788
  name: {
@@ -1797,6 +1800,7 @@ var generatedTools = [
1797
1800
  title: "Create endpoint",
1798
1801
  operationId: "createEndpoint",
1799
1802
  description: "Create a serverless endpoint. BILLABLE: state the worker's hourly price (from the catalog tools) before creating. Worker hardware is one of two choices: the gpu object (gpu.pools takes serverless pool ids from the catalog, e.g. ADA_24, never display names; gpu.count sets GPUs per worker) or the cpu array of CPU flavor configurations for a CPU endpoint. type and scaling are required and fix the request-routing model. Workers cold-start on the first job: expect minutes, poll with get-job-status wait.",
1803
+ directoryDescription: "Create a Serverless endpoint. Billable while its workers run, at the worker's hourly price. Worker hardware is either the gpu object (gpu.pools takes Serverless pool ids such as ADA_24, and gpu.count sets GPUs per worker) or the cpu array of CPU flavor configurations. type and scaling are required and set the request-routing model. Workers cold-start on their first job, which commonly takes minutes.",
1800
1804
  method: "POST",
1801
1805
  path: "/v2/serverless",
1802
1806
  params: [],
@@ -1812,7 +1816,8 @@ var generatedTools = [
1812
1816
  type: "object",
1813
1817
  properties: {
1814
1818
  body: {
1815
- $ref: "#/$defs/CreateEndpointRequest"
1819
+ $ref: "#/$defs/CreateEndpointRequest",
1820
+ type: "object"
1816
1821
  }
1817
1822
  },
1818
1823
  required: ["body"],
@@ -1861,7 +1866,7 @@ var generatedTools = [
1861
1866
  description: "Environment variables as key-value pairs",
1862
1867
  examples: [
1863
1868
  {
1864
- JUPYTER_PASSWORD: "hunter2"
1869
+ JUPYTER_PASSWORD: "changeme"
1865
1870
  }
1866
1871
  ]
1867
1872
  },
@@ -2112,7 +2117,7 @@ var generatedTools = [
2112
2117
  type: "object",
2113
2118
  required: ["volumeId"],
2114
2119
  additionalProperties: false,
2115
- description: "A volume mounted on every worker, always at `/runpod-volume`. Custom paths are not supported yet.",
2120
+ description: "A volume mounted on every worker, always at `/runpod-volume`.",
2116
2121
  properties: {
2117
2122
  volumeId: {
2118
2123
  type: "string",
@@ -2162,8 +2167,7 @@ var generatedTools = [
2162
2167
  },
2163
2168
  EndpointType: {
2164
2169
  type: "string",
2165
- description: "Request-routing semantics for a modern serverless endpoint. `QUEUE` \u2014 submit asynchronous or synchronous jobs through the managed queue. `LOAD_BALANCER` \u2014 send requests directly to worker-defined HTTP paths.",
2166
- "x-enum-varnames": ["EndpointTypeQueue", "EndpointTypeLoadBalancer"],
2170
+ description: "Request-routing semantics for a serverless endpoint. `QUEUE` \u2014 submit asynchronous or synchronous jobs through the managed queue. `LOAD_BALANCER` \u2014 send requests directly to worker-defined HTTP paths.",
2167
2171
  enum: ["QUEUE", "LOAD_BALANCER"]
2168
2172
  },
2169
2173
  EndpointWorkers: {
@@ -2257,7 +2261,8 @@ var generatedTools = [
2257
2261
  type: "object",
2258
2262
  properties: {
2259
2263
  body: {
2260
- $ref: "#/$defs/CreateGlobalVolumeRequest"
2264
+ $ref: "#/$defs/CreateGlobalVolumeRequest",
2265
+ type: "object"
2261
2266
  }
2262
2267
  },
2263
2268
  required: ["body"],
@@ -2271,7 +2276,6 @@ var generatedTools = [
2271
2276
  type: "string",
2272
2277
  minLength: 1,
2273
2278
  maxLength: 191,
2274
- pattern: "[^\\p{Z}\\t-\\r\x85]",
2275
2279
  description: "Human-readable name, 1\u2013191 characters with at least one non-whitespace character. Leading and trailing whitespace is trimmed.",
2276
2280
  examples: ["training-data"]
2277
2281
  }
@@ -2299,7 +2303,8 @@ var generatedTools = [
2299
2303
  type: "object",
2300
2304
  properties: {
2301
2305
  body: {
2302
- $ref: "#/$defs/CreateNetworkVolumeRequest"
2306
+ $ref: "#/$defs/CreateNetworkVolumeRequest",
2307
+ type: "object"
2303
2308
  }
2304
2309
  },
2305
2310
  required: ["body"],
@@ -2351,6 +2356,7 @@ var generatedTools = [
2351
2356
  title: "Create Pod",
2352
2357
  operationId: "createPod",
2353
2358
  description: 'Rent a GPU/CPU pod. BILLABLE from creation until stop/terminate: state the hourly price before creating. GPU selection is the gpu object: gpu.id takes a catalog GPU type id (e.g. "NVIDIA GeForce RTX 4090"), verified via list-gpu-types, and gpu.count sets the GPU count; cloud/data-center choice constrains stock.',
2359
+ directoryDescription: 'Create a GPU or CPU Pod. Billable from creation until it is stopped or terminated. GPU selection is the gpu object: gpu.id takes a GPU type id such as "NVIDIA GeForce RTX 4090", and gpu.count sets the number of GPUs. Cloud tier and data center choices limit which machines can host it.',
2354
2360
  method: "POST",
2355
2361
  path: "/v2/pods",
2356
2362
  params: [],
@@ -2366,7 +2372,8 @@ var generatedTools = [
2366
2372
  type: "object",
2367
2373
  properties: {
2368
2374
  body: {
2369
- $ref: "#/$defs/CreatePodRequest"
2375
+ $ref: "#/$defs/CreatePodRequest",
2376
+ type: "object"
2370
2377
  }
2371
2378
  },
2372
2379
  required: ["body"],
@@ -2415,7 +2422,7 @@ var generatedTools = [
2415
2422
  description: "Environment variables as key-value pairs",
2416
2423
  examples: [
2417
2424
  {
2418
- JUPYTER_PASSWORD: "hunter2"
2425
+ JUPYTER_PASSWORD: "changeme"
2419
2426
  }
2420
2427
  ]
2421
2428
  },
@@ -2564,7 +2571,7 @@ var generatedTools = [
2564
2571
  {
2565
2572
  type: "object",
2566
2573
  required: ["name"],
2567
- description: "Request body for creating a pod. Exactly one of `gpu` or `cpu` must be set \u2014 enforced at the handler layer.",
2574
+ description: "Request body for creating a pod. Exactly one of `gpu` or `cpu` must be set. For CPU pods, memory is derived by the API from the selected flavor's RAM multiplier; clients provide only CPU flavor and vCPU count.",
2568
2575
  properties: {
2569
2576
  name: {
2570
2577
  type: "string",
@@ -2594,7 +2601,7 @@ var generatedTools = [
2594
2601
  globalNetworking: {
2595
2602
  type: "boolean",
2596
2603
  default: false,
2597
- description: "Enable global networking, giving the pod a private IP reachable across data centers. Requires an NVIDIA GPU and a global-networking-enabled data center (both enforced upstream).",
2604
+ description: "Enable global networking, giving the pod a private IP reachable across data centers. Requires an NVIDIA GPU and a global-networking-enabled data center. See `list-data-centers` (`globalNetwork`) for eligible data centers.",
2598
2605
  examples: [false]
2599
2606
  },
2600
2607
  gpu: {
@@ -2733,7 +2740,8 @@ var generatedTools = [
2733
2740
  type: "object",
2734
2741
  properties: {
2735
2742
  body: {
2736
- $ref: "#/$defs/CreateRegistryRequest"
2743
+ $ref: "#/$defs/CreateRegistryRequest",
2744
+ type: "object"
2737
2745
  }
2738
2746
  },
2739
2747
  required: ["body"],
@@ -2778,7 +2786,7 @@ var generatedTools = [
2778
2786
  annotations: {
2779
2787
  readOnlyHint: false,
2780
2788
  destructiveHint: false,
2781
- idempotentHint: false,
2789
+ idempotentHint: true,
2782
2790
  openWorldHint: true
2783
2791
  },
2784
2792
  schemaOnDemand: true,
@@ -2786,7 +2794,8 @@ var generatedTools = [
2786
2794
  type: "object",
2787
2795
  properties: {
2788
2796
  body: {
2789
- $ref: "#/$defs/CreateSecretRequest"
2797
+ $ref: "#/$defs/CreateSecretRequest",
2798
+ type: "object"
2790
2799
  }
2791
2800
  },
2792
2801
  required: ["body"],
@@ -2841,7 +2850,8 @@ var generatedTools = [
2841
2850
  type: "object",
2842
2851
  properties: {
2843
2852
  body: {
2844
- $ref: "#/$defs/CreateTemplateRequest"
2853
+ $ref: "#/$defs/CreateTemplateRequest",
2854
+ type: "object"
2845
2855
  }
2846
2856
  },
2847
2857
  required: ["body"],
@@ -2890,7 +2900,7 @@ var generatedTools = [
2890
2900
  description: "Environment variables as key-value pairs",
2891
2901
  examples: [
2892
2902
  {
2893
- JUPYTER_PASSWORD: "hunter2"
2903
+ JUPYTER_PASSWORD: "changeme"
2894
2904
  }
2895
2905
  ]
2896
2906
  },
@@ -3028,6 +3038,7 @@ var generatedTools = [
3028
3038
  title: "Delete cluster",
3029
3039
  operationId: "deleteCluster",
3030
3040
  description: "Delete a cluster permanently: it terminates every member pod. Verify the id with get-cluster, and list-cluster-pods for what the delete takes down, before deleting; delete only clusters your own tool calls created in this conversation, or the one the user asked you to delete by id \u2014 a name found by listing is not attribution.",
3041
+ directoryDescription: "Delete an Instant Cluster permanently. Every member Pod is terminated and its container disk is lost.",
3031
3042
  method: "DELETE",
3032
3043
  path: "/v2/clusters/{id}",
3033
3044
  params: [
@@ -3059,6 +3070,7 @@ var generatedTools = [
3059
3070
  title: "Delete endpoint",
3060
3071
  operationId: "deleteEndpoint",
3061
3072
  description: "Delete a serverless endpoint permanently and immediately. Verify the id belongs to the intended endpoint (get-endpoint) before deleting; delete only endpoints your own tool calls created in this conversation, or the one the user asked you to delete by id \u2014 a name found by listing is not attribution.",
3073
+ directoryDescription: "Delete a Serverless endpoint permanently and immediately.",
3062
3074
  method: "DELETE",
3063
3075
  path: "/v2/serverless/{id}",
3064
3076
  params: [
@@ -3152,6 +3164,7 @@ var generatedTools = [
3152
3164
  title: "Delete Pod",
3153
3165
  operationId: "deletePod",
3154
3166
  description: "Terminate a pod permanently \u2014 its container disk is lost. Distinguish from stopping (pod-action stop) which releases the GPU but keeps volume data. Verify the id with get-pod first; terminate only pods your own tool calls created in this conversation, or the one the user asked you to terminate by id \u2014 a name found by listing is not attribution.",
3167
+ directoryDescription: "Terminate a Pod permanently. Its container disk is lost; data on an attached network volume is kept. Stopping a Pod instead releases its compute but keeps its disk.",
3155
3168
  method: "DELETE",
3156
3169
  path: "/v2/pods/{id}",
3157
3170
  params: [
@@ -3213,6 +3226,7 @@ var generatedTools = [
3213
3226
  title: "Delete secret",
3214
3227
  operationId: "deleteSecret",
3215
3228
  description: "Delete a secret permanently. Environment variables referencing its name ({{ RUNPOD_SECRET_<name> }}) stop resolving at the next pod or worker boot; running instances keep the value they started with. Verify the id with get-secret first; delete only secrets your own tool calls created in this conversation, or the one the user asked you to delete by id \u2014 a name found by listing is not attribution.",
3229
+ directoryDescription: "Delete a secret permanently. Environment variables that reference it ({{ RUNPOD_SECRET_<name> }}) stop resolving at the next Pod or worker boot; running instances keep the value they started with.",
3216
3230
  method: "DELETE",
3217
3231
  path: "/v2/account/secrets/{id}",
3218
3232
  params: [
@@ -3244,6 +3258,7 @@ var generatedTools = [
3244
3258
  title: "Delete template",
3245
3259
  operationId: "deleteTemplate",
3246
3260
  description: "Delete a template permanently. Verify with get-template first; a template referenced by a live endpoint should not be deleted.",
3261
+ directoryDescription: "Delete a template permanently. An endpoint that references the template can stop working once it is deleted.",
3247
3262
  method: "DELETE",
3248
3263
  path: "/v2/templates/{id}",
3249
3264
  params: [
@@ -3346,7 +3361,7 @@ var generatedTools = [
3346
3361
  items: {
3347
3362
  $ref: "#/$defs/CatalogInclude"
3348
3363
  },
3349
- description: "Comma-separated optional expansions. Supported value today: AVAILABILITY. This may expand with more include values in the future."
3364
+ description: "Comma-separated optional expansions; see `CatalogInclude` for the supported values."
3350
3365
  },
3351
3366
  product: {
3352
3367
  type: "array",
@@ -3366,7 +3381,7 @@ var generatedTools = [
3366
3381
  $defs: {
3367
3382
  CatalogInclude: {
3368
3383
  type: "string",
3369
- description: "Catalog include expansion. Only AVAILABILITY is supported today; additional include values may be added in the future.",
3384
+ description: "Catalog include expansion. `AVAILABILITY` is the only supported value.",
3370
3385
  enum: ["AVAILABILITY"]
3371
3386
  },
3372
3387
  CpuProduct: {
@@ -3592,7 +3607,7 @@ var generatedTools = [
3592
3607
  items: {
3593
3608
  $ref: "#/$defs/CatalogInclude"
3594
3609
  },
3595
- description: "Comma-separated optional expansions. Supported value today: AVAILABILITY. This may expand with more include values in the future."
3610
+ description: "Comma-separated optional expansions; see `CatalogInclude` for the supported values."
3596
3611
  },
3597
3612
  product: {
3598
3613
  type: "array",
@@ -3609,7 +3624,8 @@ var generatedTools = [
3609
3624
  },
3610
3625
  cloud: {
3611
3626
  $ref: "#/$defs/GpuCloudFilter",
3612
- description: "Cloud type for availability and lowest-price calculations. Valid only with include=AVAILABILITY. Supported values: SECURE, COMMUNITY. Upstream default when omitted: SECURE."
3627
+ description: "Cloud type for availability and lowest-price calculations. Valid only with include=AVAILABILITY. Supported values: SECURE, COMMUNITY. Upstream default when omitted: SECURE.",
3628
+ type: "string"
3613
3629
  },
3614
3630
  countryCodes: {
3615
3631
  type: "array",
@@ -3637,7 +3653,7 @@ var generatedTools = [
3637
3653
  $defs: {
3638
3654
  CatalogInclude: {
3639
3655
  type: "string",
3640
- description: "Catalog include expansion. Only AVAILABILITY is supported today; additional include values may be added in the future.",
3656
+ description: "Catalog include expansion. `AVAILABILITY` is the only supported value.",
3641
3657
  enum: ["AVAILABILITY"]
3642
3658
  },
3643
3659
  GpuCloudFilter: {
@@ -3846,6 +3862,99 @@ var generatedTools = [
3846
3862
  required: ["id"]
3847
3863
  }
3848
3864
  },
3865
+ {
3866
+ name: "list-audit-logs",
3867
+ title: "List audit logs",
3868
+ operationId: "listAuditLogs",
3869
+ description: "List audit logs. Returns the account's audit trail, newest first, cursor-paginated; an omitted `limit` defaults to 200. Each entry records who acted (`actorId`, `email`), what they did (`action`), to which resource (`resourceType`, `resourceId`), and the details of the change (`value`). When the caller belongs to an organization the trail is the organization's, and `actorIds` narrows it to specific members; otherwise it is the trail of the account the request acts for. Filters combine with AND. Entries older than the account's audit log retention window are not returned, and an account whose plan does not include audit logs is answered 403. Follow `pagination.nextCursor` until `hasNextPage` is false.",
3870
+ directoryDescription: "List the account's audit trail, newest first. Results are cursor-paginated and record the actor, action, resource, timestamp, and change details. Filters include actor IDs, actions, time range, and text search. The account's retention window and plan determine which entries are available.",
3871
+ method: "GET",
3872
+ path: "/v2/audit-logs",
3873
+ params: [
3874
+ {
3875
+ name: "actorIds",
3876
+ location: "query",
3877
+ explode: false
3878
+ },
3879
+ {
3880
+ name: "actions",
3881
+ location: "query",
3882
+ explode: false
3883
+ },
3884
+ {
3885
+ name: "startTime",
3886
+ location: "query"
3887
+ },
3888
+ {
3889
+ name: "endTime",
3890
+ location: "query"
3891
+ },
3892
+ {
3893
+ name: "search",
3894
+ location: "query"
3895
+ },
3896
+ {
3897
+ name: "cursor",
3898
+ location: "query"
3899
+ },
3900
+ {
3901
+ name: "limit",
3902
+ location: "query"
3903
+ }
3904
+ ],
3905
+ hasBody: false,
3906
+ annotations: {
3907
+ readOnlyHint: true,
3908
+ destructiveHint: false,
3909
+ idempotentHint: true,
3910
+ openWorldHint: true
3911
+ },
3912
+ inputSchema: {
3913
+ type: "object",
3914
+ properties: {
3915
+ actorIds: {
3916
+ type: "array",
3917
+ items: {
3918
+ type: "string"
3919
+ },
3920
+ description: "Only return entries performed by these users. Comma-separated user IDs. Available to organization accounts only; a personal or team account is answered 400."
3921
+ },
3922
+ actions: {
3923
+ type: "array",
3924
+ items: {
3925
+ type: "string"
3926
+ },
3927
+ description: "Only return entries whose `action` is one of these names, matched exactly as recorded. Comma-separated."
3928
+ },
3929
+ startTime: {
3930
+ type: "string",
3931
+ format: "date-time",
3932
+ description: "Earliest instant to include, inclusive (RFC 3339). The account's audit log retention window still applies: entries that have aged out are not returned even when this reaches further back."
3933
+ },
3934
+ endTime: {
3935
+ type: "string",
3936
+ format: "date-time",
3937
+ description: "Latest instant to include, inclusive (RFC 3339). Must be after `startTime` when both are given; 400 otherwise."
3938
+ },
3939
+ search: {
3940
+ type: "string",
3941
+ minLength: 1,
3942
+ description: "Case-insensitive substring match against `email`, `resourceType`, `resourceId`, `action` and `value`; `actorId` is not searched. Surrounding whitespace is ignored."
3943
+ },
3944
+ cursor: {
3945
+ type: "string",
3946
+ minLength: 1,
3947
+ description: "Opaque resume cursor \u2014 pass the previous response's `pagination.nextCursor` through verbatim; omit for the first page. A cursor is only valid for the operation and parameters that issued it; a malformed or foreign cursor is rejected."
3948
+ },
3949
+ limit: {
3950
+ type: "integer",
3951
+ minimum: 1,
3952
+ maximum: 200,
3953
+ description: "Page size, 1\u2013200. Defaults to 200 when omitted."
3954
+ }
3955
+ }
3956
+ }
3957
+ },
3849
3958
  {
3850
3959
  name: "list-billing",
3851
3960
  title: "List billing",
@@ -3893,7 +4002,8 @@ var generatedTools = [
3893
4002
  },
3894
4003
  bucketSize: {
3895
4004
  $ref: "#/$defs/BillingBucketSize",
3896
- description: "Length of each billing time bucket. Defaults to day."
4005
+ description: "Length of each billing time bucket. Defaults to day.",
4006
+ type: "string"
3897
4007
  },
3898
4008
  lastN: {
3899
4009
  type: "integer",
@@ -3905,13 +4015,6 @@ var generatedTools = [
3905
4015
  BillingBucketSize: {
3906
4016
  type: "string",
3907
4017
  enum: ["hour", "day", "week", "month", "year"],
3908
- "x-enum-varnames": [
3909
- "BillingBucketSizeHour",
3910
- "BillingBucketSizeDay",
3911
- "BillingBucketSizeWeek",
3912
- "BillingBucketSizeMonth",
3913
- "BillingBucketSizeYear"
3914
- ],
3915
4018
  default: "day",
3916
4019
  description: "Length of each billing time bucket.",
3917
4020
  examples: ["day"]
@@ -3970,7 +4073,8 @@ var generatedTools = [
3970
4073
  },
3971
4074
  bucketSize: {
3972
4075
  $ref: "#/$defs/BillingBucketSize",
3973
- description: "Length of each billing time bucket. Defaults to day."
4076
+ description: "Length of each billing time bucket. Defaults to day.",
4077
+ type: "string"
3974
4078
  },
3975
4079
  lastN: {
3976
4080
  type: "integer",
@@ -3986,13 +4090,6 @@ var generatedTools = [
3986
4090
  BillingBucketSize: {
3987
4091
  type: "string",
3988
4092
  enum: ["hour", "day", "week", "month", "year"],
3989
- "x-enum-varnames": [
3990
- "BillingBucketSizeHour",
3991
- "BillingBucketSizeDay",
3992
- "BillingBucketSizeWeek",
3993
- "BillingBucketSizeMonth",
3994
- "BillingBucketSizeYear"
3995
- ],
3996
4093
  default: "day",
3997
4094
  description: "Length of each billing time bucket.",
3998
4095
  examples: ["day"]
@@ -4111,7 +4208,7 @@ var generatedTools = [
4111
4208
  items: {
4112
4209
  $ref: "#/$defs/CatalogInclude"
4113
4210
  },
4114
- description: "Comma-separated optional expansions. Supported value today: AVAILABILITY. This may expand with more include values in the future."
4211
+ description: "Comma-separated optional expansions; see `CatalogInclude` for the supported values."
4115
4212
  },
4116
4213
  product: {
4117
4214
  type: "array",
@@ -4130,7 +4227,7 @@ var generatedTools = [
4130
4227
  $defs: {
4131
4228
  CatalogInclude: {
4132
4229
  type: "string",
4133
- description: "Catalog include expansion. Only AVAILABILITY is supported today; additional include values may be added in the future.",
4230
+ description: "Catalog include expansion. `AVAILABILITY` is the only supported value.",
4134
4231
  enum: ["AVAILABILITY"]
4135
4232
  },
4136
4233
  CpuProduct: {
@@ -4336,7 +4433,8 @@ var generatedTools = [
4336
4433
  },
4337
4434
  bucketSize: {
4338
4435
  $ref: "#/$defs/BillingBucketSize",
4339
- description: "Length of each billing time bucket. Defaults to day."
4436
+ description: "Length of each billing time bucket. Defaults to day.",
4437
+ type: "string"
4340
4438
  },
4341
4439
  lastN: {
4342
4440
  type: "integer",
@@ -4348,13 +4446,6 @@ var generatedTools = [
4348
4446
  BillingBucketSize: {
4349
4447
  type: "string",
4350
4448
  enum: ["hour", "day", "week", "month", "year"],
4351
- "x-enum-varnames": [
4352
- "BillingBucketSizeHour",
4353
- "BillingBucketSizeDay",
4354
- "BillingBucketSizeWeek",
4355
- "BillingBucketSizeMonth",
4356
- "BillingBucketSizeYear"
4357
- ],
4358
4449
  default: "day",
4359
4450
  description: "Length of each billing time bucket.",
4360
4451
  examples: ["day"]
@@ -4591,7 +4682,7 @@ var generatedTools = [
4591
4682
  items: {
4592
4683
  $ref: "#/$defs/CatalogInclude"
4593
4684
  },
4594
- description: "Comma-separated optional expansions. Supported value today: AVAILABILITY. This may expand with more include values in the future."
4685
+ description: "Comma-separated optional expansions; see `CatalogInclude` for the supported values."
4595
4686
  },
4596
4687
  product: {
4597
4688
  type: "array",
@@ -4608,7 +4699,8 @@ var generatedTools = [
4608
4699
  },
4609
4700
  cloud: {
4610
4701
  $ref: "#/$defs/GpuCloudFilter",
4611
- description: "Cloud type for availability and lowest-price calculations. Valid only with include=AVAILABILITY. Supported values: SECURE, COMMUNITY. Upstream default when omitted: SECURE."
4702
+ description: "Cloud type for availability and lowest-price calculations. Valid only with include=AVAILABILITY. Supported values: SECURE, COMMUNITY. Upstream default when omitted: SECURE.",
4703
+ type: "string"
4612
4704
  },
4613
4705
  countryCodes: {
4614
4706
  type: "array",
@@ -4635,7 +4727,7 @@ var generatedTools = [
4635
4727
  $defs: {
4636
4728
  CatalogInclude: {
4637
4729
  type: "string",
4638
- description: "Catalog include expansion. Only AVAILABILITY is supported today; additional include values may be added in the future.",
4730
+ description: "Catalog include expansion. `AVAILABILITY` is the only supported value.",
4639
4731
  enum: ["AVAILABILITY"]
4640
4732
  },
4641
4733
  GpuCloudFilter: {
@@ -4702,7 +4794,8 @@ var generatedTools = [
4702
4794
  },
4703
4795
  bucketSize: {
4704
4796
  $ref: "#/$defs/BillingBucketSize",
4705
- description: "Length of each billing time bucket. Defaults to day."
4797
+ description: "Length of each billing time bucket. Defaults to day.",
4798
+ type: "string"
4706
4799
  },
4707
4800
  lastN: {
4708
4801
  type: "integer",
@@ -4718,13 +4811,6 @@ var generatedTools = [
4718
4811
  BillingBucketSize: {
4719
4812
  type: "string",
4720
4813
  enum: ["hour", "day", "week", "month", "year"],
4721
- "x-enum-varnames": [
4722
- "BillingBucketSizeHour",
4723
- "BillingBucketSizeDay",
4724
- "BillingBucketSizeWeek",
4725
- "BillingBucketSizeMonth",
4726
- "BillingBucketSizeYear"
4727
- ],
4728
4814
  default: "day",
4729
4815
  description: "Length of each billing time bucket.",
4730
4816
  examples: ["day"]
@@ -4824,7 +4910,8 @@ var generatedTools = [
4824
4910
  },
4825
4911
  bucketSize: {
4826
4912
  $ref: "#/$defs/BillingBucketSize",
4827
- description: "Length of each billing time bucket. Defaults to day."
4913
+ description: "Length of each billing time bucket. Defaults to day.",
4914
+ type: "string"
4828
4915
  },
4829
4916
  lastN: {
4830
4917
  type: "integer",
@@ -4840,13 +4927,6 @@ var generatedTools = [
4840
4927
  BillingBucketSize: {
4841
4928
  type: "string",
4842
4929
  enum: ["hour", "day", "week", "month", "year"],
4843
- "x-enum-varnames": [
4844
- "BillingBucketSizeHour",
4845
- "BillingBucketSizeDay",
4846
- "BillingBucketSizeWeek",
4847
- "BillingBucketSizeMonth",
4848
- "BillingBucketSizeYear"
4849
- ],
4850
4930
  default: "day",
4851
4931
  description: "Length of each billing time bucket.",
4852
4932
  examples: ["day"]
@@ -4991,6 +5071,7 @@ var generatedTools = [
4991
5071
  title: "List Serverless billing",
4992
5072
  operationId: "listServerlessBilling",
4993
5073
  description: "Get serverless billing history, split into time buckets. SIZE WARNING: with defaults this emits one record per endpoint PER BUCKET \u2014 on an account with many endpoints the response overflows the tool-result limit and becomes unusable. Always pass lastN: 1 (or a bucketSize spanning the whole window) for one record per endpoint, and serverlessId when you need one endpoint. Distinct from pod billing, which covers standalone pods.",
5074
+ directoryDescription: "Get Serverless billing history, split into time buckets. By default the response has one record per endpoint per bucket, which can be very large on accounts with many endpoints; lastN: 1 (or one bucket spanning the whole window) returns one record per endpoint, and serverlessId narrows it to a single endpoint. Pod billing is reported separately.",
4994
5075
  method: "GET",
4995
5076
  path: "/v2/billing/serverless",
4996
5077
  params: [
@@ -5037,7 +5118,8 @@ var generatedTools = [
5037
5118
  },
5038
5119
  bucketSize: {
5039
5120
  $ref: "#/$defs/BillingBucketSize",
5040
- description: "Length of each billing time bucket. Defaults to day."
5121
+ description: "Length of each billing time bucket. Defaults to day.",
5122
+ type: "string"
5041
5123
  },
5042
5124
  lastN: {
5043
5125
  type: "integer",
@@ -5053,13 +5135,6 @@ var generatedTools = [
5053
5135
  BillingBucketSize: {
5054
5136
  type: "string",
5055
5137
  enum: ["hour", "day", "week", "month", "year"],
5056
- "x-enum-varnames": [
5057
- "BillingBucketSizeHour",
5058
- "BillingBucketSizeDay",
5059
- "BillingBucketSizeWeek",
5060
- "BillingBucketSizeMonth",
5061
- "BillingBucketSizeYear"
5062
- ],
5063
5138
  default: "day",
5064
5139
  description: "Length of each billing time bucket.",
5065
5140
  examples: ["day"]
@@ -5094,7 +5169,8 @@ var generatedTools = [
5094
5169
  type: "string"
5095
5170
  },
5096
5171
  body: {
5097
- $ref: "#/$defs/PodActionRequest"
5172
+ $ref: "#/$defs/PodActionRequest",
5173
+ type: "object"
5098
5174
  }
5099
5175
  },
5100
5176
  required: ["id", "body"],
@@ -5164,7 +5240,7 @@ var generatedTools = [
5164
5240
  annotations: {
5165
5241
  readOnlyHint: false,
5166
5242
  destructiveHint: false,
5167
- idempotentHint: false,
5243
+ idempotentHint: true,
5168
5244
  openWorldHint: true
5169
5245
  },
5170
5246
  inputSchema: {
@@ -5175,7 +5251,8 @@ var generatedTools = [
5175
5251
  description: "Cluster identifier"
5176
5252
  },
5177
5253
  body: {
5178
- $ref: "#/$defs/UpdateClusterRequest"
5254
+ $ref: "#/$defs/UpdateClusterRequest",
5255
+ type: "object"
5179
5256
  }
5180
5257
  },
5181
5258
  required: ["id", "body"],
@@ -5201,6 +5278,7 @@ var generatedTools = [
5201
5278
  title: "Update endpoint",
5202
5279
  operationId: "updateEndpoint",
5203
5280
  description: "Partially update a serverless endpoint (PATCH): only fields present in the body change, omitted ones are untouched, with one exception. DESTRUCTIVE GOTCHA: gpu.pools and gpu.excludedTypes are a single selection, so sending pools without excludedTypes clears any exclusions pinned elsewhere (the console or set-endpoint-gpus) \u2014 read the endpoint first with get-endpoint and resend excludedTypes if you still want them. An exclusion naming a type outside pools returns 400. A CUDA-only or count-only change does not need pools at all, so omit it unless you mean to replace the selection. Mutable fields: name, gpu, cpu, workers (min/max/idleTimeout), scaling (type plus queueDelay or requestCount), dataCenterIds, networkVolumes, timeout, flashboot, and the container settings (image, args, disk, ports, env, registry). cpu completely replaces a CPU endpoint's flavor selection. Compute family is immutable: gpu on a CPU endpoint, cpu on a GPU one, or both, returns 400. Effect timing differs by field \u2014 workers/scaling/timeout reach the autoscaler promptly, while container changes (image, env) cut a new release that rolls out as workers cycle, so in-flight workers keep the previous version. Track rollout with list-endpoint-releases.",
5281
+ directoryDescription: "Partially update a Serverless endpoint (PATCH): only fields present in the body change. gpu.pools and gpu.excludedTypes are one selection, so sending pools without excludedTypes clears existing exclusions; an exclusion naming a type outside pools returns 400, and a CUDA-only or count-only change does not need pools. Mutable fields: name, gpu, cpu, workers (min/max/idleTimeout), scaling (type plus queueDelay or requestCount), dataCenterIds, networkVolumes, timeout, flashboot, and the container settings (image, args, disk, ports, env, registry). cpu replaces a CPU endpoint's whole flavor selection. The compute family is fixed: gpu on a CPU endpoint, cpu on a GPU one, or both returns 400. Worker, scaling and timeout changes apply promptly; container changes (image, env) create a new release that rolls out as workers cycle, so in-flight workers keep the previous version.",
5204
5282
  method: "PATCH",
5205
5283
  path: "/v2/serverless/{id}",
5206
5284
  params: [
@@ -5212,7 +5290,7 @@ var generatedTools = [
5212
5290
  hasBody: true,
5213
5291
  annotations: {
5214
5292
  readOnlyHint: false,
5215
- destructiveHint: false,
5293
+ destructiveHint: true,
5216
5294
  idempotentHint: false,
5217
5295
  openWorldHint: true
5218
5296
  },
@@ -5225,7 +5303,8 @@ var generatedTools = [
5225
5303
  description: "Serverless endpoint identifier"
5226
5304
  },
5227
5305
  body: {
5228
- $ref: "#/$defs/UpdateEndpointRequest"
5306
+ $ref: "#/$defs/UpdateEndpointRequest",
5307
+ type: "object"
5229
5308
  }
5230
5309
  },
5231
5310
  required: ["id", "body"],
@@ -5274,7 +5353,7 @@ var generatedTools = [
5274
5353
  description: "Environment variables as key-value pairs",
5275
5354
  examples: [
5276
5355
  {
5277
- JUPYTER_PASSWORD: "hunter2"
5356
+ JUPYTER_PASSWORD: "changeme"
5278
5357
  }
5279
5358
  ]
5280
5359
  },
@@ -5371,7 +5450,7 @@ var generatedTools = [
5371
5450
  type: "object",
5372
5451
  required: ["volumeId"],
5373
5452
  additionalProperties: false,
5374
- description: "A volume mounted on every worker, always at `/runpod-volume`. Custom paths are not supported yet.",
5453
+ description: "A volume mounted on every worker, always at `/runpod-volume`.",
5375
5454
  properties: {
5376
5455
  volumeId: {
5377
5456
  type: "string",
@@ -5604,7 +5683,7 @@ var generatedTools = [
5604
5683
  annotations: {
5605
5684
  readOnlyHint: false,
5606
5685
  destructiveHint: false,
5607
- idempotentHint: false,
5686
+ idempotentHint: true,
5608
5687
  openWorldHint: true
5609
5688
  },
5610
5689
  inputSchema: {
@@ -5615,7 +5694,8 @@ var generatedTools = [
5615
5694
  description: "Global volume identifier"
5616
5695
  },
5617
5696
  body: {
5618
- $ref: "#/$defs/UpdateGlobalVolumeRequest"
5697
+ $ref: "#/$defs/UpdateGlobalVolumeRequest",
5698
+ type: "object"
5619
5699
  }
5620
5700
  },
5621
5701
  required: ["id", "body"],
@@ -5630,7 +5710,6 @@ var generatedTools = [
5630
5710
  type: "string",
5631
5711
  minLength: 1,
5632
5712
  maxLength: 191,
5633
- pattern: "[^\\p{Z}\\t-\\r\x85]",
5634
5713
  description: "New human-readable name, 1\u2013191 characters with at least one non-whitespace character. Leading and trailing whitespace is trimmed.",
5635
5714
  examples: ["renamed-volume"]
5636
5715
  }
@@ -5656,7 +5735,7 @@ var generatedTools = [
5656
5735
  annotations: {
5657
5736
  readOnlyHint: false,
5658
5737
  destructiveHint: false,
5659
- idempotentHint: false,
5738
+ idempotentHint: true,
5660
5739
  openWorldHint: true
5661
5740
  },
5662
5741
  inputSchema: {
@@ -5667,7 +5746,8 @@ var generatedTools = [
5667
5746
  description: "Network volume identifier"
5668
5747
  },
5669
5748
  body: {
5670
- $ref: "#/$defs/UpdateNetworkVolumeRequest"
5749
+ $ref: "#/$defs/UpdateNetworkVolumeRequest",
5750
+ type: "object"
5671
5751
  }
5672
5752
  },
5673
5753
  required: ["id", "body"],
@@ -5712,7 +5792,7 @@ var generatedTools = [
5712
5792
  hasBody: true,
5713
5793
  annotations: {
5714
5794
  readOnlyHint: false,
5715
- destructiveHint: false,
5795
+ destructiveHint: true,
5716
5796
  idempotentHint: false,
5717
5797
  openWorldHint: true
5718
5798
  },
@@ -5725,7 +5805,8 @@ var generatedTools = [
5725
5805
  description: "Pod identifier"
5726
5806
  },
5727
5807
  body: {
5728
- $ref: "#/$defs/UpdatePodRequest"
5808
+ $ref: "#/$defs/UpdatePodRequest",
5809
+ type: "object"
5729
5810
  }
5730
5811
  },
5731
5812
  required: ["id", "body"],
@@ -5774,7 +5855,7 @@ var generatedTools = [
5774
5855
  description: "Environment variables as key-value pairs",
5775
5856
  examples: [
5776
5857
  {
5777
- JUPYTER_PASSWORD: "hunter2"
5858
+ JUPYTER_PASSWORD: "changeme"
5778
5859
  }
5779
5860
  ]
5780
5861
  },
@@ -5912,7 +5993,7 @@ var generatedTools = [
5912
5993
  properties: {
5913
5994
  globalNetworking: {
5914
5995
  type: "boolean",
5915
- description: "Enable (true) or disable (false) global networking. Takes effect on the next pod start/restart, not live. Requires an NVIDIA GPU and a global-networking-enabled data center (both enforced upstream)."
5996
+ description: "Enable (true) or disable (false) global networking. Takes effect on the next pod start/restart, not live. Requires an NVIDIA GPU and a global-networking-enabled data center."
5916
5997
  },
5917
5998
  locked: {
5918
5999
  type: "boolean",
@@ -5954,7 +6035,7 @@ var generatedTools = [
5954
6035
  hasBody: true,
5955
6036
  annotations: {
5956
6037
  readOnlyHint: false,
5957
- destructiveHint: false,
6038
+ destructiveHint: true,
5958
6039
  idempotentHint: false,
5959
6040
  openWorldHint: true
5960
6041
  },
@@ -5967,7 +6048,8 @@ var generatedTools = [
5967
6048
  description: "Secret identifier"
5968
6049
  },
5969
6050
  body: {
5970
- $ref: "#/$defs/UpdateSecretRequest"
6051
+ $ref: "#/$defs/UpdateSecretRequest",
6052
+ type: "object"
5971
6053
  }
5972
6054
  },
5973
6055
  required: ["id", "body"],
@@ -6013,7 +6095,8 @@ var generatedTools = [
6013
6095
  type: "object",
6014
6096
  properties: {
6015
6097
  body: {
6016
- $ref: "#/$defs/UpdateSshKeysRequest"
6098
+ $ref: "#/$defs/UpdateSshKeysRequest",
6099
+ type: "object"
6017
6100
  }
6018
6101
  },
6019
6102
  required: ["body"],
@@ -6057,8 +6140,8 @@ var generatedTools = [
6057
6140
  hasBody: true,
6058
6141
  annotations: {
6059
6142
  readOnlyHint: false,
6060
- destructiveHint: false,
6061
- idempotentHint: false,
6143
+ destructiveHint: true,
6144
+ idempotentHint: true,
6062
6145
  openWorldHint: true
6063
6146
  },
6064
6147
  schemaOnDemand: true,
@@ -6069,7 +6152,8 @@ var generatedTools = [
6069
6152
  type: "string"
6070
6153
  },
6071
6154
  body: {
6072
- $ref: "#/$defs/UpdateTemplateRequest"
6155
+ $ref: "#/$defs/UpdateTemplateRequest",
6156
+ type: "object"
6073
6157
  }
6074
6158
  },
6075
6159
  required: ["id", "body"],
@@ -6118,7 +6202,7 @@ var generatedTools = [
6118
6202
  description: "Environment variables as key-value pairs",
6119
6203
  examples: [
6120
6204
  {
6121
- JUPYTER_PASSWORD: "hunter2"
6205
+ JUPYTER_PASSWORD: "changeme"
6122
6206
  }
6123
6207
  ]
6124
6208
  },
@@ -6238,80 +6322,43 @@ var generatedTools = [
6238
6322
  }
6239
6323
  ];
6240
6324
 
6241
- // src/specgen/pagination.ts
6242
- var DEFAULT_LIST_LIMIT = 20;
6243
- var MAX_LIST_LIMIT = 100;
6244
- var listPaginationProperties = {
6245
- limit: {
6246
- type: "integer",
6247
- minimum: 1,
6248
- maximum: MAX_LIST_LIMIT,
6249
- description: `Maximum number of items to return (default ${DEFAULT_LIST_LIMIT}, max ${MAX_LIST_LIMIT}). Use the returned nextCursor to fetch the next page.`
6250
- },
6251
- cursor: {
6252
- type: "string",
6253
- description: "Opaque pagination cursor from a previous response (nextCursor). Omit to start from the beginning."
6254
- }
6325
+ // src/specgen/tools/annotations.ts
6326
+ var readOnly = {
6327
+ readOnlyHint: true,
6328
+ destructiveHint: false,
6329
+ idempotentHint: true,
6330
+ openWorldHint: true
6331
+ };
6332
+ var bundledRead = {
6333
+ readOnlyHint: true,
6334
+ destructiveHint: false,
6335
+ idempotentHint: true,
6336
+ openWorldHint: false
6337
+ };
6338
+ var write = {
6339
+ readOnlyHint: false,
6340
+ destructiveHint: false,
6341
+ idempotentHint: false,
6342
+ openWorldHint: true
6343
+ };
6344
+ var idempotentWrite = {
6345
+ readOnlyHint: false,
6346
+ destructiveHint: false,
6347
+ idempotentHint: true,
6348
+ openWorldHint: true
6349
+ };
6350
+ var destructive = {
6351
+ readOnlyHint: false,
6352
+ destructiveHint: true,
6353
+ idempotentHint: true,
6354
+ openWorldHint: true
6355
+ };
6356
+ var destructiveWrite = {
6357
+ readOnlyHint: false,
6358
+ destructiveHint: true,
6359
+ idempotentHint: false,
6360
+ openWorldHint: true
6255
6361
  };
6256
- function clampListLimit(limit) {
6257
- const requested = Number(limit);
6258
- return Math.min(
6259
- Number.isFinite(requested) && requested >= 1 ? Math.floor(requested) : DEFAULT_LIST_LIMIT,
6260
- MAX_LIST_LIMIT
6261
- );
6262
- }
6263
- function serverPageQuery(args) {
6264
- const cursor = typeof args.cursor === "string" && args.cursor !== "" ? args.cursor : void 0;
6265
- return { limit: clampListLimit(args.limit), ...cursor ? { cursor } : {} };
6266
- }
6267
- function serverPagination(pagination, returned) {
6268
- const hasNextPage = pagination?.hasNextPage === true;
6269
- return {
6270
- returned,
6271
- hasNextPage,
6272
- nextCursor: pagination?.nextCursor ?? null,
6273
- ...hasNextPage ? { note: "More results exist. Pass cursor=nextCursor to fetch them." } : {}
6274
- };
6275
- }
6276
- function decodeCursorOffset(cursor) {
6277
- if (!cursor) return 0;
6278
- try {
6279
- const decoded = Buffer.from(cursor, "base64").toString("utf8");
6280
- if (!/^\d+$/.test(decoded)) return 0;
6281
- const offset = Number.parseInt(decoded, 10);
6282
- return Number.isFinite(offset) && offset >= 0 ? offset : 0;
6283
- } catch {
6284
- return 0;
6285
- }
6286
- }
6287
- function encodeCursorOffset(offset) {
6288
- return Buffer.from(String(offset), "utf8").toString("base64");
6289
- }
6290
- function capList(items, options, extra) {
6291
- const limit = clampListLimit(options.limit);
6292
- const offset = decodeCursorOffset(options.cursor);
6293
- const total = items.length;
6294
- const page = items.slice(offset, offset + limit);
6295
- const nextOffset = offset + page.length;
6296
- const hasMore = nextOffset < total;
6297
- const { items: _i, pagination: _p, ...safeExtra } = extra ?? {};
6298
- void _i;
6299
- void _p;
6300
- return {
6301
- ...safeExtra,
6302
- items: page,
6303
- pagination: {
6304
- total,
6305
- returned: page.length,
6306
- offset,
6307
- truncated: hasMore,
6308
- nextCursor: hasMore ? encodeCursorOffset(nextOffset) : null,
6309
- ...hasMore ? {
6310
- note: `Showing ${page.length} of ${total}. Pass cursor=nextCursor to fetch more, or narrow the query with filters.`
6311
- } : {}
6312
- }
6313
- };
6314
- }
6315
6362
 
6316
6363
  // src/specgen/clients/http-error.ts
6317
6364
  var HttpError = class extends Error {
@@ -6406,37 +6453,270 @@ async function runTool(body) {
6406
6453
  }
6407
6454
  }
6408
6455
 
6409
- // src/specgen/tools/annotations.ts
6410
- var readOnly = {
6411
- readOnlyHint: true,
6412
- destructiveHint: false,
6413
- idempotentHint: true,
6414
- openWorldHint: true
6415
- };
6416
- var bundledRead = {
6417
- readOnlyHint: true,
6418
- destructiveHint: false,
6419
- idempotentHint: true,
6420
- openWorldHint: false
6421
- };
6422
- var write = {
6423
- readOnlyHint: false,
6424
- destructiveHint: false,
6425
- idempotentHint: false,
6426
- openWorldHint: true
6456
+ // src/specgen/tools/pod-transitions.ts
6457
+ var podAction = generatedTools.find((tool) => tool.name === "pod-action");
6458
+ if (!podAction)
6459
+ throw new Error("pod-action is missing from the generated tools");
6460
+ var POD_ID = {
6461
+ type: "object",
6462
+ properties: { id: { type: "string", description: "ID of the Pod" } },
6463
+ required: ["id"],
6464
+ additionalProperties: false
6427
6465
  };
6428
- var idempotentWrite = {
6429
- readOnlyHint: false,
6430
- destructiveHint: false,
6431
- idempotentHint: true,
6432
- openWorldHint: true
6466
+ function transition(action, title, description, annotations) {
6467
+ return {
6468
+ name: `${action}-pod`,
6469
+ title,
6470
+ description,
6471
+ inputSchema: POD_ID,
6472
+ annotations,
6473
+ handler: (ctx, args) => runTool(
6474
+ () => dispatchGeneratedTool(ctx.sdk, podAction, {
6475
+ id: args.id,
6476
+ body: { action }
6477
+ })
6478
+ )
6479
+ };
6480
+ }
6481
+ var podTransitionTools = [
6482
+ transition(
6483
+ "start",
6484
+ "Start Pod",
6485
+ "Start a stopped Pod (status EXITED or ERROR). Billable: the Pod accrues its hourly price while it runs. Returns the updated Pod; a Pod in any other status returns 409.",
6486
+ write
6487
+ ),
6488
+ transition(
6489
+ "stop",
6490
+ "Stop Pod",
6491
+ "Stop a running or provisioning Pod. It releases its GPU or CPU and stops compute billing; the container disk is wiped, while the volume disk and any attached network volume keep their data and volume storage keeps billing. Returns the updated Pod; a Pod in any other status returns 409.",
6492
+ destructiveWrite
6493
+ ),
6494
+ transition(
6495
+ "restart",
6496
+ "Restart Pod",
6497
+ "Restart a running Pod's container in place. Whatever is running in the container is interrupted and the container disk is wiped; the volume disk and any attached network volume keep their data. Returns the updated Pod; a Pod that is not RUNNING returns 409.",
6498
+ destructiveWrite
6499
+ )
6500
+ ];
6501
+
6502
+ // src/specgen/profile.ts
6503
+ var IN = { include: true };
6504
+ var CREDENTIAL_MANAGEMENT = "Manages stored credentials; OpenAI restricts plugins that handle access credentials, so the directory leaves the whole credential family out.";
6505
+ var CREDENTIAL_INPUT = "Takes a secret or password as input; directories forbid collecting credentials.";
6506
+ var ALP = "Collects conversation-derived data beyond the task; the directory profile never serves it.";
6507
+ var DIRECTORY_TOOLS = {
6508
+ "cancel-job": IN,
6509
+ "create-cluster": IN,
6510
+ "create-delegation": IN,
6511
+ "create-endpoint": IN,
6512
+ "create-global-volume": IN,
6513
+ "create-network-volume": IN,
6514
+ "create-pod": IN,
6515
+ "create-template": IN,
6516
+ "delete-cluster": IN,
6517
+ "delete-endpoint": IN,
6518
+ "delete-global-volume": IN,
6519
+ "delete-network-volume": IN,
6520
+ "delete-pod": IN,
6521
+ "delete-template": IN,
6522
+ "deploy-hub-repo": IN,
6523
+ "endpoint-health": IN,
6524
+ "get-capacity": IN,
6525
+ "get-cluster": IN,
6526
+ "get-cpu-type": IN,
6527
+ "get-data-center": IN,
6528
+ "get-endpoint": IN,
6529
+ "get-endpoint-build": IN,
6530
+ "get-global-volume": IN,
6531
+ "get-gpu-type": IN,
6532
+ "get-job-status": IN,
6533
+ "get-network-volume": IN,
6534
+ "get-organization": IN,
6535
+ "get-pod": IN,
6536
+ "get-ssh-keys": IN,
6537
+ "get-template": IN,
6538
+ "list-audit-logs": IN,
6539
+ "list-billing": IN,
6540
+ "list-cluster-billing": IN,
6541
+ "list-cluster-pods": IN,
6542
+ "list-clusters": IN,
6543
+ "list-cpu-types": IN,
6544
+ "list-data-centers": IN,
6545
+ "list-delegations": IN,
6546
+ "list-endpoint-billing": IN,
6547
+ "list-endpoint-builds": IN,
6548
+ "list-endpoint-releases": IN,
6549
+ "list-endpoint-workers": IN,
6550
+ "list-endpoints": IN,
6551
+ "list-global-volumes": IN,
6552
+ "list-gpu-types": IN,
6553
+ "list-hub-repos": IN,
6554
+ "list-network-volume-billing": IN,
6555
+ "list-network-volumes": IN,
6556
+ "list-pod-billing": IN,
6557
+ "list-pods": IN,
6558
+ "list-public-endpoints": IN,
6559
+ "list-public-templates": IN,
6560
+ "list-serverless-billing": IN,
6561
+ "list-templates": IN,
6562
+ "lookup-concept": IN,
6563
+ "purge-endpoint-queue": IN,
6564
+ "retry-job": IN,
6565
+ "revoke-delegation": IN,
6566
+ "search-concepts": IN,
6567
+ "search-docs": IN,
6568
+ "set-endpoint-gpus": IN,
6569
+ "stream-job": IN,
6570
+ "stream-pod-logs": IN,
6571
+ "stream-worker-logs": IN,
6572
+ "update-cluster": IN,
6573
+ "update-endpoint": IN,
6574
+ "update-global-volume": IN,
6575
+ "update-network-volume": IN,
6576
+ "update-pod": IN,
6577
+ "update-ssh-keys": IN,
6578
+ "update-template": IN,
6579
+ "run-endpoint": { include: true, omitInputs: ["s3Config"] },
6580
+ "runsync-endpoint": { include: true, omitInputs: ["s3Config"] },
6581
+ "pod-action": {
6582
+ include: false,
6583
+ reason: "Takes the transition as an argument; OpenAI asks for one tool per operation, so the directory serves start-pod, stop-pod and restart-pod (terminate is delete-pod)."
6584
+ },
6585
+ "start-pod": IN,
6586
+ "stop-pod": IN,
6587
+ "restart-pod": IN,
6588
+ "list-guides": {
6589
+ include: false,
6590
+ reason: "Serves playbooks that instruct the model how to behave."
6591
+ },
6592
+ "read-guide": {
6593
+ include: false,
6594
+ reason: "Serves playbooks that instruct the model how to behave."
6595
+ },
6596
+ "describe-tool": {
6597
+ include: false,
6598
+ reason: "Fetches schemas the directory already lists in full; directories reject schema fetching."
6599
+ },
6600
+ "create-secret": { include: false, reason: CREDENTIAL_INPUT },
6601
+ "get-secret": { include: false, reason: CREDENTIAL_MANAGEMENT },
6602
+ "list-secrets": { include: false, reason: CREDENTIAL_MANAGEMENT },
6603
+ "delete-secret": { include: false, reason: CREDENTIAL_MANAGEMENT },
6604
+ "get-registry": { include: false, reason: CREDENTIAL_MANAGEMENT },
6605
+ "list-registries": { include: false, reason: CREDENTIAL_MANAGEMENT },
6606
+ "delete-registry": { include: false, reason: CREDENTIAL_MANAGEMENT },
6607
+ "update-secret": { include: false, reason: CREDENTIAL_INPUT },
6608
+ "create-registry": { include: false, reason: CREDENTIAL_INPUT },
6609
+ report_feedback: { include: false, reason: ALP },
6610
+ report_how_user_found_runpod: { include: false, reason: ALP },
6611
+ save_to_journal: { include: false, reason: ALP },
6612
+ read_journal: { include: false, reason: ALP },
6613
+ ask_question: { include: false, reason: ALP }
6433
6614
  };
6434
- var destructive = {
6435
- readOnlyHint: false,
6436
- destructiveHint: true,
6437
- idempotentHint: true,
6438
- openWorldHint: true
6615
+ function directoryIncludes(name) {
6616
+ return DIRECTORY_TOOLS[name]?.include === true;
6617
+ }
6618
+ function directoryOmittedInputs(name) {
6619
+ const decision = DIRECTORY_TOOLS[name];
6620
+ return decision?.include ? decision.omitInputs ?? [] : [];
6621
+ }
6622
+
6623
+ // src/specgen/redact.ts
6624
+ var REDACTED = "[redacted]";
6625
+ var SECRET_KEY = /pass(word|wd)?|secret|token|api_?key|private_?key|credential|auth/i;
6626
+ var SECRET_REFERENCE = /^\s*\{\{\s*RUNPOD_SECRET_[^}]+\}\}\s*$/;
6627
+ function redactEnv(env) {
6628
+ return Object.fromEntries(
6629
+ Object.entries(env).map(([key, value]) => [
6630
+ key,
6631
+ typeof value === "string" && value !== "" && SECRET_KEY.test(key) && !SECRET_REFERENCE.test(value) ? REDACTED : value
6632
+ ])
6633
+ );
6634
+ }
6635
+ function redactSecretEnv(payload) {
6636
+ if (Array.isArray(payload)) return payload.map(redactSecretEnv);
6637
+ if (!payload || typeof payload !== "object") return payload;
6638
+ return Object.fromEntries(
6639
+ Object.entries(payload).map(([key, value]) => [
6640
+ key,
6641
+ key === "env" && value && typeof value === "object" && !Array.isArray(value) ? redactEnv(value) : redactSecretEnv(value)
6642
+ ])
6643
+ );
6644
+ }
6645
+
6646
+ // src/specgen/pagination.ts
6647
+ var DEFAULT_LIST_LIMIT = 20;
6648
+ var MAX_LIST_LIMIT = 100;
6649
+ var listPaginationProperties = {
6650
+ limit: {
6651
+ type: "integer",
6652
+ minimum: 1,
6653
+ maximum: MAX_LIST_LIMIT,
6654
+ description: `Maximum number of items to return (default ${DEFAULT_LIST_LIMIT}, max ${MAX_LIST_LIMIT}). Use the returned nextCursor to fetch the next page.`
6655
+ },
6656
+ cursor: {
6657
+ type: "string",
6658
+ description: "Opaque pagination cursor from a previous response (nextCursor). Omit to start from the beginning."
6659
+ }
6439
6660
  };
6661
+ function clampListLimit(limit) {
6662
+ const requested = Number(limit);
6663
+ return Math.min(
6664
+ Number.isFinite(requested) && requested >= 1 ? Math.floor(requested) : DEFAULT_LIST_LIMIT,
6665
+ MAX_LIST_LIMIT
6666
+ );
6667
+ }
6668
+ function serverPageQuery(args) {
6669
+ const cursor = typeof args.cursor === "string" && args.cursor !== "" ? args.cursor : void 0;
6670
+ return { limit: clampListLimit(args.limit), ...cursor ? { cursor } : {} };
6671
+ }
6672
+ function serverPagination(pagination, returned) {
6673
+ const hasNextPage = pagination?.hasNextPage === true;
6674
+ return {
6675
+ returned,
6676
+ hasNextPage,
6677
+ nextCursor: pagination?.nextCursor ?? null,
6678
+ ...hasNextPage ? { note: "More results exist. Pass cursor=nextCursor to fetch them." } : {}
6679
+ };
6680
+ }
6681
+ function decodeCursorOffset(cursor) {
6682
+ if (!cursor) return 0;
6683
+ try {
6684
+ const decoded = Buffer.from(cursor, "base64").toString("utf8");
6685
+ if (!/^\d+$/.test(decoded)) return 0;
6686
+ const offset = Number.parseInt(decoded, 10);
6687
+ return Number.isFinite(offset) && offset >= 0 ? offset : 0;
6688
+ } catch {
6689
+ return 0;
6690
+ }
6691
+ }
6692
+ function encodeCursorOffset(offset) {
6693
+ return Buffer.from(String(offset), "utf8").toString("base64");
6694
+ }
6695
+ function capList(items, options, extra) {
6696
+ const limit = clampListLimit(options.limit);
6697
+ const offset = decodeCursorOffset(options.cursor);
6698
+ const total = items.length;
6699
+ const page = items.slice(offset, offset + limit);
6700
+ const nextOffset = offset + page.length;
6701
+ const hasMore = nextOffset < total;
6702
+ const { items: _i, pagination: _p, ...safeExtra } = extra ?? {};
6703
+ void _i;
6704
+ void _p;
6705
+ return {
6706
+ ...safeExtra,
6707
+ items: page,
6708
+ pagination: {
6709
+ total,
6710
+ returned: page.length,
6711
+ offset,
6712
+ truncated: hasMore,
6713
+ nextCursor: hasMore ? encodeCursorOffset(nextOffset) : null,
6714
+ ...hasMore ? {
6715
+ note: `Showing ${page.length} of ${total}. Pass cursor=nextCursor to fetch more, or narrow the query with filters.`
6716
+ } : {}
6717
+ }
6718
+ };
6719
+ }
6440
6720
 
6441
6721
  // src/specgen/tools/capacity.ts
6442
6722
  var CUDA_VERSION_REGEX = /^\d{1,2}\.\d{1,2}$/;
@@ -6473,6 +6753,7 @@ function rankByStock(rows, stats, includeUnavailable) {
6473
6753
  var getCapacity = {
6474
6754
  name: "get-capacity",
6475
6755
  title: "Get GPU capacity by CUDA version",
6756
+ directoryDescription: "GPU capacity across host CUDA versions, as a matrix. By default one call returns, for each GPU type, overall stock plus AVAILABLE or UNAVAILABLE per host CUDA version. With cudaVersions it checks each listed version and returns graded stock (High, Medium, Low, Out) and the lowest on-demand price per version; a check that fails transiently reports an error for that version only. Out-of-stock GPUs are included unless includeUnavailable is false. Live public catalog data, so page cursors can shift between calls.",
6476
6757
  annotations: readOnly,
6477
6758
  description: "GPU capacity across host CUDA versions, as a matrix. Use this to choose an endpoint's allowedCudaVersions/minCudaVersion (or diagnose/widen a capacity-starved one) and to distinguish capacity problems from compatibility problems. Default mode is one call returning, per GPU type, overall stock plus AVAILABLE/UNAVAILABLE per host-reported CUDA version. Pass cudaVersions to deep-probe instead: one stock lookup per listed version, returning graded stock (High/Medium/Low/Out) and the lowest on-demand price per version; a probe that fails transiently reports a per-version error instead of failing the call. Nothing is hidden by default \u2014 set includeUnavailable:false to drop GPUs with no stock on any listed version. Credential-free public catalog data. Stock is live, so page cursors can shift between calls.",
6478
6759
  inputSchema: {
@@ -6675,7 +6956,9 @@ function formatGpuIds(gpu) {
6675
6956
  var setEndpointGpus = {
6676
6957
  name: "set-endpoint-gpus",
6677
6958
  title: "Set endpoint GPUs",
6678
- annotations: idempotentWrite,
6959
+ directoryDescription: "Set which GPUs a Serverless endpoint's workers run on, including pinning specific GPU types. Takes either a raw gpuIds string, or pools plus optional excludeGpuTypeIds, from which the exclusion string is built: a pool allows every GPU type in it, and excluding all but one pins that type. Changes only GPU settings and keeps the endpoint's other settings.",
6960
+ // Replaces the whole GPU selection: exclusions not resent are cleared.
6961
+ annotations: destructive,
6679
6962
  description: "Set which GPUs a Serverless endpoint's workers run on \u2014 including pinning specific GPU SKUs. Provide either a raw gpuIds string, or pools plus optional excludeGpuTypeIds (GPU type ids from list-gpu-types) and the exclusion string is built for you: a pool allows every SKU in it, and excluding all but one SKU pins that SKU exactly. Updates only GPU settings through REST v2, preserving other endpoint settings. create-endpoint/update-endpoint also support gpu.excludedTypes.",
6680
6963
  inputSchema: {
6681
6964
  type: "object",
@@ -6870,6 +7153,7 @@ function randomSuffix() {
6870
7153
  var listHubRepos = {
6871
7154
  name: "list-hub-repos",
6872
7155
  title: "List Hub repos",
7156
+ directoryDescription: "List repos published to the Runpod Hub (prebuilt Serverless workers and Pod templates, such as vLLM and ComfyUI), sorted by deploy count. Public catalog; no sign-in needed. Each result includes the listed release with its hubReleaseId and image name. includeConfig: true adds each release's config (hardware requirements and environment-variable schema), which is large; repoOwner and searchTerm narrow the list.",
6873
7157
  annotations: readOnly,
6874
7158
  description: "List repos published to the Runpod Hub (prebuilt Serverless workers and Pod templates, e.g. vLLM, ComfyUI). Public catalog \u2014 no auth required. Each result includes the currently listed release with its hubReleaseId and prebuilt image name. Results are sorted by deploy count (most popular first). Set includeConfig:true to also return the release config (hardware requirements and environment-variable schema) \u2014 it is large, so prefer requesting it for a single repo via the repoOwner/searchTerm filters.",
6875
7159
  inputSchema: {
@@ -6973,6 +7257,7 @@ var listHubRepos = {
6973
7257
  var deployHubRepo = {
6974
7258
  name: "deploy-hub-repo",
6975
7259
  title: "Deploy Hub repo",
7260
+ directoryDescription: `Deploy a Runpod Hub repo's listed release as a new Serverless endpoint, the same as clicking Deploy on the Hub. Identifies the repo by repo ("owner/name") or hubReleaseId. The release supplies the image, container disk, CUDA constraints and environment-variable defaults; env overrides or fills in values, and keys the release requires without a default have to be supplied. GPUs come from the release config when it sets them, otherwise from gpuIds (pool names such as 'ADA_24'). Billable while the endpoint's workers run.`,
6976
7261
  // Two sequential upstream calls: together they can outlast a client's request timeout.
6977
7262
  holdsResponse: true,
6978
7263
  annotations: write,
@@ -7434,6 +7719,7 @@ function validateWait(wait) {
7434
7719
  var runEndpoint = {
7435
7720
  name: "run-endpoint",
7436
7721
  title: "Submit Serverless job",
7722
+ directoryDescription: "Submit an asynchronous job to a Serverless endpoint. Returns a job ID immediately; the result stays available for 30 minutes after the job completes.",
7437
7723
  annotations: write,
7438
7724
  description: "Submit an asynchronous job to a Serverless endpoint. Returns a job ID immediately \u2014 use get-job-status to poll for results (pass its `wait` to block through a cold start instead of tight-looping). Async results are available for 30 minutes after completion.",
7439
7725
  inputSchema: {
@@ -7465,6 +7751,7 @@ var runEndpoint = {
7465
7751
  var runsyncEndpoint = {
7466
7752
  name: "runsync-endpoint",
7467
7753
  title: "Run Serverless job and wait",
7754
+ directoryDescription: `Submit a synchronous job to a Serverless endpoint and wait up to ${HTTP_LONG_POLL_BUDGET_MS} ms for the result. If the job outlives the wait, the response carries the job ID and its current status (IN_QUEUE or IN_PROGRESS). Maximum payload 20 MB; results expire 1 minute after completion.`,
7468
7755
  holdsResponse: true,
7469
7756
  annotations: write,
7470
7757
  description: "Submit a synchronous job to a Serverless endpoint and wait for the result. Best for fast tasks: if the job outlives the wait, the response returns a job ID and a non-terminal status (IN_QUEUE or IN_PROGRESS) to poll with get-job-status. Max payload 20 MB; results expire after 1 minute. The wait parameter extends the server-side wait" + (HOSTED ? ` \u2014 this server runs behind a 60-second gateway deadline, so waits clamp to ${HTTP_LONG_POLL_BUDGET_MS} ms, which is also the effective default. For longer jobs use run-endpoint + get-job-status.` : " to up to 5 minutes (300000 ms); it defaults to 90000 (90 seconds)."),
@@ -7511,6 +7798,7 @@ var runsyncEndpoint = {
7511
7798
  var getJobStatus = {
7512
7799
  name: "get-job-status",
7513
7800
  title: "Get job status",
7801
+ directoryDescription: `Get the status of a Serverless job, and its output once it completes. Statuses: IN_QUEUE, IN_PROGRESS, COMPLETED, FAILED, CANCELLED, TIMED_OUT. With wait (milliseconds, up to ${HTTP_LONG_POLL_BUDGET_MS}) the server polls until the job reaches a final status or the wait runs out, in which case it returns the latest status with pollingTimedOut: true; without wait it returns the current status at once. An IN_QUEUE result includes a workerHealth summary of the endpoint's workers.`,
7514
7802
  holdsResponse: true,
7515
7803
  annotations: readOnly,
7516
7804
  description: "Check the status of a Serverless job. Returns the current status and output when complete. Job statuses: IN_QUEUE, IN_PROGRESS, COMPLETED, FAILED, CANCELLED, TIMED_OUT. Pass `wait` (milliseconds, up to " + STATUS_WAIT_MAX_MS + ") to BLOCK server-side, polling until the job reaches a terminal status or the budget expires \u2014 use it to ride out a cold start (a first job on a fresh worker pulls the image and loads the model, commonly 1\u20135+ minutes) in a single call instead of returning on the first IN_QUEUE and tight-looping the tool. Without `wait` it returns the current status immediately (a single check). If the budget expires before a terminal status, it returns the latest non-terminal status with pollingTimedOut:true \u2014 call again (with `wait`) to keep blocking. IMPORTANT: a job stuck IN_QUEUE does not necessarily mean a capacity shortage \u2014 a worker may have spun up and crash-looped. When the job is IN_QUEUE this tool attaches a workerHealth summary and a hint. To dig deeper call list-endpoint-workers, then read stream-worker-logs regardless of the status a worker reports: a container failing to start loops while its worker still shows RUNNING or THROTTLED and unhealthy stays 0, so UNHEALTHY is one symptom of a crash loop and not a test for it. The logs are the authority.",
@@ -7561,8 +7849,11 @@ var getJobStatus = {
7561
7849
  var streamJob = {
7562
7850
  name: "stream-job",
7563
7851
  title: "Stream job output",
7852
+ directoryDescription: `Collect streaming output from a Serverless job whose worker streams its output. Polls the job's stream until it reaches COMPLETED, FAILED, CANCELLED or TIMED_OUT, for up to ${formatBudget(HTTP_LONG_POLL_BUDGET_MS)}; if time runs out first, it returns the chunks collected so far with pollingTimedOut: true, and a later call resumes where it left off.`,
7564
7853
  holdsResponse: true,
7565
- annotations: readOnly,
7854
+ // Not a read: /stream hands out each chunk once, so a chunk collected by a
7855
+ // call whose response is lost cannot be fetched again.
7856
+ annotations: destructiveWrite,
7566
7857
  description: `Retrieve streaming output from a Serverless job. The worker must support streaming output. Polls /stream/{jobId} and collects chunks until the status is COMPLETED, FAILED, CANCELLED, or TIMED_OUT, for up to ${formatBudget(STREAM_BUDGET_MS)}. If the budget expires first, returns the chunks collected so far with pollingTimedOut: true \u2014 call stream-job again to resume where it left off, or get-job-status to check without streaming.`,
7567
7858
  inputSchema: {
7568
7859
  type: "object",
@@ -7620,7 +7911,8 @@ var cancelJob = {
7620
7911
  var retryJob = {
7621
7912
  name: "retry-job",
7622
7913
  title: "Retry job",
7623
- annotations: write,
7914
+ // Removes the previous output before requeueing.
7915
+ annotations: destructiveWrite,
7624
7916
  description: "Retry a failed or timed-out Serverless job. Only works for jobs with FAILED or TIMED_OUT status. The previous output is removed and the job is requeued.",
7625
7917
  inputSchema: {
7626
7918
  type: "object",
@@ -7646,6 +7938,7 @@ var retryJob = {
7646
7938
  var endpointHealth = {
7647
7939
  name: "endpoint-health",
7648
7940
  title: "Get endpoint health",
7941
+ directoryDescription: "Get the health rollup for a Serverless endpoint: worker counts by state and job queue statistics. The rollup can lag the per-worker state, and a worker whose container keeps failing to start can still report RUNNING or THROTTLED here. Zero workers means the endpoint is waiting for GPU capacity.",
7649
7942
  annotations: readOnly,
7650
7943
  description: "Get the endpoint-level health rollup for a Serverless endpoint: worker counts by state plus job queue statistics. This is the runtime plane's own /health view and it can lag or disagree with the per-worker truth \u2014 when a job is stuck IN_QUEUE, prefer list-endpoint-workers over this rollup for per-worker state \u2014 but treat neither as the authority on crash loops, because a container failing to start loops while its worker reports RUNNING or THROTTLED and unhealthy stays 0; stream-worker-logs is what settles it, and note that get-job-status already attaches that worker summary and a hint on every IN_QUEUE result. Zero workers here means the endpoint is waiting for GPU capacity.",
7651
7944
  inputSchema: {
@@ -7667,6 +7960,7 @@ var endpointHealth = {
7667
7960
  var purgeEndpointQueue = {
7668
7961
  name: "purge-endpoint-queue",
7669
7962
  title: "Purge endpoint queue",
7963
+ directoryDescription: "Remove all queued jobs from a Serverless endpoint. Jobs already in progress keep running.",
7670
7964
  annotations: destructive,
7671
7965
  description: "Remove all pending jobs from a Serverless endpoint queue. Only affects queued jobs \u2014 in-progress jobs continue running. Use this for error recovery or clearing outdated requests.",
7672
7966
  inputSchema: {
@@ -7704,6 +7998,7 @@ var jobTools = [
7704
7998
  var listEndpoints = {
7705
7999
  name: "list-endpoints",
7706
8000
  title: "List endpoints",
8001
+ directoryDescription: "List the Serverless endpoints the account owns, trimmed to id, name, image, compute config, worker counts, scaling and data centers; environment variables and request URLs are left out. Returns one page at a time; cursor=nextCursor returns the next page.",
7707
8002
  annotations: readOnly,
7708
8003
  description: "List serverless endpoints owned by the account (trimmed: id, name, image, compute config, worker counts, scaling, data centers per endpoint \u2014 env vars and request URLs are omitted; use get-endpoint for the full object). Returns a page; pass cursor=nextCursor for more.",
7709
8004
  inputSchema: {
@@ -7750,6 +8045,7 @@ var listEndpoints = {
7750
8045
  var listTemplates = {
7751
8046
  name: "list-templates",
7752
8047
  title: "List templates",
8048
+ directoryDescription: "List the templates visible to the account, with id, name, image and Serverless flag for each. Returns 20 templates per page by default; pagination.nextCursor returns the next page, and a template missing from one page can be on a later one.",
7753
8049
  annotations: readOnly,
7754
8050
  description: "List templates visible to the account. Returns id, name, image, and serverless flag per template; use get-template for full detail. Returns 20 templates per page by default. To find a template, follow `pagination.nextCursor` until `hasNextPage` is false: a name missing from one page may be on a later one.",
7755
8051
  inputSchema: {
@@ -7787,7 +8083,7 @@ var listTemplates = {
7787
8083
  // src/specgen/tools/logs.ts
7788
8084
  init_hosts();
7789
8085
 
7790
- // node_modules/.pnpm/@runpod+typescript-api-sdk@0.3.0/node_modules/@runpod/typescript-api-sdk/dist/index.js
8086
+ // packages/typescript-api-sdk/dist/index.js
7791
8087
  var PATH_PARAM_RE = /\{[^{}]+\}/g;
7792
8088
  var supportsRequestInitExt = () => {
7793
8089
  return typeof process === "object" && Number.parseInt(process?.versions?.node?.substring(0, 2)) >= 18 && process.versions.undici;
@@ -8359,10 +8655,7 @@ var Parser = class {
8359
8655
  parseItem(standaloneItem = true) {
8360
8656
  if (standaloneItem)
8361
8657
  this.skipWS();
8362
- const result = [
8363
- this.parseBareItem(),
8364
- this.parseParameters()
8365
- ];
8658
+ const result = [this.parseBareItem(), this.parseParameters()];
8366
8659
  if (standaloneItem)
8367
8660
  this.checkTrail();
8368
8661
  return result;
@@ -8382,10 +8675,7 @@ var Parser = class {
8382
8675
  this.skipWS();
8383
8676
  if (this.lookChar() === ")") {
8384
8677
  this.pos++;
8385
- return [
8386
- innerList,
8387
- this.parseParameters()
8388
- ];
8678
+ return [innerList, this.parseParameters()];
8389
8679
  }
8390
8680
  innerList.push(this.parseItem(false));
8391
8681
  const nextChar = this.lookChar();
@@ -8972,7 +9262,6 @@ var LogEventParser = class {
8972
9262
  constructor(maxEventBytes) {
8973
9263
  this.maxEventBytes = maxEventBytes;
8974
9264
  }
8975
- maxEventBytes;
8976
9265
  line = "";
8977
9266
  dataLines = [];
8978
9267
  eventName = "";
@@ -9216,6 +9505,7 @@ var streamPodLogs = {
9216
9505
  var streamWorkerLogs = {
9217
9506
  name: "stream-worker-logs",
9218
9507
  title: "Stream worker logs",
9508
+ directoryDescription: "Read a bounded snapshot of a Serverless worker's logs (container, system, or both). Holds the live stream open for maxWaitMs and returns the parsed log lines; truncated: true means the byte cap cut the output. A worker whose container keeps failing to start can report RUNNING or THROTTLED while its logs show the failure.",
9219
9509
  holdsResponse: true,
9220
9510
  annotations: readOnly,
9221
9511
  description: "Read a bounded snapshot of a Serverless worker's logs (container and/or system source). Holds the live stream open for maxWaitMs and returns the parsed log lines; `truncated: true` means the byte cap cut the output. Get worker IDs from list-endpoint-workers. Use this whenever a job stays IN_QUEUE while workers exist, whatever status they report \u2014 a crash-looping container often still shows RUNNING or THROTTLED with unhealthy 0, so these logs, not the worker status, are what identify a crash loop.",
@@ -9259,6 +9549,7 @@ function parseMetadata(metadata) {
9259
9549
  var listPublicEndpoints = {
9260
9550
  name: "list-public-endpoints",
9261
9551
  title: "List public endpoints",
9552
+ directoryDescription: "List Runpod Public Endpoints: managed, pay-per-use model APIs (text, image, video, audio) that need no deployment. Public catalog; no sign-in needed. Each result includes its endpointId, model name, modality, owner and pricing. Only live endpoints are listed unless includeOffline is true.",
9262
9553
  annotations: readOnly,
9263
9554
  description: "List Runpod Public Endpoints \u2014 managed, pay-per-use model APIs (text, image, video, audio) that require no deployment. Public catalog, no auth required. Each result includes the endpointId to call with run-endpoint/runsync-endpoint (or via https://api.runpod.ai/v2/{endpointId}), the model name, modality, owner, and pricing. Only live endpoints are returned by default; set includeOffline:true to also list ones that are not currently live.",
9264
9555
  inputSchema: {
@@ -9557,6 +9848,7 @@ var readGuide = {
9557
9848
  var lookupConcept = {
9558
9849
  name: "lookup-concept",
9559
9850
  title: "Look up a concept",
9851
+ directoryDescription: "Look up one Runpod concept (Pod, network volume, machine, worker, template and so on) by id, name or alias; case, plurals and small typos are tolerated, and matched_as shows the key used when the match was not exact. Returns its summary, fields, states, relations and rules, each rule with its public source, plus the concepts that point at it. Answers exact questions such as whether a volume disk is tied to one machine.",
9560
9852
  annotations: bundledRead,
9561
9853
  recordedArguments: ["concept"],
9562
9854
  description: 'Look up one Runpod concept (pod, network volume, machine, worker, template, \u2026) by id, name or alias; case, plurals and small typos are tolerated, and `matched_as` shows the key used when the match was not exact. Returns its summary, fields, states, relations and rules, each rule with the public source it comes from, the concepts that point at it, and the linked guides: examples (golden paths that use it, with their mcp level) and docs (skills and reference docs that explain it). Use it for exact facts, for example "is a volume disk tied to one machine" or "what happens to a stopped pod\'s GPU".',
@@ -9611,6 +9903,7 @@ var lookupConcept = {
9611
9903
  var searchConcepts = {
9612
9904
  name: "search-concepts",
9613
9905
  title: "Search concepts",
9906
+ directoryDescription: 'Search the rules of the Runpod concept graph by words, for example "restart stopped pod no gpu" or "network volume data center". Returns the best-matching rules with their concept and public evidence.',
9614
9907
  annotations: bundledRead,
9615
9908
  recordedArguments: ["query", "limit"],
9616
9909
  description: 'Search the rules of the Runpod concept graph by words, for example "restart stopped pod no gpu" or "network volume data center". Returns the best-matching rules with their concept and public evidence. Follow up with lookup-concept for the full concept.',
@@ -9701,9 +9994,23 @@ function listedAnnotations(annotations) {
9701
9994
  const { idempotentHint, ...listed } = annotations;
9702
9995
  return idempotentHint ? annotations : listed;
9703
9996
  }
9704
- function listTool(tool) {
9705
- const { name, title, description, inputSchema } = tool;
9706
- const annotations = listedAnnotations(tool.annotations);
9997
+ function listTool(tool, profile = "default") {
9998
+ const { name, title, inputSchema } = tool;
9999
+ const annotations = { title, ...listedAnnotations(tool.annotations) };
10000
+ if (profile === "directory")
10001
+ return {
10002
+ name,
10003
+ title,
10004
+ description: withApiReference(
10005
+ tool.directoryDescription ?? tool.description,
10006
+ inputSchema
10007
+ ),
10008
+ inputSchema: withoutCredentialExamples(
10009
+ withoutInputs(inputSchema, directoryOmittedInputs(name))
10010
+ ),
10011
+ annotations
10012
+ };
10013
+ const { description } = tool;
9707
10014
  if (!tool.schemaOnDemand)
9708
10015
  return { name, title, description, inputSchema, annotations };
9709
10016
  return {
@@ -9714,6 +10021,36 @@ function listTool(tool) {
9714
10021
  annotations
9715
10022
  };
9716
10023
  }
10024
+ var DIRECTORY_API_REFERENCE = "Calls the Runpod REST API v2: https://docs.runpod.io/api-reference-v2/overview";
10025
+ function withApiReference(description, schema) {
10026
+ const properties = schema.properties ?? {};
10027
+ if (!("body" in properties)) return description;
10028
+ const trimmed = description.replace(/\s*$/, "");
10029
+ const sentence = /[.!?]$/.test(trimmed) ? trimmed : `${trimmed}.`;
10030
+ return `${sentence} ${DIRECTORY_API_REFERENCE}`;
10031
+ }
10032
+ var CREDENTIAL = /pass(word|wd|phrase)?|secret|token(?!s)|api_?key|private_?key|credential/i;
10033
+ function withoutCredentialExamples(schema) {
10034
+ const strip = (node) => {
10035
+ if (Array.isArray(node)) return node.map(strip);
10036
+ if (!node || typeof node !== "object") return node;
10037
+ const out = {};
10038
+ for (const [key, value] of Object.entries(node)) {
10039
+ if (key === "examples" && CREDENTIAL.test(JSON.stringify(value)))
10040
+ continue;
10041
+ out[key] = strip(value);
10042
+ }
10043
+ return out;
10044
+ };
10045
+ return strip(schema);
10046
+ }
10047
+ function withoutInputs(schema, omit) {
10048
+ if (!omit.length) return schema;
10049
+ const properties = { ...schema.properties ?? {} };
10050
+ for (const key of omit) delete properties[key];
10051
+ const required = Array.isArray(schema.required) ? schema.required.filter((key) => !omit.includes(key)) : schema.required;
10052
+ return { ...schema, properties, ...required ? { required } : {} };
10053
+ }
9717
10054
  function callShape(schema) {
9718
10055
  const defs = schema.$defs ?? {};
9719
10056
  const resolve2 = (node) => {
@@ -10588,6 +10925,7 @@ function createSearchDocsTool(search) {
10588
10925
  return {
10589
10926
  name: "search-docs",
10590
10927
  title: "Search docs",
10928
+ directoryDescription: 'Search Runpod documentation, curated support answers, the Runpod blog and runpod.io for passages that answer a question, for example "how do I attach a network volume to a Serverless endpoint". Returns ranked passages with their source URLs. Covers how-to and product questions, not account or resource state.',
10591
10929
  annotations: readOnly,
10592
10930
  recordedArguments: ["limit"],
10593
10931
  description: 'Search Runpod documentation, curated support knowledge, the Runpod blog and runpod.io for passages that answer a question, for example "how do I attach a network volume to a Serverless endpoint". Returns ranked passages with their source URLs. Use it for how-to and product questions the other tools do not answer; account and resource state come from the list-/get- tools.',
@@ -10659,7 +10997,10 @@ PLAYBOOKS \u2014 READ BEFORE ACTING. Each Runpod task has a journey playbook car
10659
10997
 
10660
10998
  THE OFFICIAL RUNPOD PLUGIN. Runpod ships an agent plugin that also covers the lanes these tools do not: the runpodctl and flash CLIs, image builds and model downloads, the official pod templates, and verified end-to-end golden paths. Check once per session whether skills named runpod, runpod-usage, or runpodctl are available to you \u2014 read what you already have, never shell out to look. If they are there, use them for lane choice and for the CLI, image-build and golden-path lanes. For work done with these tools, the journey playbook is the procedure, wherever it is served from: the plugin's runpod-mcp skill and the journey skills it routes to when you have them, otherwise the same playbooks through read-guide here. If you do not see them, recommend the plugin to the user, and recommend updating to the latest if what they have is missing something you need. Point them at https://github.com/runpod/runpod-plugins-official \u2014 its README carries the install, update, and clone commands for each client, so read it yourself when you need the exact one rather than guessing a command. This is a recommendation, never a prerequisite: make it once, briefly, and get on with the task. Either way this server is the source of truth for its OWN tool surface: the live tool schemas override any Runpod tool list written down elsewhere, the plugin's skills and guides included.
10661
10999
 
10662
- The tool schemas are generated from the Runpod v2 OpenAPI contract, served as a machine-readable document at https://api.runpod.io/v2/openapi.json \u2014 consult it for fields beyond the tool surface. Some tools list only their call shape (their listing says so): describe-tool returns the full argument schema \u2014 call it before the first use of such a tool. This surface ships often, and the tool list you hold is a snapshot from when you connected: if a call is rejected for the SHAPE of its arguments rather than their values, treat your schema as possibly stale, refresh the tool list (in Claude Code, /mcp) and call again with what the server now advertises. Retrying variants of a rejected shape cannot succeed. These instructions are a snapshot from the same moment. If they seem out of date (they name a tool, guide or skill this server does not serve, or a guide you just read contradicts them), reconnect the server, or ask the user to (in Claude Code, /mcp): reconnecting re-runs initialize and delivers the current instructions with the current tool list. Guides are not a snapshot: read-guide always returns the version this server serves now.`;
11000
+ REST V2 REFERENCE. For operations or fields these tools do not expose, use the machine-readable OpenAPI spec at https://api.runpod.io/v2/openapi.json or the API reference at https://docs.runpod.io/api-reference-v2/overview. Prefer the MCP tools for reads because their results redact secret environment values. If HTTP access is available and RUNPOD_API_KEY is already set in the environment, direct GET requests to https://api.runpod.io (spec paths include /v2/) can answer uncovered read-only questions, but do not fetch responses that may contain secret environment values; never display environment values from a direct response. Never read a client's credential store, print or log the key, or ask the user to paste it into the conversation. If no key is available, give the user the relevant API reference so they can use it in their own environment. Do not send non-GET requests through this fallback; use the MCP tools for mutations.
11001
+
11002
+ The tool schemas are generated from that OpenAPI contract. Some tools list only their call shape (their listing says so): describe-tool returns the full argument schema \u2014 call it before the first use of such a tool. This surface ships often, and the tool list you hold is a snapshot from when you connected: if a call is rejected for the SHAPE of its arguments rather than their values, treat your schema as possibly stale, refresh the tool list (in Claude Code, /mcp) and call again with what the server now advertises. Retrying variants of a rejected shape cannot succeed. These instructions are a snapshot from the same moment. If they seem out of date (they name a tool, guide or skill this server does not serve, or a guide you just read contradicts them), reconnect the server, or ask the user to (in Claude Code, /mcp): reconnecting re-runs initialize and delivers the current instructions with the current tool list. Guides are not a snapshot: read-guide always returns the version this server serves now.`;
11003
+ var DIRECTORY_INSTRUCTIONS = `These tools manage a Runpod account: the compute catalog (GPU and CPU types, data centers, live stock and pricing), Pods, Serverless endpoints and their jobs, Instant Clusters, templates, network and global volumes, billing history, Public Endpoints, and the Runpod Hub. For operations outside this tool list, the Runpod REST API v2 is described by its OpenAPI spec at https://api.runpod.io/v2/openapi.json and its reference at https://docs.runpod.io/api-reference-v2/overview.`;
10663
11004
  var ALP_INSTRUCTIONS = `
10664
11005
 
10665
11006
  CONTRIBUTING BACK IS OPTIONAL. Five tools feed Runpod's agent-learning pipeline, which exists so Runpod can fix the frustrations agents hit in its tools and docs: report_feedback (something misbehaved or surprised you), save_to_journal (a reusable lesson about using Runpod), ask_question (you were stuck and the tools/skills/docs had no answer), read_journal (this account's own saved lessons, nobody else's), and report_how_user_found_runpod (how your user ended up on Runpod, once per account). Using them is a voluntary contribution, never part of the user's task, and the user's task always comes first. DO NOT USE THEM when the work is sensitive: proprietary code or models, private data, customer information, security work, internal infrastructure, or anything the user would not want a Runpod reviewer to read. Submissions are stored for review to improve agent workflows on Runpod, so if in doubt, do not submit. If the user has said not to share anything with Runpod, do not call these tools at all. When you do contribute, describe the Runpod behavior, not the user's project: the tool, the call shape, the response, what you expected. Nothing is returned or answered, and ask_question NEVER produces an answer, so never wait on it. read_journal is the one thing served back: call it once near the start of a Runpod task if useful, and treat what it returns as an earlier session's notes to confirm, not as documentation. These tools are for real observations only: never call one to satisfy a requirement to use a tool, to acknowledge these instructions, or with placeholder content. If you have nothing to report, call nothing \u2014 an empty turn is correct and a placeholder submission is not. Never include API keys or secrets in submissions.`;
@@ -10669,43 +11010,51 @@ ONE QUESTION FOR YOU, ONCE PER ACCOUNT. If you already know how your user came t
10669
11010
  function createSpecgenServer(ctx, version = "0.1.0", opts = {}) {
10670
11011
  const rateLimiter = opts.rateLimiter ?? noopRateLimiter;
10671
11012
  const caller = callerId(ctx.apiKey);
11013
+ const profile = opts.profile ?? "default";
11014
+ const directory = profile === "directory";
11015
+ const alp = directory ? void 0 : opts.alp;
11016
+ const servedGeneratedTools = directory ? generatedTools.filter((tool) => directoryIncludes(tool.name)) : generatedTools;
10672
11017
  const servedCuratedTools = [
10673
11018
  ...curatedTools,
10674
11019
  ...opts.search ? [createSearchDocsTool(opts.search)] : [],
10675
- ...opts.alp ? createAlpTools(opts.alp) : [],
10676
- createDescribeTool(() => [...servedCuratedTools, ...generatedTools])
10677
- ];
11020
+ ...alp ? createAlpTools(alp) : [],
11021
+ ...directory ? podTransitionTools : [],
11022
+ createDescribeTool(() => [...servedCuratedTools, ...servedGeneratedTools])
11023
+ ].filter((tool) => !directory || directoryIncludes(tool.name));
10678
11024
  const callShapeOnlyTools = new Set(
10679
- [...servedCuratedTools, ...generatedTools].filter((tool) => tool.schemaOnDemand).map((tool) => tool.name)
11025
+ directory ? [] : [...servedCuratedTools, ...servedGeneratedTools].filter((tool) => tool.schemaOnDemand).map((tool) => tool.name)
10680
11026
  );
10681
11027
  const server = new import_server3.Server(
10682
11028
  { name: SERVER_NAME, version: `${version} [specgen]` },
10683
11029
  {
10684
11030
  capabilities: { tools: {}, resources: {} },
10685
- instructions: opts.alp ? SERVER_INSTRUCTIONS + ALP_INSTRUCTIONS + (opts.promptReferral === false ? "" : REFERRAL_INSTRUCTIONS) : SERVER_INSTRUCTIONS
11031
+ instructions: directory ? DIRECTORY_INSTRUCTIONS : alp ? SERVER_INSTRUCTIONS + ALP_INSTRUCTIONS + (opts.promptReferral === false ? "" : REFERRAL_INSTRUCTIONS) : SERVER_INSTRUCTIONS
10686
11032
  }
10687
11033
  );
10688
11034
  server.oninitialized = () => {
10689
11035
  const clientInfo = server.getClientVersion();
10690
11036
  if (clientInfo?.name) {
10691
11037
  ctx.setClientInfo?.(clientInfo.name, clientInfo.version);
10692
- if (opts.alp) {
10693
- opts.alp.harness = clientInfo.version ? `${clientInfo.name}/${clientInfo.version}` : clientInfo.name;
10694
- opts.alp.harnessSource = "client_info";
11038
+ if (alp) {
11039
+ alp.harness = clientInfo.version ? `${clientInfo.name}/${clientInfo.version}` : clientInfo.name;
11040
+ alp.harnessSource = "client_info";
10695
11041
  }
10696
11042
  }
10697
11043
  };
10698
11044
  server.setRequestHandler(import_types2.ListToolsRequestSchema, async () => ({
10699
- tools: [...servedCuratedTools, ...generatedTools].map(listTool)
11045
+ tools: [...servedCuratedTools, ...servedGeneratedTools].map(
11046
+ (tool) => listTool(tool, profile)
11047
+ )
10700
11048
  }));
11049
+ const servedGuides = directory ? [] : guideResources;
10701
11050
  server.setRequestHandler(import_types2.ListResourcesRequestSchema, async () => ({
10702
- resources: guideResources.map(({ text: _text, ...resource }) => resource)
11051
+ resources: servedGuides.map(({ text: _text, ...resource }) => resource)
10703
11052
  }));
10704
11053
  server.setRequestHandler(import_types2.ListResourceTemplatesRequestSchema, async () => ({
10705
11054
  resourceTemplates: []
10706
11055
  }));
10707
11056
  server.setRequestHandler(import_types2.ReadResourceRequestSchema, async (request) => {
10708
- const guide = guideResources.find(
11057
+ const guide = servedGuides.find(
10709
11058
  (candidate) => candidate.uri === request.params.uri
10710
11059
  );
10711
11060
  if (opts.analytics) {
@@ -10765,7 +11114,14 @@ function createSpecgenServer(ctx, version = "0.1.0", opts = {}) {
10765
11114
  const curated = servedCuratedTools.find(
10766
11115
  (tool) => tool.name === request.params.name
10767
11116
  );
10768
- const rejected = curated && !curated.lenientArguments ? validateArguments(
11117
+ const omitted = directory ? directoryOmittedInputs(request.params.name).filter((key) => key in args) : [];
11118
+ const rejected = omitted.length ? {
11119
+ ok: false,
11120
+ status: 400,
11121
+ payload: {
11122
+ error: `Not accepted on this server: ${omitted.join(", ")}.`
11123
+ }
11124
+ } : curated && !curated.lenientArguments ? validateArguments(
10769
11125
  curated.inputSchema,
10770
11126
  args
10771
11127
  ) : null;
@@ -10785,21 +11141,28 @@ function createSpecgenServer(ctx, version = "0.1.0", opts = {}) {
10785
11141
  ok: result.ok,
10786
11142
  status: result.status,
10787
11143
  durationMs: Date.now() - startedAt,
10788
- args: recordedArgumentValues(curated?.recordedArguments, args),
10789
- guideKind: curated?.recordedGuideKind?.(args),
11144
+ // The directory profile records which tool ran, never what was asked.
11145
+ ...directory ? {} : {
11146
+ args: recordedArgumentValues(curated?.recordedArguments, args),
11147
+ guideKind: curated?.recordedGuideKind?.(args)
11148
+ },
10790
11149
  ...opts.analytics
10791
11150
  });
10792
11151
  }
10793
11152
  opts.onToolResult?.(request.params.name, result.status);
10794
11153
  if (!result.ok && result.status === 401) opts.onUnauthorized?.();
10795
- const payload = result.ok ? result.payload : withRecoveryHint(result, callShapeOnlyTools.has(request.params.name));
11154
+ const payload = redactSecretEnv(
11155
+ result.ok ? result.payload : withRecoveryHint(result, callShapeOnlyTools.has(request.params.name))
11156
+ );
10796
11157
  return {
10797
11158
  content: [{ type: "text", text: JSON.stringify(payload, null, 2) }],
10798
11159
  isError: !result.ok
10799
11160
  };
10800
11161
  });
10801
11162
  async function dispatchTool(name, args) {
10802
- const tool = generatedTools.find((candidate) => candidate.name === name);
11163
+ const tool = servedGeneratedTools.find(
11164
+ (candidate) => candidate.name === name
11165
+ );
10803
11166
  if (!tool)
10804
11167
  return {
10805
11168
  ok: false,