@turbot/tailpipe-mcp
Version:
Tailpipe MCP server to query cloud and security logs using AI.
105 lines • 4.32 kB
JavaScript
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { DatabaseService } from "./services/database.js";
import { setupTools, tools } from "./tools/index.js";
import { setupPromptHandlers, promptCapabilities } from "./prompts/index.js";
import { setupResourceHandlers, resourceCapabilities } from "./resources/index.js";
import { setupResourceTemplateHandlers, resourceTemplateCapabilities } from "./resourceTemplates/index.js";
import { logger } from "./services/logger.js";
import { readFileSync } from "fs";
import { fileURLToPath } from "url";
import { dirname, join } from "path";
// Read package.json for server metadata
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const packageJson = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf8'));
// Server metadata
const SERVER_INFO = {
name: "tailpipe",
version: packageJson.version,
description: packageJson.description,
vendor: packageJson.author,
homepage: packageJson.homepage,
};
// Parse command line arguments for database path
const args = process.argv.slice(2);
const providedDatabasePath = args[0] || process.env.TAILPIPE_MCP_DATABASE_PATH;
// Track server start time
let serverStartTime;
// Handle graceful shutdown
// NOTE: we cannot do any logging here! doing so causes the MCP inspector
// to crash when you refresh the browser, assumedly because we get an
// invalid message format sent over the wire to it from this MCP server.
// I couldn't use logger.{debug,info,error} at all, and it took ages to
// find the cause of the crash.
function setupShutdownHandlers(db) {
const gracefulShutdown = async () => {
if (db) {
try {
await db.close();
}
catch (error) {
logger.error(`Error closing database: ${error instanceof Error ? error.message : String(error)}`);
}
}
process.exit(0);
};
process.on('SIGTERM', gracefulShutdown);
process.on('SIGINT', gracefulShutdown);
}
// Start server
async function startServer() {
try {
logger.info("Starting MCP server...");
// Record start time
serverStartTime = new Date().toISOString();
// Create MCP server
const server = new Server(SERVER_INFO, {
capabilities: {
tools,
prompts: promptCapabilities.prompts,
resources: resourceCapabilities.resources,
resourceTemplates: resourceTemplateCapabilities.resourceTemplates
}
});
// Initialize database connection
const db = await DatabaseService.create(providedDatabasePath);
logger.info("Database connection initialized successfully");
// Set up shutdown handlers
logger.info("Setting up shutdown handlers...");
setupShutdownHandlers(db);
logger.info("Shutdown handlers configured");
logger.info(`Server started at: ${serverStartTime}`);
// Set up handlers
logger.info("Configuring server handlers...");
setupTools(server, db);
setupPromptHandlers(server);
setupResourceHandlers(server, db);
setupResourceTemplateHandlers(server);
logger.info("Server handlers configured");
// Connect transport
logger.info("Initializing transport connection...");
const transport = new StdioServerTransport();
// Connect to transport and handle any errors
try {
await server.connect(transport);
logger.info("Transport connection established");
}
catch (error) {
logger.error(`Failed to connect transport: ${error instanceof Error ? error.message : String(error)}`);
// Don't crash the process, just log the error
}
logger.info("MCP server started successfully");
}
catch (error) {
logger.error(`Failed to start server: ${error instanceof Error ? error.message : String(error)}`);
process.exit(1);
}
}
startServer();
// Export for use in other modules
export function getServerStartTime() {
return serverStartTime;
}
//# sourceMappingURL=index.js.map