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
108 lines (107 loc) • 4.54 kB
JavaScript
/**
* @fileoverview Main entry point for the MCP (Model Context Protocol) server.
* This file orchestrates the server's lifecycle:
* 1. Initializes the core `McpServer` instance.
* 2. Registers available tools.
* 3. Selects and starts the appropriate communication transport.
* 4. Handles top-level error management during startup.
* @module src/mcp-server/server
*/
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { config, environment } from "../config/index.js";
import { BaseErrorCode } from "../types-global/errors.js";
import { ErrorHandler, logger, requestContextService } from "../utils/index.js";
// Import registration functions for all tools (alphabetized)
import { registerPerplexityAskTool } from "./tools/perplexityAsk/index.js";
import { registerPerplexityDeepResearchTool } from "./tools/perplexityDeepResearch/index.js";
import { registerPerplexityThinkAndAnalyzeTool } from "./tools/perplexityThinkAndAnalyze/index.js";
// Import transport setup functions
import { startHttpTransport } from "./transports/httpTransport.js";
import { connectStdioTransport } from "./transports/stdioTransport.js";
/**
* Creates and configures a new instance of the `McpServer`.
* @returns A promise resolving with the configured `McpServer` instance.
* @throws {McpError} If any tool registration fails.
*/
async function createMcpServerInstance() {
const context = requestContextService.createRequestContext({
operation: "createMcpServerInstance",
});
logger.info("Initializing MCP server instance", context);
requestContextService.configure({
appName: config.mcpServerName,
appVersion: config.mcpServerVersion,
environment,
});
const server = new McpServer({ name: config.mcpServerName, version: config.mcpServerVersion }, {
capabilities: {
logging: {},
resources: { listChanged: true },
tools: { listChanged: true },
},
});
await ErrorHandler.tryCatch(async () => {
logger.debug("Registering tools...", context);
await registerPerplexityAskTool(server);
await registerPerplexityDeepResearchTool(server);
await registerPerplexityThinkAndAnalyzeTool(server);
logger.info("Tools registered successfully", context);
}, {
operation: "registerAllTools",
context,
errorCode: BaseErrorCode.INITIALIZATION_FAILED,
critical: true,
});
return server;
}
/**
* Selects, sets up, and starts the appropriate MCP transport layer.
* @returns Resolves with `McpServer` for 'stdio', `http.Server` for 'http', or `void`.
* @throws {Error} If transport type is unsupported or setup fails.
*/
async function startTransport() {
const transportType = config.mcpTransportType;
const context = requestContextService.createRequestContext({
operation: "startTransport",
transport: transportType,
});
logger.info(`Starting transport: ${transportType}`, context);
const server = await createMcpServerInstance();
if (transportType === "http") {
// Wrap the created server instance in a function to match the expected signature
return startHttpTransport(() => Promise.resolve(server), context);
}
if (transportType === "stdio") {
await connectStdioTransport(server, context);
return server;
}
throw new Error(`Unsupported transport type: ${transportType}. Must be 'stdio' or 'http'.`);
}
/**
* Main application entry point. Initializes and starts the MCP server.
*/
export async function initializeAndStartServer() {
const context = requestContextService.createRequestContext({
operation: "initializeAndStartServer",
});
logger.info("MCP Server initialization sequence started.", context);
try {
const result = await startTransport();
logger.info("MCP Server initialization sequence completed successfully.", context);
return result;
}
catch (err) {
logger.fatal("Critical error during MCP server initialization.", {
...context,
error: err instanceof Error ? err.message : String(err),
stack: err instanceof Error ? err.stack : undefined,
});
ErrorHandler.handleError(err, {
operation: "initializeAndStartServer_Catch",
context: context,
critical: true,
});
logger.info("Exiting process due to critical initialization error.", context);
process.exit(1);
}
}