import type { IncomingMessage, ServerResponse } from 'node:http'; import { WebStandardStreamableHTTPServerTransport } from '@modelcontextprotocol/server'; import type { Transport } from '@modelcontextprotocol/server'; /** Task 5 消费驱动的接口收敛(2026-09-30):原类型为 SDK 名义类 McpServer,但 GodotServer * 持有的是同包的 Server 类(Protocol 直系)——两者互不名义兼容,而本端点只消费 * connect(transport)。结构最小接口让 SDK Server / McpServer / 测试 fake 三者都天然 * 满足(依赖倒置),免 as 断言(禁 any 纪律)。运行时语义:connect 即 Protocol 基类的 * transport 接线,两类一致。 */ export type McpConnectable = { connect(transport: Transport): Promise; }; /** D-4 fix(2026-10-01 审查):/mcp POST body 上限(字节)。4MB 为宽裕值——tools/call * 可携带大段 GDScript 代码(execute_gdscript)或大 JSON 布局(ui_build_layout),取 * 远超正常调用的上限只堵无界流:原实现 for await 全量缓冲无 maxBytes,持 token 者 * 可持续发送无界流做内存 DoS。对齐 web-gui 面板侧双上限模式(server.ts 64KB/600KB: * content-length 预检 + chunked 累计上限,超限 413 不进内存)。导出供测试锚定。 */ export declare const MCP_MAX_BODY_BYTES: number; export interface McpEndpointDeps { mcpServer: McpConnectable; token: string; /** 端口(constructing Web Request 的 URL 与规范化 Host 用)。 */ port: number; /** 单会话闸(spec §3.6)的活性超时 ms:会话超过此时长无任何请求流量即视为死 * 残留(拦截判定视作无活跃会话,并触发 transport 重建)。缺省 5 分钟——SDK * onsessionclosed 仅 DELETE 触发(dist/index.mjs:770-775),客户端崩溃/断连时 * 计数单调高估,纯计数拦截会让新连接永远 409 死锁;正常 MCP 客户端有请求流或 * SSE 心跳(keepalive 秒级),5 分钟零流量视为死是合理启发(代价:空闲超阈值的 * 活会话被误放一次——旧会话被新会话顶替,SDK validateSession 404 旧 id,不产生 * 双活互踩)。注意:SDK transport 的 _initialized/_closed 是**实例终态无 reset** * (审查核实 dist/index.mjs:655/:658/:667/:820),终态后的放行必须换新 transport * 实例(见 rebuildTransport),否则 DELETE 后永久 404、崩溃残留后新 Initialize * 撞 400 "Server already initialized"——死锁只是换了错误码,没真解。 */ sessionStaleMs?: number; /** 测试注入假 transport(鸭子:仅用 handleRequest);缺省构造真 stateful transport。 * 真 transport 端到端由 Task 1 spike 脚本 + 批 C 真机验收覆盖,单测不起真 McpServer。 */ _transportForTest?: WebStandardStreamableHTTPServerTransport; /** 测试注入 transport 重建工厂(终态后新 Initialize 触发重建时调用;缺省造真 * transport)——与 _transportForTest 配对验证重建路径(fake 不触发真回调)。 */ _rebuildTransportForTest?: () => WebStandardStreamableHTTPServerTransport; /** 测试注入种子活性状态(fake transport 不触发 onsessioninitialized/closed 真 * 回调,单测直接摆状态驱动闸门分支;生产不传)。 */ _sessionStateForTest?: { activeSessions?: number; /** [sessionId, lastSeenAt(epoch ms)] 种子条目。 */ lastSeen?: Array<[string, number]>; /** 种子"当前 transport 已服务过会话"(模拟 DELETE 完成/崩溃残留的终态)。 */ transportServed?: boolean; }; } export interface McpEndpoint { /** 即 WebGuiServerOptions.mcpHandler 的实现(签名逐字一致);Promise 不外抛(全内消)。 */ handler: (req: IncomingMessage, res: ServerResponse) => Promise; /** 当前活跃 transport(终态重建后重指向新实例——消费方经 getter 取,勿缓存引用)。 */ transport: WebStandardStreamableHTTPServerTransport; /** 活跃会话数(真 transport 由 onsessioninitialized/closed 维护;批 C 单会话拦截消费)。 */ activeSessionCount(): number; /** 活性判定(daemon 前端批 C,2026-09-30):面板实例区「会话占用中/空闲」的数据源。 * 与单会话 409 闸门同源同判(计数>0 AND lastSeen 新鲜)——SDK 计数在客户端崩溃/ * 断连时残留虚高(onsessionclosed 仅 DELETE 触发),裸暴露 activeSessionCount 会把 * 死残留误报成「占用中」。调用带懒清理副作用(顺手删 stale 条目),对展示无害。 */ hasLiveSession(): boolean; /** 把 transport 交给 McpServer(Task 2 GodotServer.connectTransport 的等价直连)。 */ connect(): Promise; } export declare function createMcpEndpoint(deps: McpEndpointDeps): McpEndpoint;