@runpod/mcp-server 4.7.0 → 4.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/stdio.mjs CHANGED
@@ -12,7 +12,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
12
12
 
13
13
  // src/server.ts
14
14
  var SERVER_NAME = "Runpod API Server";
15
- var SERVER_VERSION = true ? "4.7.0" : "dev";
15
+ var SERVER_VERSION = true ? "4.8.0" : "dev";
16
16
 
17
17
  // src/specgen/server.ts
18
18
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
@@ -477,9 +477,36 @@ var generatedTools = [
477
477
  },
478
478
  ClusterMounts: {
479
479
  description: "Storage mounts for a cluster create: `persistent` or `network`, not both. Clusters cannot mount global volumes, so `global` is rejected.",
480
+ "x-go-type": "BaseMounts",
480
481
  allOf: [
481
482
  {
482
483
  $ref: "#/$defs/BaseMounts"
484
+ },
485
+ {
486
+ type: "object",
487
+ properties: {
488
+ persistent: {
489
+ type: "object",
490
+ properties: {
491
+ path: {
492
+ type: "string",
493
+ minLength: 1
494
+ }
495
+ }
496
+ },
497
+ network: {
498
+ type: "array",
499
+ items: {
500
+ type: "object",
501
+ properties: {
502
+ path: {
503
+ type: "string",
504
+ minLength: 1
505
+ }
506
+ }
507
+ }
508
+ }
509
+ }
483
510
  }
484
511
  ],
485
512
  unevaluatedProperties: false
@@ -2555,6 +2582,37 @@ var generatedTools = [
2555
2582
  properties: {}
2556
2583
  }
2557
2584
  },
2585
+ {
2586
+ name: "get-organization-user",
2587
+ title: "Get organization user",
2588
+ operationId: "getOrganizationUser",
2589
+ description: "Get an organization member. Returns one member of the authenticated caller's organization by user ID, with the role they hold. Any member can read it. A user who is not a member, including one from another organization, returns 404. Returns 404 when the caller does not belong to an organization, or 403 when organizations are unavailable to the caller.",
2590
+ method: "GET",
2591
+ path: "/v2/organization/users/{id}",
2592
+ params: [
2593
+ {
2594
+ name: "id",
2595
+ location: "path"
2596
+ }
2597
+ ],
2598
+ hasBody: false,
2599
+ annotations: {
2600
+ readOnlyHint: true,
2601
+ destructiveHint: false,
2602
+ idempotentHint: true,
2603
+ openWorldHint: true
2604
+ },
2605
+ inputSchema: {
2606
+ type: "object",
2607
+ properties: {
2608
+ id: {
2609
+ type: "string",
2610
+ description: "User identifier"
2611
+ }
2612
+ },
2613
+ required: ["id"]
2614
+ }
2615
+ },
2558
2616
  {
2559
2617
  name: "get-pod",
2560
2618
  title: "Get Pod",
@@ -3694,6 +3752,26 @@ var generatedTools = [
3694
3752
  }
3695
3753
  }
3696
3754
  },
