@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/http.d.cts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { JSONRPCMessage } from '@modelcontextprotocol/sdk/types.js';
2
+ import { ServerProfile } from './specgen/profile.cjs';
2
3
  import { IncomingMessage, ServerResponse } from 'node:http';
3
4
 
4
5
  type CredentialVerdict = {
@@ -32,8 +33,6 @@ interface RpcSummary {
32
33
  client?: string;
33
34
  }
34
35
 
35
- type ServerProfile = 'default' | 'directory';
36
-
37
36
  /**
38
37
  * Extract the bearer token from an HTTP request's Authorization header.
39
38
  * Returns null if the header is missing or malformed.
package/dist/http.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { JSONRPCMessage } from '@modelcontextprotocol/sdk/types.js';
2
+ import { ServerProfile } from './specgen/profile.js';
2
3
  import { IncomingMessage, ServerResponse } from 'node:http';
3
4
 
4
5
  type CredentialVerdict = {
@@ -32,8 +33,6 @@ interface RpcSummary {
32
33
  client?: string;
33
34
  }
34
35
 
35
- type ServerProfile = 'default' | 'directory';
36
-
37
36
  /**
38
37
  * Extract the bearer token from an HTTP request's Authorization header.
39
38
  * Returns null if the header is missing or malformed.
package/dist/http.mjs CHANGED
@@ -1,3 +1,10 @@
1
+ import {
2
+ DIRECTORY_PATH,
3
+ directoryIncludes,
4
+ directoryOmittedInputs,
5
+ profileForPath
6
+ } from "./chunk-6IETGSON.mjs";
7
+
1
8
  // src/http.ts
2
9
  import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
3
10
  import {
@@ -543,9 +550,36 @@ var generatedTools = [
543
550
  },
544
551
  ClusterMounts: {
545
552
  description: "Storage mounts for a cluster create: `persistent` or `network`, not both. Clusters cannot mount global volumes, so `global` is rejected.",
553
+ "x-go-type": "BaseMounts",
546
554
  allOf: [
547
555
  {
548
556
  $ref: "#/$defs/BaseMounts"
557
+ },
558
+ {
559
+ type: "object",
560
+ properties: {
561
+ persistent: {
562
+ type: "object",
563
+ properties: {
564
+ path: {
565
+ type: "string",
566
+ minLength: 1
567
+ }
568
+ }
569
+ },
570
+ network: {
571
+ type: "array",
572
+ items: {
573
+ type: "object",
574
+ properties: {
575
+ path: {
576
+ type: "string",
577
+ minLength: 1
578
+ }
579
+ }
580
+ }
581
+ }
582
+ }
549
583
  }
550
584
  ],
551
585
  unevaluatedProperties: false
@@ -2621,6 +2655,37 @@ var generatedTools = [
2621
2655
  properties: {}
2622
2656
  }
2623
2657
  },
2658
+ {
2659
+ name: "get-organization-user",
2660
+ title: "Get organization user",
2661
+ operationId: "getOrganizationUser",
2662
+ 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.",
2663
+ method: "GET",
2664
+ path: "/v2/organization/users/{id}",
2665
+ params: [
2666
+ {
2667
+ name: "id",
2668
+ location: "path"
2669
+ }
2670
+ ],
2671
+ hasBody: false,
2672
+ annotations: {
2673
+ readOnlyHint: true,
2674
+ destructiveHint: false,
2675
+ idempotentHint: true,
2676
+ openWorldHint: true
2677
+ },
2678
+ inputSchema: {
2679
+ type: "object",
2680
+ properties: {
2681
+ id: {
2682
+ type: "string",
2683
+ description: "User identifier"
2684
+ }
2685
+ },
2686
+ required: ["id"]
2687
+ }
2688
+ },
2624
2689
  {
2625
2690
  name: "get-pod",
2626
2691
  title: "Get Pod",
@@ -3760,6 +3825,26 @@ var generatedTools = [
3760
3825
  }
3761
3826
  }
3762
3827
  },
3828
+ {
3829
+ name: "list-organization-users",
3830
+ title: "List organization users",
3831
+ operationId: "listOrganizationUsers",
3832
+ 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.",
3833
+ method: "GET",
3834
+ path: "/v2/organization/users",
3835
+ params: [],
3836
+ hasBody: false,
3837
+ annotations: {
3838
+ readOnlyHint: true,
3839
+ destructiveHint: false,
3840
+ idempotentHint: true,
3841
+ openWorldHint: true
3842
+ },
3843
+ inputSchema: {
3844
+ type: "object",
3845
+ properties: {}
3846
+ }
3847
+ },
3763
3848
  {
3764
3849
  name: "list-pod-billing",
3765
3850
  title: "List Pod billing",
@@ -5316,6 +5401,7 @@ function networkFailureResult(error) {
5316
5401
  return {
5317
5402
  ok: false,
5318
5403
  status: unreached ? 503 : 502,
5404
+ requestDelivery: unreached ? "not_sent" : "uncertain",
5319
5405
  payload: unreached ? {
5320
5406
  error: "Could not reach the Runpod API.",
5321
5407
  cause: code,
@@ -5342,6 +5428,7 @@ async function runTool(body) {
5342
5428
  return {
5343
5429
  ok: false,
5344
5430
  status: 504,
5431
+ requestDelivery: "uncertain",
5345
5432
  payload: {
5346
5433
  error: "The Runpod API did not respond before the request deadline.",
5347
5434
  hint: "Transient upstream stall: retry the same call once; if it persists, check https://uptime.runpod.io."
@@ -5400,131 +5487,6 @@ var podTransitionTools = [
5400
5487
  )
5401
5488
  ];
5402
5489
 
5403
- // src/specgen/profile.ts
5404
- var DIRECTORY_PATH = "/directory";
5405
- var IN = { include: true };
5406
- var CREDENTIAL_MANAGEMENT = "Manages stored credentials; OpenAI restricts plugins that handle access credentials, so the directory leaves the whole credential family out.";
5407
- var CREDENTIAL_INPUT = "Takes a secret or password as input; directories forbid collecting credentials.";
5408
- var ALP = "Collects conversation-derived data beyond the task; the directory profile never serves it.";
5409
- var DIRECTORY_TOOLS = {
5410
- "cancel-job": IN,
5411
- "create-cluster": IN,
5412
- "create-delegation": IN,
5413
- "create-endpoint": IN,
5414
- "create-global-volume": IN,
5415
- "create-network-volume": IN,
5416
- "create-pod": IN,
5417
- "create-template": IN,
5418
- "delete-cluster": IN,
5419
- "delete-endpoint": IN,
5420
- "delete-global-volume": IN,
5421
- "delete-network-volume": IN,
5422
- "delete-pod": IN,
5423
- "delete-template": IN,
5424
- "deploy-hub-repo": IN,
5425
- "endpoint-health": IN,
5426
- "get-capacity": IN,
5427
- "get-cluster": IN,
5428
- "get-cpu-type": IN,
5429
- "get-data-center": IN,
5430
- "get-endpoint": IN,
5431
- "get-endpoint-build": IN,
5432
- "get-global-volume": IN,
5433
- "get-gpu-type": IN,
5434
- "get-job-status": IN,
5435
- "get-network-volume": IN,
5436
- "get-organization": IN,
5437
- "get-pod": IN,
5438
- "get-ssh-keys": IN,
5439
- "get-template": IN,
5440
- "list-audit-logs": IN,
5441
- "list-billing": IN,
5442
- "list-cluster-billing": IN,
5443
- "list-cluster-pods": IN,
5444
- "list-clusters": IN,
5445
- "list-cpu-types": IN,
5446
- "list-data-centers": IN,
5447
- "list-delegations": IN,
5448
- "list-endpoint-billing": IN,
5449
- "list-endpoint-builds": IN,
5450
- "list-endpoint-releases": IN,
5451
- "list-endpoint-workers": IN,
5452
- "list-endpoints": IN,
5453
- "list-global-volumes": IN,
5454
- "list-gpu-types": IN,
5455
- "list-hub-repos": IN,
5456
- "list-network-volume-billing": IN,
5457
- "list-network-volumes": IN,
5458
- "list-pod-billing": IN,
5459
- "list-pods": IN,
5460
- "list-public-endpoints": IN,
5461
- "list-public-templates": IN,
5462
- "list-serverless-billing": IN,
5463
- "list-templates": IN,
5464
- "lookup-concept": IN,
5465
- "purge-endpoint-queue": IN,
5466
- "retry-job": IN,
5467
- "revoke-delegation": IN,
5468
- "search-concepts": IN,
5469
- "search-docs": IN,
5470
- "set-endpoint-gpus": IN,
5471
- "stream-job": IN,
5472
- "stream-pod-logs": IN,
5473
- "stream-worker-logs": IN,
5474
- "update-cluster": IN,
5475
- "update-endpoint": IN,
5476
- "update-global-volume": IN,
5477
- "update-network-volume": IN,
5478
- "update-pod": IN,
5479
- "update-ssh-keys": IN,
5480
- "update-template": IN,
5481
- "run-endpoint": { include: true, omitInputs: ["s3Config"] },
5482
- "runsync-endpoint": { include: true, omitInputs: ["s3Config"] },
5483
- "pod-action": {
5484
- include: false,
5485
- reason: "Takes the transition as an argument; OpenAI asks for one tool per operation, so the directory serves start-pod, stop-pod and restart-pod (terminate is delete-pod)."
5486
- },
5487
- "start-pod": IN,
5488
- "stop-pod": IN,
5489
- "restart-pod": IN,
5490
- "list-guides": {
5491
- include: false,
5492
- reason: "Serves playbooks that instruct the model how to behave."
5493
- },
5494
- "read-guide": {
5495
- include: false,
5496
- reason: "Serves playbooks that instruct the model how to behave."
5497
- },
5498
- "describe-tool": {
5499
- include: false,
5500
- reason: "Fetches schemas the directory already lists in full; directories reject schema fetching."
5501
- },
5502
- "create-secret": { include: false, reason: CREDENTIAL_INPUT },
5503
- "get-secret": { include: false, reason: CREDENTIAL_MANAGEMENT },
5504
- "list-secrets": { include: false, reason: CREDENTIAL_MANAGEMENT },
5505
- "delete-secret": { include: false, reason: CREDENTIAL_MANAGEMENT },
5506
- "get-registry": { include: false, reason: CREDENTIAL_MANAGEMENT },
5507
- "list-registries": { include: false, reason: CREDENTIAL_MANAGEMENT },
5508
- "delete-registry": { include: false, reason: CREDENTIAL_MANAGEMENT },
5509
- "update-secret": { include: false, reason: CREDENTIAL_INPUT },
5510
- "create-registry": { include: false, reason: CREDENTIAL_INPUT },
5511
- report_feedback: { include: false, reason: ALP },
5512
- report_how_user_found_runpod: { include: false, reason: ALP },
5513
- save_to_journal: { include: false, reason: ALP },
5514
- read_journal: { include: false, reason: ALP },
5515
- ask_question: { include: false, reason: ALP }
5516
- };
5517
- function directoryIncludes(name) {
5518
- return DIRECTORY_TOOLS[name]?.include === true;
5519
- }
5520
- function directoryOmittedInputs(name) {
5521
- const decision = DIRECTORY_TOOLS[name];
5522
- return decision?.include ? decision.omitInputs ?? [] : [];
5523
- }
5524
- function profileForPath(pathname) {
5525
- return pathname.replace(/\/+$/, "") === DIRECTORY_PATH ? "directory" : "default";
5526
- }
5527
-
5528
5490
  // src/specgen/redact.ts
5529
5491
  var REDACTED = "[redacted]";
5530
5492
  var SECRET_KEY = /pass(word|wd)?|secret|token|api_?key|private_?key|credential|auth/i;
@@ -9076,7 +9038,7 @@ function words2(name) {
9076
9038
 
9077
9039
  // src/server.ts
9078
9040
  var SERVER_NAME = "Runpod API Server";
9079
- var SERVER_VERSION = true ? "4.7.0" : "dev";
9041
+ var SERVER_VERSION = true ? "4.8.0" : "dev";
9080
9042
 
9081
9043
  // src/specgen/analytics.ts
9082
9044
  import { createHmac } from "crypto";
@@ -9145,6 +9107,7 @@ function captureToolCall(apiKey, event) {
9145
9107
  ...event.clientName ? { client_name: event.clientName } : {},
9146
9108
  ...event.guideKind ? { guide_kind: event.guideKind } : {},
9147
9109
  ...event.blockedBy ? { blocked_by: event.blockedBy } : {},
9110
+ ...event.profile ? { profile: event.profile } : {},
9148
9111
  ...args
9149
9112
  });
9150
9113
  }
@@ -9777,6 +9740,7 @@ function createSpecgenServer(ctx, version = "0.1.0", opts = {}) {
9777
9740
  status: 429,
9778
9741
  durationMs: 0,
9779
9742
  ...verdict.reason ? { blockedBy: verdict.reason } : {},
9743
+ profile,
9780
9744
  ...opts.analytics
9781
9745
  });
9782
9746
  }
@@ -9797,6 +9761,9 @@ function createSpecgenServer(ctx, version = "0.1.0", opts = {}) {
9797
9761
  const curated = servedCuratedTools.find(
9798
9762
  (tool) => tool.name === request.params.name
9799
9763
  );
9764
+ const generated = servedGeneratedTools.find(
9765
+ (tool) => tool.name === request.params.name
9766
+ );
9800
9767
  const omitted = directory ? directoryOmittedInputs(request.params.name).filter((key) => key in args) : [];
9801
9768
  const rejected = omitted.length ? {
9802
9769
  ok: false,
@@ -9809,7 +9776,7 @@ function createSpecgenServer(ctx, version = "0.1.0", opts = {}) {
9809
9776
  args
9810
9777
  ) : null;
9811
9778
  const result = rejected ?? await runTool(
9812
- () => curated ? curated.handler(ctx, args) : dispatchTool(request.params.name, args)
9779
+ () => curated ? curated.handler(ctx, args) : dispatchTool(generated, request.params.name, args)
9813
9780
  );
9814
9781
  logToolCall({
9815
9782
  tool: request.params.name,
@@ -9829,23 +9796,27 @@ function createSpecgenServer(ctx, version = "0.1.0", opts = {}) {
9829
9796
  args: recordedArgumentValues(curated?.recordedArguments, args),
9830
9797
  guideKind: curated?.recordedGuideKind?.(args)
9831
9798
  },
9799
+ profile,
9832
9800
  ...opts.analytics
9833
9801
  });
9834
9802
  }
9835
9803
  opts.onToolResult?.(request.params.name, result.status);
9836
9804
  if (!result.ok && result.status === 401) opts.onUnauthorized?.();
9805
+ const annotations = curated?.annotations ?? generated?.annotations;
9837
9806
  const payload = redactSecretEnv(
9838
- result.ok ? result.payload : withRecoveryHint(result, callShapeOnlyTools.has(request.params.name))
9807
+ result.ok ? result.payload : withRecoveryHint(
9808
+ result,
9809
+ annotations?.idempotentHint === true,
9810
+ request.params.name,
9811
+ callShapeOnlyTools.has(request.params.name)
9812
+ )
9839
9813
  );
9840
9814
  return {
9841
9815
  content: [{ type: "text", text: JSON.stringify(payload, null, 2) }],
9842
9816
  isError: !result.ok
9843
9817
  };
9844
9818
  });
9845
- async function dispatchTool(name, args) {
9846
- const tool = servedGeneratedTools.find(
9847
- (candidate) => candidate.name === name
9848
- );
9819
+ async function dispatchTool(tool, name, args) {
9849
9820
  if (!tool)
9850
9821
  return {
9851
9822
  ok: false,
@@ -9893,8 +9864,24 @@ function errorHint(status, detail) {
9893
9864
  return void 0;
9894
9865
  }
9895
9866
  var CALL_SHAPE_ONLY_HINT = `This tool lists its call shape only; ${DESCRIBE_TOOL_NAME} serves the full argument schema.`;
9896
- function withRecoveryHint(result, listsCallShapeOnly = false) {
9867
+ 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.";
9868
+ 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.";
9869
+ 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.";
9870
+ var JOB_SUBMISSION_TOOLS = /* @__PURE__ */ new Set(["run-endpoint", "runsync-endpoint"]);
9871
+ function withRecoveryHint(result, idempotent, toolName, listsCallShapeOnly = false) {
9897
9872
  const payload = asRecord(result.payload) ?? { error: result.payload };
9873
+ if (!idempotent && result.status >= 500 && result.requestDelivery !== "not_sent") {
9874
+ const detail = asRecord(payload.detail);
9875
+ const safeDetail = detail ? { ...detail } : void 0;
9876
+ if (safeDetail) delete safeDetail.hint;
9877
+ return {
9878
+ ...payload,
9879
+ ...safeDetail ? { detail: safeDetail } : {},
9880
+ ...payload.code !== void 0 ? { upstreamCode: payload.code } : {},
9881
+ code: "outcome_unknown",
9882
+ hint: toolName === "retry-job" ? RETRY_JOB_OUTCOME_UNKNOWN_HINT : JOB_SUBMISSION_TOOLS.has(toolName) ? JOB_OUTCOME_UNKNOWN_HINT : OUTCOME_UNKNOWN_HINT
9883
+ };
9884
+ }
9898
9885
  const hint = payload.hint ?? asRecord(payload.detail)?.hint ?? errorHint(result.status, detailText(payload));
9899
9886
  const shapeRejected = result.status === 400 || result.status === 422;
9900
9887
  return {