#!/usr/bin/env node
/**
 * Minimal MCP server for OpenAI chat completions.
 * Accepts ANY model string (gpt-5.2, gpt-5.4, etc.) — no hardcoded enum.
 * Communicates over stdio using JSON-RPC (MCP protocol).
 */

import { createInterface } from "readline";

const OPENAI_API_KEY = process.env.OPENAI_API_KEY;
if (!OPENAI_API_KEY) {
  process.stderr.write("ERROR: OPENAI_API_KEY environment variable is required\n");
  process.exit(1);
}

const SERVER_INFO = {
  name: "openai-chat",
  version: "1.0.0",
};

const TOOLS = [
  {
    name: "openai_chat",
    description:
      "Send messages to OpenAI chat completions API. Supports all OpenAI models including GPT-5.x series.",
    inputSchema: {
      type: "object",
      properties: {
        model: {
          type: "string",
          description:
            "OpenAI model name (e.g. gpt-5.2, gpt-5.4, gpt-4o, etc.)",
          default: "gpt-5.2",
        },
        messages: {
          type: "array",
          description: "Array of chat messages",
          items: {
            type: "object",
            properties: {
              role: {
                type: "string",
                enum: ["system", "user", "assistant"],
              },
              content: { type: "string" },
            },
            required: ["role", "content"],
          },
        },
      },
      required: ["messages"],
    },
  },
];

async function callOpenAI(model, messages) {
  const resp = await fetch("https://api.openai.com/v1/chat/completions", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Authorization: `Bearer ${OPENAI_API_KEY}`,
    },
    body: JSON.stringify({ model, messages }),
  });

  if (!resp.ok) {
    const errText = await resp.text();
    throw new Error(`OpenAI API error ${resp.status}: ${errText}`);
  }

  const data = await resp.json();
  return data.choices?.[0]?.message?.content ?? "(no response)";
}

function jsonRpcResponse(id, result) {
  return JSON.stringify({ jsonrpc: "2.0", id, result });
}

function jsonRpcError(id, code, message) {
  return JSON.stringify({ jsonrpc: "2.0", id, error: { code, message } });
}

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

  switch (method) {
    case "initialize":
      return jsonRpcResponse(id, {
        protocolVersion: "2024-11-05",
        capabilities: { tools: {} },
        serverInfo: SERVER_INFO,
      });

    case "notifications/initialized":
      return null; // no response needed for notifications

    case "tools/list":
      return jsonRpcResponse(id, { tools: TOOLS });

    case "tools/call": {
      const toolName = params?.name;
      if (toolName !== "openai_chat") {
        return jsonRpcError(id, -32602, `Unknown tool: ${toolName}`);
      }
      const args = params?.arguments ?? {};
      const model = args.model || "gpt-5.2";
      const messages = args.messages || [];

      if (!messages.length) {
        return jsonRpcError(id, -32602, "messages array is required");
      }

      try {
        const content = await callOpenAI(model, messages);
        return jsonRpcResponse(id, {
          content: [{ type: "text", text: content }],
        });
      } catch (err) {
        return jsonRpcResponse(id, {
          content: [{ type: "text", text: `Error: ${err.message}` }],
          isError: true,
        });
      }
    }

    case "ping":
      return jsonRpcResponse(id, {});

    default:
      if (method?.startsWith("notifications/")) return null;
      return jsonRpcError(id, -32601, `Method not found: ${method}`);
  }
}

// stdio transport
const rl = createInterface({ input: process.stdin });

rl.on("line", async (line) => {
  try {
    const req = JSON.parse(line);
    const resp = await handleRequest(req);
    if (resp) {
      process.stdout.write(resp + "\n");
    }
  } catch (err) {
    process.stderr.write(`Parse error: ${err.message}\n`);
  }
});
