noodle-perplexity-mcp
Version:
A Perplexity API Model Context Protocol (MCP) server that unlocks Perplexity's search-augmented AI capabilities for LLM agents. Features robust error handling, secure input validation, transparent reasoning, and multimodal support with file attachments (P
104 lines (103 loc) • 4.3 kB
JavaScript
/**
* @fileoverview Main entry point for the MCP application.
* This script initializes the configuration, sets up the logger, starts the
* MCP server, and handles graceful shutdown.
* @module src/index
*/
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import http from "http";
import { config, environment } from "./config/index.js";
import { initializeAndStartServer } from "./mcp-server/server.js";
import { requestContextService } from "./utils/internal/requestContext.js";
import { logger } from "./utils/internal/logger.js";
let mcpStdioServer;
let actualHttpServer;
const shutdown = async (signal) => {
const shutdownContext = requestContextService.createRequestContext({
operation: "ServerShutdown",
triggerEvent: signal,
});
logger.info(`Received ${signal}. Initiating graceful shutdown...`, shutdownContext);
const shutdownPromises = [];
if (mcpStdioServer) {
shutdownPromises.push(mcpStdioServer.close().catch(err => {
logger.error("Error closing MCP server (STDIO).", { ...shutdownContext, error: err });
}));
}
if (actualHttpServer) {
shutdownPromises.push(new Promise((resolve) => {
actualHttpServer.close((err) => {
if (err) {
logger.error("Error closing HTTP server.", { ...shutdownContext, error: err });
}
resolve();
});
}));
}
await Promise.allSettled(shutdownPromises);
logger.info("Graceful shutdown completed successfully. Exiting.", shutdownContext);
process.exit(0);
};
const start = async () => {
const validMcpLogLevels = [
"debug",
"info",
"notice",
"warning",
"error",
"crit",
"alert",
"emerg",
];
const initialLogLevelConfig = config.logLevel;
let validatedMcpLogLevel = "info";
if (validMcpLogLevels.includes(initialLogLevelConfig)) {
validatedMcpLogLevel = initialLogLevelConfig;
}
else {
console.warn(`[Startup Warning] Invalid LOG_LEVEL "${initialLogLevelConfig}" found in configuration. ` +
`Defaulting to log level "info". Valid levels are: ${validMcpLogLevels.join(", ")}.`);
}
await logger.initialize(validatedMcpLogLevel);
const startupContext = requestContextService.createRequestContext({
operation: `ServerStartupSequence_${config.mcpTransportType}`,
applicationName: config.mcpServerName,
applicationVersion: config.mcpServerVersion,
nodeEnvironment: environment,
});
logger.info(`Starting ${config.mcpServerName} (v${config.mcpServerVersion}, Transport: ${config.mcpTransportType}, Env: ${environment})...`, startupContext);
try {
const serverInstance = await initializeAndStartServer();
if (config.mcpTransportType === "stdio" && serverInstance instanceof McpServer) {
mcpStdioServer = serverInstance;
}
else if (config.mcpTransportType === "http" && serverInstance instanceof http.Server) {
actualHttpServer = serverInstance;
}
logger.info(`${config.mcpServerName} is now running.`, { ...startupContext, serverStartTime: new Date().toISOString() });
process.on("SIGTERM", () => shutdown("SIGTERM"));
process.on("SIGINT", () => shutdown("SIGINT"));
process.on("uncaughtException", (error) => {
logger.error("FATAL: Uncaught exception.", { ...startupContext, error: error.message, stack: error.stack });
shutdown("uncaughtException");
});
process.on("unhandledRejection", (reason) => {
logger.error("FATAL: Unhandled promise rejection.", { ...startupContext, reason });
shutdown("unhandledRejection");
});
}
catch (error) {
logger.error("CRITICAL ERROR DURING STARTUP. Exiting.", { ...startupContext, error: error instanceof Error ? error.message : String(error), stack: error instanceof Error ? error.stack : undefined });
process.exit(1);
}
};
(async () => {
try {
await start();
}
catch (error) {
console.error("[GLOBAL CATCH] Unexpected error during startup:", error);
process.exit(1);
}
})();