MCP Base

  • server
// Generic MCP Server using Ollama for embeddings and text generation import { McpServer, ResourceTemplate, } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js"; import { z } from "zod"; import express from "express"; import dotenv from "dotenv"; import cors from "cors"; // Import the Ollama services import OllamaEmbeddingsService from "./utils/ollama_embedding.js"; import OllamaTextGenerationService from "./utils/ollama_text_generation.js"; // Conditionally import Supabase let createClient; try { ({ createClient } = await import("@supabase/supabase-js")); } catch (error) { console.log("Supabase SDK not installed, running without database support"); } // Import sample components import { registerSampleTool } from "./tools/sample-tool.js"; import { registerSamplePrompts } from "./prompts/sample-prompt.js"; import { registerSampleResources } from "./resources/sample-resource.js"; console.log("Loading environment variables..."); // Load environment variables dotenv.config(); // Configuration const config = { port: process.env.PORT || 3000, supabaseUrl: process.env.SUPABASE_URL, supabaseKey: process.env.SUPABASE_SERVICE_KEY, ollamaUrl: process.env.OLLAMA_URL || "http://localhost:11434", embedModel: process.env.OLLAMA_EMBED_MODEL || "nomic-embed-text", llmModel: process.env.OLLAMA_LLM_MODEL || "llama3", serverMode: process.env.SERVER_MODE || "http", // 'stdio' or 'http' }; // Check if Supabase is available and configured const supabaseEnabled = !!(createClient && config.supabaseUrl && config.supabaseKey); if (!supabaseEnabled) { console.log("Supabase integration is disabled. Running without database support."); } // Initialize the Ollama services console.log("Initializing Ollama services..."); const embeddings = new OllamaEmbeddingsService({ baseUrl: config.ollamaUrl, model: config.embedModel, }); const textGenerator = new OllamaTextGenerationService({ baseUrl: config.ollamaUrl, model: config.llmModel, }); // Initialize Supabase if enabled let supabase = null; if (supabaseEnabled) { console.log("Connecting to Supabase..."); supabase = createClient(config.supabaseUrl, config.supabaseKey); } else { console.log("Skipping Supabase initialization"); } // Initialize the database (if needed) async function initializeDatabase() { try { console.log("Checking Ollama availability..."); if (!(await embeddings.isAvailable())) { throw new Error( "Ollama service is not available. Make sure Ollama is running." ); } console.log("Pulling embedding model if needed..."); await embeddings.pullModelIfNeeded(); console.log("Pulling LLM model if needed..."); await textGenerator.pullModelIfNeeded(); // Add your database initialization code here // For example: // await initializeCollections(); console.log("Database initialization complete"); } catch (error) { console.error("Error initializing database:", error); throw error; } } // Create the MCP server console.log("Creating MCP server..."); const server = new McpServer({ name: "MCP Server Base", version: "1.0.0", }); // ------------ RESOURCES ------------ // Register resources registerSampleResources(server, supabase); // ------------ TOOLS ------------ // Register tools registerSampleTool(server, textGenerator, embeddings, supabase); // ------------ PROMPTS ------------ // Register prompts registerSamplePrompts(server, supabase); // Main function to start the server async function startServer() { try { console.log("Initializing database..."); await initializeDatabase(); console.log("Determining transport mode..."); if (config.serverMode === "stdio") { console.log("Starting server with stdio transport..."); const transport = new StdioServerTransport(); await server.connect(transport); console.log("MCP Server started with stdio transport"); } else { console.log("Starting server with HTTP/SSE transport..."); const app = express(); app.use(cors()); // Use a single transport for simplicity let transport; // Simple SSE endpoint app.get("/sse", async (req, res) => { transport = new SSEServerTransport("/message", res); await server.connect(transport); }); app.post("/message", async (req, res) => { await transport.handlePostMessage(req, res); }); // Health check endpoint app.get("/health", async (req, res) => { try { console.log("Performing health check..."); const ollamaAvailable = await embeddings.isAvailable(); let dbAvailable = false; if (supabaseEnabled) { try { // Try connecting to Supabase const { data, error } = await supabase.from("health_check").select("count"); dbAvailable = !error; } catch (e) { console.error("Supabase health check error:", e); } } res.json({ status: "ok", services: { ollama: ollamaAvailable ? "available" : "unavailable", database: supabaseEnabled ? (dbAvailable ? "available" : "unavailable") : "disabled", }, models: { embedding: config.embedModel, llm: config.llmModel, } }); } catch (error) { console.error("Error during health check:", error); res.status(500).json({ status: "error", message: error.message, }); } }); // Documentation endpoint app.get("/", (req, res) => { console.log("Serving documentation..."); res.send(` <html> <head> <title>MCP Server Base</title> <style> body { font-family: sans-serif; max-width: 800px; margin: 0 auto; padding: 20px; } h1 { color: #0ea5e9; } pre { background: #f5f5f5; padding: 10px; border-radius: 4px; overflow: auto; } .endpoint { background: #eee; padding: 10px; margin: 10px 0; border-radius: 4px; } </style> </head> <body> <h1>MCP Server Base</h1> <p>This server provides a Model Context Provider (MCP) interface.</p> <h2>Endpoints</h2> <div class="endpoint"> <h3>SSE Connection</h3> <code>GET /sse</code> <p>Connect to the server using Server-Sent Events (SSE)</p> </div> <div class="endpoint"> <h3>Message</h3> <code>POST /message</code> <p>Send messages to the server</p> </div> <div class="endpoint"> <h3>Health Check</h3> <code>GET /health</code> <p>Check server health and service status</p> </div> <h2>Available Resources</h2> <p>No resources defined yet.</p> <h2>Available Tools</h2> <p>No tools defined yet.</p> <h2>Available Prompts</h2> <p>No prompts defined yet.</p> </body> </html> `); }); // Start HTTP server app.listen(config.port, () => { console.log(`MCP Server running on http://localhost:${config.port}`); console.log(`- SSE endpoint: http://localhost:${config.port}/sse`); console.log( `- Message endpoint: http://localhost:${config.port}/message` ); console.log(`- Health check: http://localhost:${config.port}/health`); }); } } catch (error) { console.error("Error starting server:", error); process.exit(1); } } // Start the server console.log("Starting server..."); startServer().catch((error) => { console.error("Error starting server:", error); process.exit(1); }); export default server;