← Files OpenAI DevelopersARCHIVED FILE

mcp/server.mjs

14.5 KB · Nov 3, 2026 · 18:15 UTC

↓ Download file

See the change to this file →

import { createHmac, randomBytes, randomUUID, timingSafeEqual } from "node:crypto";
import path from "node:path";
import readline from "node:readline";

const SERVER_INFO = { name: "OpenAI Developers MCP", version: "0.1.0" };
const PROTOCOL = "2026-07-28";
const MCP = "io.modelcontextprotocol/";
const continuationKey = randomBytes(32);
let protocol;

const DEFAULT_ENV_NAME = "OPENAI_API_KEY";
const ENV_NAME_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
const SETUP_CHOICES = [
  { const: "create", title: "Create an API key" },
  { const: "configured", title: "I have an API key configured" },
  { const: "skip", title: "Skip" },
];
const TOOL_ANNOTATIONS = {
  readOnlyHint: true,
  destructiveHint: false,
  idempotentHint: true,
  openWorldHint: false,
};
const DESTINATION_TOOL = {
  name: "confirm_openai_api_key_local_destination",
  title: "Confirm OpenAI API Key Local Destination",
  description:
    "Ask the developer to confirm or edit the local env-file destination for a new OpenAI API key. Call this after the Platform picker returns the confirmed key name and target ids, and proceed only when it returns approved.",
  inputSchema: {
    type: "object",
    properties: {
      workspacePath: {
        type: "string",
        description: "Absolute workspace root used to confine the local env-file write.",
      },
      targetPath: {
        type: "string",
        description: "Recommended env-file path inside the workspace, such as .env.local.",
      },
      envName: {
        type: "string",
        description: "Environment variable name to create or update. Defaults to OPENAI_API_KEY.",
        default: DEFAULT_ENV_NAME,
      },
    },
    required: ["workspacePath", "targetPath"],
  },
  annotations: TOOL_ANNOTATIONS,
};
const SETUP_TOOL = {
  name: "choose_openai_api_key_setup",
  title: "Choose OpenAI API Key Setup",
  description:
    "Present the native API key setup choices during OpenAI Developers onboarding. Returns the user's confirmed choice, or not_selected when canceled or declined.",
  inputSchema: { type: "object", properties: {}, additionalProperties: false },
  annotations: TOOL_ANNOTATIONS,
};
const PROMO_ORG_TOOL = {
  name: "confirm_api_credit_promo_org",
  title: "Confirm API Credit Promo Organization",
  description:
    "Ask the user to choose an organization from discover_api_orgs. On approval, return the chosen organization and a generated operation ID in link_arguments for link_api_org. Reuse those arguments for retries.",
  inputSchema: {
    type: "object",
    properties: {
      destinations: {
        type: "array",
        minItems: 1,
        items: {
          type: "object",
          properties: {
            destination_type: { type: "string", const: "api_org" },
            destination_account_id: { type: "string", minLength: 1, maxLength: 128 },
            display_name: { type: "string" },
          },
          required: ["destination_type", "destination_account_id", "display_name"],
        },
      },
    },
    required: ["destinations"],
    additionalProperties: false,
  },
  annotations: { ...TOOL_ANNOTATIONS, idempotentHint: false },
};
const JsonRpcError = {
  METHOD_NOT_FOUND: -32601,
  INVALID_PARAMS: -32602,
};

let nextRequestId = 1;
const pendingRequests = new Map();

function send(message) {
  process.stdout.write(`${JSON.stringify(message)}\n`);
}

function sendResult(id, result) {
  if (protocol === PROTOCOL) result = { resultType: "complete", ...result };
  send({ jsonrpc: "2.0", id, result });
}

function sendError(id, code, message, data) {
  send({ jsonrpc: "2.0", id, error: { code, message, data } });
}

function request(method, params) {
  const id = `server-${nextRequestId++}`;
  send({ jsonrpc: "2.0", id, method, params });
  return new Promise((resolve, reject) => {
    pendingRequests.set(id, { resolve, reject });
  });
}

// Sign each prompt with its chat and form. Retries reuse the prompt UUID as
// the credit-link operation ID without keeping abandoned prompts in memory.
async function elicit(id, params, form) {
  if (protocol !== PROTOCOL) return (await request("elicitation/create", form)) ?? { action: "cancel" };

  const { name, arguments: args, _meta, requestState, inputResponses } = params;
  const capability = _meta[MCP + "clientCapabilities"].elicitation;
  // MCP also treats an empty elicitation declaration as form-only support.
  if (!isObject(capability) || (!isObject(capability.form) && Object.keys(capability).length > 0)) {
    sendError(id, -32021, "This tool requires form elicitation.", {
      requiredCapabilities: { elicitation: { form: {} } },
    });
    return;
  }
  requireNonEmptyString(_meta.threadId, "threadId");
  const call = [_meta.threadId, _meta.sessionId, _meta.itemId, _meta.callId];
  const promptId = typeof requestState === "string" ? requestState.split(".", 1)[0] : randomUUID();
  const signature = createHmac("sha256", continuationKey)
    .update(JSON.stringify([promptId, name, args?.workspacePath, form, call]))
    .digest("base64url");
  const state = `${promptId}.${signature}`;
  if (requestState === undefined && inputResponses === undefined) {
    sendResult(id, {
      resultType: "input_required",
      inputRequests: { confirmation: { method: "elicitation/create", params: form } },
      requestState: state,
    });
    return;
  }
  if (
    typeof requestState !== "string" || Buffer.byteLength(requestState) !== Buffer.byteLength(state) ||
    !timingSafeEqual(Buffer.from(requestState), Buffer.from(state))
  ) {
    throw new Error("Confirmation does not belong to this tool call.");
  }
  const response = inputResponses?.confirmation;
  if (!["accept", "decline", "cancel"].includes(response?.action)) {
    throw new Error("Missing or invalid confirmation response.");
  }
  return { ...response, promptId };
}

