import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
import express from "express";
import { CONFIG } from "./config.js";
import { initDb } from "./db.js";
import { Logger } from "./logger.js";
import { registerMcpHandlers } from "./mcp-handlers.js";
const app = express();
let transport = null;
let httpServer = null;
/**
* 初期化処理を実行
*/
try {
initDb();
Logger.info('Database initialized');
} catch (error) {
Logger.error('Failed to initialize database', error);
process.exit(1);
}
/**
* MCP サーバーを作成
*/
const server = new Server(
{
name: CONFIG.mcp.name,
version: CONFIG.mcp.version,
},
{
capabilities: {
tools: {},
},
}
);
registerMcpHandlers(server);
/**
* SSE トランスポートエラーハンドラ
* @param {Error} error - エラーオブジェクト
*/
function handleTransportError(error) {
Logger.error('Transport error', error);
transport = null;
}
/**
* MCP SSE サーバーを起動
* @param {number} port - ポート番号
* @returns {Object} HTTPサーバーオブジェクト
* @throws {Error} サーバー起動に失敗した場合
*/
export function startMcpServer(port = 3000) {
try {
// ポート番号の検証
if (!Number.isInteger(port) || port < 1 || port > 65535) {
throw new Error(`Invalid port number: ${port}`);
}
app.use(express.json());
/**
* SSE 接続エンドポイント
* @route GET /sse
*/
app.get(CONFIG.mcp.ssePath, async (req, res) => {
try {
Logger.info('SSE connection established');
transport = new SSEServerTransport(CONFIG.mcp.messagesPath, res);
transport.on('error', handleTransportError);
await server.connect(transport);
} catch (error) {
Logger.error('Failed to establish SSE connection', error);
res.status(500).send('Failed to establish SSE connection');
}
});
/**
* メッセージハンドラエンドポイント
* @route POST /messages
*/
app.post(CONFIG.mcp.messagesPath, async (req, res) => {
try {
if (!transport) {
Logger.warn('No active transport connection');
return res.status(400).send('No transport connection');
}
await transport.handlePostMessage(req, res);
} catch (error) {
Logger.error('Failed to handle post message', error);
res.status(500).send('Failed to handle message');
}
});
/**
* ヘルスチェックエンドポイント
* @route GET /health
*/
app.get('/health', (req, res) => {
res.status(200).json({
status: 'ok',
timestamp: new Date().toISOString(),
transport: transport ? 'connected' : 'disconnected',
});
});
httpServer = app.listen(port, () => {
Logger.info(`MCP SSE Server listening on http://localhost:${port}${CONFIG.mcp.ssePath}`);
});
// エラーハンドリング
httpServer.on('error', (error) => {
Logger.error('HTTP server error', error);
});
return httpServer;
} catch (error) {
Logger.error('Failed to start MCP server', error);
throw error;
}
}