Skip to main content
Glama

SearXNG Server

import express from "express"; import cors from "cors"; import { randomUUID } from "crypto"; import { Server } from "@modelcontextprotocol/sdk/server/index.js"; import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js"; import { isInitializeRequest } from "@modelcontextprotocol/sdk/types.js"; import { logMessage } from "./logging.js"; import { packageVersion } from "./index.js"; export async function createHttpServer(server: Server): Promise<express.Application> { const app = express(); app.use(express.json()); // Add CORS support for web clients app.use(cors({ origin: '*', // Configure appropriately for production exposedHeaders: ['Mcp-Session-Id'], allowedHeaders: ['Content-Type', 'mcp-session-id'], })); // Map to store transports by session ID const transports: { [sessionId: string]: StreamableHTTPServerTransport } = {}; // Handle POST requests for client-to-server communication app.post('/mcp', async (req, res) => { const sessionId = req.headers['mcp-session-id'] as string | undefined; let transport: StreamableHTTPServerTransport; if (sessionId && transports[sessionId]) { // Reuse existing transport transport = transports[sessionId]; logMessage(server, "debug", `Reusing session: ${sessionId}`); } else if (!sessionId && isInitializeRequest(req.body)) { // New initialization request logMessage(server, "info", "Creating new HTTP session"); transport = new StreamableHTTPServerTransport({ sessionIdGenerator: () => randomUUID(), onsessioninitialized: (sessionId) => { transports[sessionId] = transport; logMessage(server, "debug", `Session initialized: ${sessionId}`); }, // DNS rebinding protection disabled by default for backwards compatibility // For production, consider enabling: // enableDnsRebindingProtection: true, // allowedHosts: ['127.0.0.1', 'localhost'], }); // Clean up transport when closed transport.onclose = () => { if (transport.sessionId) { logMessage(server, "debug", `Session closed: ${transport.sessionId}`); delete transports[transport.sessionId]; } }; // Connect the existing server to the new transport await server.connect(transport); } else { // Invalid request res.status(400).json({ jsonrpc: '2.0', error: { code: -32000, message: 'Bad Request: No valid session ID provided', }, id: null, }); return; } // Handle the request await transport.handleRequest(req, res, req.body); }); // Handle GET requests for server-to-client notifications via SSE app.get('/mcp', async (req, res) => { const sessionId = req.headers['mcp-session-id'] as string | undefined; if (!sessionId || !transports[sessionId]) { res.status(400).send('Invalid or missing session ID'); return; } const transport = transports[sessionId]; await transport.handleRequest(req, res); }); // Handle DELETE requests for session termination app.delete('/mcp', async (req, res) => { const sessionId = req.headers['mcp-session-id'] as string | undefined; if (!sessionId || !transports[sessionId]) { res.status(400).send('Invalid or missing session ID'); return; } const transport = transports[sessionId]; await transport.handleRequest(req, res); }); // Health check endpoint app.get('/health', (_req, res) => { res.json({ status: 'healthy', server: 'ihor-sokoliuk/mcp-searxng', version: packageVersion, transport: 'http' }); }); return app; }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ihor-sokoliuk/mcp-searxng'

If you have feedback or need assistance with the MCP directory API, please join our Discord server