UNPKG

@boseong/mcp-openai-gpt5

Version:

MCP server for OpenAI GPT-5 API with dual interface support (simple + messages)

230 lines (229 loc) 8.57 kB
#!/usr/bin/env node import { Server } from "@modelcontextprotocol/sdk/server/index.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { ListToolsRequestSchema, CallToolRequestSchema, ErrorCode, McpError, } from "@modelcontextprotocol/sdk/types.js"; import path from "path"; import { fileURLToPath } from "url"; import dotenv from "dotenv"; import { z } from "zod"; import { zodToJsonSchema } from "zod-to-json-schema"; import { callGPT5, callGPT5WithMessages } from "./utils.js"; // Initialize environment - try multiple locations import { dirname } from "path"; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); // Try to load .env from multiple locations (for local development) const possibleEnvPaths = [ path.join(__dirname, "../../.env"), // Original location for local dev path.join(process.cwd(), ".env"), // Current working directory path.join(__dirname, "../.env"), // Parent directory ]; let envLoaded = false; for (const envPath of possibleEnvPaths) { const result = dotenv.config({ path: envPath }); if (!result.error) { console.error("Environment loaded from:", envPath); envLoaded = true; break; } } if (!envLoaded) { console.error("No .env file found. Using environment variables."); } // Schema definitions const GPT5GenerateSchema = z.object({ input: z.string().describe("The input text or prompt for GPT-5"), model: z .string() .optional() .default("gpt-5") .describe("GPT-5 model variant to use"), instructions: z .string() .optional() .describe("System instructions for the model"), reasoning_effort: z .enum(["low", "medium", "high"]) .optional() .describe("Reasoning effort level"), max_tokens: z.number().optional().describe("Maximum tokens to generate"), temperature: z .number() .min(0) .max(2) .optional() .describe("Temperature for randomness (0-2)"), top_p: z .number() .min(0) .max(1) .optional() .describe("Top-p sampling parameter"), }); const GPT5MessagesSchema = z.object({ messages: z .array(z.object({ role: z .enum(["user", "developer", "assistant"]) .describe("Message role"), content: z.string().describe("Message content"), })) .describe("Array of conversation messages"), model: z .string() .optional() .default("gpt-5") .describe("GPT-5 model variant to use"), instructions: z .string() .optional() .describe("System instructions for the model"), reasoning_effort: z .enum(["low", "medium", "high"]) .optional() .describe("Reasoning effort level"), max_tokens: z.number().optional().describe("Maximum tokens to generate"), temperature: z .number() .min(0) .max(2) .optional() .describe("Temperature for randomness (0-2)"), top_p: z .number() .min(0) .max(1) .optional() .describe("Top-p sampling parameter"), }); // Main function async function main() { // Check if OPENAI_API_KEY is set if (!process.env.OPENAI_API_KEY) { console.error("Error: OPENAI_API_KEY environment variable is not set"); console.error("Please set it in .env file or as an environment variable"); process.exit(1); } // Create MCP server const server = new Server({ name: "openai-gpt5-server", version: "1.1.0", }, { capabilities: { tools: {}, }, }); // Set up error handling server.onerror = (error) => { console.error("MCP Server Error:", error); }; process.on("SIGINT", async () => { await server.close(); process.exit(0); }); // Set up tool handlers server.setRequestHandler(ListToolsRequestSchema, async () => { console.error("Handling ListToolsRequest"); return { tools: [ { name: "gpt5_generate", description: "Generate text using OpenAI GPT-5 API with a simple input prompt", inputSchema: zodToJsonSchema(GPT5GenerateSchema), }, { name: "gpt5_messages", description: "Generate text using GPT-5 with structured conversation messages", inputSchema: zodToJsonSchema(GPT5MessagesSchema), }, ], }; }); server.setRequestHandler(CallToolRequestSchema, async (request) => { console.error("Handling CallToolRequest:", JSON.stringify(request.params)); try { switch (request.params.name) { case "gpt5_generate": { const args = GPT5GenerateSchema.parse(request.params.arguments); console.error(`GPT-5 Generate: "${args.input.substring(0, 100)}..."`); const result = await callGPT5(process.env.OPENAI_API_KEY, args.input, { model: args.model, instructions: args.instructions, reasoning_effort: args.reasoning_effort, max_tokens: args.max_tokens, temperature: args.temperature, top_p: args.top_p, }); let responseText = result.content; if (result.usage) { responseText += `\n\n**Usage:** ${result.usage.prompt_tokens} prompt tokens, ${result.usage.completion_tokens} completion tokens, ${result.usage.total_tokens} total tokens`; } return { content: [ { type: "text", text: responseText, }, ], }; } case "gpt5_messages": { const args = GPT5MessagesSchema.parse(request.params.arguments); console.error(`GPT-5 Messages: ${args.messages.length} messages`); const result = await callGPT5WithMessages(process.env.OPENAI_API_KEY, args.messages, { model: args.model, instructions: args.instructions, reasoning_effort: args.reasoning_effort, max_tokens: args.max_tokens, temperature: args.temperature, top_p: args.top_p, }); let responseText = result.content; if (result.usage) { responseText += `\n\n**Usage:** ${result.usage.prompt_tokens} prompt tokens, ${result.usage.completion_tokens} completion tokens, ${result.usage.total_tokens} total tokens`; } return { content: [ { type: "text", text: responseText, }, ], }; } default: throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${request.params.name}`); } } catch (error) { console.error("ERROR during GPT-5 API call:", error); return { content: [ { type: "text", text: `GPT-5 API error: ${error instanceof Error ? error.message : String(error)}`, }, ], isError: true, }; } }); // Start the server console.error("Starting OpenAI GPT-5 MCP server"); try { const transport = new StdioServerTransport(); console.error("StdioServerTransport created"); await server.connect(transport); console.error("Server connected to transport"); console.error("OpenAI GPT-5 MCP server running on stdio"); } catch (error) { console.error("ERROR starting server:", error); throw error; } } // Main execution main().catch((error) => { console.error("Server runtime error:", error); process.exit(1); });