Skip to main content
Glama

Upstash MCP Server

Official
by upstash
index.ts6.38 kB
#!/usr/bin/env node import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js"; import { Command } from "commander"; // eslint-disable-next-line unicorn/prefer-node-protocol import { createServer, type IncomingMessage } from "http"; import { createServerInstance } from "./server.js"; import { config } from "./config"; import { testConnection } from "./test-connection"; import "dotenv/config"; /** * Last version of the MCP server required "run" command to be used. * This is a backwards compatibility fix to allow the MCP server to be used with the old command. */ // Handle legacy 'run' command format before parsing let argv = process.argv.slice(2); // Check for legacy format and transform it to the new format if (argv.length >= 3 && argv[0] === "run") { argv = ["--email", argv[1], "--api-key", argv[2], ...argv.slice(3)]; } const program = new Command() .option("--transport <stdio|http>", "transport type", "stdio") .option("--port <number>", "port for HTTP transport", "3000") .option("--email <email>", "Upstash email") .option("--api-key <key>", "Upstash API key") .option("--debug", "Enable debug mode") .allowUnknownOption(); // let other wrappers pass through extra flags program.parse(argv, { from: "user" }); const cliOptions = program.opts<{ transport: string; port: string; email?: string; apiKey?: string; debug?: boolean; }>(); export const DEBUG = cliOptions.debug ?? false; // Validate transport option const allowedTransports = ["stdio", "http"]; if (!allowedTransports.includes(cliOptions.transport)) { console.error( `Invalid --transport value: '${cliOptions.transport}'. Must be one of: stdio, http.` ); process.exit(1); } // Transport configuration const TRANSPORT_TYPE = (cliOptions.transport || "stdio") as "stdio" | "http"; // Disallow incompatible flags based on transport const passedPortFlag = process.argv.includes("--port"); if (TRANSPORT_TYPE === "stdio" && passedPortFlag) { console.error("The --port flag is not allowed when using --transport stdio."); process.exit(1); } // HTTP port configuration const CLI_PORT = (() => { const parsed = Number.parseInt(cliOptions.port, 10); return Number.isNaN(parsed) ? undefined : parsed; })(); async function main() { // Get credentials from CLI options or environment const email = cliOptions.email || process.env.UPSTASH_EMAIL; const apiKey = cliOptions.apiKey || process.env.UPSTASH_API_KEY; if (!email || !apiKey) { console.error( "Missing required credentials. Provide --email and --api-key or set UPSTASH_EMAIL and UPSTASH_API_KEY environment variables." ); process.exit(1); } // Set config config.email = email; config.apiKey = apiKey; // Test connection await testConnection(); const transportType = TRANSPORT_TYPE; if (transportType === "http") { // Get initial port from environment or use default const initialPort = CLI_PORT ?? 3000; // Keep track of which port we end up using let actualPort = initialPort; const httpServer = createServer(async (req: IncomingMessage, res: any) => { const pathname = new (globalThis as any).URL(req.url || "", `http://${req.headers.host}`) .pathname; // Set CORS headers for all responses res.setHeader("Access-Control-Allow-Origin", "*"); res.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS,DELETE"); res.setHeader( "Access-Control-Allow-Headers", "Content-Type, MCP-Session-Id, MCP-Protocol-Version, X-Upstash-API-Key, Upstash-API-Key, X-API-Key, Authorization" ); res.setHeader("Access-Control-Expose-Headers", "MCP-Session-Id"); // Handle preflight OPTIONS requests if (req.method === "OPTIONS") { res.writeHead(200); res.end(); return; } try { // Create new server instance for each request const requestServer = createServerInstance(); if (pathname === "/mcp") { const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined, }); await requestServer.connect(transport); await transport.handleRequest(req, res); } else if (pathname === "/ping") { res.writeHead(200, { "Content-Type": "application/json" }); res.end(JSON.stringify({ status: "ok", message: "pong" })); } else { res.writeHead(404, { "Content-Type": "application/json" }); res.end(JSON.stringify({ error: "Not found", status: 404 })); } } catch (error) { console.error("Error handling request:", error); if (!res.headersSent) { res.writeHead(500); res.end("Internal Server Error"); } } }); // Function to attempt server listen with port fallback const startServer = (port: number, maxAttempts = 10) => { httpServer.once("error", (err: NodeJS.ErrnoException) => { if (err.code === "EADDRINUSE" && port < initialPort + maxAttempts) { console.warn(`Port ${port} is in use, trying port ${port + 1}...`); startServer(port + 1, maxAttempts); } else { console.error(`Failed to start server: ${err.message}`); process.exit(1); } }); httpServer.listen(port, () => { actualPort = port; console.error( `Upstash MCP Server running on ${transportType.toUpperCase()} at http://localhost:${actualPort}/mcp` ); }); }; // Start the server with initial port startServer(initialPort); } else { // Stdio transport - this is already stateless by nature const server = createServerInstance(); const transport = new StdioServerTransport(); // Log the RCP messages coming to the transport // const originalOnmessage = transport.onmessage; // transport.onmessage = (message) => { // console.error("message", message); // originalOnmessage?.(message); // }; await server.connect(transport); console.error("Upstash MCP Server running on stdio"); } } // eslint-disable-next-line unicorn/prefer-top-level-await main().catch((error) => { console.error("Fatal error in main():", error); process.exit(1); });

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/upstash/mcp-server'

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