#!/usr/bin/env node
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
import { z } from "zod";
import { VERSION } from "./common/version.js";
import { config } from "dotenv";
import { getAllTools } from "./tool-registry/index.js";
import { handleToolRequest } from "./tool-handlers/index.js";
const server = new Server({
name: "fund-mcp-server",
version: VERSION,
}, {
capabilities: {
tools: {},
},
});
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: getAllTools(),
};
});
server.setRequestHandler(CallToolRequestSchema, async (request) => {
try {
if (!request.params.arguments) {
throw new Error("Arguments are required");
}
return await handleToolRequest(request);
}
catch (error) {
if (error instanceof z.ZodError) {
throw new Error(`Invalid input: ${JSON.stringify(error.errors)}`);
}
throw error;
}
});
config();
const useSSE = process.argv.includes("--sse") || process.env.MCP_TRANSPORT === "sse";
const useHttp = process.argv.includes("--http") || process.env.MCP_TRANSPORT === "http";
async function runServer() {
if (useSSE || useHttp) {
const { default: express } = await import("express");
const app = express();
const port = process.env.PORT || 3000;
// 添加CORS中间件,支持跨域访问
app.use((req, res, next) => {
// 允许所有来源
res.header("Access-Control-Allow-Origin", "*");
// 允许的HTTP方法
res.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
// 允许的请求头
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization");
// 允许发送凭证
res.header("Access-Control-Allow-Credentials", "true");
// 处理预检请求
if (req.method === "OPTIONS") {
res.sendStatus(200);
}
else {
next();
}
});
app.use(express.json({ limit: "10mb" }));
// 新增:普通HTTP REST API端点
if (useHttp) {
// 列出所有可用工具
app.get("/api/tools", async (req, res) => {
try {
const tools = getAllTools();
res.json({
success: true,
data: tools,
});
}
catch (error) {
res.status(500).json({
success: false,
error: error instanceof Error ? error.message : "Unknown error",
});
}
});
// 调用工具
app.post("/api/tools/call", async (req, res) => {
try {
const { name, arguments: args } = req.body;
if (!name) {
return res.status(400).json({
success: false,
error: "Tool name is required",
});
}
if (!args) {
return res.status(400).json({
success: false,
error: "Arguments are required",
});
}
// 创建模拟的MCP请求格式
const mockRequest = {
params: {
name,
arguments: args,
},
};
const result = await handleToolRequest(mockRequest);
res.json({
success: true,
data: result,
});
}
catch (error) {
res.status(500).json({
success: false,
error: error instanceof Error ? error.message : "Unknown error",
});
}
});
// 健康检查
app.get("/api/health", (req, res) => {
res.json({
success: true,
message: "fund MCP Server is running",
version: VERSION,
mode: "HTTP REST API",
});
});
}
// 原有的SSE模式
if (useSSE) {
const sessions = {};
app.get("/sse", async (req, res) => {
const sseTransport = new SSEServerTransport("/messages", res);
const sessionId = sseTransport.sessionId;
if (sessionId) {
sessions[sessionId] = { transport: sseTransport, server };
}
try {
await server.connect(sseTransport);
}
catch (error) {
res.status(500).send("Server error");
}
});
app.post("/messages", async (req, res) => {
const sessionId = req.query.sessionId;
const session = sessions[sessionId];
if (!session) {
res.status(404).send("Session not found");
return;
}
try {
await session.transport.handlePostMessage(req, res, req.body);
}
catch (error) {
res.status(500).send("Server error");
}
});
}
const serverInstance = app.listen(port, () => {
if (useHttp) {
console.log(`fund MCP Server running in HTTP REST API mode on port ${port}`);
console.log(`Health check: http://localhost:${port}/api/health`);
console.log(`List tools: http://localhost:${port}/api/tools`);
console.log(`Call tool: POST http://localhost:${port}/api/tools/call`);
console.log(`LLM API: POST http://localhost:${port}/api/llm/call`);
}
if (useSSE) {
console.log(`fund MCP Server running in SSE mode on port ${port}`);
console.log(`SSE endpoint: http://localhost:${port}/sse`);
}
});
process.on("SIGINT", () => {
serverInstance.close(() => {
process.exit(0);
});
});
}
else {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("fund MCP Server running on stdio");
}
}
runServer().catch(() => {
process.exit(1);
});