bc_resource_mcp
Version:
MCP server for Baichuan resource
102 lines (101 loc) • 4.06 kB
JavaScript
import express from "express";
import cors from "cors";
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
import { createMcpServer } from "./server.js";
import { Logger } from "../utils/logger.js";
import { loadConfig } from "../utils/config.js";
// 将服务器启动逻辑封装到函数中
export async function startSseServer() {
const config = loadConfig();
const app = express();
app.use(cors({
origin: config.allowedOrigins,
methods: ["GET", "POST"],
allowedHeaders: ["Content-Type", "Authorization"],
}));
const transports = {};
app.get("/health", (req, res) => {
res.status(200).json({
status: "ok",
version: config.version,
uptime: process.uptime(),
timestamp: new Date().toISOString(),
connections: transports.size,
});
});
app.get("/sse", async (req, res) => {
const transport = new SSEServerTransport("/messages", res);
const moduleId = req.headers["moduleid"];
Logger.debug("收到 SSE 连接请求", { headers: req.headers });
if (!moduleId) {
Logger.error("缺少必要的 moduleId");
res.status(400).json({ error: "Missing moduleId" });
return;
}
const sessionId = transport.sessionId;
Logger.info(`新的 SSE 连接建立: ${sessionId}`);
transports[sessionId] = transport;
req.on("close", () => {
Logger.info(`SSE 连接关闭: ${sessionId}`);
delete transports[sessionId];
});
const mcpServer = createMcpServer(moduleId);
await mcpServer.connect(transport);
Logger.info(`MCP 服务器连接成功: ${sessionId}`);
});
app.post("/messages", async (req, res) => {
try {
Logger.debug("收到客户端消息", req.query);
const sessionId = req.query.sessionId;
if (Object.keys(transports).length === 0) {
throw new Error(`没有活跃的SSE连接`);
}
const transport = transports[sessionId];
if (!transport) {
throw new Error(`没有找到会话ID为 ${sessionId} 的SSE连接`);
}
await transport.handlePostMessage(req, res);
}
catch (error) {
Logger.error("处理客户端消息失败", error);
res.status(500).json({ error: "处理消息失败", message: error.message });
}
});
async function closeAllConnections() {
Logger.info(`关闭所有连接 (${Object.keys(transports).length}个)`);
for (const [sessionId, transport] of Object.entries(transports)) {
try {
await transport.close();
Logger.info(`已关闭连接:${sessionId}`);
}
catch (error) {
Logger.error(`关闭连接失败:${sessionId}`, error);
}
}
for (const sessionId in transports) {
delete transports[sessionId];
}
}
app.use((error, req, res, next) => {
Logger.error("未处理的异常", error);
res.status(500).json({ error: "服务器内部错误", message: error.message });
});
process.on("SIGINT", async () => {
Logger.info("收到SIGINT信号,正在关闭服务器...");
await closeAllConnections();
process.exit(0);
});
process.on("SIGTERM", async () => {
Logger.info("收到SIGTERM信号,正在关闭服务器...");
await closeAllConnections();
process.exit(0);
});
const port = config.port;
const server = app.listen(port, () => {
Logger.info(`BC Resource MCP 服务器已启动,监听端口:${port}`);
Logger.info(`- SSE 连接端点: http://localhost:${port}/sse`);
Logger.info(`- SSE 消息处理端点: http://localhost:${port}/messages`);
Logger.info(`- 健康检查端点: http://localhost:${port}/health`);
});
return server;
}