@runpod/mcp-server 4.5.0 → 4.6.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.mjs CHANGED
@@ -12,7 +12,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
12
12
 
13
13
  // src/server.ts
14
14
  var SERVER_NAME = "Runpod API Server";
15
- var SERVER_VERSION = true ? "4.5.0" : "dev";
15
+ var SERVER_VERSION = true ? "4.6.0" : "dev";
16
16
 
17
17
  // src/specgen/server.ts
18
18
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
@@ -348,6 +348,7 @@ var generatedTools = [
348
348
  title: "Create cluster",
349
349
  operationId: "createCluster",
350
350
  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.",
351
+ 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.",
351
352
  method: "POST",
352
353
  path: "/v2/clusters",
353
354
  params: [],
@@ -363,7 +364,8 @@ var generatedTools = [
363
364
  type: "object",
364
365
  properties: {
365
366
  body: {
366
- $ref: "#/$defs/CreateClusterRequest"
367
+ $ref: "#/$defs/CreateClusterRequest",
368
+ type: "object"
367
369
  }
368
370
  },
369
371
  required: ["body"],
@@ -600,7 +602,8 @@ var generatedTools = [
600
602
  type: "object",
601
603
  properties: {
602
604
  body: {
603
- $ref: "#/$defs/CreateDelegationRequest"
605
+ $ref: "#/$defs/CreateDelegationRequest",
606
+ type: "object"
604
607
  }
605
608
  },
606
609
  required: ["body"],
@@ -632,6 +635,7 @@ var generatedTools = [
632
635
  title: "Create endpoint",
633
636
  operationId: "createEndpoint",
634
637
  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.",
638
+ 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.",
635
639
  method: "POST",
636
640
  path: "/v2/serverless",
637
641
  params: [],
@@ -647,7 +651,8 @@ var generatedTools = [
647
651
  type: "object",
648
652
  properties: {
649
653
  body: {
650
- $ref: "#/$defs/CreateEndpointRequest"
654
+ $ref: "#/$defs/CreateEndpointRequest",
655
+ type: "object"
651
656
  }
652
657
  },
653
658
  required: ["body"],
@@ -1092,7 +1097,8 @@ var generatedTools = [
1092
1097
  type: "object",
1093
1098
  properties: {
1094
1099
  body: {
1095
- $ref: "#/$defs/CreateGlobalVolumeRequest"
1100
+ $ref: "#/$defs/CreateGlobalVolumeRequest",
1101
+ type: "object"
1096
1102
  }
1097
1103
  },
1098
1104
  required: ["body"],
@@ -1134,7 +1140,8 @@ var generatedTools = [
1134
1140
  type: "object",
1135
1141
  properties: {
1136
1142
  body: {
1137
- $ref: "#/$defs/CreateNetworkVolumeRequest"
1143
+ $ref: "#/$defs/CreateNetworkVolumeRequest",
1144
+ type: "object"
1138
1145
  }
1139
1146
  },
1140
1147
  required: ["body"],
@@ -1186,6 +1193,7 @@ var generatedTools = [
1186
1193
  title: "Create Pod",
1187
1194
  operationId: "createPod",
1188
1195
  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.',
1196
+ 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.',
1189
1197
  method: "POST",
1190
1198
  path: "/v2/pods",
1191
1199
  params: [],
@@ -1201,7 +1209,8 @@ var generatedTools = [
1201
1209
  type: "object",
1202
1210
  properties: {
1203
1211
  body: {
1204
- $ref: "#/$defs/CreatePodRequest"
1212
+ $ref: "#/$defs/CreatePodRequest",
1213
+ type: "object"
1205
1214
  }
1206
1215
  },
1207
1216
  required: ["body"],
@@ -1568,7 +1577,8 @@ var generatedTools = [
1568
1577
  type: "object",
1569
1578
  properties: {
1570
1579
  body: {
1571
- $ref: "#/$defs/CreateRegistryRequest"
1580
+ $ref: "#/$defs/CreateRegistryRequest",
1581
+ type: "object"
1572
1582
  }
1573
1583
  },
1574
1584
  required: ["body"],
@@ -1613,7 +1623,7 @@ var generatedTools = [
1613
1623
  annotations: {
1614
1624
  readOnlyHint: false,
1615
1625
  destructiveHint: false,
1616
- idempotentHint: false,
1626
+ idempotentHint: true,
1617
1627
  openWorldHint: true
1618
1628
  },
1619
1629
  schemaOnDemand: true,
@@ -1621,7 +1631,8 @@ var generatedTools = [
1621
1631
  type: "object",
1622
1632
  properties: {
1623
1633
  body: {
1624
- $ref: "#/$defs/CreateSecretRequest"
1634
+ $ref: "#/$defs/CreateSecretRequest",
1635
+ type: "object"
1625
1636
  }
1626
1637
  },
1627
1638
  required: ["body"],
@@ -1676,7 +1687,8 @@ var generatedTools = [
1676
1687
  type: "object",
1677
1688
  properties: {
1678
1689
  body: {
1679
- $ref: "#/$defs/CreateTemplateRequest"
1690
+ $ref: "#/$defs/CreateTemplateRequest",
1691
+ type: "object"
1680
1692
  }
1681
1693
  },
1682
1694
  required: ["body"],
@@ -1863,6 +1875,7 @@ var generatedTools = [
1863
1875
  title: "Delete cluster",
1864
1876
  operationId: "deleteCluster",
1865
1877
  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.",
1878
+ directoryDescription: "Delete an Instant Cluster permanently. Every member Pod is terminated and its container disk is lost.",
1866
1879
  method: "DELETE",
1867
1880
  path: "/v2/clusters/{id}",
1868
1881
  params: [
@@ -1894,6 +1907,7 @@ var generatedTools = [
1894
1907
  title: "Delete endpoint",
1895
1908
  operationId: "deleteEndpoint",
1896
1909
  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.",
1910
+ directoryDescription: "Delete a Serverless endpoint permanently and immediately.",
1897
1911
  method: "DELETE",
1898
1912
  path: "/v2/serverless/{id}",
1899
1913
  params: [
@@ -1987,6 +2001,7 @@ var generatedTools = [
1987
2001
  title: "Delete Pod",
1988
2002
  operationId: "deletePod",
1989
2003
  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.",
2004
+ 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.",
1990
2005
  method: "DELETE",
1991
2006
  path: "/v2/pods/{id}",
1992
2007
  params: [
@@ -2048,6 +2063,7 @@ var generatedTools = [
2048
2063
  title: "Delete secret",
2049
2064
  operationId: "deleteSecret",
2050
2065
  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.",
2066
+ 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.",
2051
2067
  method: "DELETE",
2052
2068
  path: "/v2/account/secrets/{id}",
2053
2069
  params: [
@@ -2079,6 +2095,7 @@ var generatedTools = [
2079
2095
  title: "Delete template",
2080
2096
  operationId: "deleteTemplate",
2081
2097
  description: "Delete a template permanently. Verify with get-template first; a template referenced by a live endpoint should not be deleted.",
2098
+ directoryDescription: "Delete a template permanently. An endpoint that references the template can stop working once it is deleted.",
2082
2099
  method: "DELETE",
2083
2100
  path: "/v2/templates/{id}",
2084
2101
  params: [
@@ -2444,7 +2461,8 @@ var generatedTools = [
2444
2461
  },
2445
2462
  cloud: {
2446
2463
  $ref: "#/$defs/GpuCloudFilter",
2447
- description: "Cloud type for availability and lowest-price calculations. Valid only with include=AVAILABILITY. Supported values: SECURE, COMMUNITY. Upstream default when omitted: SECURE."
2464
+ description: "Cloud type for availability and lowest-price calculations. Valid only with include=AVAILABILITY. Supported values: SECURE, COMMUNITY. Upstream default when omitted: SECURE.",
2465
+ type: "string"
2448
2466
  },
2449
2467
  countryCodes: {
2450
2468
  type: "array",
@@ -2728,7 +2746,8 @@ var generatedTools = [
2728
2746
  },
2729
2747
  bucketSize: {
2730
2748
  $ref: "#/$defs/BillingBucketSize",
2731
- description: "Length of each billing time bucket. Defaults to day."
2749
+ description: "Length of each billing time bucket. Defaults to day.",
2750
+ type: "string"
2732
2751
  },
2733
2752
  lastN: {
2734
2753
  type: "integer",
@@ -2805,7 +2824,8 @@ var generatedTools = [
2805
2824
  },
2806
2825
  bucketSize: {
2807
2826
  $ref: "#/$defs/BillingBucketSize",
2808
- description: "Length of each billing time bucket. Defaults to day."
2827
+ description: "Length of each billing time bucket. Defaults to day.",
2828
+ type: "string"
2809
2829
  },
2810
2830
  lastN: {
2811
2831
  type: "integer",
@@ -3171,7 +3191,8 @@ var generatedTools = [
3171
3191
  },
3172
3192
  bucketSize: {
3173
3193
  $ref: "#/$defs/BillingBucketSize",
3174
- description: "Length of each billing time bucket. Defaults to day."
3194
+ description: "Length of each billing time bucket. Defaults to day.",
3195
+ type: "string"
3175
3196
  },
3176
3197
  lastN: {
3177
3198
  type: "integer",
@@ -3443,7 +3464,8 @@ var generatedTools = [
3443
3464
  },
3444
3465
  cloud: {
3445
3466
  $ref: "#/$defs/GpuCloudFilter",
3446
- description: "Cloud type for availability and lowest-price calculations. Valid only with include=AVAILABILITY. Supported values: SECURE, COMMUNITY. Upstream default when omitted: SECURE."
3467
+ description: "Cloud type for availability and lowest-price calculations. Valid only with include=AVAILABILITY. Supported values: SECURE, COMMUNITY. Upstream default when omitted: SECURE.",
3468
+ type: "string"
3447
3469
  },
3448
3470
  countryCodes: {
3449
3471
  type: "array",
@@ -3537,7 +3559,8 @@ var generatedTools = [
3537
3559
  },
3538
3560
  bucketSize: {
3539
3561
  $ref: "#/$defs/BillingBucketSize",
3540
- description: "Length of each billing time bucket. Defaults to day."
3562
+ description: "Length of each billing time bucket. Defaults to day.",
3563
+ type: "string"
3541
3564
  },
3542
3565
  lastN: {
3543
3566
  type: "integer",
@@ -3659,7 +3682,8 @@ var generatedTools = [
3659
3682
  },
3660
3683
  bucketSize: {
3661
3684
  $ref: "#/$defs/BillingBucketSize",
3662
- description: "Length of each billing time bucket. Defaults to day."
3685
+ description: "Length of each billing time bucket. Defaults to day.",
3686
+ type: "string"
3663
3687
  },
3664
3688
  lastN: {
3665
3689
  type: "integer",
@@ -3826,6 +3850,7 @@ var generatedTools = [
3826
3850
  title: "List Serverless billing",
3827
3851
  operationId: "listServerlessBilling",
3828
3852
  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.",
3853
+ 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.",
3829
3854
  method: "GET",
3830
3855
  path: "/v2/billing/serverless",
3831
3856
  params: [
@@ -3872,7 +3897,8 @@ var generatedTools = [
3872
3897
  },
3873
3898
  bucketSize: {
3874
3899
  $ref: "#/$defs/BillingBucketSize",
3875
- description: "Length of each billing time bucket. Defaults to day."
3900
+ description: "Length of each billing time bucket. Defaults to day.",
3901
+ type: "string"
3876
3902
  },
3877
3903
  lastN: {
3878
3904
  type: "integer",
@@ -3929,7 +3955,8 @@ var generatedTools = [
3929
3955
  type: "string"
3930
3956
  },
3931
3957
  body: {
3932
- $ref: "#/$defs/PodActionRequest"
3958
+ $ref: "#/$defs/PodActionRequest",
3959
+ type: "object"
3933
3960
  }
3934
3961
  },
3935
3962
  required: ["id", "body"],
@@ -3999,7 +4026,7 @@ var generatedTools = [
3999
4026
  annotations: {
4000
4027
  readOnlyHint: false,
4001
4028
  destructiveHint: false,
4002
- idempotentHint: false,
4029
+ idempotentHint: true,
4003
4030
  openWorldHint: true
4004
4031
  },
4005
4032
  inputSchema: {
@@ -4010,7 +4037,8 @@ var generatedTools = [
4010
4037
  description: "Cluster identifier"
4011
4038
  },
4012
4039
  body: {
4013
- $ref: "#/$defs/UpdateClusterRequest"
4040
+ $ref: "#/$defs/UpdateClusterRequest",
4041
+ type: "object"
4014
4042
  }
4015
4043
  },
4016
4044
  required: ["id", "body"],
@@ -4036,6 +4064,7 @@ var generatedTools = [
4036
4064
  title: "Update endpoint",
4037
4065
  operationId: "updateEndpoint",
4038
4066
  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.",
4067
+ 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.",
4039
4068
  method: "PATCH",
4040
4069
  path: "/v2/serverless/{id}",
4041
4070
  params: [
@@ -4047,7 +4076,7 @@ var generatedTools = [
4047
4076
  hasBody: true,
4048
4077
  annotations: {
4049
4078
  readOnlyHint: false,
4050
- destructiveHint: false,
4079
+ destructiveHint: true,
4051
4080
  idempotentHint: false,
4052
4081
  openWorldHint: true
4053
4082
  },
@@ -4060,7 +4089,8 @@ var generatedTools = [
4060
4089
  description: "Serverless endpoint identifier"
4061
4090
  },
4062
4091
  body: {
4063
- $ref: "#/$defs/UpdateEndpointRequest"
4092
+ $ref: "#/$defs/UpdateEndpointRequest",
4093
+ type: "object"
4064
4094
  }
4065
4095
  },
4066
4096
  required: ["id", "body"],
@@ -4439,7 +4469,7 @@ var generatedTools = [
4439
4469
  annotations: {
4440
4470
  readOnlyHint: false,
4441
4471
  destructiveHint: false,
4442
- idempotentHint: false,
4472
+ idempotentHint: true,
4443
4473
  openWorldHint: true
4444
4474
  },
4445
4475
  inputSchema: {
@@ -4450,7 +4480,8 @@ var generatedTools = [
4450
4480
  description: "Global volume identifier"
4451
4481
  },
4452
4482
  body: {
4453
- $ref: "#/$defs/UpdateGlobalVolumeRequest"
4483
+ $ref: "#/$defs/UpdateGlobalVolumeRequest",
4484
+ type: "object"
4454
4485
  }
4455
4486
  },
4456
4487
  required: ["id", "body"],
@@ -4491,7 +4522,7 @@ var generatedTools = [
4491
4522
  annotations: {
4492
4523
  readOnlyHint: false,
4493
4524
  destructiveHint: false,
4494
- idempotentHint: false,
4525
+ idempotentHint: true,
4495
4526
  openWorldHint: true
4496
4527
  },
4497
4528
  inputSchema: {
@@ -4502,7 +4533,8 @@ var generatedTools = [
4502
4533
  description: "Network volume identifier"
4503
4534
  },
4504
4535
  body: {
4505
- $ref: "#/$defs/UpdateNetworkVolumeRequest"
4536
+ $ref: "#/$defs/UpdateNetworkVolumeRequest",
4537
+ type: "object"
4506
4538
  }
4507
4539
  },
4508
4540
  required: ["id", "body"],
@@ -4547,7 +4579,7 @@ var generatedTools = [
4547
4579
  hasBody: true,
4548
4580
  annotations: {
4549
4581
  readOnlyHint: false,
4550
- destructiveHint: false,
4582
+ destructiveHint: true,
4551
4583
  idempotentHint: false,
4552
4584
  openWorldHint: true
4553
4585
  },
@@ -4560,7 +4592,8 @@ var generatedTools = [
4560
4592
  description: "Pod identifier"
4561
4593
  },
4562
4594
  body: {
4563
- $ref: "#/$defs/UpdatePodRequest"
4595
+ $ref: "#/$defs/UpdatePodRequest",
4596
+ type: "object"
4564
4597
  }
4565
4598
  },
4566
4599
  required: ["id", "body"],
@@ -4789,7 +4822,7 @@ var generatedTools = [
4789
4822
  hasBody: true,
4790
4823
  annotations: {
4791
4824
  readOnlyHint: false,
4792
- destructiveHint: false,
4825
+ destructiveHint: true,
4793
4826
  idempotentHint: false,
4794
4827
  openWorldHint: true
4795
4828
  },
@@ -4802,7 +4835,8 @@ var generatedTools = [
4802
4835
  description: "Secret identifier"
4803
4836
  },
4804
4837
  body: {
4805
- $ref: "#/$defs/UpdateSecretRequest"
4838
+ $ref: "#/$defs/UpdateSecretRequest",
4839
+ type: "object"
4806
4840
  }
4807
4841
  },
4808
4842
  required: ["id", "body"],
@@ -4848,7 +4882,8 @@ var generatedTools = [
4848
4882
  type: "object",
4849
4883
  properties: {
4850
4884
  body: {
4851
- $ref: "#/$defs/UpdateSshKeysRequest"
4885
+ $ref: "#/$defs/UpdateSshKeysRequest",
4886
+ type: "object"
4852
4887
  }
4853
4888
  },
4854
4889
  required: ["body"],
@@ -4893,7 +4928,7 @@ var generatedTools = [
4893
4928
  annotations: {
4894
4929
  readOnlyHint: false,
4895
4930
  destructiveHint: false,
4896
- idempotentHint: false,
4931
+ idempotentHint: true,
4897
4932
  openWorldHint: true
4898
4933
  },
4899
4934
  schemaOnDemand: true,
@@ -4904,7 +4939,8 @@ var generatedTools = [
4904
4939
  type: "string"
4905
4940
  },
4906
4941
  body: {
4907
- $ref: "#/$defs/UpdateTemplateRequest"
4942
+ $ref: "#/$defs/UpdateTemplateRequest",
4943
+ type: "object"
4908
4944
  }
4909
4945
  },
4910
4946
  required: ["id", "body"],
@@ -5073,6 +5109,142 @@ var generatedTools = [
5073
5109
  }
5074
5110
  ];
5075
5111
 
5112
+ // src/specgen/profile.ts
5113
+ var IN = { include: true };
5114
+ var CREDENTIAL_INPUT = "Takes a secret or password as input; directories forbid collecting credentials.";
5115
+ var ALP = "Collects conversation-derived data beyond the task; the directory profile never serves it.";
5116
+ var DIRECTORY_TOOLS = {
5117
+ "cancel-job": IN,
5118
+ "create-cluster": IN,
5119
+ "create-delegation": IN,
5120
+ "create-endpoint": IN,
5121
+ "create-global-volume": IN,
5122
+ "create-network-volume": IN,
5123
+ "create-pod": IN,
5124
+ "create-template": IN,
5125
+ "delete-cluster": IN,
5126
+ "delete-endpoint": IN,
5127
+ "delete-global-volume": IN,
5128
+ "delete-network-volume": IN,
5129
+ "delete-pod": IN,
5130
+ "delete-registry": IN,
5131
+ "delete-secret": IN,
5132
+ "delete-template": IN,
5133
+ "deploy-hub-repo": IN,
5134
+ "endpoint-health": IN,
5135
+ "get-capacity": IN,
5136
+ "get-cluster": IN,
5137
+ "get-cpu-type": IN,
5138
+ "get-data-center": IN,
5139
+ "get-endpoint": IN,
5140
+ "get-endpoint-build": IN,
5141
+ "get-global-volume": IN,
5142
+ "get-gpu-type": IN,
5143
+ "get-job-status": IN,
5144
+ "get-network-volume": IN,
5145
+ "get-organization": IN,
5146
+ "get-pod": IN,
5147
+ "get-registry": IN,
5148
+ "get-secret": IN,
5149
+ "get-ssh-keys": IN,
5150
+ "get-template": IN,
5151
+ "list-billing": IN,
5152
+ "list-cluster-billing": IN,
5153
+ "list-cluster-pods": IN,
5154
+ "list-clusters": IN,
5155
+ "list-cpu-types": IN,
5156
+ "list-data-centers": IN,
5157
+ "list-delegations": IN,
5158
+ "list-endpoint-billing": IN,
5159
+ "list-endpoint-builds": IN,
5160
+ "list-endpoint-releases": IN,
5161
+ "list-endpoint-workers": IN,
5162
+ "list-endpoints": IN,
5163
+ "list-global-volumes": IN,
5164
+ "list-gpu-types": IN,
5165
+ "list-hub-repos": IN,
5166
+ "list-network-volume-billing": IN,
5167
+ "list-network-volumes": IN,
5168
+ "list-pod-billing": IN,
5169
+ "list-pods": IN,
5170
+ "list-public-endpoints": IN,
5171
+ "list-public-templates": IN,
5172
+ "list-registries": IN,
5173
+ "list-secrets": IN,
5174
+ "list-serverless-billing": IN,
5175
+ "list-templates": IN,
5176
+ "lookup-concept": IN,
5177
+ "pod-action": IN,
5178
+ "purge-endpoint-queue": IN,
5179
+ "retry-job": IN,
5180
+ "revoke-delegation": IN,
5181
+ "search-concepts": IN,
5182
+ "search-docs": IN,
5183
+ "set-endpoint-gpus": IN,
5184
+ "stream-job": IN,
5185
+ "stream-pod-logs": IN,
5186
+ "stream-worker-logs": IN,
5187
+ "update-cluster": IN,
5188
+ "update-endpoint": IN,
5189
+ "update-global-volume": IN,
5190
+ "update-network-volume": IN,
5191
+ "update-pod": IN,
5192
+ "update-ssh-keys": IN,
5193
+ "update-template": IN,
5194
+ "run-endpoint": { include: true, omitInputs: ["s3Config"] },
5195
+ "runsync-endpoint": { include: true, omitInputs: ["s3Config"] },
5196
+ "list-guides": {
5197
+ include: false,
5198
+ reason: "Serves playbooks that instruct the model how to behave."
5199
+ },
5200
+ "read-guide": {
5201
+ include: false,
5202
+ reason: "Serves playbooks that instruct the model how to behave."
5203
+ },
5204
+ "describe-tool": {
5205
+ include: false,
5206
+ reason: "Fetches schemas the directory already lists in full; directories reject schema fetching."
5207
+ },
5208
+ "create-secret": { include: false, reason: CREDENTIAL_INPUT },
5209
+ "update-secret": { include: false, reason: CREDENTIAL_INPUT },
5210
+ "create-registry": { include: false, reason: CREDENTIAL_INPUT },
5211
+ report_feedback: { include: false, reason: ALP },
5212
+ report_how_user_found_runpod: { include: false, reason: ALP },
5213
+ save_to_journal: { include: false, reason: ALP },
5214
+ read_journal: { include: false, reason: ALP },
5215
+ ask_question: { include: false, reason: ALP }
5216
+ };
5217
+ function directoryIncludes(name) {
5218
+ return DIRECTORY_TOOLS[name]?.include === true;
5219
+ }
5220
+ function directoryOmittedInputs(name) {
5221
+ const decision = DIRECTORY_TOOLS[name];
5222
+ return decision?.include ? decision.omitInputs ?? [] : [];
5223
+ }
5224
+
5225
+ // src/specgen/redact.ts
5226
+ var REDACTED = "[redacted]";
5227
+ var SECRET_KEY = /pass(word|wd)?|secret|token|api_?key|private_?key|credential|auth/i;
5228
+ var SECRET_REFERENCE = /^\s*\{\{\s*RUNPOD_SECRET_[^}]+\}\}\s*$/;
5229
+ function redactEnv(env) {
5230
+ return Object.fromEntries(
5231
+ Object.entries(env).map(([key, value]) => [
5232
+ key,
5233
+ typeof value === "string" && value !== "" && SECRET_KEY.test(key) && !SECRET_REFERENCE.test(value) ? REDACTED : value
5234
+ ])
5235
+ );
5236
+ }
5237
+ function redactSecretEnv(payload) {
5238
+ if (Array.isArray(payload)) return payload.map(redactSecretEnv);
5239
+ if (!payload || typeof payload !== "object") return payload;
5240
+ return Object.fromEntries(
5241
+ Object.entries(payload).map(([key, value]) => [
5242
+ key,
5243
+ key === "env" && value && typeof value === "object" && !Array.isArray(value) ? redactEnv(value) : redactSecretEnv(value)
5244
+ ])
5245
+ );
5246
+ }
5247
+
5076
5248
  // src/specgen/pagination.ts
5077
5249
  var DEFAULT_LIST_LIMIT = 20;
5078
5250
  var MAX_LIST_LIMIT = 100;
@@ -5272,6 +5444,12 @@ var destructive = {
5272
5444
  idempotentHint: true,
5273
5445
  openWorldHint: true
5274
5446
  };
5447
+ var destructiveWrite = {
5448
+ readOnlyHint: false,
5449
+ destructiveHint: true,
5450
+ idempotentHint: false,
5451
+ openWorldHint: true
5452
+ };
5275
5453
 
5276
5454
  // src/specgen/tools/capacity.ts
5277
5455
  var CUDA_VERSION_REGEX = /^\d{1,2}\.\d{1,2}$/;
@@ -5308,6 +5486,7 @@ function rankByStock(rows, stats, includeUnavailable) {
5308
5486
  var getCapacity = {
5309
5487
  name: "get-capacity",
5310
5488
  title: "Get GPU capacity by CUDA version",
5489
+ 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.",
5311
5490
  annotations: readOnly,
5312
5491
  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.",
5313
5492
  inputSchema: {
@@ -5510,7 +5689,9 @@ function formatGpuIds(gpu) {
5510
5689
  var setEndpointGpus = {
5511
5690
  name: "set-endpoint-gpus",
5512
5691
  title: "Set endpoint GPUs",
5513
- annotations: idempotentWrite,
5692
+ 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.",
5693
+ // Replaces the whole GPU selection: exclusions not resent are cleared.
5694
+ annotations: destructive,
5514
5695
  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.",
5515
5696
  inputSchema: {
5516
5697
  type: "object",
@@ -5705,6 +5886,7 @@ function randomSuffix() {
5705
5886
  var listHubRepos = {
5706
5887
  name: "list-hub-repos",
5707
5888
  title: "List Hub repos",
5889
+ 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.",
5708
5890
  annotations: readOnly,
5709
5891
  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.",
5710
5892
  inputSchema: {
@@ -5808,6 +5990,7 @@ var listHubRepos = {
5808
5990
  var deployHubRepo = {
5809
5991
  name: "deploy-hub-repo",
5810
5992
  title: "Deploy Hub repo",
5993
+ 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.`,
5811
5994
  // Two sequential upstream calls: together they can outlast a client's request timeout.
5812
5995
  holdsResponse: true,
5813
5996
  annotations: write,
@@ -6269,6 +6452,7 @@ function validateWait(wait) {
6269
6452
  var runEndpoint = {
6270
6453
  name: "run-endpoint",
6271
6454
  title: "Submit Serverless job",
6455
+ 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.",
6272
6456
  annotations: write,
6273
6457
  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.",
6274
6458
  inputSchema: {
@@ -6300,6 +6484,7 @@ var runEndpoint = {
6300
6484
  var runsyncEndpoint = {
6301
6485
  name: "runsync-endpoint",
6302
6486
  title: "Run Serverless job and wait",
6487
+ 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.`,
6303
6488
  holdsResponse: true,
6304
6489
  annotations: write,
6305
6490
  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)."),
@@ -6346,6 +6531,7 @@ var runsyncEndpoint = {
6346
6531
  var getJobStatus = {
6347
6532
  name: "get-job-status",
6348
6533
  title: "Get job status",
6534
+ 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.`,
6349
6535
  holdsResponse: true,
6350
6536
  annotations: readOnly,
6351
6537
  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.",
@@ -6396,8 +6582,11 @@ var getJobStatus = {
6396
6582
  var streamJob = {
6397
6583
  name: "stream-job",
6398
6584
  title: "Stream job output",
6585
+ 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.`,
6399
6586
  holdsResponse: true,
6400
- annotations: readOnly,
6587
+ // Not a read: /stream hands out each chunk once, so a chunk collected by a
6588
+ // call whose response is lost cannot be fetched again.
6589
+ annotations: destructiveWrite,
6401
6590
  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.`,
6402
6591
  inputSchema: {
6403
6592
  type: "object",
@@ -6455,7 +6644,8 @@ var cancelJob = {
6455
6644
  var retryJob = {
6456
6645
  name: "retry-job",
6457
6646
  title: "Retry job",
6458
- annotations: write,
6647
+ // Removes the previous output before requeueing.
6648
+ annotations: destructiveWrite,
6459
6649
  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.",
6460
6650
  inputSchema: {
6461
6651
  type: "object",
@@ -6481,6 +6671,7 @@ var retryJob = {
6481
6671
  var endpointHealth = {
6482
6672
  name: "endpoint-health",
6483
6673
  title: "Get endpoint health",
6674
+ 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.",
6484
6675
  annotations: readOnly,
6485
6676
  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.",
6486
6677
  inputSchema: {
@@ -6502,6 +6693,7 @@ var endpointHealth = {
6502
6693
  var purgeEndpointQueue = {
6503
6694
  name: "purge-endpoint-queue",
6504
6695
  title: "Purge endpoint queue",
6696
+ directoryDescription: "Remove all queued jobs from a Serverless endpoint. Jobs already in progress keep running.",
6505
6697
  annotations: destructive,
6506
6698
  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.",
6507
6699
  inputSchema: {
@@ -6539,6 +6731,7 @@ var jobTools = [
6539
6731
  var listEndpoints = {
6540
6732
  name: "list-endpoints",
6541
6733
  title: "List endpoints",
6734
+ 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.",
6542
6735
  annotations: readOnly,
6543
6736
  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.",
6544
6737
  inputSchema: {
@@ -6585,6 +6778,7 @@ var listEndpoints = {
6585
6778
  var listTemplates = {
6586
6779
  name: "list-templates",
6587
6780
  title: "List templates",
6781
+ 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.",
6588
6782
  annotations: readOnly,
6589
6783
  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.",
6590
6784
  inputSchema: {
@@ -8048,6 +8242,7 @@ var streamPodLogs = {
8048
8242
  var streamWorkerLogs = {
8049
8243
  name: "stream-worker-logs",
8050
8244
  title: "Stream worker logs",
8245
+ 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.",
8051
8246
  holdsResponse: true,
8052
8247
  annotations: readOnly,
8053
8248
  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.",
@@ -8091,6 +8286,7 @@ function parseMetadata(metadata) {
8091
8286
  var listPublicEndpoints = {
8092
8287
  name: "list-public-endpoints",
8093
8288
  title: "List public endpoints",
8289
+ 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.",
8094
8290
  annotations: readOnly,
8095
8291
  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.",
8096
8292
  inputSchema: {
@@ -8391,6 +8587,7 @@ var readGuide = {
8391
8587
  var lookupConcept = {
8392
8588
  name: "lookup-concept",
8393
8589
  title: "Look up a concept",
8590
+ 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.",
8394
8591
  annotations: bundledRead,
8395
8592
  recordedArguments: ["concept"],
8396
8593
  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".',
@@ -8445,6 +8642,7 @@ var lookupConcept = {
8445
8642
  var searchConcepts = {
8446
8643
  name: "search-concepts",
8447
8644
  title: "Search concepts",
8645
+ 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.',
8448
8646
  annotations: bundledRead,
8449
8647
  recordedArguments: ["query", "limit"],
8450
8648
  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.',
@@ -8535,9 +8733,21 @@ function listedAnnotations(annotations) {
8535
8733
  const { idempotentHint, ...listed } = annotations;
8536
8734
  return idempotentHint ? annotations : listed;
8537
8735
  }
8538
- function listTool(tool) {
8539
- const { name, title, description, inputSchema } = tool;
8540
- const annotations = listedAnnotations(tool.annotations);
8736
+ function listTool(tool, profile = "default") {
8737
+ const { name, title, inputSchema } = tool;
8738
+ const annotations = { title, ...listedAnnotations(tool.annotations) };
8739
+ if (profile === "directory")
8740
+ return {
8741
+ name,
8742
+ title,
8743
+ description: withApiReference(
8744
+ tool.directoryDescription ?? tool.description,
8745
+ inputSchema
8746
+ ),
8747
+ inputSchema: withoutInputs(inputSchema, directoryOmittedInputs(name)),
8748
+ annotations
8749
+ };
8750
+ const { description } = tool;
8541
8751
  if (!tool.schemaOnDemand)
8542
8752
  return { name, title, description, inputSchema, annotations };
8543
8753
  return {
@@ -8548,6 +8758,21 @@ function listTool(tool) {
8548
8758
  annotations
8549
8759
  };
8550
8760
  }
8761
+ var DIRECTORY_API_REFERENCE = "Calls the Runpod REST API v2: https://docs.runpod.io/api-reference-v2/overview";
8762
+ function withApiReference(description, schema) {
8763
+ const properties = schema.properties ?? {};
8764
+ if (!("body" in properties)) return description;
8765
+ const trimmed = description.replace(/\s*$/, "");
8766
+ const sentence = /[.!?]$/.test(trimmed) ? trimmed : `${trimmed}.`;
8767
+ return `${sentence} ${DIRECTORY_API_REFERENCE}`;
8768
+ }
8769
+ function withoutInputs(schema, omit) {
8770
+ if (!omit.length) return schema;
8771
+ const properties = { ...schema.properties ?? {} };
8772
+ for (const key of omit) delete properties[key];
8773
+ const required = Array.isArray(schema.required) ? schema.required.filter((key) => !omit.includes(key)) : schema.required;
8774
+ return { ...schema, properties, ...required ? { required } : {} };
8775
+ }
8551
8776
  function callShape(schema) {
8552
8777
  const defs = schema.$defs ?? {};
8553
8778
  const resolve = (node) => {
@@ -9421,6 +9646,7 @@ function createSearchDocsTool(search) {
9421
9646
  return {
9422
9647
  name: "search-docs",
9423
9648
  title: "Search docs",
9649
+ 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.',
9424
9650
  annotations: readOnly,
9425
9651
  recordedArguments: ["limit"],
9426
9652
  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.',
@@ -9493,6 +9719,7 @@ PLAYBOOKS \u2014 READ BEFORE ACTING. Each Runpod task has a journey playbook car
9493
9719
  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.
9494
9720
 
9495
9721
  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.`;
9722
+ 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, secrets, SSH keys, container registry credentials, billing history, Public Endpoints, and the Runpod Hub. Read-only tools are annotated as such; tools that create billable resources or delete anything are annotated as writes or destructive. Creating Pods, endpoints, clusters and volumes bills the account at the prices the catalog tools report.`;
9496
9723
  var ALP_INSTRUCTIONS = `
9497
9724
 
9498
9725
  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.`;
@@ -9502,43 +9729,50 @@ ONE QUESTION FOR YOU, ONCE PER ACCOUNT. If you already know how your user came t
9502
9729
  function createSpecgenServer(ctx, version = "0.1.0", opts = {}) {
9503
9730
  const rateLimiter = opts.rateLimiter ?? noopRateLimiter;
9504
9731
  const caller = callerId(ctx.apiKey);
9732
+ const profile = opts.profile ?? "default";
9733
+ const directory = profile === "directory";
9734
+ const alp = directory ? void 0 : opts.alp;
9735
+ const servedGeneratedTools = directory ? generatedTools.filter((tool) => directoryIncludes(tool.name)) : generatedTools;
9505
9736
  const servedCuratedTools = [
9506
9737
  ...curatedTools,
9507
9738
  ...opts.search ? [createSearchDocsTool(opts.search)] : [],
9508
- ...opts.alp ? createAlpTools(opts.alp) : [],
9509
- createDescribeTool(() => [...servedCuratedTools, ...generatedTools])
9510
- ];
9739
+ ...alp ? createAlpTools(alp) : [],
9740
+ createDescribeTool(() => [...servedCuratedTools, ...servedGeneratedTools])
9741
+ ].filter((tool) => !directory || directoryIncludes(tool.name));
9511
9742
  const callShapeOnlyTools = new Set(
9512
- [...servedCuratedTools, ...generatedTools].filter((tool) => tool.schemaOnDemand).map((tool) => tool.name)
9743
+ directory ? [] : [...servedCuratedTools, ...servedGeneratedTools].filter((tool) => tool.schemaOnDemand).map((tool) => tool.name)
9513
9744
  );
9514
9745
  const server = new Server(
9515
9746
  { name: SERVER_NAME, version: `${version} [specgen]` },
9516
9747
  {
9517
9748
  capabilities: { tools: {}, resources: {} },
9518
- instructions: opts.alp ? SERVER_INSTRUCTIONS + ALP_INSTRUCTIONS + (opts.promptReferral === false ? "" : REFERRAL_INSTRUCTIONS) : SERVER_INSTRUCTIONS
9749
+ instructions: directory ? DIRECTORY_INSTRUCTIONS : alp ? SERVER_INSTRUCTIONS + ALP_INSTRUCTIONS + (opts.promptReferral === false ? "" : REFERRAL_INSTRUCTIONS) : SERVER_INSTRUCTIONS
9519
9750
  }
9520
9751
  );
9521
9752
  server.oninitialized = () => {
9522
9753
  const clientInfo = server.getClientVersion();
9523
9754
  if (clientInfo?.name) {
9524
9755
  ctx.setClientInfo?.(clientInfo.name, clientInfo.version);
9525
- if (opts.alp) {
9526
- opts.alp.harness = clientInfo.version ? `${clientInfo.name}/${clientInfo.version}` : clientInfo.name;
9527
- opts.alp.harnessSource = "client_info";
9756
+ if (alp) {
9757
+ alp.harness = clientInfo.version ? `${clientInfo.name}/${clientInfo.version}` : clientInfo.name;
9758
+ alp.harnessSource = "client_info";
9528
9759
  }
9529
9760
  }
9530
9761
  };
9531
9762
  server.setRequestHandler(ListToolsRequestSchema, async () => ({
9532
- tools: [...servedCuratedTools, ...generatedTools].map(listTool)
9763
+ tools: [...servedCuratedTools, ...servedGeneratedTools].map(
9764
+ (tool) => listTool(tool, profile)
9765
+ )
9533
9766
  }));
9767
+ const servedGuides = directory ? [] : guideResources;
9534
9768
  server.setRequestHandler(ListResourcesRequestSchema, async () => ({
9535
- resources: guideResources.map(({ text: _text, ...resource }) => resource)
9769
+ resources: servedGuides.map(({ text: _text, ...resource }) => resource)
9536
9770
  }));
9537
9771
  server.setRequestHandler(ListResourceTemplatesRequestSchema, async () => ({
9538
9772
  resourceTemplates: []
9539
9773
  }));
9540
9774
  server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
9541
- const guide = guideResources.find(
9775
+ const guide = servedGuides.find(
9542
9776
  (candidate) => candidate.uri === request.params.uri
9543
9777
  );
9544
9778
  if (opts.analytics) {
@@ -9598,7 +9832,14 @@ function createSpecgenServer(ctx, version = "0.1.0", opts = {}) {
9598
9832
  const curated = servedCuratedTools.find(
9599
9833
  (tool) => tool.name === request.params.name
9600
9834
  );
9601
- const rejected = curated && !curated.lenientArguments ? validateArguments(
9835
+ const omitted = directory ? directoryOmittedInputs(request.params.name).filter((key) => key in args) : [];
9836
+ const rejected = omitted.length ? {
9837
+ ok: false,
9838
+ status: 400,
9839
+ payload: {
9840
+ error: `Not accepted on this server: ${omitted.join(", ")}.`
9841
+ }
9842
+ } : curated && !curated.lenientArguments ? validateArguments(
9602
9843
  curated.inputSchema,
9603
9844
  args
9604
9845
  ) : null;
@@ -9618,21 +9859,28 @@ function createSpecgenServer(ctx, version = "0.1.0", opts = {}) {
9618
9859
  ok: result.ok,
9619
9860
  status: result.status,
9620
9861
  durationMs: Date.now() - startedAt,
9621
- args: recordedArgumentValues(curated?.recordedArguments, args),
9622
- guideKind: curated?.recordedGuideKind?.(args),
9862
+ // The directory profile records which tool ran, never what was asked.
9863
+ ...directory ? {} : {
9864
+ args: recordedArgumentValues(curated?.recordedArguments, args),
9865
+ guideKind: curated?.recordedGuideKind?.(args)
9866
+ },
9623
9867
  ...opts.analytics
9624
9868
  });
9625
9869
  }
9626
9870
  opts.onToolResult?.(request.params.name, result.status);
9627
9871
  if (!result.ok && result.status === 401) opts.onUnauthorized?.();
9628
- const payload = result.ok ? result.payload : withRecoveryHint(result, callShapeOnlyTools.has(request.params.name));
9872
+ const payload = redactSecretEnv(
9873
+ result.ok ? result.payload : withRecoveryHint(result, callShapeOnlyTools.has(request.params.name))
9874
+ );
9629
9875
  return {
9630
9876
  content: [{ type: "text", text: JSON.stringify(payload, null, 2) }],
9631
9877
  isError: !result.ok
9632
9878
  };
9633
9879
  });
9634
9880
  async function dispatchTool(name, args) {
9635
- const tool = generatedTools.find((candidate) => candidate.name === name);
9881
+ const tool = servedGeneratedTools.find(
9882
+ (candidate) => candidate.name === name
9883
+ );
9636
9884
  if (!tool)
9637
9885
  return {
9638
9886
  ok: false,