function isObject(value) {
  return value !== null && typeof value === "object" && !Array.isArray(value);
}

function requireNonEmptyString(value, name) {
  if (typeof value !== "string" || value.trim().length === 0) {
    throw new Error(`${name} must be a non-empty string.`);
  }
  return value.trim();
}

function resolveTarget(workspacePath, targetPath) {
  const root = requireNonEmptyString(workspacePath, "workspacePath");
  // On Windows a rooted path without a drive still depends on the helper's cwd.
  if (protocol === PROTOCOL && (
    !path.isAbsolute(root) || (process.platform === "win32" && path.parse(root).root.length === 1)
  )) {
    throw new Error("workspacePath must be absolute for a shared confirmation.");
  }
  const workspace = path.resolve(root);
  const target = path.resolve(
    workspace,
    requireNonEmptyString(targetPath, "targetPath"),
  );
  const relative = path.relative(workspace, target);
  if (
    relative === ".." ||
    relative.startsWith(`..${path.sep}`) ||
    path.isAbsolute(relative)
  ) {
    throw new Error("The env file must be inside the selected workspace.");
  }
  return { workspace, target };
}

async function handleSetupChoice(id, params) {
  const elicitation = await elicit(id, params, {
    mode: "form",
    message: "You'll need an OpenAI API key to build with the OpenAI API",
    requestedSchema: {
      type: "object",
      properties: { setupChoice: { type: "string", oneOf: SETUP_CHOICES } },
      required: ["setupChoice"],
    },
  });
  if (!elicitation) return;
  const choice = elicitation.content?.setupChoice;
  if (elicitation.action !== "accept" || !SETUP_CHOICES.some((option) => option.const === choice)) {
    sendResult(id, {
      content: [{ type: "text", text: "No API key setup choice was confirmed." }],
      structuredContent: { status: "not_selected" },
    });
    return;
  }
  sendResult(id, {
    content: [{ type: "text", text: `The developer selected: ${choice}.` }],
    structuredContent: { status: "selected", choice },
  });
}

async function handlePromoOrgConfirmation(id, params) {
  const args = params.arguments;
  if (!Array.isArray(args?.destinations) || args.destinations.length === 0 || Object.keys(args).length !== 1) {
    throw new Error("Pass the non-empty destinations returned by discover_api_orgs.");
  }
  const orgIds = new Set();
  const choices = args.destinations.map((destination) => {
    const orgId = destination?.destination_account_id;
    if (
      destination?.destination_type !== "api_org" ||
      typeof orgId !== "string" ||
      orgId.length === 0 ||
      orgId.length > 128 ||
      orgId.trim() !== orgId ||
      typeof destination.display_name !== "string" ||
      orgIds.has(orgId)
    ) {
      throw new Error("Each destination must identify a distinct Platform organization.");
    }
    orgIds.add(orgId);
    return {
      const: orgId,
      title: destination.display_name ? `${destination.display_name} (${orgId})` : orgId,
    };
  });
  const elicitation = await elicit(id, params, {
    mode: "form",
    message:
      "Your ChatGPT subscription includes free API credits. Choose the API organization that will receive them. You can't change the organization for this claim later.",
    requestedSchema: {
      type: "object",
      properties: {
        destination_account_id: { type: "string", title: "Platform organization", oneOf: choices },
      },
      required: ["destination_account_id"],
    },
  });
  if (!elicitation) return;
  const orgId = elicitation.content?.destination_account_id;
  const result =
    elicitation.action === "accept" && orgIds.has(orgId)
      ? {
          status: "approved",
          link_arguments: {
            destination_account_id: orgId,
            operation_id: protocol === PROTOCOL ? elicitation.promptId : randomUUID(),
          },
        }
      : { status: "not_approved" };
  sendResult(id, {
    content: [{ type: "text", text: JSON.stringify(result) }],
    structuredContent: result,
  });
}

