@runpod/mcp-server 4.3.0 → 4.5.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/CHANGELOG.md +35 -0
- package/README.md +16 -0
- package/dist/{chunk-DDX42UTT.mjs → chunk-4GF3CMSH.mjs} +6 -2
- package/dist/{chunk-DDX42UTT.mjs.map → chunk-4GF3CMSH.mjs.map} +1 -1
- package/dist/http.cjs +523 -36
- package/dist/http.cjs.map +1 -1
- package/dist/http.d.cts +12 -1
- package/dist/http.d.ts +12 -1
- package/dist/http.mjs +522 -36
- package/dist/http.mjs.map +1 -1
- package/dist/stdio.cjs +384 -20
- package/dist/stdio.cjs.map +1 -1
- package/dist/stdio.mjs +380 -21
- package/dist/stdio.mjs.map +1 -1
- package/dist/{wizard-L25AYBNQ.mjs → wizard-KKTBTVXE.mjs} +4 -3
- package/dist/wizard-KKTBTVXE.mjs.map +1 -0
- package/package.json +2 -2
- package/dist/wizard-L25AYBNQ.mjs.map +0 -1
package/dist/stdio.cjs
CHANGED
|
@@ -46,6 +46,9 @@ function publicGraphqlBase(env) {
|
|
|
46
46
|
function authedGraphqlBase(env) {
|
|
47
47
|
return pick(env.RUNPOD_AUTHED_GRAPHQL_URL, "https://api.runpod.io/graphql");
|
|
48
48
|
}
|
|
49
|
+
function hostedMcpBase(env) {
|
|
50
|
+
return pick(env.RUNPOD_MCP_URL, "https://mcp.getrunpod.io");
|
|
51
|
+
}
|
|
49
52
|
var init_hosts = __esm({
|
|
50
53
|
"src/_shared/hosts.ts"() {
|
|
51
54
|
"use strict";
|
|
@@ -736,9 +739,10 @@ var init_clients = __esm({
|
|
|
736
739
|
path = __toESM(require("path"), 1);
|
|
737
740
|
import_child_process = require("child_process");
|
|
738
741
|
jsonc = __toESM(require("jsonc-parser"), 1);
|
|
742
|
+
init_hosts();
|
|
739
743
|
SERVER_NAME2 = "runpod";
|
|
740
744
|
NPM_PACKAGE = "@runpod/mcp-server@latest";
|
|
741
|
-
HOSTED_URL = process.env
|
|
745
|
+
HOSTED_URL = `${hostedMcpBase(process.env)}/`;
|
|
742
746
|
PROJECT_BOUNDARY_MARKERS = [
|
|
743
747
|
".git",
|
|
744
748
|
"package.json",
|
|
@@ -1179,7 +1183,7 @@ var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
|
1179
1183
|
|
|
1180
1184
|
// src/server.ts
|
|
1181
1185
|
var SERVER_NAME = "Runpod API Server";
|
|
1182
|
-
var SERVER_VERSION = true ? "4.
|
|
1186
|
+
var SERVER_VERSION = true ? "4.5.0" : "dev";
|
|
1183
1187
|
|
|
1184
1188
|
// src/specgen/server.ts
|
|
1185
1189
|
var import_server3 = require("@modelcontextprotocol/sdk/server/index.js");
|
|
@@ -1506,6 +1510,7 @@ function coerceScalars(value, schema, defs, depth = 0) {
|
|
|
1506
1510
|
var generatedTools = [
|
|
1507
1511
|
{
|
|
1508
1512
|
name: "create-cluster",
|
|
1513
|
+
title: "Create cluster",
|
|
1509
1514
|
operationId: "createCluster",
|
|
1510
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.",
|
|
1511
1516
|
method: "POST",
|
|
@@ -1743,6 +1748,7 @@ var generatedTools = [
|
|
|
1743
1748
|
},
|
|
1744
1749
|
{
|
|
1745
1750
|
name: "create-delegation",
|
|
1751
|
+
title: "Create ECR delegation",
|
|
1746
1752
|
operationId: "createDelegation",
|
|
1747
1753
|
description: "Register an ECR delegation",
|
|
1748
1754
|
method: "POST",
|
|
@@ -1788,6 +1794,7 @@ var generatedTools = [
|
|
|
1788
1794
|
},
|
|
1789
1795
|
{
|
|
1790
1796
|
name: "create-endpoint",
|
|
1797
|
+
title: "Create endpoint",
|
|
1791
1798
|
operationId: "createEndpoint",
|
|
1792
1799
|
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.",
|
|
1793
1800
|
method: "POST",
|
|
@@ -2233,6 +2240,7 @@ var generatedTools = [
|
|
|
2233
2240
|
},
|
|
2234
2241
|
{
|
|
2235
2242
|
name: "create-global-volume",
|
|
2243
|
+
title: "Create global volume",
|
|
2236
2244
|
operationId: "createGlobalVolume",
|
|
2237
2245
|
description: "Create a global volume. Provisions a new global volume \u2014 storage that mounts into workloads in any data center. Only a `name` is required; storage is provisioned for you. Accounts have a cap on how many global volumes they can hold; creating one past it fails with `400`. Returns `201` with the created global volume, including its assigned `id`.",
|
|
2238
2246
|
method: "POST",
|
|
@@ -2274,6 +2282,7 @@ var generatedTools = [
|
|
|
2274
2282
|
},
|
|
2275
2283
|
{
|
|
2276
2284
|
name: "create-network-volume",
|
|
2285
|
+
title: "Create network volume",
|
|
2277
2286
|
operationId: "createNetworkVolume",
|
|
2278
2287
|
description: "Create a network volume. Provisions a new network volume \u2014 persistent, network-attached storage that can be mounted into pods and serverless workers. Required inputs are `name`, `size` (in GB), and `dataCenter`; an optional `type` selects the storage tier and is immutable after creation. See `CreateNetworkVolumeRequest` for the size bounds and tier options. This creates a billable persistent resource that keeps incurring storage charges until it is deleted. Returns `201` with the created network volume, including its assigned `id`.",
|
|
2279
2288
|
method: "POST",
|
|
@@ -2339,6 +2348,7 @@ var generatedTools = [
|
|
|
2339
2348
|
},
|
|
2340
2349
|
{
|
|
2341
2350
|
name: "create-pod",
|
|
2351
|
+
title: "Create Pod",
|
|
2342
2352
|
operationId: "createPod",
|
|
2343
2353
|
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.',
|
|
2344
2354
|
method: "POST",
|
|
@@ -2706,6 +2716,7 @@ var generatedTools = [
|
|
|
2706
2716
|
},
|
|
2707
2717
|
{
|
|
2708
2718
|
name: "create-registry",
|
|
2719
|
+
title: "Create registry credential",
|
|
2709
2720
|
operationId: "createRegistry",
|
|
2710
2721
|
description: "Create a container registry credential. Stores credentials for a private container registry. Credentials are write-only.",
|
|
2711
2722
|
method: "POST",
|
|
@@ -2757,6 +2768,7 @@ var generatedTools = [
|
|
|
2757
2768
|
},
|
|
2758
2769
|
{
|
|
2759
2770
|
name: "create-secret",
|
|
2771
|
+
title: "Create secret",
|
|
2760
2772
|
operationId: "createSecret",
|
|
2761
2773
|
description: "Create a secret. Stores a new account-scoped encrypted string. `name` must be unique across the account's secrets and is immutable; `value` is write-only and can never be read back through the API. Use the secret from pods, serverless endpoints, and templates by setting an environment variable's value to `{{ RUNPOD_SECRET_<name> }}` \u2014 Runpod substitutes the stored value when the pod or worker boots. Returns `201` with the created secret's metadata, or `409` when the name is already taken.",
|
|
2762
2774
|
method: "POST",
|
|
@@ -2811,6 +2823,7 @@ var generatedTools = [
|
|
|
2811
2823
|
},
|
|
2812
2824
|
{
|
|
2813
2825
|
name: "create-template",
|
|
2826
|
+
title: "Create template",
|
|
2814
2827
|
operationId: "createTemplate",
|
|
2815
2828
|
description: "Create a template. Creates a reusable container-configuration preset \u2014 image, disk, ports, env, registry, and mount settings \u2014 for pods and serverless endpoints. Pass its ID as `templateId` to `createPod` or `createEndpoint`, or spread its fields into the request body directly. Returns the created template.",
|
|
2816
2829
|
method: "POST",
|
|
@@ -3012,6 +3025,7 @@ var generatedTools = [
|
|
|
3012
3025
|
},
|
|
3013
3026
|
{
|
|
3014
3027
|
name: "delete-cluster",
|
|
3028
|
+
title: "Delete cluster",
|
|
3015
3029
|
operationId: "deleteCluster",
|
|
3016
3030
|
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.",
|
|
3017
3031
|
method: "DELETE",
|
|
@@ -3042,6 +3056,7 @@ var generatedTools = [
|
|
|
3042
3056
|
},
|
|
3043
3057
|
{
|
|
3044
3058
|
name: "delete-endpoint",
|
|
3059
|
+
title: "Delete endpoint",
|
|
3045
3060
|
operationId: "deleteEndpoint",
|
|
3046
3061
|
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.",
|
|
3047
3062
|
method: "DELETE",
|
|
@@ -3072,6 +3087,7 @@ var generatedTools = [
|
|
|
3072
3087
|
},
|
|
3073
3088
|
{
|
|
3074
3089
|
name: "delete-global-volume",
|
|
3090
|
+
title: "Delete global volume",
|
|
3075
3091
|
operationId: "deleteGlobalVolume",
|
|
3076
3092
|
description: "Delete a global volume. Permanently deletes a global volume and its stored data. Fails with `409` while the volume is still mounted: terminate every pod that mounts it (stopped pods count) and detach it from every serverless endpoint first. Nothing is detached or terminated on your behalf.",
|
|
3077
3093
|
method: "DELETE",
|
|
@@ -3102,6 +3118,7 @@ var generatedTools = [
|
|
|
3102
3118
|
},
|
|
3103
3119
|
{
|
|
3104
3120
|
name: "delete-network-volume",
|
|
3121
|
+
title: "Delete network volume",
|
|
3105
3122
|
operationId: "deleteNetworkVolume",
|
|
3106
3123
|
description: "Delete a network volume. Permanently deletes a network volume and releases its storage.",
|
|
3107
3124
|
method: "DELETE",
|
|
@@ -3132,6 +3149,7 @@ var generatedTools = [
|
|
|
3132
3149
|
},
|
|
3133
3150
|
{
|
|
3134
3151
|
name: "delete-pod",
|
|
3152
|
+
title: "Delete Pod",
|
|
3135
3153
|
operationId: "deletePod",
|
|
3136
3154
|
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.",
|
|
3137
3155
|
method: "DELETE",
|
|
@@ -3162,6 +3180,7 @@ var generatedTools = [
|
|
|
3162
3180
|
},
|
|
3163
3181
|
{
|
|
3164
3182
|
name: "delete-registry",
|
|
3183
|
+
title: "Delete registry credential",
|
|
3165
3184
|
operationId: "deleteRegistry",
|
|
3166
3185
|
description: "Delete a container registry credential. Permanently deletes a container registry credential by ID. Rejected if any pod currently uses this credential to pull its image. Templates that reference it are not part of that check \u2014 they silently lose the reference (`registry` becomes null) instead of blocking the delete.",
|
|
3167
3186
|
method: "DELETE",
|
|
@@ -3191,6 +3210,7 @@ var generatedTools = [
|
|
|
3191
3210
|
},
|
|
3192
3211
|
{
|
|
3193
3212
|
name: "delete-secret",
|
|
3213
|
+
title: "Delete secret",
|
|
3194
3214
|
operationId: "deleteSecret",
|
|
3195
3215
|
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.",
|
|
3196
3216
|
method: "DELETE",
|
|
@@ -3221,6 +3241,7 @@ var generatedTools = [
|
|
|
3221
3241
|
},
|
|
3222
3242
|
{
|
|
3223
3243
|
name: "delete-template",
|
|
3244
|
+
title: "Delete template",
|
|
3224
3245
|
operationId: "deleteTemplate",
|
|
3225
3246
|
description: "Delete a template permanently. Verify with get-template first; a template referenced by a live endpoint should not be deleted.",
|
|
3226
3247
|
method: "DELETE",
|
|
@@ -3250,6 +3271,7 @@ var generatedTools = [
|
|
|
3250
3271
|
},
|
|
3251
3272
|
{
|
|
3252
3273
|
name: "get-cluster",
|
|
3274
|
+
title: "Get cluster",
|
|
3253
3275
|
operationId: "getCluster",
|
|
3254
3276
|
description: "Get a cluster. Returns a single cluster by ID. The pods field is an aggregate summary (total + count by status); fetch the member pods themselves from /v2/clusters/{id}/pods.",
|
|
3255
3277
|
method: "GET",
|
|
@@ -3280,6 +3302,7 @@ var generatedTools = [
|
|
|
3280
3302
|
},
|
|
3281
3303
|
{
|
|
3282
3304
|
name: "get-cpu-type",
|
|
3305
|
+
title: "Get CPU type",
|
|
3283
3306
|
operationId: "getCpuType",
|
|
3284
3307
|
description: "Get a CPU type. Returns a single CPU type with pricing. Availability details are included only when requested with include=AVAILABILITY, which requires `product` \u2014 stock differs by product context.",
|
|
3285
3308
|
method: "GET",
|
|
@@ -3356,6 +3379,7 @@ var generatedTools = [
|
|
|
3356
3379
|
},
|
|
3357
3380
|
{
|
|
3358
3381
|
name: "get-data-center",
|
|
3382
|
+
title: "Get data center",
|
|
3359
3383
|
operationId: "getDataCenter",
|
|
3360
3384
|
description: "Get a data center. Returns a single data center. Availability is included only when requested with include=GPU_AVAILABILITY or include=CPU_AVAILABILITY.",
|
|
3361
3385
|
method: "GET",
|
|
@@ -3405,6 +3429,7 @@ var generatedTools = [
|
|
|
3405
3429
|
},
|
|
3406
3430
|
{
|
|
3407
3431
|
name: "get-endpoint",
|
|
3432
|
+
title: "Get endpoint",
|
|
3408
3433
|
operationId: "getEndpoint",
|
|
3409
3434
|
description: "Get a serverless endpoint. Returns a single serverless endpoint by ID.",
|
|
3410
3435
|
method: "GET",
|
|
@@ -3435,6 +3460,7 @@ var generatedTools = [
|
|
|
3435
3460
|
},
|
|
3436
3461
|
{
|
|
3437
3462
|
name: "get-endpoint-build",
|
|
3463
|
+
title: "Get endpoint build",
|
|
3438
3464
|
operationId: "getEndpointBuild",
|
|
3439
3465
|
description: "Get a serverless endpoint build. Returns one of the endpoint's GitHub builds by id, regardless of age \u2014 no need to page through `GET /v2/serverless/{id}/builds` to reach it.",
|
|
3440
3466
|
method: "GET",
|
|
@@ -3473,6 +3499,7 @@ var generatedTools = [
|
|
|
3473
3499
|
},
|
|
3474
3500
|
{
|
|
3475
3501
|
name: "get-global-volume",
|
|
3502
|
+
title: "Get global volume",
|
|
3476
3503
|
operationId: "getGlobalVolume",
|
|
3477
3504
|
description: "Get a global volume. Returns a single global volume by ID.",
|
|
3478
3505
|
method: "GET",
|
|
@@ -3503,6 +3530,7 @@ var generatedTools = [
|
|
|
3503
3530
|
},
|
|
3504
3531
|
{
|
|
3505
3532
|
name: "get-gpu-type",
|
|
3533
|
+
title: "Get GPU type",
|
|
3506
3534
|
operationId: "getGpuType",
|
|
3507
3535
|
description: "Get a GPU type. Returns a single GPU type with pricing. Availability details are included only when requested with include=AVAILABILITY, which requires `product` \u2014 stock differs by product context.",
|
|
3508
3536
|
method: "GET",
|
|
@@ -3627,6 +3655,7 @@ var generatedTools = [
|
|
|
3627
3655
|
},
|
|
3628
3656
|
{
|
|
3629
3657
|
name: "get-network-volume",
|
|
3658
|
+
title: "Get network volume",
|
|
3630
3659
|
operationId: "getNetworkVolume",
|
|
3631
3660
|
description: "Get a network volume. Returns a single network volume by ID.",
|
|
3632
3661
|
method: "GET",
|
|
@@ -3657,6 +3686,7 @@ var generatedTools = [
|
|
|
3657
3686
|
},
|
|
3658
3687
|
{
|
|
3659
3688
|
name: "get-organization",
|
|
3689
|
+
title: "Get organization",
|
|
3660
3690
|
operationId: "getOrganization",
|
|
3661
3691
|
description: "Get your current organization. Returns the authenticated caller's current organization. Organization context comes from the caller's membership; no organization selector is required. Returns 404 when the caller does not belong to an organization, or 403 when organizations are unavailable to the caller.",
|
|
3662
3692
|
method: "GET",
|
|
@@ -3676,6 +3706,7 @@ var generatedTools = [
|
|
|
3676
3706
|
},
|
|
3677
3707
|
{
|
|
3678
3708
|
name: "get-pod",
|
|
3709
|
+
title: "Get Pod",
|
|
3679
3710
|
operationId: "getPod",
|
|
3680
3711
|
description: "Get a pod. Returns a single pod by ID.",
|
|
3681
3712
|
method: "GET",
|
|
@@ -3706,6 +3737,7 @@ var generatedTools = [
|
|
|
3706
3737
|
},
|
|
3707
3738
|
{
|
|
3708
3739
|
name: "get-registry",
|
|
3740
|
+
title: "Get registry credential",
|
|
3709
3741
|
operationId: "getRegistry",
|
|
3710
3742
|
description: "Get a container registry credential. Returns a single container registry credential by ID. `username` and `password` are never included in the response \u2014 credentials are write-only, matching `createRegistry`.",
|
|
3711
3743
|
method: "GET",
|
|
@@ -3735,6 +3767,7 @@ var generatedTools = [
|
|
|
3735
3767
|
},
|
|
3736
3768
|
{
|
|
3737
3769
|
name: "get-secret",
|
|
3770
|
+
title: "Get secret",
|
|
3738
3771
|
operationId: "getSecret",
|
|
3739
3772
|
description: "Get a secret. Returns a single secret's metadata by ID. The value is write-only and never returned.",
|
|
3740
3773
|
method: "GET",
|
|
@@ -3765,6 +3798,7 @@ var generatedTools = [
|
|
|
3765
3798
|
},
|
|
3766
3799
|
{
|
|
3767
3800
|
name: "get-ssh-keys",
|
|
3801
|
+
title: "Get SSH keys",
|
|
3768
3802
|
operationId: "getSshKeys",
|
|
3769
3803
|
description: "List registered SSH public keys. Returns the account's registered SSH public keys \u2014 the keys provisioned into pods created with `startSsh` and used to authenticate the SSH connections reported in a pod's `ssh` block.",
|
|
3770
3804
|
method: "GET",
|
|
@@ -3784,6 +3818,7 @@ var generatedTools = [
|
|
|
3784
3818
|
},
|
|
3785
3819
|
{
|
|
3786
3820
|
name: "get-template",
|
|
3821
|
+
title: "Get template",
|
|
3787
3822
|
operationId: "getTemplate",
|
|
3788
3823
|
description: "Get a template. Returns the full configuration of a single template by ID. Serves both templates you own and public catalog templates \u2014 everything you can read. Updates and deletes remain restricted to templates you own.",
|
|
3789
3824
|
method: "GET",
|
|
@@ -3813,6 +3848,7 @@ var generatedTools = [
|
|
|
3813
3848
|
},
|
|
3814
3849
|
{
|
|
3815
3850
|
name: "list-billing",
|
|
3851
|
+
title: "List billing",
|
|
3816
3852
|
operationId: "listBilling",
|
|
3817
3853
|
description: "Get aggregated billing history. Returns time-bucketed total spend across all billable Runpod resources for the authenticated user. Use startTime/endTime with bucketSize for an explicit range, or lastN with bucketSize for the most recent buckets. Each record reports one bucket's total plus pod, serverless, storage, public endpoint, and Instant Cluster cost components. The metadata block echoes the resolved query window, record count, and totals across all returned buckets.",
|
|
3818
3854
|
method: "GET",
|
|
@@ -3885,6 +3921,7 @@ var generatedTools = [
|
|
|
3885
3921
|
},
|
|
3886
3922
|
{
|
|
3887
3923
|
name: "list-cluster-billing",
|
|
3924
|
+
title: "List cluster billing",
|
|
3888
3925
|
operationId: "listClusterBilling",
|
|
3889
3926
|
description: "Get cluster billing history. Returns Cluster billing history for the authenticated user, split into time buckets by startTime/endTime with bucketSize or by lastN recent buckets. Use clusterId to filter to one cluster; without it, records are emitted per cluster per bucket. Each record includes GPU compute, disk, inter-node networking, and total amounts. Clusters are GPU-only, so no CPU cost component is returned.",
|
|
3890
3927
|
method: "GET",
|
|
@@ -3965,6 +4002,7 @@ var generatedTools = [
|
|
|
3965
4002
|
},
|
|
3966
4003
|
{
|
|
3967
4004
|
name: "list-cluster-pods",
|
|
4005
|
+
title: "List cluster Pods",
|
|
3968
4006
|
operationId: "listClusterPods",
|
|
3969
4007
|
description: "List a cluster's pods. Returns the full member pods of a cluster. The cluster summary (`GET /v2/clusters/{id}`) carries only aggregate pod counts; this endpoint returns each member as a complete Pod object.",
|
|
3970
4008
|
method: "GET",
|
|
@@ -3995,6 +4033,7 @@ var generatedTools = [
|
|
|
3995
4033
|
},
|
|
3996
4034
|
{
|
|
3997
4035
|
name: "list-clusters",
|
|
4036
|
+
title: "List clusters",
|
|
3998
4037
|
operationId: "listClusters",
|
|
3999
4038
|
description: "List clusters. Returns clusters owned by the authenticated user, cursor-paginated newest-first; an omitted `limit` defaults to 1000. Follow `pagination.nextCursor` until `hasNextPage` is false.",
|
|
4000
4039
|
method: "GET",
|
|
@@ -4035,6 +4074,7 @@ var generatedTools = [
|
|
|
4035
4074
|
},
|
|
4036
4075
|
{
|
|
4037
4076
|
name: "list-cpu-types",
|
|
4077
|
+
title: "List CPU types",
|
|
4038
4078
|
operationId: "listCpuTypes",
|
|
4039
4079
|
description: "List CPU types. Returns available CPU flavors. Availability is included only when requested with include=AVAILABILITY, which requires `product` \u2014 stock differs by product context.",
|
|
4040
4080
|
method: "GET",
|
|
@@ -4103,6 +4143,7 @@ var generatedTools = [
|
|
|
4103
4143
|
},
|
|
4104
4144
|
{
|
|
4105
4145
|
name: "list-data-centers",
|
|
4146
|
+
title: "List data centers",
|
|
4106
4147
|
operationId: "listDataCenters",
|
|
4107
4148
|
description: "List data centers. Returns available data center locations with region, compliance, supported network volume tiers, and global networking support. Use include=GPU_AVAILABILITY or include=CPU_AVAILABILITY to add per-resource availability arrays to each data center. The regions, networkVolumeTypes, compliance, and globalNetwork query parameters filter the list before it is returned.",
|
|
4108
4149
|
method: "GET",
|
|
@@ -4230,6 +4271,7 @@ var generatedTools = [
|
|
|
4230
4271
|
},
|
|
4231
4272
|
{
|
|
4232
4273
|
name: "list-delegations",
|
|
4274
|
+
title: "List ECR delegations",
|
|
4233
4275
|
operationId: "listDelegations",
|
|
4234
4276
|
description: "List all ECR delegations",
|
|
4235
4277
|
method: "GET",
|
|
@@ -4249,6 +4291,7 @@ var generatedTools = [
|
|
|
4249
4291
|
},
|
|
4250
4292
|
{
|
|
4251
4293
|
name: "list-endpoint-billing",
|
|
4294
|
+
title: "List endpoint billing",
|
|
4252
4295
|
operationId: "listEndpointBilling",
|
|
4253
4296
|
description: "Get public endpoint billing history. Returns Runpod public endpoint billing history for the authenticated user, split into time buckets by startTime/endTime with bucketSize or by lastN recent buckets. Each record reports the endpoint total for one bucket, and metadata echoes the resolved query window, record count, and total endpoint amount across all returned records.",
|
|
4254
4297
|
method: "GET",
|
|
@@ -4321,6 +4364,7 @@ var generatedTools = [
|
|
|
4321
4364
|
},
|
|
4322
4365
|
{
|
|
4323
4366
|
name: "list-endpoint-builds",
|
|
4367
|
+
title: "List endpoint builds",
|
|
4324
4368
|
operationId: "listEndpointBuilds",
|
|
4325
4369
|
description: "List serverless endpoint builds. Returns the endpoint's GitHub build history, newest first (Runpod GitHub-build integration), cursor-paginated; an omitted `limit` defaults to 100, so a bare request returns at most the 100 most recent builds. Any build can also be fetched by id via `GET /v2/serverless/{id}/builds/{buildId}`. Stream a build's logs via `/v2/serverless/{id}/builds/{buildId}/logs`.",
|
|
4326
4370
|
method: "GET",
|
|
@@ -4370,6 +4414,7 @@ var generatedTools = [
|
|
|
4370
4414
|
},
|
|
4371
4415
|
{
|
|
4372
4416
|
name: "list-endpoint-releases",
|
|
4417
|
+
title: "List endpoint releases",
|
|
4373
4418
|
operationId: "listEndpointReleases",
|
|
4374
4419
|
description: "List serverless endpoint releases. Returns the endpoint's release history (newest first) plus a rollout summary of how many workers are running the current version. Each release is a versioned configuration snapshot with a `diff` of what changed; build-driven releases carry a `buildId` (fetch build detail via the builds sub-routes). Releases are cursor-paginated newest-first; an omitted `limit` defaults to 1000. The rollout summary always describes the endpoint's current state, independent of the page requested.",
|
|
4375
4420
|
method: "GET",
|
|
@@ -4419,6 +4464,7 @@ var generatedTools = [
|
|
|
4419
4464
|
},
|
|
4420
4465
|
{
|
|
4421
4466
|
name: "list-endpoint-workers",
|
|
4467
|
+
title: "List endpoint workers",
|
|
4422
4468
|
operationId: "listEndpointWorkers",
|
|
4423
4469
|
description: "List serverless endpoint workers. Lists the active workers for a serverless endpoint. **Returns.** A `200` with a `ListEndpointWorkersResponse`: a `workers` array (one entry per active worker, each carrying its `id`, `status`, and runtime details) plus a `summary` of worker counts grouped by status. Only currently active workers are included; scaled-down workers are not returned. **How `status` is determined.** Each worker's `status` is derived by reconciling the worker pod's lifecycle status with the endpoint's live job-queue view (which workers are actively serving requests). When the job-queue view is unavailable, the response degrades gracefully: the shape is unchanged, but each `status` and the summary counts fall back to pod lifecycle alone.",
|
|
4424
4470
|
method: "GET",
|
|
@@ -4449,6 +4495,7 @@ var generatedTools = [
|
|
|
4449
4495
|
},
|
|
4450
4496
|
{
|
|
4451
4497
|
name: "list-global-volumes",
|
|
4498
|
+
title: "List global volumes",
|
|
4452
4499
|
operationId: "listGlobalVolumes",
|
|
4453
4500
|
description: "List global volumes. Returns global volumes owned by the authenticated user, cursor-paginated newest-first; an omitted `limit` defaults to 1000. Follow `pagination.nextCursor` until `hasNextPage` is false.",
|
|
4454
4501
|
method: "GET",
|
|
@@ -4489,6 +4536,7 @@ var generatedTools = [
|
|
|
4489
4536
|
},
|
|
4490
4537
|
{
|
|
4491
4538
|
name: "list-gpu-types",
|
|
4539
|
+
title: "List GPU types",
|
|
4492
4540
|
operationId: "listGpuTypes",
|
|
4493
4541
|
description: 'List GPU types. Returns available GPU types with pricing. Availability is included only when requested with include=AVAILABILITY, which requires `product` \u2014 stock differs by product context. With countryCodes, the list is narrowed to GPU types deployable in those countries, so "this geography + this chip" resolves in one read.',
|
|
4494
4542
|
method: "GET",
|
|
@@ -4605,6 +4653,7 @@ var generatedTools = [
|
|
|
4605
4653
|
},
|
|
4606
4654
|
{
|
|
4607
4655
|
name: "list-network-volume-billing",
|
|
4656
|
+
title: "List network volume billing",
|
|
4608
4657
|
operationId: "listNetworkVolumeBilling",
|
|
4609
4658
|
description: "Get network volume billing history. Returns network volume billing history for the authenticated user, split into time buckets by startTime/endTime with bucketSize or by lastN recent buckets. Use networkVolumeId to filter to one volume; without it, records are emitted per volume per bucket. Each record includes standard storage, high-performance storage, and total amounts, while metadata reports the resolved query, distinct volume count, and totals across the returned records.",
|
|
4610
4659
|
method: "GET",
|
|
@@ -4685,6 +4734,7 @@ var generatedTools = [
|
|
|
4685
4734
|
},
|
|
4686
4735
|
{
|
|
4687
4736
|
name: "list-network-volumes",
|
|
4737
|
+
title: "List network volumes",
|
|
4688
4738
|
operationId: "listNetworkVolumes",
|
|
4689
4739
|
description: "List network volumes. Returns network volumes owned by the authenticated user, cursor-paginated newest-first; an omitted `limit` defaults to 1000. Follow `pagination.nextCursor` until `hasNextPage` is false.",
|
|
4690
4740
|
method: "GET",
|
|
@@ -4725,6 +4775,7 @@ var generatedTools = [
|
|
|
4725
4775
|
},
|
|
4726
4776
|
{
|
|
4727
4777
|
name: "list-pod-billing",
|
|
4778
|
+
title: "List Pod billing",
|
|
4728
4779
|
operationId: "listPodBilling",
|
|
4729
4780
|
description: "Get pod billing history. Returns pod-only billing detail for the authenticated user, split into time buckets by startTime/endTime with bucketSize or by lastN recent buckets. Use podId to narrow the response to one GPU or CPU pod; without it, records are emitted per pod per bucket. Each record includes podId, GPU, CPU, disk, and total amounts, while metadata echoes the resolved query and totals across the pod records. Use listBilling when you need aggregate spend across every billable resource family.",
|
|
4730
4781
|
method: "GET",
|
|
@@ -4805,6 +4856,7 @@ var generatedTools = [
|
|
|
4805
4856
|
},
|
|
4806
4857
|
{
|
|
4807
4858
|
name: "list-pods",
|
|
4859
|
+
title: "List Pods",
|
|
4808
4860
|
operationId: "listPods",
|
|
4809
4861
|
description: "List pods. Returns pods owned by the authenticated user. Cluster member pods are excluded by default; set `includeClusterPods=true` to include them (each carries a non-null `cluster` membership block). Results are cursor-paginated newest-first; an omitted `limit` defaults to 1000. The cluster-member exclusion is applied before the page is cut, so a page holds `limit` pods whenever that many remain. Follow `pagination.nextCursor` until `hasNextPage` is false.",
|
|
4810
4862
|
method: "GET",
|
|
@@ -4854,6 +4906,7 @@ var generatedTools = [
|
|
|
4854
4906
|
},
|
|
4855
4907
|
{
|
|
4856
4908
|
name: "list-public-templates",
|
|
4909
|
+
title: "List public templates",
|
|
4857
4910
|
operationId: "listPublicTemplates",
|
|
4858
4911
|
description: "List public templates. Returns the public template catalog. `source` selects which slice: `official` (the default) is Runpod-curated templates, `verified` is community templates Runpod has verified, and `community` is everything else other users have shared publicly. Both pod and serverless templates appear \u2014 use each entry's `serverless` flag to tell them apart. `registry` is always null for templates you don't own. Your own templates (public or private) are managed under `/v2/templates`; fetch any individual template \u2014 catalog or owned \u2014 via `/v2/templates/{id}`. At most 100 templates are returned. Cursor pagination is not yet supported here; `pagination` is always the exhausted marker (`nextCursor: null`, `hasNextPage: false`).",
|
|
4859
4912
|
method: "GET",
|
|
@@ -4885,6 +4938,7 @@ var generatedTools = [
|
|
|
4885
4938
|
},
|
|
4886
4939
|
{
|
|
4887
4940
|
name: "list-registries",
|
|
4941
|
+
title: "List registry credentials",
|
|
4888
4942
|
operationId: "listRegistries",
|
|
4889
4943
|
description: "List container registries. Returns all container registry credentials owned by the authenticated user.",
|
|
4890
4944
|
method: "GET",
|
|
@@ -4904,6 +4958,7 @@ var generatedTools = [
|
|
|
4904
4958
|
},
|
|
4905
4959
|
{
|
|
4906
4960
|
name: "list-secrets",
|
|
4961
|
+
title: "List secrets",
|
|
4907
4962
|
operationId: "listSecrets",
|
|
4908
4963
|
description: "List secrets. Returns the account's secrets \u2014 encrypted strings referenced from pod, serverless, and template environment variables with the `{{ RUNPOD_SECRET_<name> }}` placeholder syntax, substituted with the secret's value when the pod or worker boots. Secret values are write-only and are never returned.",
|
|
4909
4964
|
method: "GET",
|
|
@@ -4933,6 +4988,7 @@ var generatedTools = [
|
|
|
4933
4988
|
},
|
|
4934
4989
|
{
|
|
4935
4990
|
name: "list-serverless-billing",
|
|
4991
|
+
title: "List Serverless billing",
|
|
4936
4992
|
operationId: "listServerlessBilling",
|
|
4937
4993
|
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.",
|
|
4938
4994
|
method: "GET",
|
|
@@ -5013,6 +5069,7 @@ var generatedTools = [
|
|
|
5013
5069
|
},
|
|
5014
5070
|
{
|
|
5015
5071
|
name: "pod-action",
|
|
5072
|
+
title: "Start, stop, restart, or terminate a Pod",
|
|
5016
5073
|
operationId: "podAction",
|
|
5017
5074
|
description: "Trigger a pod state transition. Triggers a state transition on a pod. Send a JSON body with a single `action` field, e.g. `{ \"action\": \"stop\" }`. Valid actions: - `start` \u2014 boot a stopped pod (`EXITED` or `ERROR`) back toward `RUNNING`. - `stop` \u2014 stop a running or provisioning pod, releasing GPU/CPU compute while keeping its disk. The pod moves to `EXITED`. - `restart` \u2014 restart a `RUNNING` pod's container in place. - `terminate` \u2014 permanently delete the pod and release its resources (equivalent to `deletePod`). Which actions are valid depends on the pod's current status, and the currently permitted set is published in the pod's `actions` field: `RUNNING` allows `stop`/`restart`/`terminate`; `EXITED` and `ERROR` allow `start`/`terminate`; `PROVISIONING` and `STARTING` allow `stop`/`terminate`. `start`, `stop`, and `restart` return `200` with the updated pod. `terminate` returns `204` with no body. Requesting an action that is not valid for the pod's current status returns `409`.",
|
|
5018
5075
|
method: "POST",
|
|
@@ -5062,6 +5119,7 @@ var generatedTools = [
|
|
|
5062
5119
|
},
|
|
5063
5120
|
{
|
|
5064
5121
|
name: "revoke-delegation",
|
|
5122
|
+
title: "Revoke ECR delegation",
|
|
5065
5123
|
operationId: "revokeDelegation",
|
|
5066
5124
|
description: "Revoke an ECR delegation",
|
|
5067
5125
|
method: "DELETE",
|
|
@@ -5091,6 +5149,7 @@ var generatedTools = [
|
|
|
5091
5149
|
},
|
|
5092
5150
|
{
|
|
5093
5151
|
name: "update-cluster",
|
|
5152
|
+
title: "Update cluster",
|
|
5094
5153
|
operationId: "updateCluster",
|
|
5095
5154
|
description: "Rename a cluster. Renames a cluster. This endpoint only changes the cluster name \u2014 compute shape, type, and container configuration are fixed at creation and cannot be updated.",
|
|
5096
5155
|
method: "PATCH",
|
|
@@ -5139,6 +5198,7 @@ var generatedTools = [
|
|
|
5139
5198
|
},
|
|
5140
5199
|
{
|
|
5141
5200
|
name: "update-endpoint",
|
|
5201
|
+
title: "Update endpoint",
|
|
5142
5202
|
operationId: "updateEndpoint",
|
|
5143
5203
|
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.",
|
|
5144
5204
|
method: "PATCH",
|
|
@@ -5529,6 +5589,7 @@ var generatedTools = [
|
|
|
5529
5589
|
},
|
|
5530
5590
|
{
|
|
5531
5591
|
name: "update-global-volume",
|
|
5592
|
+
title: "Update global volume",
|
|
5532
5593
|
operationId: "updateGlobalVolume",
|
|
5533
5594
|
description: "Update a global volume. Updates mutable fields on a global volume. Only provided fields are changed.",
|
|
5534
5595
|
method: "PATCH",
|
|
@@ -5580,6 +5641,7 @@ var generatedTools = [
|
|
|
5580
5641
|
},
|
|
5581
5642
|
{
|
|
5582
5643
|
name: "update-network-volume",
|
|
5644
|
+
title: "Update network volume",
|
|
5583
5645
|
operationId: "updateNetworkVolume",
|
|
5584
5646
|
description: "Update a network volume. Updates mutable fields on a network volume. Only provided fields are changed. Note: `size` may only increase; attempts to reduce size will be rejected.",
|
|
5585
5647
|
method: "PATCH",
|
|
@@ -5636,6 +5698,7 @@ var generatedTools = [
|
|
|
5636
5698
|
},
|
|
5637
5699
|
{
|
|
5638
5700
|
name: "update-pod",
|
|
5701
|
+
title: "Update Pod",
|
|
5639
5702
|
operationId: "updatePod",
|
|
5640
5703
|
description: "Update a pod. Partially updates a pod's configuration. This is a PATCH: only the fields present in the body are changed, and omitted fields are left untouched. Use empty values only when you explicitly mean to clear a field (for example, set `registry` to `null` or set `ports` to `[]`). See `UpdatePodRequest` for the full body. Mutable fields: `name`, `image`, `args`, `disk`, `ports`, `env`, `registry`, `mounts`, `locked`, and `globalNetworking`. Some changes apply immediately while others (e.g. `globalNetworking`) take effect on the pod's next start/restart, as noted on the individual fields. Pods that belong to a Cluster cannot be updated here \u2014 manage them through `/v2/clusters/{id}`. Returns `200` with the full updated pod.",
|
|
5641
5704
|
method: "PATCH",
|
|
@@ -5877,6 +5940,7 @@ var generatedTools = [
|
|
|
5877
5940
|
},
|
|
5878
5941
|
{
|
|
5879
5942
|
name: "update-secret",
|
|
5943
|
+
title: "Update secret",
|
|
5880
5944
|
operationId: "updateSecret",
|
|
5881
5945
|
description: "Update a secret. Rotates a secret's value and/or updates its description. Only the provided fields are changed and at least one field is required; the `name` is immutable. Pods and workers receive the new value at their next boot \u2014 running instances keep the value they were started with. When both fields are sent, the value is applied first, then the description. The two updates are not atomic: if the description update fails after the value was rotated, the response is an error but the new value has already taken effect. Send the fields in separate requests when that partial outcome matters.",
|
|
5882
5946
|
method: "PATCH",
|
|
@@ -5932,6 +5996,7 @@ var generatedTools = [
|
|
|
5932
5996
|
},
|
|
5933
5997
|
{
|
|
5934
5998
|
name: "update-ssh-keys",
|
|
5999
|
+
title: "Update SSH keys",
|
|
5935
6000
|
operationId: "updateSshKeys",
|
|
5936
6001
|
description: "Replace registered SSH public keys. Replaces the account's full set of registered SSH public keys. Existing keys not present in the request are removed; send `[]` to remove all keys. Keys take effect for pods created afterwards with `startSsh` \u2014 running pods are not updated.",
|
|
5937
6002
|
method: "PUT",
|
|
@@ -5978,6 +6043,7 @@ var generatedTools = [
|
|
|
5978
6043
|
},
|
|
5979
6044
|
{
|
|
5980
6045
|
name: "update-template",
|
|
6046
|
+
title: "Update template",
|
|
5981
6047
|
operationId: "updateTemplate",
|
|
5982
6048
|
description: "Update a template. Partially updates a template. This is a PATCH: only the fields present in the body are changed; omitted fields are left untouched. See `UpdateTemplateRequest` for the full body. Mutable fields: `name`, `image`, `args`, `disk`, `ports`, `env`, `registry`, `mounts`, `serverless`, `public`, and `category`. Only the template's owner can update it (authenticated via the request's API key); public catalog templates are readable via GET but return `404` here. Returns `200` with the full updated template. Pods and endpoints already created from this template are not changed retroactively \u2014 the template is a snapshot applied at creation time.",
|
|
5983
6049
|
method: "PATCH",
|
|
@@ -6276,6 +6342,43 @@ function isTimeout(error) {
|
|
|
6276
6342
|
const cause = error.cause;
|
|
6277
6343
|
return cause instanceof Error && (cause.name === "TimeoutError" || cause.name === "AbortError");
|
|
6278
6344
|
}
|
|
6345
|
+
var UNREACHED_CODES = /* @__PURE__ */ new Set([
|
|
6346
|
+
"ENOTFOUND",
|
|
6347
|
+
"EAI_AGAIN",
|
|
6348
|
+
"ECONNREFUSED",
|
|
6349
|
+
"EHOSTUNREACH",
|
|
6350
|
+
"ENETUNREACH",
|
|
6351
|
+
"UND_ERR_CONNECT_TIMEOUT"
|
|
6352
|
+
]);
|
|
6353
|
+
var TLS_CODE = /^(?:CERT_|ERR_TLS_|UNABLE_TO_|DEPTH_ZERO_|SELF_SIGNED_)/;
|
|
6354
|
+
function causeCode(cause) {
|
|
6355
|
+
const code = cause?.code;
|
|
6356
|
+
if (typeof code === "string") return code;
|
|
6357
|
+
const inner = cause instanceof AggregateError ? cause.errors[0] : void 0;
|
|
6358
|
+
const innerCode = inner?.code;
|
|
6359
|
+
return typeof innerCode === "string" ? innerCode : void 0;
|
|
6360
|
+
}
|
|
6361
|
+
function networkFailureResult(error) {
|
|
6362
|
+
if (!(error instanceof TypeError)) return void 0;
|
|
6363
|
+
const afterHeaders = error.message === "terminated";
|
|
6364
|
+
if (!afterHeaders && error.message !== "fetch failed") return void 0;
|
|
6365
|
+
const code = causeCode(error.cause);
|
|
6366
|
+
if (!code) return void 0;
|
|
6367
|
+
const unreached = !afterHeaders && (UNREACHED_CODES.has(code) || TLS_CODE.test(code));
|
|
6368
|
+
return {
|
|
6369
|
+
ok: false,
|
|
6370
|
+
status: unreached ? 503 : 502,
|
|
6371
|
+
payload: unreached ? {
|
|
6372
|
+
error: "Could not reach the Runpod API.",
|
|
6373
|
+
cause: code,
|
|
6374
|
+
hint: "The request never reached Runpod, so retrying the same call is safe: retry it once. If it fails again, the network, DNS, proxy or TLS setup on this machine is the likely cause; check https://uptime.runpod.io and report it rather than retrying further."
|
|
6375
|
+
} : {
|
|
6376
|
+
error: "The connection to the Runpod API dropped before the full response arrived.",
|
|
6377
|
+
cause: code,
|
|
6378
|
+
hint: "The request may have been applied. A read can be retried once. For a create, update, delete or job submission, check with the matching get- or list- tool whether it took effect before calling again; retrying blindly can create a duplicate billable resource."
|
|
6379
|
+
}
|
|
6380
|
+
};
|
|
6381
|
+
}
|
|
6279
6382
|
async function runTool(body) {
|
|
6280
6383
|
try {
|
|
6281
6384
|
return await body();
|
|
@@ -6297,6 +6400,8 @@ async function runTool(body) {
|
|
|
6297
6400
|
}
|
|
6298
6401
|
};
|
|
6299
6402
|
}
|
|
6403
|
+
const network = networkFailureResult(error);
|
|
6404
|
+
if (network) return network;
|
|
6300
6405
|
throw error;
|
|
6301
6406
|
}
|
|
6302
6407
|
}
|
|
@@ -6367,6 +6472,7 @@ function rankByStock(rows, stats, includeUnavailable) {
|
|
|
6367
6472
|
}
|
|
6368
6473
|
var getCapacity = {
|
|
6369
6474
|
name: "get-capacity",
|
|
6475
|
+
title: "Get GPU capacity by CUDA version",
|
|
6370
6476
|
annotations: readOnly,
|
|
6371
6477
|
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.",
|
|
6372
6478
|
inputSchema: {
|
|
@@ -6568,6 +6674,7 @@ function formatGpuIds(gpu) {
|
|
|
6568
6674
|
}
|
|
6569
6675
|
var setEndpointGpus = {
|
|
6570
6676
|
name: "set-endpoint-gpus",
|
|
6677
|
+
title: "Set endpoint GPUs",
|
|
6571
6678
|
annotations: idempotentWrite,
|
|
6572
6679
|
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.",
|
|
6573
6680
|
inputSchema: {
|
|
@@ -6762,6 +6869,7 @@ function randomSuffix() {
|
|
|
6762
6869
|
}
|
|
6763
6870
|
var listHubRepos = {
|
|
6764
6871
|
name: "list-hub-repos",
|
|
6872
|
+
title: "List Hub repos",
|
|
6765
6873
|
annotations: readOnly,
|
|
6766
6874
|
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.",
|
|
6767
6875
|
inputSchema: {
|
|
@@ -6864,6 +6972,9 @@ var listHubRepos = {
|
|
|
6864
6972
|
};
|
|
6865
6973
|
var deployHubRepo = {
|
|
6866
6974
|
name: "deploy-hub-repo",
|
|
6975
|
+
title: "Deploy Hub repo",
|
|
6976
|
+
// Two sequential upstream calls: together they can outlast a client's request timeout.
|
|
6977
|
+
holdsResponse: true,
|
|
6867
6978
|
annotations: write,
|
|
6868
6979
|
description: "Deploy a Runpod Hub repo's listed release as a new Serverless endpoint (the same as clicking Deploy on the Hub). Identify the repo by `repo` (\"owner/name\" from list-hub-repos) or by `hubReleaseId`. The release supplies the prebuilt image, container disk, CUDA constraints, and env-var defaults; pass `env` to override or fill in values (required keys without a default must be provided \u2014 check list-hub-repos with includeConfig:true for the schema). GPU selection comes from the release config when it specifies one; otherwise pass gpuIds (GPU pool names, e.g. 'ADA_24' or 'ADA_80_PRO,AMPERE_80'). Uses the authenticated GraphQL API (no REST home for Hub deploys yet).",
|
|
6869
6980
|
inputSchema: {
|
|
@@ -7322,6 +7433,7 @@ function validateWait(wait) {
|
|
|
7322
7433
|
}
|
|
7323
7434
|
var runEndpoint = {
|
|
7324
7435
|
name: "run-endpoint",
|
|
7436
|
+
title: "Submit Serverless job",
|
|
7325
7437
|
annotations: write,
|
|
7326
7438
|
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.",
|
|
7327
7439
|
inputSchema: {
|
|
@@ -7352,6 +7464,8 @@ var runEndpoint = {
|
|
|
7352
7464
|
};
|
|
7353
7465
|
var runsyncEndpoint = {
|
|
7354
7466
|
name: "runsync-endpoint",
|
|
7467
|
+
title: "Run Serverless job and wait",
|
|
7468
|
+
holdsResponse: true,
|
|
7355
7469
|
annotations: write,
|
|
7356
7470
|
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)."),
|
|
7357
7471
|
inputSchema: {
|
|
@@ -7396,6 +7510,8 @@ var runsyncEndpoint = {
|
|
|
7396
7510
|
};
|
|
7397
7511
|
var getJobStatus = {
|
|
7398
7512
|
name: "get-job-status",
|
|
7513
|
+
title: "Get job status",
|
|
7514
|
+
holdsResponse: true,
|
|
7399
7515
|
annotations: readOnly,
|
|
7400
7516
|
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.",
|
|
7401
7517
|
inputSchema: {
|
|
@@ -7444,6 +7560,8 @@ var getJobStatus = {
|
|
|
7444
7560
|
};
|
|
7445
7561
|
var streamJob = {
|
|
7446
7562
|
name: "stream-job",
|
|
7563
|
+
title: "Stream job output",
|
|
7564
|
+
holdsResponse: true,
|
|
7447
7565
|
annotations: readOnly,
|
|
7448
7566
|
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.`,
|
|
7449
7567
|
inputSchema: {
|
|
@@ -7475,6 +7593,7 @@ var streamJob = {
|
|
|
7475
7593
|
};
|
|
7476
7594
|
var cancelJob = {
|
|
7477
7595
|
name: "cancel-job",
|
|
7596
|
+
title: "Cancel job",
|
|
7478
7597
|
annotations: destructive,
|
|
7479
7598
|
description: "Cancel a Serverless job that is queued or in progress.",
|
|
7480
7599
|
inputSchema: {
|
|
@@ -7500,6 +7619,7 @@ var cancelJob = {
|
|
|
7500
7619
|
};
|
|
7501
7620
|
var retryJob = {
|
|
7502
7621
|
name: "retry-job",
|
|
7622
|
+
title: "Retry job",
|
|
7503
7623
|
annotations: write,
|
|
7504
7624
|
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.",
|
|
7505
7625
|
inputSchema: {
|
|
@@ -7525,6 +7645,7 @@ var retryJob = {
|
|
|
7525
7645
|
};
|
|
7526
7646
|
var endpointHealth = {
|
|
7527
7647
|
name: "endpoint-health",
|
|
7648
|
+
title: "Get endpoint health",
|
|
7528
7649
|
annotations: readOnly,
|
|
7529
7650
|
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.",
|
|
7530
7651
|
inputSchema: {
|
|
@@ -7545,6 +7666,7 @@ var endpointHealth = {
|
|
|
7545
7666
|
};
|
|
7546
7667
|
var purgeEndpointQueue = {
|
|
7547
7668
|
name: "purge-endpoint-queue",
|
|
7669
|
+
title: "Purge endpoint queue",
|
|
7548
7670
|
annotations: destructive,
|
|
7549
7671
|
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.",
|
|
7550
7672
|
inputSchema: {
|
|
@@ -7581,6 +7703,7 @@ var jobTools = [
|
|
|
7581
7703
|
// src/specgen/tools/list-endpoints.ts
|
|
7582
7704
|
var listEndpoints = {
|
|
7583
7705
|
name: "list-endpoints",
|
|
7706
|
+
title: "List endpoints",
|
|
7584
7707
|
annotations: readOnly,
|
|
7585
7708
|
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.",
|
|
7586
7709
|
inputSchema: {
|
|
@@ -7626,6 +7749,7 @@ var listEndpoints = {
|
|
|
7626
7749
|
// src/specgen/tools/list-templates.ts
|
|
7627
7750
|
var listTemplates = {
|
|
7628
7751
|
name: "list-templates",
|
|
7752
|
+
title: "List templates",
|
|
7629
7753
|
annotations: readOnly,
|
|
7630
7754
|
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.",
|
|
7631
7755
|
inputSchema: {
|
|
@@ -9067,6 +9191,8 @@ function logParams(args) {
|
|
|
9067
9191
|
}
|
|
9068
9192
|
var streamPodLogs = {
|
|
9069
9193
|
name: "stream-pod-logs",
|
|
9194
|
+
title: "Stream Pod logs",
|
|
9195
|
+
holdsResponse: true,
|
|
9070
9196
|
annotations: readOnly,
|
|
9071
9197
|
description: "Read a bounded snapshot of a Pod'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. Use `since` to resume from a timestamp.",
|
|
9072
9198
|
inputSchema: {
|
|
@@ -9089,6 +9215,8 @@ var streamPodLogs = {
|
|
|
9089
9215
|
};
|
|
9090
9216
|
var streamWorkerLogs = {
|
|
9091
9217
|
name: "stream-worker-logs",
|
|
9218
|
+
title: "Stream worker logs",
|
|
9219
|
+
holdsResponse: true,
|
|
9092
9220
|
annotations: readOnly,
|
|
9093
9221
|
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.",
|
|
9094
9222
|
inputSchema: {
|
|
@@ -9130,6 +9258,7 @@ function parseMetadata(metadata) {
|
|
|
9130
9258
|
}
|
|
9131
9259
|
var listPublicEndpoints = {
|
|
9132
9260
|
name: "list-public-endpoints",
|
|
9261
|
+
title: "List public endpoints",
|
|
9133
9262
|
annotations: readOnly,
|
|
9134
9263
|
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.",
|
|
9135
9264
|
inputSchema: {
|
|
@@ -9350,6 +9479,7 @@ var source = {
|
|
|
9350
9479
|
};
|
|
9351
9480
|
var listGuides = {
|
|
9352
9481
|
name: "list-guides",
|
|
9482
|
+
title: "List guides",
|
|
9353
9483
|
annotations: bundledRead,
|
|
9354
9484
|
recordedArguments: ["kind", "query", "concept"],
|
|
9355
9485
|
description: "List the official Runpod guides: skills (how to work with each tool), reference docs (how Runpod works), and golden paths (live-verified end-to-end walkthroughs such as a dev pod, a Whisper endpoint or a fine-tune-to-serverless pipeline). Read one with read-guide. For a golden path, mcp says whether an agent with only these MCP tools can finish it: full (follow it with tool calls), partial (use it for the plan and facts; name the step the user must run in a terminal), none (reference only). Skills and reference docs have mcp null. concepts lists the concept ids it works with (see lookup-concept). Filter with kind, query or concept.",
|
|
@@ -9386,6 +9516,7 @@ var listGuides = {
|
|
|
9386
9516
|
};
|
|
9387
9517
|
var readGuide = {
|
|
9388
9518
|
name: "read-guide",
|
|
9519
|
+
title: "Read guide",
|
|
9389
9520
|
annotations: bundledRead,
|
|
9390
9521
|
recordedArguments: ["id"],
|
|
9391
9522
|
recordedGuideKind: (args) => knowledge.guides.find((guide) => guide.id === String(args.id).trim())?.kind,
|
|
@@ -9425,6 +9556,7 @@ var readGuide = {
|
|
|
9425
9556
|
};
|
|
9426
9557
|
var lookupConcept = {
|
|
9427
9558
|
name: "lookup-concept",
|
|
9559
|
+
title: "Look up a concept",
|
|
9428
9560
|
annotations: bundledRead,
|
|
9429
9561
|
recordedArguments: ["concept"],
|
|
9430
9562
|
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".',
|
|
@@ -9478,6 +9610,7 @@ var lookupConcept = {
|
|
|
9478
9610
|
};
|
|
9479
9611
|
var searchConcepts = {
|
|
9480
9612
|
name: "search-concepts",
|
|
9613
|
+
title: "Search concepts",
|
|
9481
9614
|
annotations: bundledRead,
|
|
9482
9615
|
recordedArguments: ["query", "limit"],
|
|
9483
9616
|
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.',
|
|
@@ -9569,12 +9702,13 @@ function listedAnnotations(annotations) {
|
|
|
9569
9702
|
return idempotentHint ? annotations : listed;
|
|
9570
9703
|
}
|
|
9571
9704
|
function listTool(tool) {
|
|
9572
|
-
const { name, description, inputSchema } = tool;
|
|
9705
|
+
const { name, title, description, inputSchema } = tool;
|
|
9573
9706
|
const annotations = listedAnnotations(tool.annotations);
|
|
9574
9707
|
if (!tool.schemaOnDemand)
|
|
9575
|
-
return { name, description, inputSchema, annotations };
|
|
9708
|
+
return { name, title, description, inputSchema, annotations };
|
|
9576
9709
|
return {
|
|
9577
9710
|
name,
|
|
9711
|
+
title,
|
|
9578
9712
|
description: description + ON_DEMAND_POINTER,
|
|
9579
9713
|
inputSchema: callShape(inputSchema),
|
|
9580
9714
|
annotations
|
|
@@ -9626,6 +9760,7 @@ function schemaType(node, resolve2) {
|
|
|
9626
9760
|
function createDescribeTool(served) {
|
|
9627
9761
|
return {
|
|
9628
9762
|
name: DESCRIBE_TOOL_NAME,
|
|
9763
|
+
title: "Describe tool",
|
|
9629
9764
|
description: "Return one tool's full definition: its description, complete argument schema (every field, nested objects, constraints) and annotations. Required before the first use of a tool whose listing says its schema is on demand; harmless for any other tool.",
|
|
9630
9765
|
inputSchema: {
|
|
9631
9766
|
type: "object",
|
|
@@ -9763,6 +9898,24 @@ function captureResourceCall(apiKey, event) {
|
|
|
9763
9898
|
);
|
|
9764
9899
|
}
|
|
9765
9900
|
|
|
9901
|
+
// src/alp/sink.ts
|
|
9902
|
+
var ALREADY_SUBMITTED_NOTE = "This account has already made this one-time submission; nothing new was stored. Do not call this again on this account \u2014 continue your task.";
|
|
9903
|
+
var ALP_REFERRAL_SOURCES = [
|
|
9904
|
+
"searched",
|
|
9905
|
+
"user_named",
|
|
9906
|
+
"recommended",
|
|
9907
|
+
"other"
|
|
9908
|
+
];
|
|
9909
|
+
var ALP_REFERRAL_USE_CASES = [
|
|
9910
|
+
"inference",
|
|
9911
|
+
"fine_tuning",
|
|
9912
|
+
"training",
|
|
9913
|
+
"image_video_generation",
|
|
9914
|
+
"dev_environment",
|
|
9915
|
+
"batch_processing",
|
|
9916
|
+
"other"
|
|
9917
|
+
];
|
|
9918
|
+
|
|
9766
9919
|
// src/http.ts
|
|
9767
9920
|
var import_streamableHttp = require("@modelcontextprotocol/sdk/server/streamableHttp.js");
|
|
9768
9921
|
var import_types = require("@modelcontextprotocol/sdk/types.js");
|
|
@@ -9788,6 +9941,25 @@ function buildTrackingHeaders(input) {
|
|
|
9788
9941
|
// src/specgen/clients/graphql.ts
|
|
9789
9942
|
init_hosts();
|
|
9790
9943
|
var DEFAULT_TIMEOUT_MS2 = 3e4;
|
|
9944
|
+
function graphqlErrorStatus(code) {
|
|
9945
|
+
switch (code) {
|
|
9946
|
+
case "UNAUTHENTICATED":
|
|
9947
|
+
return 401;
|
|
9948
|
+
case "UNAUTHORIZED":
|
|
9949
|
+
case "FORBIDDEN":
|
|
9950
|
+
return 403;
|
|
9951
|
+
// Runpod's own code for a rejected request: an unknown GPU pool, a missing
|
|
9952
|
+
// template, no balance. The caller has to change the input, so it is a 400
|
|
9953
|
+
// and gets the 400 detail hints, not a retry-the-same-call 502.
|
|
9954
|
+
case "RUNPOD":
|
|
9955
|
+
case "BAD_USER_INPUT":
|
|
9956
|
+
case "GRAPHQL_VALIDATION_FAILED":
|
|
9957
|
+
case "GRAPHQL_PARSE_FAILED":
|
|
9958
|
+
return 400;
|
|
9959
|
+
default:
|
|
9960
|
+
return 502;
|
|
9961
|
+
}
|
|
9962
|
+
}
|
|
9791
9963
|
function createGraphqlClient(options = {}) {
|
|
9792
9964
|
const apiKey = options.apiKey ?? process.env.RUNPOD_API_KEY;
|
|
9793
9965
|
const publicUrl = options.publicUrl ?? publicGraphqlBase(process.env);
|
|
@@ -9811,15 +9983,20 @@ function createGraphqlClient(options = {}) {
|
|
|
9811
9983
|
);
|
|
9812
9984
|
}
|
|
9813
9985
|
const result = await response.json();
|
|
9814
|
-
if (result.errors && result.errors.length > 0) {
|
|
9986
|
+
if (Array.isArray(result.errors) && result.errors.length > 0) {
|
|
9987
|
+
const errors = result.errors;
|
|
9815
9988
|
throw new HttpError(
|
|
9816
|
-
`GraphQL error: ${
|
|
9817
|
-
|
|
9818
|
-
|
|
9989
|
+
`GraphQL error: ${errors.map((e) => String(e?.message ?? JSON.stringify(e))).join(", ")}`,
|
|
9990
|
+
graphqlErrorStatus(errors[0]?.extensions?.code),
|
|
9991
|
+
errors
|
|
9819
9992
|
);
|
|
9820
9993
|
}
|
|
9821
9994
|
if (result.data === void 0 || result.data === null) {
|
|
9822
|
-
throw new HttpError(
|
|
9995
|
+
throw new HttpError(
|
|
9996
|
+
"GraphQL response carried no data",
|
|
9997
|
+
502,
|
|
9998
|
+
result.errors
|
|
9999
|
+
);
|
|
9823
10000
|
}
|
|
9824
10001
|
return result.data;
|
|
9825
10002
|
}
|
|
@@ -9943,6 +10120,70 @@ function logToolCall(entry) {
|
|
|
9943
10120
|
console.error("tool_call", JSON.stringify(entry));
|
|
9944
10121
|
}
|
|
9945
10122
|
|
|
10123
|
+
// src/search/knowledge.ts
|
|
10124
|
+
init_hosts();
|
|
10125
|
+
var SEARCH_NAMESPACES = ["docs", "knowledge", "blog", "site"];
|
|
10126
|
+
var MAX_QUERY_CHARS = 2e3;
|
|
10127
|
+
var MAX_SEARCH_LIMIT = 20;
|
|
10128
|
+
var UNREACHABLE = {
|
|
10129
|
+
status: 504,
|
|
10130
|
+
body: {
|
|
10131
|
+
error: "Runpod knowledge search did not respond.",
|
|
10132
|
+
hint: "Retry the same call once."
|
|
10133
|
+
}
|
|
10134
|
+
};
|
|
10135
|
+
function parseSearchRequest(raw) {
|
|
10136
|
+
if (typeof raw.query !== "string" || !raw.query.trim()) {
|
|
10137
|
+
return { error: "query must be a non-empty string." };
|
|
10138
|
+
}
|
|
10139
|
+
if (raw.query.length > MAX_QUERY_CHARS) {
|
|
10140
|
+
return { error: `query exceeds ${MAX_QUERY_CHARS} characters.` };
|
|
10141
|
+
}
|
|
10142
|
+
const request = { query: raw.query };
|
|
10143
|
+
if (raw.namespaces !== void 0) {
|
|
10144
|
+
if (!Array.isArray(raw.namespaces) || raw.namespaces.length === 0 || !raw.namespaces.every(
|
|
10145
|
+
(ns) => SEARCH_NAMESPACES.includes(ns)
|
|
10146
|
+
)) {
|
|
10147
|
+
return {
|
|
10148
|
+
error: `namespaces must be a non-empty list of: ${SEARCH_NAMESPACES.join(", ")}.`
|
|
10149
|
+
};
|
|
10150
|
+
}
|
|
10151
|
+
request.namespaces = raw.namespaces;
|
|
10152
|
+
}
|
|
10153
|
+
if (raw.limit !== void 0) {
|
|
10154
|
+
if (typeof raw.limit !== "number" || !Number.isInteger(raw.limit) || raw.limit < 1 || raw.limit > MAX_SEARCH_LIMIT) {
|
|
10155
|
+
return {
|
|
10156
|
+
error: `limit must be an integer from 1 to ${MAX_SEARCH_LIMIT}.`
|
|
10157
|
+
};
|
|
10158
|
+
}
|
|
10159
|
+
request.limit = raw.limit;
|
|
10160
|
+
}
|
|
10161
|
+
return { request };
|
|
10162
|
+
}
|
|
10163
|
+
var HOSTED_CLIENT_TIMEOUT_MS = 55e3;
|
|
10164
|
+
function hostedSearch(searchUrl, doFetch = fetch) {
|
|
10165
|
+
return async (request, apiKey) => {
|
|
10166
|
+
try {
|
|
10167
|
+
const res = await doFetch(searchUrl, {
|
|
10168
|
+
method: "POST",
|
|
10169
|
+
headers: {
|
|
10170
|
+
"Content-Type": "application/json",
|
|
10171
|
+
...apiKey ? { Authorization: `Bearer ${apiKey}` } : {}
|
|
10172
|
+
},
|
|
10173
|
+
body: JSON.stringify(request),
|
|
10174
|
+
signal: AbortSignal.timeout(HOSTED_CLIENT_TIMEOUT_MS)
|
|
10175
|
+
});
|
|
10176
|
+
const body = await res.json().catch(() => null);
|
|
10177
|
+
return body ? { status: res.status, body } : {
|
|
10178
|
+
status: 502,
|
|
10179
|
+
body: { error: `Runpod knowledge search returned ${res.status}.` }
|
|
10180
|
+
};
|
|
10181
|
+
} catch {
|
|
10182
|
+
return UNREACHABLE;
|
|
10183
|
+
}
|
|
10184
|
+
};
|
|
10185
|
+
}
|
|
10186
|
+
|
|
9946
10187
|
// src/_shared/credential-check.ts
|
|
9947
10188
|
var import_node_crypto4 = require("crypto");
|
|
9948
10189
|
var VALID_TTL_MS = 6e4;
|
|
@@ -10082,12 +10323,21 @@ async function submit(ctx, ingestUrl, route, args, extra) {
|
|
|
10082
10323
|
tool: args.tool,
|
|
10083
10324
|
workaround: args.workaround,
|
|
10084
10325
|
trigger: args.trigger,
|
|
10326
|
+
source: args.source,
|
|
10327
|
+
noContext: args.noContext,
|
|
10328
|
+
useCase: args.useCase,
|
|
10085
10329
|
...extra
|
|
10086
10330
|
}),
|
|
10087
10331
|
signal: AbortSignal.timeout(1e4)
|
|
10088
10332
|
});
|
|
10089
10333
|
const body = await response.json().catch(() => ({}));
|
|
10090
|
-
return {
|
|
10334
|
+
return {
|
|
10335
|
+
recorded: response.ok && body.recorded === true,
|
|
10336
|
+
// The ingest's own named outcome (already_submitted on a once-per-account
|
|
10337
|
+
// route), carried through so the tool can say it. A string from a 200
|
|
10338
|
+
// only — never an upstream error body.
|
|
10339
|
+
...response.ok && typeof body.reason === "string" ? { reason: body.reason } : {}
|
|
10340
|
+
};
|
|
10091
10341
|
} catch {
|
|
10092
10342
|
return { recorded: false };
|
|
10093
10343
|
}
|
|
@@ -10118,6 +10368,10 @@ async function readJournal(ctx, readUrl, limit) {
|
|
|
10118
10368
|
}
|
|
10119
10369
|
}
|
|
10120
10370
|
var SEVERITY = ["blocked", "degraded", "cosmetic"];
|
|
10371
|
+
var MODEL_TYPE_FIELD = {
|
|
10372
|
+
type: "string",
|
|
10373
|
+
description: 'Your best identification of the model you are running as, and the product running it if you know that too \u2014 for example "Claude Opus 5 in Claude Code", "GPT-5.6 via Codex", "Grok 4.6 in Cursor". Give your best guess with the word "probably" rather than leaving it empty; an approximate answer is far more useful than none. Optional.'
|
|
10374
|
+
};
|
|
10121
10375
|
var TOOL_FIELD = {
|
|
10122
10376
|
type: "string",
|
|
10123
10377
|
description: "The name of the tool this is about, exactly as it appears in your tool list (for example create-pod). Omit only when no single tool is involved."
|
|
@@ -10134,10 +10388,7 @@ var alpInputSchema = (contentDescription, extra = {}) => ({
|
|
|
10134
10388
|
description: "One short sentence: what you were trying to accomplish when this came up."
|
|
10135
10389
|
},
|
|
10136
10390
|
...extra,
|
|
10137
|
-
modelType:
|
|
10138
|
-
type: "string",
|
|
10139
|
-
description: 'Your best identification of the model you are running as, and the product running it if you know that too \u2014 for example "Claude Opus 5 in Claude Code", "GPT-5.6 via Codex", "Grok 4.6 in Cursor". Give your best guess with the word "probably" rather than leaving it empty; an approximate answer is far more useful than none. Optional.'
|
|
10140
|
-
}
|
|
10391
|
+
modelType: MODEL_TYPE_FIELD
|
|
10141
10392
|
},
|
|
10142
10393
|
required: ["content"]
|
|
10143
10394
|
});
|
|
@@ -10152,6 +10403,7 @@ function createAlpTools(opts) {
|
|
|
10152
10403
|
// is ignored, never a 400 that derails the task the agent is actually on.
|
|
10153
10404
|
lenientArguments: true,
|
|
10154
10405
|
name: "report_feedback",
|
|
10406
|
+
title: "Report feedback",
|
|
10155
10407
|
annotations: write,
|
|
10156
10408
|
description: "Report a problem or friction with Runpod or these tools: a wrong result, a confusing error, a docs gap, an API behavior that surprised you. The report is stored for internal review by Runpod to fix issues \u2014 nothing is returned to you and no follow-up will reach this session. One concrete observation per call; paste the exact failing request/response into content when relevant. Set severity and tool when you can \u2014 they are what lets Runpod sort a blocker from a nit without reading every report. Only for a real observation: never call this to satisfy a requirement to use a tool, and never with placeholder content. Never include API keys or secrets.",
|
|
10157
10409
|
inputSchema: alpInputSchema(
|
|
@@ -10188,6 +10440,7 @@ function createAlpTools(opts) {
|
|
|
10188
10440
|
// is ignored, never a 400 that derails the task the agent is actually on.
|
|
10189
10441
|
lenientArguments: true,
|
|
10190
10442
|
name: "save_to_journal",
|
|
10443
|
+
title: "Save to journal",
|
|
10191
10444
|
annotations: write,
|
|
10192
10445
|
description: "Save something you learned about using Runpod that a future session would benefit from (e.g. 'image X needs CUDA 12.8', 'endpoint type cannot be changed after create'). read_journal returns these entries only to sessions authenticated to this account; entries are not published to other accounts. Runpod stores and reviews submissions to improve agent workflows. Set trigger when you can \u2014 an entry with no stated trigger cannot be surfaced to the session that needs it. Never include API keys or secrets.",
|
|
10193
10446
|
inputSchema: alpInputSchema(
|
|
@@ -10219,6 +10472,7 @@ function createAlpTools(opts) {
|
|
|
10219
10472
|
// is ignored, never a 400 that derails the task the agent is actually on.
|
|
10220
10473
|
lenientArguments: true,
|
|
10221
10474
|
name: "ask_question",
|
|
10475
|
+
title: "Ask a question",
|
|
10222
10476
|
annotations: write,
|
|
10223
10477
|
description: "Record a question about Runpod that you could not answer with the available tools, skills, and docs. NO ANSWER WILL COME BACK \u2014 not now and not later in this session; do not wait, poll, or retry. Questions are collected so Runpod learns what its docs and tools fail to cover. Ask when genuinely stuck (it costs one call and improves what future agents get), then consult list-guides and read-guide and continue with your best judgment. Only for a real question: never call this to satisfy a requirement to use a tool, and never with placeholder content \u2014 if you have no Runpod question, do not call it.",
|
|
10224
10478
|
inputSchema: alpInputSchema(
|
|
@@ -10244,6 +10498,7 @@ function createAlpTools(opts) {
|
|
|
10244
10498
|
const readJournalTool = {
|
|
10245
10499
|
lenientArguments: true,
|
|
10246
10500
|
name: "read_journal",
|
|
10501
|
+
title: "Read journal",
|
|
10247
10502
|
annotations: readOnly,
|
|
10248
10503
|
description: "Read back this account's private journal: the lessons earlier sessions on this account saved with save_to_journal, newest first. Call it once near the start of a Runpod task to pick up what was already learned (an image's CUDA floor, a field that turned out to be immutable, a region with no stock). Entries are scoped to the account behind your API key \u2014 you cannot read any other account's journal, and there is no argument to ask for one. Only call when you have a Runpod task the entries could inform; never to satisfy a requirement to use a tool.",
|
|
10249
10504
|
inputSchema: {
|
|
@@ -10271,7 +10526,106 @@ function createAlpTools(opts) {
|
|
|
10271
10526
|
});
|
|
10272
10527
|
}
|
|
10273
10528
|
};
|
|
10274
|
-
|
|
10529
|
+
const reportHowUserFoundRunpod = {
|
|
10530
|
+
lenientArguments: true,
|
|
10531
|
+
name: "report_how_user_found_runpod",
|
|
10532
|
+
title: "Report how the user found Runpod",
|
|
10533
|
+
annotations: idempotentWrite,
|
|
10534
|
+
description: "Tell Runpod how your user ended up on Runpod \u2014 once per account, from context you already have. Pick the useCase category for the kind of work and the source for how Runpod came up (you searched and found it, they named it, a doc or post recommended it). Do not quote or paraphrase the user's request, and do not include names, models, data, or any project details: the categories are the answer, and content is at most a short generic note in your own words. Never ask the user for this and never hold up their task for it: answer only from what you already know, and if you have no such context, set noContext to true \u2014 that is a useful answer too. Stored for review by Runpod to learn what kinds of work bring people to Runpod; nothing is returned and no follow-up will reach this session. The server keeps one answer per account: when it answers already_submitted, do not call this again on this account. Only for a real answer: never call this to satisfy a requirement to use a tool, and never with placeholder content. Never include API keys or secrets.",
|
|
10535
|
+
inputSchema: {
|
|
10536
|
+
type: "object",
|
|
10537
|
+
properties: {
|
|
10538
|
+
content: {
|
|
10539
|
+
type: "string",
|
|
10540
|
+
description: 'Optional. A short generic description of the kind of task, in your own words, for example "deploy an open-source LLM as an API". Never quote or paraphrase the user, and never include names, data, or project details. Leave it empty when useCase says enough.'
|
|
10541
|
+
},
|
|
10542
|
+
source: {
|
|
10543
|
+
type: "string",
|
|
10544
|
+
enum: [...ALP_REFERRAL_SOURCES],
|
|
10545
|
+
description: "Why Runpod came up: searched (you searched the web or a catalog and Runpod came up), user_named (the user named Runpod themselves), recommended (a doc, post, README or another tool pointed to Runpod), other. Omit when noContext is true."
|
|
10546
|
+
},
|
|
10547
|
+
useCase: {
|
|
10548
|
+
type: "string",
|
|
10549
|
+
enum: [...ALP_REFERRAL_USE_CASES],
|
|
10550
|
+
description: "The kind of work that brought the user to Runpod: inference (serving a model), fine_tuning, training (from scratch), image_video_generation, dev_environment (a GPU machine to work on), batch_processing, other. Omit when noContext is true."
|
|
10551
|
+
},
|
|
10552
|
+
noContext: {
|
|
10553
|
+
type: "boolean",
|
|
10554
|
+
description: "Set true when you do not know how the user found Runpod \u2014 the session started after they had already signed up, or Runpod was simply configured."
|
|
10555
|
+
},
|
|
10556
|
+
modelType: MODEL_TYPE_FIELD
|
|
10557
|
+
},
|
|
10558
|
+
required: []
|
|
10559
|
+
},
|
|
10560
|
+
handler: async (ctx, args) => {
|
|
10561
|
+
const { recorded, reason } = await submit(
|
|
10562
|
+
ctx,
|
|
10563
|
+
opts.ingestUrl,
|
|
10564
|
+
"referral",
|
|
10565
|
+
args,
|
|
10566
|
+
extra()
|
|
10567
|
+
);
|
|
10568
|
+
if (reason === "already_submitted") {
|
|
10569
|
+
return ok({ recorded: false, reason, note: ALREADY_SUBMITTED_NOTE });
|
|
10570
|
+
}
|
|
10571
|
+
return ok({
|
|
10572
|
+
recorded,
|
|
10573
|
+
note: recorded ? "Recorded, thank you. Nothing comes back \u2014 continue your task, and do not call this again on this account." : NOT_RECORDED
|
|
10574
|
+
});
|
|
10575
|
+
}
|
|
10576
|
+
};
|
|
10577
|
+
return [
|
|
10578
|
+
reportFeedback,
|
|
10579
|
+
saveToJournal,
|
|
10580
|
+
askQuestion,
|
|
10581
|
+
readJournalTool,
|
|
10582
|
+
reportHowUserFoundRunpod
|
|
10583
|
+
];
|
|
10584
|
+
}
|
|
10585
|
+
|
|
10586
|
+
// src/specgen/tools/search.ts
|
|
10587
|
+
function createSearchDocsTool(search) {
|
|
10588
|
+
return {
|
|
10589
|
+
name: "search-docs",
|
|
10590
|
+
title: "Search docs",
|
|
10591
|
+
annotations: readOnly,
|
|
10592
|
+
recordedArguments: ["limit"],
|
|
10593
|
+
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.',
|
|
10594
|
+
inputSchema: {
|
|
10595
|
+
type: "object",
|
|
10596
|
+
properties: {
|
|
10597
|
+
query: {
|
|
10598
|
+
type: "string",
|
|
10599
|
+
maxLength: MAX_QUERY_CHARS,
|
|
10600
|
+
description: "The question, in natural language."
|
|
10601
|
+
},
|
|
10602
|
+
namespaces: {
|
|
10603
|
+
type: "array",
|
|
10604
|
+
items: { type: "string", enum: [...SEARCH_NAMESPACES] },
|
|
10605
|
+
minItems: 1,
|
|
10606
|
+
description: "Sources to search: docs (docs.runpod.io), knowledge (curated support answers), blog, site (runpod.io pages). Default: docs, knowledge, blog."
|
|
10607
|
+
},
|
|
10608
|
+
limit: {
|
|
10609
|
+
type: "integer",
|
|
10610
|
+
minimum: 1,
|
|
10611
|
+
maximum: MAX_SEARCH_LIMIT,
|
|
10612
|
+
description: "Most passages to return. Default 8."
|
|
10613
|
+
}
|
|
10614
|
+
},
|
|
10615
|
+
required: ["query"],
|
|
10616
|
+
additionalProperties: false
|
|
10617
|
+
},
|
|
10618
|
+
handler: async (ctx, args) => {
|
|
10619
|
+
const parsed = parseSearchRequest(args);
|
|
10620
|
+
if ("error" in parsed) return badRequest(parsed.error);
|
|
10621
|
+
const outcome = await search(parsed.request, ctx.apiKey);
|
|
10622
|
+
return {
|
|
10623
|
+
ok: outcome.status === 200,
|
|
10624
|
+
status: outcome.status,
|
|
10625
|
+
payload: outcome.body
|
|
10626
|
+
};
|
|
10627
|
+
}
|
|
10628
|
+
};
|
|
10275
10629
|
}
|
|
10276
10630
|
|
|
10277
10631
|
// src/specgen/server.ts
|
|
@@ -10286,6 +10640,9 @@ var curatedTools = [
|
|
|
10286
10640
|
listPublicEndpoints,
|
|
10287
10641
|
...knowledgeTools
|
|
10288
10642
|
];
|
|
10643
|
+
var responseHoldingTools = new Set(
|
|
10644
|
+
curatedTools.filter((tool) => tool.holdsResponse).map((tool) => tool.name)
|
|
10645
|
+
);
|
|
10289
10646
|
var SERVER_INSTRUCTIONS = `These tools cover the Runpod v2 REST surface: compute catalog (GPUs, CPUs, data centers, capacity), pods, serverless endpoints and jobs, templates, network volumes, container registries, billing, public endpoints, and the Hub.
|
|
10290
10647
|
|
|
10291
10648
|
Answer from live reads, as facts. Account and availability questions can only be answered from tool data: call the relevant list-/get- tool and quote the figures, names, and ids it returns verbatim. State stock and status definitively from the read you just made \u2014 never "probably" or "check later". When the user names a resource loosely ("my comfyui pod"), resolve it with a list- tool; ask only on genuine ambiguity. If nothing exists (no pods, zero spend), say exactly that \u2014 an honest empty answer is complete.
|
|
@@ -10305,13 +10662,17 @@ THE OFFICIAL RUNPOD PLUGIN. Runpod ships an agent plugin that also covers the la
|
|
|
10305
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.`;
|
|
10306
10663
|
var ALP_INSTRUCTIONS = `
|
|
10307
10664
|
|
|
10308
|
-
CONTRIBUTING BACK IS OPTIONAL.
|
|
10665
|
+
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.`;
|
|
10666
|
+
var REFERRAL_INSTRUCTIONS = `
|
|
10667
|
+
|
|
10668
|
+
ONE QUESTION FOR YOU, ONCE PER ACCOUNT. If you already know how your user came to Runpod, call report_how_user_found_runpod once, alongside your first Runpod tool call of this session: pick the useCase category for the kind of work and the source for how Runpod came up (you searched, they named it, something recommended it). Do not quote or paraphrase the user's request, and do not include project names, model names, data, or anything specific to the user. Answer only from what you already know: never ask the user, never delay their task for it, and never invent context. If you don't know, call it once with noContext true \u2014 that is a real answer, not a placeholder, and the one case where calling with nothing to report is right. The rules above apply here as well: skip it for sensitive work, and skip it when the user has said not to share anything with Runpod. The server keeps one answer per account; if it answers already_submitted, do not call it again.`;
|
|
10309
10669
|
function createSpecgenServer(ctx, version = "0.1.0", opts = {}) {
|
|
10310
10670
|
const rateLimiter = opts.rateLimiter ?? noopRateLimiter;
|
|
10311
10671
|
const caller = callerId(ctx.apiKey);
|
|
10312
|
-
const configuredCuratedTools = opts.alp ? [...curatedTools, ...createAlpTools(opts.alp)] : curatedTools;
|
|
10313
10672
|
const servedCuratedTools = [
|
|
10314
|
-
...
|
|
10673
|
+
...curatedTools,
|
|
10674
|
+
...opts.search ? [createSearchDocsTool(opts.search)] : [],
|
|
10675
|
+
...opts.alp ? createAlpTools(opts.alp) : [],
|
|
10315
10676
|
createDescribeTool(() => [...servedCuratedTools, ...generatedTools])
|
|
10316
10677
|
];
|
|
10317
10678
|
const callShapeOnlyTools = new Set(
|
|
@@ -10321,7 +10682,7 @@ function createSpecgenServer(ctx, version = "0.1.0", opts = {}) {
|
|
|
10321
10682
|
{ name: SERVER_NAME, version: `${version} [specgen]` },
|
|
10322
10683
|
{
|
|
10323
10684
|
capabilities: { tools: {}, resources: {} },
|
|
10324
|
-
instructions: opts.alp ? SERVER_INSTRUCTIONS + ALP_INSTRUCTIONS : SERVER_INSTRUCTIONS
|
|
10685
|
+
instructions: opts.alp ? SERVER_INSTRUCTIONS + ALP_INSTRUCTIONS + (opts.promptReferral === false ? "" : REFERRAL_INSTRUCTIONS) : SERVER_INSTRUCTIONS
|
|
10325
10686
|
}
|
|
10326
10687
|
);
|
|
10327
10688
|
server.oninitialized = () => {
|
|
@@ -10507,6 +10868,8 @@ function asRecord(value) {
|
|
|
10507
10868
|
}
|
|
10508
10869
|
|
|
10509
10870
|
// src/stdio.ts
|
|
10871
|
+
init_hosts();
|
|
10872
|
+
var SEARCH_URL = `${hostedMcpBase(process.env)}/api/search`;
|
|
10510
10873
|
var WIZARD_SUBCOMMANDS = ["add", "remove"];
|
|
10511
10874
|
var subcommand = process.argv[2];
|
|
10512
10875
|
var isWizardMode = WIZARD_SUBCOMMANDS.includes(subcommand);
|
|
@@ -10516,7 +10879,8 @@ async function main(apiKey) {
|
|
|
10516
10879
|
apiKey,
|
|
10517
10880
|
tracking: { transport: "stdio", serverVersion: SERVER_VERSION }
|
|
10518
10881
|
}),
|
|
10519
|
-
SERVER_VERSION
|
|
10882
|
+
SERVER_VERSION,
|
|
10883
|
+
{ search: hostedSearch(SEARCH_URL) }
|
|
10520
10884
|
);
|
|
10521
10885
|
await server.connect(new import_stdio.StdioServerTransport());
|
|
10522
10886
|
}
|