cq-mcp-server 0.3.0 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +56 -23
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
3
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
4
|
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
5
|
+
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
|
|
5
6
|
import { createServer } from "node:http";
|
|
6
7
|
import { randomUUID } from "node:crypto";
|
|
7
8
|
import { z } from "zod";
|
|
@@ -330,42 +331,74 @@ log.info(`CloudQuery MCP Server 启动 transport=${MCP_TRANSPORT}`);
|
|
|
330
331
|
if (MCP_TRANSPORT === "http") {
|
|
331
332
|
// session_id → transport 映射,支持多用户并发
|
|
332
333
|
const sessions = new Map();
|
|
334
|
+
// SSE transport 映射(sessionId → transport),用于兼容 Dify 等旧版客户端
|
|
335
|
+
const sseSessions = new Map();
|
|
333
336
|
const httpServer = createServer(async (req, res) => {
|
|
337
|
+
// 允许跨域(Dify 可能从不同域访问)
|
|
338
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
339
|
+
res.setHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, OPTIONS");
|
|
340
|
+
res.setHeader("Access-Control-Allow-Headers", "Content-Type, mcp-session-id");
|
|
341
|
+
res.setHeader("Access-Control-Expose-Headers", "mcp-session-id");
|
|
342
|
+
if (req.method === "OPTIONS") {
|
|
343
|
+
res.writeHead(204).end();
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
334
346
|
if (!req.url?.startsWith("/mcp")) {
|
|
335
347
|
res.writeHead(404).end("Not Found");
|
|
336
348
|
return;
|
|
337
349
|
}
|
|
338
|
-
//
|
|
339
|
-
|
|
340
|
-
if (
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
350
|
+
// ── SSE transport(兼容 Dify)──
|
|
351
|
+
// GET /mcp → 建立 SSE 连接
|
|
352
|
+
if (req.method === "GET") {
|
|
353
|
+
const sseTransport = new SSEServerTransport("/mcp", res);
|
|
354
|
+
sseSessions.set(sseTransport.sessionId, sseTransport);
|
|
355
|
+
log.info(`SSE 连接建立: ${sseTransport.sessionId}`);
|
|
356
|
+
const mcpServer = createMcpServer();
|
|
357
|
+
await mcpServer.connect(sseTransport);
|
|
358
|
+
req.on("close", () => {
|
|
359
|
+
sseSessions.delete(sseTransport.sessionId);
|
|
360
|
+
log.info(`SSE 连接关闭: ${sseTransport.sessionId},当前活跃: ${sseSessions.size}`);
|
|
344
361
|
});
|
|
345
|
-
|
|
346
|
-
await server.connect(transport);
|
|
347
|
-
transport.onclose = () => {
|
|
348
|
-
const sid = transport.sessionId;
|
|
349
|
-
if (sid) {
|
|
350
|
-
sessions.delete(sid);
|
|
351
|
-
log.info(`Session 关闭: ${sid},当前活跃: ${sessions.size}`);
|
|
352
|
-
}
|
|
353
|
-
};
|
|
354
|
-
await transport.handleRequest(req, res);
|
|
355
|
-
// handleRequest 后 sessionId 已生成,存入 map
|
|
356
|
-
if (transport.sessionId) {
|
|
357
|
-
sessions.set(transport.sessionId, transport);
|
|
358
|
-
log.info(`新 Session: ${transport.sessionId},当前活跃: ${sessions.size}`);
|
|
359
|
-
}
|
|
362
|
+
return;
|
|
360
363
|
}
|
|
361
|
-
|
|
362
|
-
|
|
364
|
+
// POST /mcp?sessionId=xxx → SSE 消息(Dify 旧版协议)
|
|
365
|
+
const urlObj = new URL(req.url, `http://${req.headers.host}`);
|
|
366
|
+
const sseSessionId = urlObj.searchParams.get("sessionId");
|
|
367
|
+
if (sseSessionId && sseSessions.has(sseSessionId)) {
|
|
368
|
+
await sseSessions.get(sseSessionId).handlePostMessage(req, res);
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
// ── Streamable HTTP transport(新版协议)──
|
|
372
|
+
const sessionId = req.headers["mcp-session-id"];
|
|
373
|
+
if (sessionId) {
|
|
363
374
|
const transport = sessions.get(sessionId);
|
|
364
375
|
if (!transport) {
|
|
365
376
|
res.writeHead(404).end("Session not found");
|
|
366
377
|
return;
|
|
367
378
|
}
|
|
368
379
|
await transport.handleRequest(req, res);
|
|
380
|
+
return;
|
|
381
|
+
}
|
|
382
|
+
if (req.method !== "POST") {
|
|
383
|
+
res.writeHead(400).end("Missing mcp-session-id");
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
const transport = new StreamableHTTPServerTransport({
|
|
387
|
+
sessionIdGenerator: () => randomUUID(),
|
|
388
|
+
});
|
|
389
|
+
const mcpServer = createMcpServer();
|
|
390
|
+
await mcpServer.connect(transport);
|
|
391
|
+
transport.onclose = () => {
|
|
392
|
+
const sid = transport.sessionId;
|
|
393
|
+
if (sid) {
|
|
394
|
+
sessions.delete(sid);
|
|
395
|
+
log.info(`Session 关闭: ${sid},当前活跃: ${sessions.size}`);
|
|
396
|
+
}
|
|
397
|
+
};
|
|
398
|
+
await transport.handleRequest(req, res);
|
|
399
|
+
if (transport.sessionId) {
|
|
400
|
+
sessions.set(transport.sessionId, transport);
|
|
401
|
+
log.info(`新 Session: ${transport.sessionId},当前活跃: ${sessions.size}`);
|
|
369
402
|
}
|
|
370
403
|
});
|
|
371
404
|
httpServer.listen(MCP_PORT, () => {
|
package/package.json
CHANGED