async function handleToolCall(id, params) {
  if (params?.name === SETUP_TOOL.name) {
    return handleSetupChoice(id, params);
  }
  if (params?.name === PROMO_ORG_TOOL.name) {
    return handlePromoOrgConfirmation(id, params);
  }
  if (params?.name !== DESTINATION_TOOL.name) {
    sendError(id, JsonRpcError.INVALID_PARAMS, `Unknown tool: ${params?.name ?? ""}`);
    return;
  }

  const args = params.arguments ?? {};
  const envName = args.envName ?? DEFAULT_ENV_NAME;
  if (typeof envName !== "string" || !ENV_NAME_PATTERN.test(envName)) {
    throw new Error("envName must be a valid environment variable name.");
  }

  const { workspace, target: recommendedTarget } = resolveTarget(
    args.workspacePath,
    args.targetPath,
  );
  const elicitation = await elicit(id, params, {
    mode: "form",
    message: `Choose where OpenAI Developers should save the new API key as ${envName}.`,
    requestedSchema: {
      type: "object",
      properties: {
        targetPath: {
          type: "string",
          title: "Save location",
          default: recommendedTarget,
          minLength: 1,
        },
      },
      required: ["targetPath"],
    },
  });

  if (!elicitation) return;
  if (elicitation.action !== "accept") {
    sendResult(id, {
      content: [
        {
          type: "text",
          text: "The local API key destination was not approved. Do not create or write a key.",
        },
      ],
      structuredContent: {
        status: "not_approved",
        action: elicitation.action ?? "cancel",
      },
    });
    return;
  }

  const { target } = resolveTarget(workspace, elicitation.content?.targetPath);
  sendResult(id, {
    content: [
      {
        type: "text",
        text: `The developer approved ${target} for ${envName}. Continue with secure key creation and write only to that env file.`,
      },
    ],
    structuredContent: {
      status: "approved",
      workspacePath: workspace,
      targetPath: target,
      envName,
    },
  });
}

async function handleRequest(message) {
  const { id, method, params } = message;

  if (id === undefined) return;
  const meta = params?._meta;
  const version = meta?.[MCP + "protocolVersion"];
  if (method === "server/discover" || version !== undefined || protocol === PROTOCOL ||
      (protocol === "discovered" && method !== "initialize")) {
    if (version !== PROTOCOL) {
      if (version === undefined) sendError(id, -32602, "Missing protocol version.");
      else sendError(id, -32022, "Unsupported protocol version.", { supported: [PROTOCOL], requested: version });
      return;
    }
    const capabilities = meta[MCP + "clientCapabilities"];
    if (protocol === "legacy" || !isObject(capabilities)) {
      sendError(id, -32602, "Invalid modern MCP request.");
      return;
    }
    if (method === "server/discover") {
      protocol ??= "discovered";
      sendResult(id, {
        resultType: "complete",
        supportedVersions: [PROTOCOL],
        capabilities: { tools: {} },
        _meta: { [MCP + "serverInfo"]: SERVER_INFO },
        ttlMs: 0,
        cacheScope: "private",
      });
      return;
    }
    protocol = PROTOCOL;
  }
  if (method === "initialize" && protocol !== PROTOCOL) {
    protocol = "legacy";
    sendResult(id, {
      protocolVersion: params?.protocolVersion ?? "2025-11-25",
      capabilities: { tools: {} },
      serverInfo: SERVER_INFO,
      instructions:
        "Use choose_openai_api_key_setup during onboarding. Use confirm_openai_api_key_local_destination after the OpenAI Platform picker returns a key name and target ids, before creating or writing a secret.",
    });
    return;
  }

  if (method === "ping" && protocol !== PROTOCOL) {
    sendResult(id, {});
    return;
  }

  if (method === "tools/list") {
    sendResult(id, {
      tools: [DESTINATION_TOOL, SETUP_TOOL, PROMO_ORG_TOOL],
      ...(protocol === PROTOCOL && { ttlMs: 0, cacheScope: "private" }),
    });
    return;
  }

  if (method === "tools/call") {
    protocol ??= "legacy";
    try {
      await handleToolCall(id, params);
    } catch (error) {
      sendError(
        id,
        JsonRpcError.INVALID_PARAMS,
        error instanceof Error ? error.message : String(error),
      );
    }
    return;
  }

  sendError(id, JsonRpcError.METHOD_NOT_FOUND, `Method not found: ${method}`);
}

const lines = readline.createInterface({
  input: process.stdin,
  crlfDelay: Infinity,
});

lines.on("line", (line) => {
  if (line.trim().length === 0) {
    return;
  }

  let message;
  try {
    message = JSON.parse(line);
  } catch {
    return;
  }

  if (message.method === undefined && message.id !== undefined) {
    const pending = pendingRequests.get(message.id);
    if (pending !== undefined) {
      pendingRequests.delete(message.id);
      if (message.error !== undefined) {
        pending.reject(new Error(message.error.message ?? "MCP request failed."));
      } else {
        pending.resolve(message.result);
      }
    }
    return;
  }

  void handleRequest(message);
});

SHA-256: 7ef272c5fffdae3ff96b4db424ab1a167f452e4d5391493d0c7dc0b4c8bd1feb