using System; using System.Net.Http; using System.Threading.Tasks; using CodexMcpServer.Tools; using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using OpenHarbor.MCP.AspNetCore.Extensions; using OpenHarbor.MCP.Core; namespace CodexMcpServer; /// /// CODEX MCP Server entry point. /// Exposes 6 CODEX tools via Model Context Protocol. /// Supports both HTTP (default) and stdio transports. /// internal class Program { private static async Task Main(string[] args) { // Check if stdio mode is requested bool useStdio = args.Length > 0 && args[0] == "--stdio"; if (useStdio) { await RunStdioModeAsync(); } else { await RunHttpModeAsync(args); } } /// /// Runs the MCP server in HTTP mode (default). /// Listens on http://localhost:5050 for MCP requests. /// private static async Task RunHttpModeAsync(string[] args) { var builder = WebApplication.CreateBuilder(args); // Configure services builder.Services.AddSingleton(sp => new HttpClient { BaseAddress = new Uri("http://localhost:5099"), Timeout = TimeSpan.FromSeconds(30) }); // Create and register MCP server var httpClient = new HttpClient { BaseAddress = new Uri("http://localhost:5099"), Timeout = TimeSpan.FromSeconds(30) }; var registry = new ToolRegistry(); registry.AddTool(new SearchCodexTool(httpClient)); registry.AddTool(new GetDocumentTool(httpClient)); registry.AddTool(new ListDocumentsTool(httpClient)); registry.AddTool(new SearchByTagTool(httpClient)); registry.AddTool(new GetDocumentSectionsTool(httpClient)); registry.AddTool(new ListTagsTool(httpClient)); var server = new McpServer(registry); builder.Services.AddMcpServer(server); // Configure Kestrel to listen on port 5050 builder.WebHost.ConfigureKestrel(options => { options.ListenLocalhost(5050); }); var app = builder.Build(); // Map MCP endpoints app.MapMcpEndpoints(server); Console.WriteLine("=== CODEX MCP Server (HTTP Mode) ==="); Console.WriteLine("Listening on: http://localhost:5050"); Console.WriteLine("Endpoints:"); Console.WriteLine(" POST /mcp/invoke - MCP JSON-RPC endpoint"); Console.WriteLine(" GET /health - Health check"); Console.WriteLine(); Console.WriteLine("Connected to CODEX API: http://localhost:5099"); Console.WriteLine(); Console.WriteLine("Available Tools:"); Console.WriteLine(" - search_codex"); Console.WriteLine(" - get_document"); Console.WriteLine(" - list_documents"); Console.WriteLine(" - search_by_tag"); Console.WriteLine(" - get_document_sections"); Console.WriteLine(" - list_tags"); Console.WriteLine(); Console.WriteLine("Press Ctrl+C to shutdown"); Console.WriteLine(); await app.RunAsync(); } /// /// Runs the MCP server in stdio mode (legacy). /// Communicates via stdin/stdout for Claude Desktop integration. /// private static async Task RunStdioModeAsync() { try { // Initialize HTTP client for CODEX API calls var httpClient = new HttpClient { BaseAddress = new Uri("http://localhost:5099"), Timeout = TimeSpan.FromSeconds(30) }; // Create tool registry and register all 6 CODEX tools var registry = new ToolRegistry(); registry.AddTool(new SearchCodexTool(httpClient)); registry.AddTool(new GetDocumentTool(httpClient)); registry.AddTool(new ListDocumentsTool(httpClient)); registry.AddTool(new SearchByTagTool(httpClient)); registry.AddTool(new GetDocumentSectionsTool(httpClient)); registry.AddTool(new ListTagsTool(httpClient)); // Create MCP server var server = new McpServer(registry); // Create stdio transport (JSON-RPC 2.0 over stdin/stdout) using var transport = new StdioTransport( Console.OpenStandardInput(), Console.OpenStandardOutput() ); // Main request/response loop while (true) { var request = await transport.ReadRequestAsync(); if (request == null) { // End of stream - exit gracefully break; } var response = await server.HandleRequestAsync(request); await transport.WriteResponseAsync(response); } } catch (Exception ex) { // Log errors to stderr (stdout is reserved for MCP protocol) await Console.Error.WriteLineAsync($"Fatal error: {ex.Message}"); await Console.Error.WriteLineAsync(ex.StackTrace); Environment.Exit(1); } } }