@runpod/mcp-server 1.3.0 → 1.4.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
@@ -6,7 +6,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
6
6
  // src/server.ts
7
7
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
8
8
  var SERVER_NAME = "Runpod API Server";
9
- var SERVER_VERSION = true ? "1.3.0" : "dev";
9
+ var SERVER_VERSION = true ? "1.4.0" : "dev";
10
10
  function createServer(version = SERVER_VERSION) {
11
11
  return new McpServer({
12
12
  name: SERVER_NAME,
@@ -19,19 +19,78 @@ function createServer(version = SERVER_VERSION) {
19
19
  }
20
20
 
21
21
  // src/tools.ts
22
- import { z } from "zod";
22
+ import { z as z2 } from "zod";
23
23
  import fetch from "node-fetch";
24
24
  import { randomUUID } from "crypto";
25
+
26
+ // src/pagination.ts
27
+ import { z } from "zod";
28
+ var DEFAULT_LIST_LIMIT = 20;
29
+ var MAX_LIST_LIMIT = 100;
30
+ var listPaginationParams = {
31
+ limit: z.number().int().positive().max(MAX_LIST_LIMIT).optional().describe(
32
+ `Maximum number of items to return (default ${DEFAULT_LIST_LIMIT}, max ${MAX_LIST_LIMIT}). Use the returned nextCursor to fetch the next page.`
33
+ ),
34
+ cursor: z.string().optional().describe(
35
+ "Opaque pagination cursor from a previous response (nextCursor). Omit to start from the beginning."
36
+ )
37
+ };
38
+ function decodeCursorOffset(cursor) {
39
+ if (!cursor) return 0;
40
+ try {
41
+ const decoded = Buffer.from(cursor, "base64").toString("utf8");
42
+ const offset = Number.parseInt(decoded, 10);
43
+ return Number.isFinite(offset) && offset >= 0 ? offset : 0;
44
+ } catch {
45
+ return 0;
46
+ }
47
+ }
48
+ function encodeCursorOffset(offset) {
49
+ return Buffer.from(String(offset), "utf8").toString("base64");
50
+ }
51
+ function capListResult(result, options) {
52
+ const limit = Math.min(options.limit ?? DEFAULT_LIST_LIMIT, MAX_LIST_LIMIT);
53
+ const offset = decodeCursorOffset(options.cursor);
54
+ if (!Array.isArray(result)) {
55
+ return {
56
+ content: [
57
+ { type: "text", text: JSON.stringify(result, null, 2) }
58
+ ]
59
+ };
60
+ }
61
+ const total = result.length;
62
+ const page = result.slice(offset, offset + limit);
63
+ const nextOffset = offset + page.length;
64
+ const hasMore = nextOffset < total;
65
+ const envelope = {
66
+ items: page,
67
+ pagination: {
68
+ total,
69
+ returned: page.length,
70
+ offset,
71
+ truncated: hasMore,
72
+ nextCursor: hasMore ? encodeCursorOffset(nextOffset) : null,
73
+ note: hasMore ? `Showing ${page.length} of ${total}. Pass cursor=nextCursor to fetch more, or narrow the query with filters.` : void 0
74
+ }
75
+ };
76
+ return {
77
+ content: [
78
+ { type: "text", text: JSON.stringify(envelope, null, 2) }
79
+ ]
80
+ };
81
+ }
82
+
83
+ // src/tools.ts
25
84
  var API_BASE_URL = process.env.RUNPOD_REST_API_URL ?? "https://rest.runpod.io/v1";
26
85
  var SERVERLESS_API_BASE_URL = process.env.RUNPOD_SERVERLESS_API_URL ?? "https://api.runpod.ai/v2";
27
86
  var GRAPHQL_URL = process.env.RUNPOD_PUBLIC_GRAPHQL_URL ?? "https://api.runpod.io/graphql";
28
- var MCP_SERVER_VERSION = true ? "1.3.0" : "dev";
87
+ var MCP_SERVER_VERSION = true ? "1.4.0" : "dev";
29
88
  var SESSION_ID = randomUUID();
30
89
  function sanitizeUaToken(value) {
31
90
  return value.replace(/[()<>@,;:\\"/[\]?={}\s]/g, "_").slice(0, 64);
32
91
  }
33
- function trackingHeaders(server2, ctx) {
34
- const info = server2.server.getClientVersion();
92
+ function trackingHeaders(server, ctx) {
93
+ const info = server.server.getClientVersion();
35
94
  const fallbackName = ctx.clientUserAgent || "unknown";
36
95
  const name = sanitizeUaToken(info?.name || fallbackName);
37
96
  const version = sanitizeUaToken(info?.version || "unknown");
@@ -128,20 +187,20 @@ function createServerlessRequest(apiKey, tracking) {
128
187
  }
129
188
  };
130
189
  }
131
- function registerTools(server2, ctx) {
132
- const tracking = () => trackingHeaders(server2, ctx);
190
+ function registerTools(server, ctx) {
191
+ const tracking = () => trackingHeaders(server, ctx);
133
192
  const runpodRequest = createRunpodRequest(ctx.apiKey, tracking);
134
193
  const serverlessRequest = createServerlessRequest(ctx.apiKey, tracking);
135
- server2.tool(
194
+ server.tool(
136
195
  "list-gpu-types",
137
196
  {
138
- minMemoryGb: z.number().optional().describe("Filter to GPUs with at least this much VRAM in GB"),
139
- secureCloudOnly: z.boolean().optional().describe("Filter to only GPUs available in secure cloud"),
140
- communityCloudOnly: z.boolean().optional().describe("Filter to only GPUs available in community cloud"),
141
- searchTerm: z.string().optional().describe(
197
+ minMemoryGb: z2.number().optional().describe("Filter to GPUs with at least this much VRAM in GB"),
198
+ secureCloudOnly: z2.boolean().optional().describe("Filter to only GPUs available in secure cloud"),
199
+ communityCloudOnly: z2.boolean().optional().describe("Filter to only GPUs available in community cloud"),
200
+ searchTerm: z2.string().optional().describe(
142
201
  "Search term to filter GPUs by name (e.g., 'A100', 'RTX 4090')"
143
202
  ),
144
- includeUnavailable: z.boolean().optional().describe(
203
+ includeUnavailable: z2.boolean().optional().describe(
145
204
  "Include GPUs that are currently out of stock. Default is false"
146
205
  )
147
206
  },
@@ -218,10 +277,10 @@ function registerTools(server2, ctx) {
218
277
  };
219
278
  }
220
279
  );
221
- server2.tool(
280
+ server.tool(
222
281
  "list-data-centers",
223
282
  {
224
- region: z.string().optional().describe(
283
+ region: z2.string().optional().describe(
225
284
  "Filter by region/location (e.g., 'United States', 'Europe', 'Canada')"
226
285
  )
227
286
  },
@@ -255,15 +314,16 @@ function registerTools(server2, ctx) {
255
314
  };
256
315
  }
257
316
  );
258
- server2.tool(
317
+ server.tool(
259
318
  "list-pods",
260
319
  {
261
- computeType: z.enum(["GPU", "CPU"]).optional().describe("Filter to only GPU or only CPU Pods"),
262
- gpuTypeId: z.array(z.string()).optional().describe("Filter to Pods with any of the listed GPU types"),
263
- dataCenterId: z.array(z.string()).optional().describe("Filter to Pods in any of the provided data centers"),
264
- name: z.string().optional().describe("Filter to Pods with the provided name"),
265
- includeMachine: z.boolean().optional().describe("Include information about the machine"),
266
- includeNetworkVolume: z.boolean().optional().describe("Include information about attached network volumes")
320
+ ...listPaginationParams,
321
+ computeType: z2.enum(["GPU", "CPU"]).optional().describe("Filter to only GPU or only CPU Pods"),
322
+ gpuTypeId: z2.array(z2.string()).optional().describe("Filter to Pods with any of the listed GPU types"),
323
+ dataCenterId: z2.array(z2.string()).optional().describe("Filter to Pods in any of the provided data centers"),
324
+ name: z2.string().optional().describe("Filter to Pods with the provided name"),
325
+ includeMachine: z2.boolean().optional().describe("Include information about the machine"),
326
+ includeNetworkVolume: z2.boolean().optional().describe("Include information about attached network volumes")
267
327
  },
268
328
  async (params) => {
269
329
  const queryParams = new URLSearchParams();
@@ -287,22 +347,18 @@ function registerTools(server2, ctx) {
287
347
  );
288
348
  const queryString = queryParams.toString() ? `?${queryParams.toString()}` : "";
289
349
  const result = await runpodRequest(`/pods${queryString}`);
290
- return {
291
- content: [
292
- {
293
- type: "text",
294
- text: JSON.stringify(result, null, 2)
295
- }
296
- ]
297
- };
350
+ return capListResult(result, {
351
+ limit: params.limit,
352
+ cursor: params.cursor
353
+ });
298
354
  }
299
355
  );
300
- server2.tool(
356
+ server.tool(
301
357
  "get-pod",
302
358
  {
303
- podId: z.string().describe("ID of the pod to retrieve"),
304
- includeMachine: z.boolean().optional().describe("Include information about the machine"),
305
- includeNetworkVolume: z.boolean().optional().describe("Include information about attached network volumes")
359
+ podId: z2.string().describe("ID of the pod to retrieve"),
360
+ includeMachine: z2.boolean().optional().describe("Include information about the machine"),
361
+ includeNetworkVolume: z2.boolean().optional().describe("Include information about attached network volumes")
306
362
  },
307
363
  async (params) => {
308
364
  const queryParams = new URLSearchParams();
@@ -325,21 +381,21 @@ function registerTools(server2, ctx) {
325
381
  };
326
382
  }
327
383
  );
328
- server2.tool(
384
+ server.tool(
329
385
  "create-pod",
330
386
  'Create a new GPU/CPU pod on Runpod. If the user does not specify an image, recommend the "Runpod Pytorch 2.8.0" image (runpod/pytorch:1.0.2-cu1281-torch280-ubuntu2404) as the default \u2014 it has the most up-to-date CUDA and PyTorch versions.',
331
387
  {
332
- name: z.string().optional().describe("Name for the pod"),
333
- imageName: z.string().describe("Docker image to use"),
334
- cloudType: z.enum(["SECURE", "COMMUNITY"]).optional().describe("SECURE or COMMUNITY cloud"),
335
- gpuTypeIds: z.array(z.string()).optional().describe("List of acceptable GPU types"),
336
- gpuCount: z.number().optional().describe("Number of GPUs"),
337
- containerDiskInGb: z.number().optional().describe("Container disk size in GB"),
338
- volumeInGb: z.number().optional().describe("Volume size in GB"),
339
- volumeMountPath: z.string().optional().describe("Path to mount the volume"),
340
- ports: z.array(z.string()).optional().describe("Ports to expose (e.g., '8888/http', '22/tcp')"),
341
- env: z.record(z.string()).optional().describe("Environment variables"),
342
- dataCenterIds: z.array(z.string()).optional().describe("List of data centers")
388
+ name: z2.string().optional().describe("Name for the pod"),
389
+ imageName: z2.string().describe("Docker image to use"),
390
+ cloudType: z2.enum(["SECURE", "COMMUNITY"]).optional().describe("SECURE or COMMUNITY cloud"),
391
+ gpuTypeIds: z2.array(z2.string()).optional().describe("List of acceptable GPU types"),
392
+ gpuCount: z2.number().optional().describe("Number of GPUs"),
393
+ containerDiskInGb: z2.number().optional().describe("Container disk size in GB"),
394
+ volumeInGb: z2.number().optional().describe("Volume size in GB"),
395
+ volumeMountPath: z2.string().optional().describe("Path to mount the volume"),
396
+ ports: z2.array(z2.string()).optional().describe("Ports to expose (e.g., '8888/http', '22/tcp')"),
397
+ env: z2.record(z2.string()).optional().describe("Environment variables"),
398
+ dataCenterIds: z2.array(z2.string()).optional().describe("List of data centers")
343
399
  },
344
400
  async (params) => {
345
401
  const result = await runpodRequest("/pods", "POST", params);
@@ -353,17 +409,17 @@ function registerTools(server2, ctx) {
353
409
  };
354
410
  }
355
411
  );
356
- server2.tool(
412
+ server.tool(
357
413
  "update-pod",
358
414
  {
359
- podId: z.string().describe("ID of the pod to update"),
360
- name: z.string().optional().describe("New name for the pod"),
361
- imageName: z.string().optional().describe("New Docker image"),
362
- containerDiskInGb: z.number().optional().describe("New container disk size in GB"),
363
- volumeInGb: z.number().optional().describe("New volume size in GB"),
364
- volumeMountPath: z.string().optional().describe("New path to mount the volume"),
365
- ports: z.array(z.string()).optional().describe("New ports to expose"),
366
- env: z.record(z.string()).optional().describe("New environment variables")
415
+ podId: z2.string().describe("ID of the pod to update"),
416
+ name: z2.string().optional().describe("New name for the pod"),
417
+ imageName: z2.string().optional().describe("New Docker image"),
418
+ containerDiskInGb: z2.number().optional().describe("New container disk size in GB"),
419
+ volumeInGb: z2.number().optional().describe("New volume size in GB"),
420
+ volumeMountPath: z2.string().optional().describe("New path to mount the volume"),
421
+ ports: z2.array(z2.string()).optional().describe("New ports to expose"),
422
+ env: z2.record(z2.string()).optional().describe("New environment variables")
367
423
  },
368
424
  async (params) => {
369
425
  const { podId, ...updateParams } = params;
@@ -382,10 +438,10 @@ function registerTools(server2, ctx) {
382
438
  };
383
439
  }
384
440
  );
385
- server2.tool(
441
+ server.tool(
386
442
  "start-pod",
387
443
  {
388
- podId: z.string().describe("ID of the pod to start")
444
+ podId: z2.string().describe("ID of the pod to start")
389
445
  },
390
446
  async (params) => {
391
447
  const result = await runpodRequest(`/pods/${params.podId}/start`, "POST");
@@ -399,10 +455,10 @@ function registerTools(server2, ctx) {
399
455
  };
400
456
  }
401
457
  );
402
- server2.tool(
458
+ server.tool(
403
459
  "stop-pod",
404
460
  {
405
- podId: z.string().describe("ID of the pod to stop")
461
+ podId: z2.string().describe("ID of the pod to stop")
406
462
  },
407
463
  async (params) => {
408
464
  const result = await runpodRequest(`/pods/${params.podId}/stop`, "POST");
@@ -416,10 +472,10 @@ function registerTools(server2, ctx) {
416
472
  };
417
473
  }
418
474
  );
419
- server2.tool(
475
+ server.tool(
420
476
  "delete-pod",
421
477
  {
422
- podId: z.string().describe("ID of the pod to delete")
478
+ podId: z2.string().describe("ID of the pod to delete")
423
479
  },
424
480
  async (params) => {
425
481
  const result = await runpodRequest(`/pods/${params.podId}`, "DELETE");
@@ -433,11 +489,12 @@ function registerTools(server2, ctx) {
433
489
  };
434
490
  }
435
491
  );
436
- server2.tool(
492
+ server.tool(
437
493
  "list-endpoints",
438
494
  {
439
- includeTemplate: z.boolean().optional().describe("Include template information"),
440
- includeWorkers: z.boolean().optional().describe("Include information about workers")
495
+ ...listPaginationParams,
496
+ includeTemplate: z2.boolean().optional().describe("Include template information"),
497
+ includeWorkers: z2.boolean().optional().describe("Include information about workers")
441
498
  },
442
499
  async (params) => {
443
500
  const queryParams = new URLSearchParams();
@@ -450,22 +507,18 @@ function registerTools(server2, ctx) {
450
507
  queryParams.append("includeWorkers", params.includeWorkers.toString());
451
508
  const queryString = queryParams.toString() ? `?${queryParams.toString()}` : "";
452
509
  const result = await runpodRequest(`/endpoints${queryString}`);
453
- return {
454
- content: [
455
- {
456
- type: "text",
457
- text: JSON.stringify(result, null, 2)
458
- }
459
- ]
460
- };
510
+ return capListResult(result, {
511
+ limit: params.limit,
512
+ cursor: params.cursor
513
+ });
461
514
  }
462
515
  );
463
- server2.tool(
516
+ server.tool(
464
517
  "get-endpoint",
465
518
  {
466
- endpointId: z.string().describe("ID of the endpoint to retrieve"),
467
- includeTemplate: z.boolean().optional().describe("Include template information"),
468
- includeWorkers: z.boolean().optional().describe("Include information about workers")
519
+ endpointId: z2.string().describe("ID of the endpoint to retrieve"),
520
+ includeTemplate: z2.boolean().optional().describe("Include template information"),
521
+ includeWorkers: z2.boolean().optional().describe("Include information about workers")
469
522
  },
470
523
  async (params) => {
471
524
  const queryParams = new URLSearchParams();
@@ -490,17 +543,17 @@ function registerTools(server2, ctx) {
490
543
  };
491
544
  }
492
545
  );
493
- server2.tool(
546
+ server.tool(
494
547
  "create-endpoint",
495
548
  {
496
- name: z.string().optional().describe("Name for the endpoint"),
497
- templateId: z.string().describe("Template ID to use"),
498
- computeType: z.enum(["GPU", "CPU"]).optional().describe("GPU or CPU endpoint"),
499
- gpuTypeIds: z.array(z.string()).optional().describe("List of acceptable GPU types"),
500
- gpuCount: z.number().optional().describe("Number of GPUs per worker"),
501
- workersMin: z.number().optional().describe("Minimum number of workers"),
502
- workersMax: z.number().optional().describe("Maximum number of workers"),
503
- dataCenterIds: z.array(z.string()).optional().describe("List of data centers")
549
+ name: z2.string().optional().describe("Name for the endpoint"),
550
+ templateId: z2.string().describe("Template ID to use"),
551
+ computeType: z2.enum(["GPU", "CPU"]).optional().describe("GPU or CPU endpoint"),
552
+ gpuTypeIds: z2.array(z2.string()).optional().describe("List of acceptable GPU types"),
553
+ gpuCount: z2.number().optional().describe("Number of GPUs per worker"),
554
+ workersMin: z2.number().optional().describe("Minimum number of workers"),
555
+ workersMax: z2.number().optional().describe("Maximum number of workers"),
556
+ dataCenterIds: z2.array(z2.string()).optional().describe("List of data centers")
504
557
  },
505
558
  async (params) => {
506
559
  const result = await runpodRequest("/endpoints", "POST", params);
@@ -514,16 +567,16 @@ function registerTools(server2, ctx) {
514
567
  };
515
568
  }
516
569
  );
517
- server2.tool(
570
+ server.tool(
518
571
  "update-endpoint",
519
572
  {
520
- endpointId: z.string().describe("ID of the endpoint to update"),
521
- name: z.string().optional().describe("New name for the endpoint"),
522
- workersMin: z.number().optional().describe("New minimum number of workers"),
523
- workersMax: z.number().optional().describe("New maximum number of workers"),
524
- idleTimeout: z.number().optional().describe("New idle timeout in seconds"),
525
- scalerType: z.enum(["QUEUE_DELAY", "REQUEST_COUNT"]).optional().describe("Scaler type"),
526
- scalerValue: z.number().optional().describe("Scaler value")
573
+ endpointId: z2.string().describe("ID of the endpoint to update"),
574
+ name: z2.string().optional().describe("New name for the endpoint"),
575
+ workersMin: z2.number().optional().describe("New minimum number of workers"),
576
+ workersMax: z2.number().optional().describe("New maximum number of workers"),
577
+ idleTimeout: z2.number().optional().describe("New idle timeout in seconds"),
578
+ scalerType: z2.enum(["QUEUE_DELAY", "REQUEST_COUNT"]).optional().describe("Scaler type"),
579
+ scalerValue: z2.number().optional().describe("Scaler value")
527
580
  },
528
581
  async (params) => {
529
582
  const { endpointId, ...updateParams } = params;
@@ -542,10 +595,10 @@ function registerTools(server2, ctx) {
542
595
  };
543
596
  }
544
597
  );
545
- server2.tool(
598
+ server.tool(
546
599
  "delete-endpoint",
547
600
  {
548
- endpointId: z.string().describe("ID of the endpoint to delete")
601
+ endpointId: z2.string().describe("ID of the endpoint to delete")
549
602
  },
550
603
  async (params) => {
551
604
  const result = await runpodRequest(
@@ -562,26 +615,26 @@ function registerTools(server2, ctx) {
562
615
  };
563
616
  }
564
617
  );
565
- const endpointIdSchema = z.string().regex(/^[a-zA-Z0-9_-]+$/, "Invalid endpoint ID format");
566
- const jobIdSchema = z.string().regex(/^[a-zA-Z0-9_-]+$/, "Invalid job ID format");
567
- const inputSchema = z.record(z.unknown()).describe(
618
+ const endpointIdSchema = z2.string().regex(/^[a-zA-Z0-9_-]+$/, "Invalid endpoint ID format");
619
+ const jobIdSchema = z2.string().regex(/^[a-zA-Z0-9_-]+$/, "Invalid job ID format");
620
+ const inputSchema = z2.record(z2.unknown()).describe(
568
621
  "Input payload for the worker handler. The expected fields depend on the deployed model or worker."
569
622
  );
570
- const webhookSchema = z.string().url().optional().describe(
623
+ const webhookSchema = z2.string().url().optional().describe(
571
624
  "Webhook URL to receive job completion notifications instead of polling"
572
625
  );
573
- const policySchema = z.object({
574
- executionTimeout: z.number().optional().describe("Maximum execution time in milliseconds"),
575
- lowPriority: z.boolean().optional().describe("Submit as a low-priority job"),
576
- ttl: z.number().optional().describe("Time-to-live for the job result in milliseconds")
626
+ const policySchema = z2.object({
627
+ executionTimeout: z2.number().optional().describe("Maximum execution time in milliseconds"),
628
+ lowPriority: z2.boolean().optional().describe("Submit as a low-priority job"),
629
+ ttl: z2.number().optional().describe("Time-to-live for the job result in milliseconds")
577
630
  }).optional().describe("Execution policy options");
578
- const s3ConfigSchema = z.object({
579
- accessId: z.string().describe("S3 access key ID"),
580
- accessSecret: z.string().describe("S3 secret access key"),
581
- bucketName: z.string().describe("S3 bucket name"),
582
- endpointUrl: z.string().describe("S3 endpoint URL")
631
+ const s3ConfigSchema = z2.object({
632
+ accessId: z2.string().describe("S3 access key ID"),
633
+ accessSecret: z2.string().describe("S3 secret access key"),
634
+ bucketName: z2.string().describe("S3 bucket name"),
635
+ endpointUrl: z2.string().describe("S3 endpoint URL")
583
636
  }).optional().describe("S3-compatible storage config for large outputs");
584
- server2.tool(
637
+ server.tool(
585
638
  "run-endpoint",
586
639
  "Submit an asynchronous job to a Serverless endpoint. Returns a job ID immediately \u2014 use get-job-status to poll for results. Async results are available for 30 minutes after completion.",
587
640
  {
@@ -611,7 +664,7 @@ function registerTools(server2, ctx) {
611
664
  };
612
665
  }
613
666
  );
614
- server2.tool(
667
+ server.tool(
615
668
  "runsync-endpoint",
616
669
  "Submit a synchronous job to a Serverless endpoint and wait for the result. Best for tasks completing within 90 seconds. If processing exceeds 90 seconds, the response returns a job ID to poll with get-job-status. Max payload: 20 MB. Results expire after 1 minute. Use the wait parameter to extend the server-side wait up to 5 minutes (300000 ms).",
617
670
  {
@@ -619,7 +672,7 @@ function registerTools(server2, ctx) {
619
672
  "ID of the Serverless endpoint to run synchronously"
620
673
  ),
621
674
  input: inputSchema,
622
- wait: z.number().min(1e3).max(3e5).optional().describe(
675
+ wait: z2.number().min(1e3).max(3e5).optional().describe(
623
676
  "How long in milliseconds the server should wait for a result before returning a job ID to poll (1000\u2013300000). Defaults to 90000 (90 seconds)."
624
677
  ),
625
678
  webhook: webhookSchema,
@@ -645,7 +698,7 @@ function registerTools(server2, ctx) {
645
698
  };
646
699
  }
647
700
  );
648
- server2.tool(
701
+ server.tool(
649
702
  "get-job-status",
650
703
  "Check the status of an asynchronous Serverless job. Returns the current status and output when complete. Job statuses: IN_QUEUE, IN_PROGRESS, COMPLETED, FAILED, CANCELLED, TIMED_OUT.",
651
704
  {
@@ -669,7 +722,7 @@ function registerTools(server2, ctx) {
669
722
  };
670
723
  }
671
724
  );
672
- server2.tool(
725
+ server.tool(
673
726
  "stream-job",
674
727
  "Retrieve all streaming output from a Serverless job by polling until the job reaches a terminal state. The worker must support streaming output. Polls /stream/{jobId} repeatedly and collects every chunk until status is COMPLETED, FAILED, CANCELLED, or TIMED_OUT.",
675
728
  {
@@ -737,7 +790,7 @@ function registerTools(server2, ctx) {
737
790
  };
738
791
  }
739
792
  );
740
- server2.tool(
793
+ server.tool(
741
794
  "cancel-job",
742
795
  "Cancel a Serverless job that is queued or in progress.",
743
796
  {
@@ -762,7 +815,7 @@ function registerTools(server2, ctx) {
762
815
  };
763
816
  }
764
817
  );
765
- server2.tool(
818
+ server.tool(
766
819
  "retry-job",
767
820
  "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.",
768
821
  {
@@ -787,7 +840,7 @@ function registerTools(server2, ctx) {
787
840
  };
788
841
  }
789
842
  );
790
- server2.tool(
843
+ server.tool(
791
844
  "endpoint-health",
792
845
  "Get the health and operational status of a Serverless endpoint, including worker counts and job statistics.",
793
846
  {
@@ -807,7 +860,7 @@ function registerTools(server2, ctx) {
807
860
  };
808
861
  }
809
862
  );
810
- server2.tool(
863
+ server.tool(
811
864
  "purge-endpoint-queue",
812
865
  "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.",
813
866
  {
@@ -831,13 +884,14 @@ function registerTools(server2, ctx) {
831
884
  };
832
885
  }
833
886
  );
834
- server2.tool(
887
+ server.tool(
835
888
  "list-templates",
836
889
  `List available templates. By default returns only the user's own templates. Use includeRunpodTemplates to also include official Runpod templates. The recommended default template for new pods is "Runpod Pytorch 2.8.0" (ID: runpod-torch-v280) \u2014 it has the latest CUDA and PyTorch versions.`,
837
890
  {
838
- includeRunpodTemplates: z.boolean().optional().describe("Include official Runpod templates in the response"),
839
- includePublicTemplates: z.boolean().optional().describe("Include community-made public templates in the response"),
840
- includeEndpointBoundTemplates: z.boolean().optional().describe(
891
+ ...listPaginationParams,
892
+ includeRunpodTemplates: z2.boolean().optional().describe("Include official Runpod templates in the response"),
893
+ includePublicTemplates: z2.boolean().optional().describe("Include community-made public templates in the response"),
894
+ includeEndpointBoundTemplates: z2.boolean().optional().describe(
841
895
  "Include templates bound to Serverless endpoints in the response"
842
896
  )
843
897
  },
@@ -853,20 +907,16 @@ function registerTools(server2, ctx) {
853
907
  const result = await runpodRequest(
854
908
  `/templates${query ? `?${query}` : ""}`
855
909
  );
856
- return {
857
- content: [
858
- {
859
- type: "text",
860
- text: JSON.stringify(result, null, 2)
861
- }
862
- ]
863
- };
910
+ return capListResult(result, {
911
+ limit: params.limit,
912
+ cursor: params.cursor
913
+ });
864
914
  }
865
915
  );
866
- server2.tool(
916
+ server.tool(
867
917
  "get-template",
868
918
  {
869
- templateId: z.string().describe("ID of the template to retrieve")
919
+ templateId: z2.string().describe("ID of the template to retrieve")
870
920
  },
871
921
  async (params) => {
872
922
  const result = await runpodRequest(`/templates/${params.templateId}`);
@@ -880,20 +930,23 @@ function registerTools(server2, ctx) {
880
930
  };
881
931
  }
882
932
  );
883
- server2.tool(
933
+ server.tool(
884
934
  "create-template",
885
935
  {
886
- name: z.string().describe("Name for the template"),
887
- imageName: z.string().describe("Docker image to use"),
888
- isServerless: z.boolean().optional().describe("Is this a serverless template"),
889
- ports: z.array(z.string()).optional().describe("Ports to expose"),
890
- dockerEntrypoint: z.array(z.string()).optional().describe("Docker entrypoint commands"),
891
- dockerStartCmd: z.array(z.string()).optional().describe("Docker start commands"),
892
- env: z.record(z.string()).optional().describe("Environment variables"),
893
- containerDiskInGb: z.number().optional().describe("Container disk size in GB"),
894
- volumeInGb: z.number().optional().describe("Volume size in GB"),
895
- volumeMountPath: z.string().optional().describe("Path to mount the volume"),
896
- readme: z.string().optional().describe("README content in markdown format")
936
+ name: z2.string().describe("Name for the template"),
937
+ imageName: z2.string().describe("Docker image to use"),
938
+ isServerless: z2.boolean().optional().describe("Is this a serverless template"),
939
+ ports: z2.array(z2.string()).optional().describe("Ports to expose"),
940
+ dockerEntrypoint: z2.array(z2.string()).optional().describe("Docker entrypoint commands"),
941
+ dockerStartCmd: z2.array(z2.string()).optional().describe("Docker start commands"),
942
+ env: z2.record(z2.string()).optional().describe("Environment variables"),
943
+ containerDiskInGb: z2.number().optional().describe("Container disk size in GB"),
944
+ volumeInGb: z2.number().optional().describe("Volume size in GB"),
945
+ volumeMountPath: z2.string().optional().describe("Path to mount the volume"),
946
+ readme: z2.string().optional().describe("README content in markdown format"),
947
+ containerRegistryAuthId: z2.string().optional().describe(
948
+ "ID of a container registry credential (from create-container-registry-auth / list-container-registry-auths) used to pull a private image. Required when imageName points at a private registry; without it serverless workers fail the image pull."
949
+ )
897
950
  },
898
951
  async (params) => {
899
952
  const result = await runpodRequest("/templates", "POST", params);
@@ -907,15 +960,18 @@ function registerTools(server2, ctx) {
907
960
  };
908
961
  }
909
962
  );
910
- server2.tool(
963
+ server.tool(
911
964
  "update-template",
912
965
  {
913
- templateId: z.string().describe("ID of the template to update"),
914
- name: z.string().optional().describe("New name for the template"),
915
- imageName: z.string().optional().describe("New Docker image"),
916
- ports: z.array(z.string()).optional().describe("New ports to expose"),
917
- env: z.record(z.string()).optional().describe("New environment variables"),
918
- readme: z.string().optional().describe("New README content in markdown format")
966
+ templateId: z2.string().describe("ID of the template to update"),
967
+ name: z2.string().optional().describe("New name for the template"),
968
+ imageName: z2.string().optional().describe("New Docker image"),
969
+ ports: z2.array(z2.string()).optional().describe("New ports to expose"),
970
+ env: z2.record(z2.string()).optional().describe("New environment variables"),
971
+ readme: z2.string().optional().describe("New README content in markdown format"),
972
+ containerRegistryAuthId: z2.string().optional().describe(
973
+ "ID of a container registry credential (from create-container-registry-auth / list-container-registry-auths) used to pull a private image. Set this to attach a credential to a template referencing a private registry."
974
+ )
919
975
  },
920
976
  async (params) => {
921
977
  const { templateId, ...updateParams } = params;
@@ -934,10 +990,10 @@ function registerTools(server2, ctx) {
934
990
  };
935
991
  }
936
992
  );
937
- server2.tool(
993
+ server.tool(
938
994
  "delete-template",
939
995
  {
940
- templateId: z.string().describe("ID of the template to delete")
996
+ templateId: z2.string().describe("ID of the template to delete")
941
997
  },
942
998
  async (params) => {
943
999
  const result = await runpodRequest(
@@ -954,21 +1010,17 @@ function registerTools(server2, ctx) {
954
1010
  };
955
1011
  }
956
1012
  );
957
- server2.tool("list-network-volumes", {}, async () => {
1013
+ server.tool("list-network-volumes", listPaginationParams, async (params) => {
958
1014
  const result = await runpodRequest("/networkvolumes");
959
- return {
960
- content: [
961
- {
962
- type: "text",
963
- text: JSON.stringify(result, null, 2)
964
- }
965
- ]
966
- };
1015
+ return capListResult(result, {
1016
+ limit: params.limit,
1017
+ cursor: params.cursor
1018
+ });
967
1019
  });
968
- server2.tool(
1020
+ server.tool(
969
1021
  "get-network-volume",
970
1022
  {
971
- networkVolumeId: z.string().describe("ID of the network volume to retrieve")
1023
+ networkVolumeId: z2.string().describe("ID of the network volume to retrieve")
972
1024
  },
973
1025
  async (params) => {
974
1026
  const result = await runpodRequest(
@@ -984,12 +1036,12 @@ function registerTools(server2, ctx) {
984
1036
  };
985
1037
  }
986
1038
  );
987
- server2.tool(
1039
+ server.tool(
988
1040
  "create-network-volume",
989
1041
  {
990
- name: z.string().describe("Name for the network volume"),
991
- size: z.number().describe("Size in GB (1-4000)"),
992
- dataCenterId: z.string().describe("Data center ID")
1042
+ name: z2.string().describe("Name for the network volume"),
1043
+ size: z2.number().describe("Size in GB (1-4000)"),
1044
+ dataCenterId: z2.string().describe("Data center ID")
993
1045
  },
994
1046
  async (params) => {
995
1047
  const result = await runpodRequest("/networkvolumes", "POST", params);
@@ -1003,12 +1055,12 @@ function registerTools(server2, ctx) {
1003
1055
  };
1004
1056
  }
1005
1057
  );
1006
- server2.tool(
1058
+ server.tool(
1007
1059
  "update-network-volume",
1008
1060
  {
1009
- networkVolumeId: z.string().describe("ID of the network volume to update"),
1010
- name: z.string().optional().describe("New name for the network volume"),
1011
- size: z.number().optional().describe("New size in GB (must be larger than current)")
1061
+ networkVolumeId: z2.string().describe("ID of the network volume to update"),
1062
+ name: z2.string().optional().describe("New name for the network volume"),
1063
+ size: z2.number().optional().describe("New size in GB (must be larger than current)")
1012
1064
  },
1013
1065
  async (params) => {
1014
1066
  const { networkVolumeId, ...updateParams } = params;
@@ -1027,10 +1079,10 @@ function registerTools(server2, ctx) {
1027
1079
  };
1028
1080
  }
1029
1081
  );
1030
- server2.tool(
1082
+ server.tool(
1031
1083
  "delete-network-volume",
1032
1084
  {
1033
- networkVolumeId: z.string().describe("ID of the network volume to delete")
1085
+ networkVolumeId: z2.string().describe("ID of the network volume to delete")
1034
1086
  },
1035
1087
  async (params) => {
1036
1088
  const result = await runpodRequest(
@@ -1047,21 +1099,21 @@ function registerTools(server2, ctx) {
1047
1099
  };
1048
1100
  }
1049
1101
  );
1050
- server2.tool("list-container-registry-auths", {}, async () => {
1051
- const result = await runpodRequest("/containerregistryauth");
1052
- return {
1053
- content: [
1054
- {
1055
- type: "text",
1056
- text: JSON.stringify(result, null, 2)
1057
- }
1058
- ]
1059
- };
1060
- });
1061
- server2.tool(
1102
+ server.tool(
1103
+ "list-container-registry-auths",
1104
+ listPaginationParams,
1105
+ async (params) => {
1106
+ const result = await runpodRequest("/containerregistryauth");
1107
+ return capListResult(result, {
1108
+ limit: params.limit,
1109
+ cursor: params.cursor
1110
+ });
1111
+ }
1112
+ );
1113
+ server.tool(
1062
1114
  "get-container-registry-auth",
1063
1115
  {
1064
- containerRegistryAuthId: z.string().describe("ID of the container registry auth to retrieve")
1116
+ containerRegistryAuthId: z2.string().describe("ID of the container registry auth to retrieve")
1065
1117
  },
1066
1118
  async (params) => {
1067
1119
  const result = await runpodRequest(
@@ -1077,12 +1129,12 @@ function registerTools(server2, ctx) {
1077
1129
  };
1078
1130
  }
1079
1131
  );
1080
- server2.tool(
1132
+ server.tool(
1081
1133
  "create-container-registry-auth",
1082
1134
  {
1083
- name: z.string().describe("Name for the container registry auth"),
1084
- username: z.string().describe("Registry username"),
1085
- password: z.string().describe("Registry password")
1135
+ name: z2.string().describe("Name for the container registry auth"),
1136
+ username: z2.string().describe("Registry username"),
1137
+ password: z2.string().describe("Registry password")
1086
1138
  },
1087
1139
  async (params) => {
1088
1140
  const result = await runpodRequest(
@@ -1100,10 +1152,10 @@ function registerTools(server2, ctx) {
1100
1152
  };
1101
1153
  }
1102
1154
  );
1103
- server2.tool(
1155
+ server.tool(
1104
1156
  "delete-container-registry-auth",
1105
1157
  {
1106
- containerRegistryAuthId: z.string().describe("ID of the container registry auth to delete")
1158
+ containerRegistryAuthId: z2.string().describe("ID of the container registry auth to delete")
1107
1159
  },
1108
1160
  async (params) => {
1109
1161
  const result = await runpodRequest(
@@ -1123,13 +1175,23 @@ function registerTools(server2, ctx) {
1123
1175
  }
1124
1176
 
1125
1177
  // src/stdio.ts
1126
- var API_KEY = process.env.RUNPOD_API_KEY;
1127
- if (!API_KEY) {
1128
- console.error("RUNPOD_API_KEY environment variable is required");
1129
- process.exit(1);
1178
+ var WIZARD_SUBCOMMANDS = ["add", "remove"];
1179
+ var subcommand = process.argv[2];
1180
+ var isWizardMode = WIZARD_SUBCOMMANDS.includes(subcommand);
1181
+ if (isWizardMode) {
1182
+ import("./wizard-37ZJSVB5.mjs").then(({ runWizard }) => runWizard(subcommand)).catch((error) => {
1183
+ console.error(error instanceof Error ? error.message : String(error));
1184
+ process.exit(1);
1185
+ });
1186
+ } else {
1187
+ const API_KEY = process.env.RUNPOD_API_KEY;
1188
+ if (!API_KEY) {
1189
+ console.error("RUNPOD_API_KEY environment variable is required");
1190
+ process.exit(1);
1191
+ }
1192
+ const server = createServer();
1193
+ registerTools(server, { apiKey: API_KEY, transport: "stdio" });
1194
+ const transport = new StdioServerTransport();
1195
+ server.connect(transport);
1130
1196
  }
1131
- var server = createServer();
1132
- registerTools(server, { apiKey: API_KEY, transport: "stdio" });
1133
- var transport = new StdioServerTransport();
1134
- server.connect(transport);
1135
1197
  //# sourceMappingURL=stdio.mjs.map