3755
+ {
3756
+ name: "list-organization-users",
3757
+ title: "List organization users",
3758
+ operationId: "listOrganizationUsers",
3759
+ description: "List organization members. Returns every member of the authenticated caller's organization with the role each holds. Any member can read the roster. The list is complete and takes no pagination parameters. Returns 404 when the caller does not belong to an organization, or 403 when organizations are unavailable to the caller.",
3760
+ method: "GET",
3761
+ path: "/v2/organization/users",
3762
+ params: [],
3763
+ hasBody: false,
3764
+ annotations: {
3765
+ readOnlyHint: true,
3766
+ destructiveHint: false,
3767
+ idempotentHint: true,
3768
+ openWorldHint: true
3769
+ },
3770
+ inputSchema: {
3771
+ type: "object",
3772
+ properties: {}
3773
+ }
3774
+ },
3697
3775
  {
3698
3776
  name: "list-pod-billing",
3699
3777
  title: "List Pod billing",
@@ -5250,6 +5328,7 @@ function networkFailureResult(error) {
5250
5328
  return {
5251
5329
  ok: false,
5252
5330
  status: unreached ? 503 : 502,
5331
+ requestDelivery: unreached ? "not_sent" : "uncertain",
5253
5332
  payload: unreached ? {
5254
5333
  error: "Could not reach the Runpod API.",
5255
5334
  cause: code,
@@ -5276,6 +5355,7 @@ async function runTool(body) {
5276
5355
  return {
5277
5356
  ok: false,
5278
5357
  status: 504,
5358
+ requestDelivery: "uncertain",
5279
5359
  payload: {
5280
5360
  error: "The Runpod API did not respond before the request deadline.",
5281
5361
  hint: "Transient upstream stall: retry the same call once; if it persists, check https://uptime.runpod.io."
@@ -5367,6 +5447,7 @@ var DIRECTORY_TOOLS = {
5367
5447
  "get-job-status": IN,
5368
5448
  "get-network-volume": IN,
5369
5449
  "get-organization": IN,
5450
+ "get-organization-user": IN,
5370
5451
  "get-pod": IN,
5371
5452
  "get-ssh-keys": IN,
5372
5453
  "get-template": IN,
@@ -5388,6 +5469,7 @@ var DIRECTORY_TOOLS = {
5388
5469
  "list-hub-repos": IN,
5389
5470
  "list-network-volume-billing": IN,
5390
5471
  "list-network-volumes": IN,
5472
+ "list-organization-users": IN,
5391
5473
  "list-pod-billing": IN,
5392
5474
  "list-pods": IN,
5393
5475
  "list-public-endpoints": IN,
@@ -9051,6 +9133,7 @@ function captureToolCall(apiKey, event) {
9051
9133
  ...event.clientName ? { client_name: event.clientName } : {},
9052
9134
  ...event.guideKind ? { guide_kind: event.guideKind } : {},
9053
9135
  ...event.blockedBy ? { blocked_by: event.blockedBy } : {},
9136
+ ...event.profile ? { profile: event.profile } : {},
9054
9137
  ...args
9055
9138
  });
9056
9139
  }
@@ -9927,6 +10010,7 @@ function createSpecgenServer(ctx, version = "0.1.0", opts = {}) {
9927
10010
  status: 429,
9928
10011
  durationMs: 0,
9929
10012
  ...verdict.reason ? { blockedBy: verdict.reason } : {},
10013
+ profile,
9930
10014
  ...opts.analytics
9931
10015
  });
9932
10016
  }
@@ -9947,6 +10031,9 @@ function createSpecgenServer(ctx, version = "0.1.0", opts = {}) {
9947
10031
  const curated = servedCuratedTools.find(
9948
10032
  (tool) => tool.name === request.params.name
9949
10033
  );
10034
+ const generated = servedGeneratedTools.find(
10035
+ (tool) => tool.name === request.params.name
10036
+ );
9950
10037
  const omitted = directory ? directoryOmittedInputs(request.params.name).filter((key) => key in args) : [];
9951
10038
  const rejected = omitted.length ? {
9952
10039
  ok: false,
@@ -9959,7 +10046,7 @@ function createSpecgenServer(ctx, version = "0.1.0", opts = {}) {
9959
10046
  args
9960
10047
  ) : null;
9961
10048
  const result = rejected ?? await runTool(
9962
- () => curated ? curated.handler(ctx, args) : dispatchTool(request.params.name, args)
10049
+ () => curated ? curated.handler(ctx, args) : dispatchTool(generated, request.params.name, args)
9963
10050
  );
9964
10051
  logToolCall({
9965
10052
  tool: request.params.name,
@@ -9979,23 +10066,27 @@ function createSpecgenServer(ctx, version = "0.1.0", opts = {}) {
9979
10066
  args: recordedArgumentValues(curated?.recordedArguments, args),
9980
10067
  guideKind: curated?.recordedGuideKind?.(args)
9981
10068
  },
10069
+ profile,
9982
10070
  ...opts.analytics
9983
10071
  });
9984
10072
  }
9985
10073
  opts.onToolResult?.(request.params.name, result.status);
9986
10074
  if (!result.ok && result.status === 401) opts.onUnauthorized?.();
10075
+ const annotations = curated?.annotations ?? generated?.annotations;
9987
10076
  const payload = redactSecretEnv(
9988
- result.ok ? result.payload : withRecoveryHint(result, callShapeOnlyTools.has(request.params.name))
10077
+ result.ok ? result.payload : withRecoveryHint(
10078
+ result,
10079
+ annotations?.idempotentHint === true,
10080
+ request.params.name,
10081
+ callShapeOnlyTools.has(request.params.name)
10082
+ )
9989
10083
  );
9990
10084
  return {
9991
10085
  content: [{ type: "text", text: JSON.stringify(payload, null, 2) }],
9992
10086
  isError: !result.ok
9993
10087
  };
9994
10088
  });
9995
- async function dispatchTool(name, args) {
9996
- const tool = servedGeneratedTools.find(
9997
- (candidate) => candidate.name === name
9998
- );
10089
+ async function dispatchTool(tool, name, args) {
9999
10090
  if (!tool)
10000
10091
  return {
10001
10092
  ok: false,
@@ -10043,8 +10134,24 @@ function errorHint(status, detail) {
10043
10134
  return void 0;
10044
10135
  }
10045
10136
  var CALL_SHAPE_ONLY_HINT = `This tool lists its call shape only; ${DESCRIBE_TOOL_NAME} serves the full argument schema.`;
10046
- function withRecoveryHint(result, listsCallShapeOnly = false) {
10137
+ var OUTCOME_UNKNOWN_HINT = "Runpod may have completed this operation even though its response failed. Do not submit it again yet. Check the matching get- or list- tool or the Runpod console using the original request details and time. Lists can lag; if you cannot confirm the outcome, stop and ask the user to verify before retrying.";
10138
+ var JOB_OUTCOME_UNKNOWN_HINT = "Runpod may have submitted this Serverless job even though its response failed. Do not submit it again yet. No job-list tool is available, and get-job-status requires a job ID that this failed response may not have returned. Check the endpoint in the Runpod console or ask the user to verify the submission. If the outcome remains uncertain, stop instead of retrying.";
10139
+ var RETRY_JOB_OUTCOME_UNKNOWN_HINT = "Runpod may have requeued this Serverless job even though its response failed. Do not retry it again yet. Check get-job-status with the endpoint and job IDs you supplied, or check the Runpod console. If you cannot confirm the outcome, stop and ask the user to verify before retrying.";
10140
+ var JOB_SUBMISSION_TOOLS = /* @__PURE__ */ new Set(["run-endpoint", "runsync-endpoint"]);
10141
+ function withRecoveryHint(result, idempotent, toolName, listsCallShapeOnly = false) {
10047
10142
  const payload = asRecord(result.payload) ?? { error: result.payload };
10143
+ if (!idempotent && result.status >= 500 && result.requestDelivery !== "not_sent") {
10144
+ const detail = asRecord(payload.detail);
10145
+ const safeDetail = detail ? { ...detail } : void 0;
10146
+ if (safeDetail) delete safeDetail.hint;
10147
+ return {
10148
+ ...payload,
10149
+ ...safeDetail ? { detail: safeDetail } : {},
10150
+ ...payload.code !== void 0 ? { upstreamCode: payload.code } : {},
10151
+ code: "outcome_unknown",
10152
+ hint: toolName === "retry-job" ? RETRY_JOB_OUTCOME_UNKNOWN_HINT : JOB_SUBMISSION_TOOLS.has(toolName) ? JOB_OUTCOME_UNKNOWN_HINT : OUTCOME_UNKNOWN_HINT
10153
+ };
10154
+ }
10048
10155
  const hint = payload.hint ?? asRecord(payload.detail)?.hint ?? errorHint(result.status, detailText(payload));
10049
10156
  const shapeRejected = result.status === 400 || result.status === 422;
10050
10157
  return {