@faapi/mcp 0.0.0-canary.0

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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/mcpServer.ts","../src/jsonRpc.ts","../src/session.ts","../src/streamableHttp.ts","../src/faapiAdapter.ts"],"sourcesContent":["/**\n * MCP Server 核心:tool/resource/prompt 注册 + JSON-RPC 方法分发\n *\n * 实现 MCP 协议的核心方法:\n * - initialize:握手,返回 serverInfo + capabilities(根据注册情况动态生成)\n * - notifications/initialized:通知,无响应\n * - tools/list、tools/call:tool 列表与调用\n * - resources/list、resources/read:资源列表与读取\n * - prompts/list、prompts/get:提示列表与获取\n * - ping:心跳\n *\n * Tool 输入参数用 zod schema 声明,通过 zod v4 内置 toJSONSchema 转为 JSON Schema。\n */\n\nimport { z, toJSONSchema } from 'zod';\nimport type { JsonRpcRequest, JsonRpcMessage, JsonRpcErrorResponse } from './jsonRpc';\nimport { createResultResponse, createErrorResponse, ErrorCode, isNotification } from './jsonRpc';\nimport { SessionManager, type McpSession, type LoggingLevel } from './session';\n\n// ─── 协议常量 ───────────────────────────────────────────\n\n/** MCP 协议版本(当前实现遵循 2025-06-18 规范) */\nexport const PROTOCOL_VERSION = '2025-06-18';\n\n/** 支持的协议版本列表 */\nexport const SUPPORTED_PROTOCOL_VERSIONS = ['2025-06-18', '2025-03-26'] as const;\n\n// ─── 类型定义 ───────────────────────────────────────────\n\nexport interface McpServerOptions {\n /** Server 名称 */\n name: string;\n /** Server 版本 */\n version: string;\n /** 可选显示名称 */\n title?: string;\n /** 可选给客户端的指引说明 */\n instructions?: string;\n /** 会话空闲超时(毫秒),默认 30 分钟;设为 0 表示永不过期 */\n sessionTtl?: number;\n /** GET SSE 流心跳间隔(毫秒),默认 30 秒 */\n sseHeartbeatMs?: number;\n /** list 方法默认每页项数,默认 100 */\n defaultPageSize?: number;\n /** tools 列表是否可变(声明 listChanged: true + removeTool 时推送通知)。默认 false */\n toolsListChanged?: boolean;\n /** resources 列表是否可变(声明 listChanged: true + removeResource 时推送通知)。默认 false */\n resourcesListChanged?: boolean;\n /** prompts 列表是否可变(声明 listChanged: true + removePrompt 时推送通知)。默认 false */\n promptsListChanged?: boolean;\n}\n\nexport interface McpToolResult {\n /** 内容数组(text/image/audio/resource_link/resource) */\n content: Array<Record<string, unknown>>;\n /** 是否为 tool 执行错误(区别于协议错误) */\n isError?: boolean;\n /** 结构化输出(配合 outputSchema 使用) */\n structuredContent?: unknown;\n}\n\n/** sendLogging 函数类型——推送日志到 session 的 SSE 订阅者 */\nexport type SendLoggingFn = (level: LoggingLevel, data: unknown, logger?: string) => void;\n\n/** sendProgress 函数类型——推送进度到 session 的 SSE 订阅者 */\nexport type SendProgressFn = (progress: number, total?: number) => void;\n\n/** 自定义方法的请求 extra(与 tool/resource/prompt handler extra 共享 send* 能力) */\nexport interface RequestExtra {\n /** 会话 ID */\n sessionId: string;\n /** 推送日志到客户端 SSE 流(无订阅者或被级别过滤时静默丢弃) */\n sendLogging: SendLoggingFn;\n /** 推送进度到客户端 SSE 流(无 progressToken 或无订阅者时静默丢弃) */\n sendProgress: SendProgressFn;\n}\n\n/** 自定义方法 handler 返回值——对象作为 result,JsonRpcErrorResponse 作为错误 */\nexport type MethodHandlerResult = Record<string, unknown> | JsonRpcErrorResponse;\n\n/** 自定义 JSON-RPC 方法 handler 类型 */\nexport type MethodHandler = (\n params: unknown,\n session: McpSession | undefined,\n extra: RequestExtra,\n) => Promise<MethodHandlerResult> | MethodHandlerResult;\n\nexport interface ToolCallExtra {\n /** 会话 ID */\n sessionId: string;\n /** 推送日志到客户端 SSE 流(无订阅者或被级别过滤时静默丢弃) */\n sendLogging: SendLoggingFn;\n /** 推送进度到客户端 SSE 流(无 progressToken 或无订阅者时静默丢弃) */\n sendProgress: SendProgressFn;\n}\n\nexport interface McpToolDefinition {\n /** 工具描述 */\n description?: string;\n /** 输入参数 schema(zod raw shape,如 { name: z.string() }) */\n input?: Record<string, z.ZodType>;\n /** 工具注解(如 readOnlyHint、destructiveHint 等) */\n annotations?: Record<string, unknown>;\n /** 处理函数 */\n handler: (\n args: Record<string, unknown>,\n extra: ToolCallExtra,\n ) => Promise<McpToolResult> | McpToolResult;\n}\n\n// ─── resource 类型 ─────────────────────────────────────\n\nexport interface McpResourceContent {\n /** 资源 URI */\n uri: string;\n /** MIME 类型 */\n mimeType?: string;\n /** 文本内容(与 blob 二选一) */\n text?: string;\n /** 二进制内容(Base64 编码,与 text 二选一) */\n blob?: string;\n}\n\nexport interface McpResourceReadResult {\n /** 资源内容数组(支持一个 URI 返回多段内容) */\n contents: McpResourceContent[];\n}\n\nexport interface ResourceReadExtra {\n /** 会话 ID */\n sessionId: string;\n /** 推送日志到客户端 SSE 流(无订阅者或被级别过滤时静默丢弃) */\n sendLogging: SendLoggingFn;\n /** 推送进度到客户端 SSE 流(无 progressToken 或无订阅者时静默丢弃) */\n sendProgress: SendProgressFn;\n}\n\nexport interface McpResourceDefinition {\n /** 资源名称(必填) */\n name: string;\n /** 资源描述 */\n description?: string;\n /** MIME 类型 */\n mimeType?: string;\n /** 读取 handler(必填) */\n read: (\n uri: string,\n extra: ResourceReadExtra,\n ) => Promise<McpResourceReadResult> | McpResourceReadResult;\n}\n\ninterface RegisteredResource {\n uri: string;\n definition: McpResourceDefinition;\n}\n\n// ─── resource template 类型 ─────────────────────────\n\nexport interface ResourceTemplateReadExtra {\n /** 会话 ID */\n sessionId: string;\n /** 推送日志到客户端 SSE 流(无订阅者或被级别过滤时静默丢弃) */\n sendLogging: SendLoggingFn;\n /** 推送进度到客户端 SSE 流(无 progressToken 或无订阅者时静默丢弃) */\n sendProgress: SendProgressFn;\n}\n\nexport interface McpResourceTemplateDefinition {\n /** 资源名称(必填) */\n name: string;\n /** 资源描述 */\n description?: string;\n /** MIME 类型 */\n mimeType?: string;\n /** 读取 handler(必填):接收实际 URI 和从 URI 模板提取的 params */\n read: (\n uri: string,\n params: Record<string, string>,\n extra: ResourceTemplateReadExtra,\n ) => Promise<McpResourceReadResult> | McpResourceReadResult;\n}\n\ninterface RegisteredResourceTemplate {\n uriTemplate: string;\n /** 编译后的正则表达式(用于匹配 URI) */\n regex: RegExp;\n /** 模板中的变量名列表(按出现顺序) */\n paramNames: string[];\n definition: McpResourceTemplateDefinition;\n}\n\n// ─── prompt 类型 ───────────────────────────────────────\n\nexport interface McpPromptArgument {\n /** 参数名称 */\n name: string;\n /** 参数描述 */\n description?: string;\n /** 是否必填 */\n required?: boolean;\n}\n\nexport interface McpPromptContent {\n /** 内容类型:text 或 image */\n type: 'text' | 'image';\n /** 文本内容(type=text 时) */\n text?: string;\n /** Base64 编码的图片数据(type=image 时) */\n data?: string;\n /** 图片 MIME 类型(type=image 时) */\n mimeType?: string;\n}\n\nexport interface McpPromptMessage {\n /** 角色 */\n role: 'user' | 'assistant';\n /** 内容 */\n content: McpPromptContent;\n}\n\nexport interface McpPromptGetResult {\n /** 提示消息列表 */\n messages: McpPromptMessage[];\n}\n\nexport interface PromptGetExtra {\n /** 会话 ID */\n sessionId: string;\n /** 推送日志到客户端 SSE 流(无订阅者或被级别过滤时静默丢弃) */\n sendLogging: SendLoggingFn;\n /** 推送进度到客户端 SSE 流(无 progressToken 或无订阅者时静默丢弃) */\n sendProgress: SendProgressFn;\n}\n\nexport interface McpPromptDefinition {\n /** 提示描述 */\n description?: string;\n /** 参数定义 */\n arguments?: McpPromptArgument[];\n /** 获取 handler(必填) */\n get: (\n args: Record<string, string>,\n extra: PromptGetExtra,\n ) => Promise<McpPromptGetResult> | McpPromptGetResult;\n}\n\ninterface RegisteredPrompt {\n name: string;\n definition: McpPromptDefinition;\n}\n\ninterface RegisteredTool {\n name: string;\n definition: McpToolDefinition;\n /** 包装后的 z.object schema(用于 safeParse) */\n inputSchema: z.ZodObject<Record<string, z.ZodType>> | undefined;\n /** JSON Schema 表示(用于 tools/list 响应) */\n jsonSchema: Record<string, unknown> | undefined;\n}\n\n// ─── completion 类型 ──────────────────────────────────\n\n/** completion 引用——指向某个 prompt 或 resource template */\nexport type CompletionRef =\n | { type: 'ref/prompt'; name: string }\n | { type: 'ref/resource'; uri: string };\n\n/** completion 调用上下文——传递给 handler */\nexport interface CompletionContext {\n /** 客户端已填写的其他参数(部分填充,key 为参数名,value 为已填值) */\n arguments: Record<string, string>;\n}\n\n/** completion 返回结果 */\nexport interface CompletionResult {\n /** 候选值数组 */\n values: string[];\n /** 总数(可选,用于客户端提示\"还有 N 项\") */\n total?: number;\n /** 是否还有更多(可选,提示客户端可分页或继续输入) */\n hasMore?: boolean;\n}\n\n/** completion handler 函数类型 */\nexport type CompletionHandler = (\n value: string,\n context: CompletionContext,\n) => Promise<CompletionResult> | CompletionResult;\n\ninterface RegisteredCompletion {\n /** 引用类型 'ref/prompt' | 'ref/resource' */\n refType: 'ref/prompt' | 'ref/resource';\n /** 引用标识(prompt name 或 resource template uri) */\n refId: string;\n /** 参数名 */\n argumentName: string;\n /** 补全 handler */\n handler: CompletionHandler;\n}\n\ninterface RegisteredMethod {\n name: string;\n handler: MethodHandler;\n}\n\n/** MCP 内置方法——禁止业务方注册同名方法,避免覆盖协议行为 */\nconst BUILTIN_METHODS = new Set<string>([\n 'initialize',\n 'ping',\n 'notifications/initialized',\n 'notifications/cancelled',\n 'tools/list',\n 'tools/call',\n 'resources/list',\n 'resources/read',\n 'resources/templates/list',\n 'resources/subscribe',\n 'resources/unsubscribe',\n 'prompts/list',\n 'prompts/get',\n 'logging/setLevel',\n 'completion/complete',\n]);\n\n// ─── 分页工具 ───────────────────────────────────────────\n\n/** 默认每页项数 */\nconst DEFAULT_PAGE_SIZE = 100;\n\n/** 将偏移量编码为不透明 cursor 字符串 */\nfunction encodeCursor(offset: number): string {\n return Buffer.from(String(offset)).toString('base64');\n}\n\n/** 解码 cursor,返回偏移量;无效时抛错 */\nfunction decodeCursor(cursor: string): number {\n const decoded = Buffer.from(cursor, 'base64').toString('utf-8');\n const offset = Number.parseInt(decoded, 10);\n if (!Number.isFinite(offset) || offset < 0 || decoded !== String(offset)) {\n throw new Error(`Invalid cursor: ${cursor}`);\n }\n return offset;\n}\n\n/** 对数组切片分页,返回当前页数据和可选的 nextCursor */\nfunction paginate<T>(\n items: T[],\n cursor: string | undefined,\n pageSize: number,\n): { items: T[]; nextCursor?: string } {\n const offset = cursor ? decodeCursor(cursor) : 0;\n if (offset > items.length) {\n throw new Error(`cursor out of range: offset ${offset} > total ${items.length}`);\n }\n const slice = items.slice(offset, offset + pageSize);\n const nextOffset = offset + pageSize;\n const nextCursor = nextOffset < items.length ? encodeCursor(nextOffset) : undefined;\n return { items: slice, nextCursor };\n}\n\n// ─── URI 模板编译/匹配 ─────────────────────────────────\n\n/** 变量名合法字符:[A-Za-z_][A-Za-z0-9_]* */\nconst VAR_NAME_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;\n\n/** 占位符正则:匹配 {varName} */\nconst PLACEHOLDER_RE = /\\{([A-Za-z_][A-Za-z0-9_]*)\\}/g;\n\n/**\n * 编译 URI 模板为正则 + 变量名列表\n *\n * - `file://docs/{path}` → regex `^file://docs/(.+)$`, paramNames `['path']`\n * - `git://repo/{owner}/{repo}` → regex `^git://repo/([^/]+)/([^/]+)$`, paramNames `['owner', 'repo']`\n *\n * 约束:\n * - 模板必须有至少一个 `{var}` 占位符\n * - 不支持 RFC 6570 操作符前缀(`{+var}`、`{?var}`、`{/var}` 等)\n * - 单变量贪婪匹配到 URI 结尾(允许包含 `/`)\n * - 多变量非贪婪匹配(不含 `/`),避免歧义\n *\n * @throws Error 模板格式无效\n */\nfunction compileUriTemplate(uriTemplate: string): { regex: RegExp; paramNames: string[] } {\n const paramNames: string[] = [];\n // 收集变量名并校验\n let match: RegExpExecArray | null;\n PLACEHOLDER_RE.lastIndex = 0;\n while ((match = PLACEHOLDER_RE.exec(uriTemplate)) !== null) {\n const name = match[1]!;\n if (!VAR_NAME_RE.test(name)) {\n throw new Error(`Invalid URI template variable name: ${name}`);\n }\n paramNames.push(name);\n }\n if (paramNames.length === 0) {\n throw new Error(`URI template must contain at least one {var} placeholder: ${uriTemplate}`);\n }\n\n // 检查重复变量名\n const seen = new Set<string>();\n for (const name of paramNames) {\n if (seen.has(name)) {\n throw new Error(`Duplicate URI template variable: ${name}`);\n }\n seen.add(name);\n }\n\n // 构建正则:转义字面字符,替换占位符\n // 单变量时贪婪(允许 /),多变量时非贪婪(不含 /)\n const isSingle = paramNames.length === 1;\n // 分段构建:按 {var} 分割,字面部分转义,占位符替换为捕获组\n const parts: string[] = [];\n let lastIdx = 0;\n PLACEHOLDER_RE.lastIndex = 0;\n let m: RegExpExecArray | null;\n while ((m = PLACEHOLDER_RE.exec(uriTemplate)) !== null) {\n // 转义字面部分\n const literal = uriTemplate.slice(lastIdx, m.index);\n parts.push(escapeRegex(literal));\n // 替换占位符为捕获组\n parts.push(isSingle ? '(.+)' : '([^/]+)');\n lastIdx = m.index + m[0]!.length;\n }\n // 尾部字面部分\n parts.push(escapeRegex(uriTemplate.slice(lastIdx)));\n const regex = new RegExp(`^${parts.join('')}$`);\n return { regex, paramNames };\n}\n\n/** 转义正则字面字符 */\nfunction escapeRegex(s: string): string {\n return s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\n/**\n * 用编译后的模板匹配 URI,提取参数\n *\n * @returns 匹配成功返回 params 对象,失败返回 null\n */\nfunction matchUriTemplate(\n regex: RegExp,\n paramNames: string[],\n uri: string,\n): Record<string, string> | null {\n const m = regex.exec(uri);\n if (!m) return null;\n const params: Record<string, string> = {};\n for (let i = 0; i < paramNames.length; i++) {\n params[paramNames[i]!] = m[i + 1]!;\n }\n return params;\n}\n\n// ─── McpServer ──────────────────────────────────────────\n\nexport class McpServer {\n private tools = new Map<string, RegisteredTool>();\n private resources = new Map<string, RegisteredResource>();\n private resourceTemplates = new Map<string, RegisteredResourceTemplate>();\n private prompts = new Map<string, RegisteredPrompt>();\n private completions = new Map<string, RegisteredCompletion>();\n private methods = new Map<string, RegisteredMethod>();\n private sessions: SessionManager;\n private readonly pageSize: number;\n private readonly toolsListChanged: boolean;\n private readonly resourcesListChanged: boolean;\n private readonly promptsListChanged: boolean;\n\n constructor(private options: McpServerOptions) {\n this.sessions = new SessionManager(this.options.sessionTtl);\n this.pageSize = this.options.defaultPageSize ?? DEFAULT_PAGE_SIZE;\n this.toolsListChanged = this.options.toolsListChanged ?? false;\n this.resourcesListChanged = this.options.resourcesListChanged ?? false;\n this.promptsListChanged = this.options.promptsListChanged ?? false;\n }\n\n /** 注册 tool */\n tool(name: string, definition: McpToolDefinition): void {\n if (this.tools.has(name)) {\n throw new Error(`Tool \"${name}\" is already registered`);\n }\n let inputSchema: z.ZodObject<Record<string, z.ZodType>> | undefined;\n let jsonSchema: Record<string, unknown> | undefined;\n\n if (definition.input) {\n // 将 raw shape 包装为 z.object\n inputSchema = buildZodObject(definition.input);\n // 转为 JSON Schema(MCP 协议要求)\n jsonSchema = toJSONSchema(inputSchema, { target: 'draft-7' }) as Record<string, unknown>;\n // 移除 $schema 字段(MCP 规范不需要)\n delete jsonSchema.$schema;\n // 移除 additionalProperties: false(MCP 客户端兼容性)\n delete jsonSchema.additionalProperties;\n }\n\n this.tools.set(name, { name, definition, inputSchema, jsonSchema });\n }\n\n /** 注册 resource */\n resource(uri: string, definition: McpResourceDefinition): void {\n if (this.resources.has(uri)) {\n throw new Error(`Resource \"${uri}\" is already registered`);\n }\n this.resources.set(uri, { uri, definition });\n }\n\n /** 注册 resource template(RFC 6570 URI 模板) */\n resourceTemplate(uriTemplate: string, definition: McpResourceTemplateDefinition): void {\n if (this.resourceTemplates.has(uriTemplate)) {\n throw new Error(`Resource template \"${uriTemplate}\" is already registered`);\n }\n const { regex, paramNames } = compileUriTemplate(uriTemplate);\n this.resourceTemplates.set(uriTemplate, {\n uriTemplate,\n regex,\n paramNames,\n definition,\n });\n }\n\n /** 注册 prompt */\n prompt(name: string, definition: McpPromptDefinition): void {\n if (this.prompts.has(name)) {\n throw new Error(`Prompt \"${name}\" is already registered`);\n }\n this.prompts.set(name, { name, definition });\n }\n\n /**\n * 注册参数补全 handler\n *\n * - `ref`:`{ type: 'ref/prompt', name }` 或 `{ type: 'ref/resource', uri }`(对资源模板,uri 是模板字符串)\n * - `argumentName`:补全的参数名(对应 prompt arguments 中的 name,或 resource template URI 模板中的变量名)\n * - 同一 (ref, argumentName) 重复注册抛错\n */\n completion(ref: CompletionRef, argumentName: string, handler: CompletionHandler): void {\n const refType = ref.type;\n const refId = refType === 'ref/prompt' ? ref.name : ref.uri;\n const key = completionKey(refType, refId, argumentName);\n if (this.completions.has(key)) {\n throw new Error(\n `Completion for ${refType} \"${refId}\" argument \"${argumentName}\" is already registered`,\n );\n }\n this.completions.set(key, { refType, refId, argumentName, handler });\n }\n\n /**\n * 注册自定义 JSON-RPC 方法 handler(业务拓展)\n *\n * - 方法名建议使用 `appName/action` 格式,避免与 MCP 标准方法冲突\n * - 与 MCP 内置方法(initialize/ping/tools/* 等)冲突时抛错\n * - 重复注册同名方法抛错\n *\n * handler 返回值规则:\n * - 返回普通对象:作为 JSON-RPC result 字段\n * - 返回 JsonRpcErrorResponse(含 error 字段):作为错误响应\n */\n method(name: string, handler: MethodHandler): void {\n if (BUILTIN_METHODS.has(name)) {\n throw new Error(`Cannot register built-in method \"${name}\": it is reserved by MCP protocol`);\n }\n if (this.methods.has(name)) {\n throw new Error(`Method \"${name}\" is already registered`);\n }\n this.methods.set(name, { name, handler });\n }\n\n /** 获取已注册 tool 名称列表 */\n listTools(): string[] {\n return [...this.tools.keys()];\n }\n\n /** 获取已注册 resource URI 列表 */\n listResources(): string[] {\n return [...this.resources.keys()];\n }\n\n /** 获取已注册 prompt 名称列表 */\n listPrompts(): string[] {\n return [...this.prompts.keys()];\n }\n\n /** 获取已注册自定义方法名列表(业务拓展) */\n listMethods(): string[] {\n return [...this.methods.keys()];\n }\n\n // ─── remove 方法(运行时删除注册项) ───────────────────\n\n /**\n * 删除已注册 tool\n *\n * - `toolsListChanged: true` 时自动推送 `notifications/tools/list_changed`\n * - `toolsListChanged: false` 时静默删除(用于 dev 热替换,客户端不感知)\n */\n removeTool(name: string): boolean {\n const deleted = this.tools.delete(name);\n if (deleted && this.toolsListChanged) {\n this.notifyToolsListChanged();\n }\n return deleted;\n }\n\n /**\n * 删除已注册 resource\n *\n * - `resourcesListChanged: true` 时自动推送 `notifications/resources/list_changed`\n */\n removeResource(uri: string): boolean {\n const deleted = this.resources.delete(uri);\n if (deleted && this.resourcesListChanged) {\n this.notifyResourcesListChanged();\n }\n return deleted;\n }\n\n /**\n * 删除已注册 resource template\n *\n * - `resourcesListChanged: true` 时自动推送 `notifications/resources/list_changed`\n */\n removeResourceTemplate(uriTemplate: string): boolean {\n const deleted = this.resourceTemplates.delete(uriTemplate);\n if (deleted && this.resourcesListChanged) {\n this.notifyResourcesListChanged();\n }\n return deleted;\n }\n\n /**\n * 删除已注册 prompt\n *\n * - `promptsListChanged: true` 时自动推送 `notifications/prompts/list_changed`\n */\n removePrompt(name: string): boolean {\n const deleted = this.prompts.delete(name);\n if (deleted && this.promptsListChanged) {\n this.notifyPromptsListChanged();\n }\n return deleted;\n }\n\n /**\n * 删除已注册 completion handler\n *\n * - completion 无 list_changed 通知机制(客户端按需请求,无需感知列表变化)\n */\n removeCompletion(ref: CompletionRef, argumentName: string): boolean {\n const refType = ref.type;\n const refId = refType === 'ref/prompt' ? ref.name : ref.uri;\n const key = completionKey(refType, refId, argumentName);\n return this.completions.delete(key);\n }\n\n /** 删除已注册自定义方法 */\n removeMethod(name: string): boolean {\n return this.methods.delete(name);\n }\n\n // ─── list_changed 通知 ───────────────────────────────\n\n /**\n * 推送 `notifications/tools/list_changed` 到所有 session 的 SSE 订阅者\n *\n * 客户端收到后应重新调用 `tools/list` 拉取最新列表。\n * `removeTool` 在 `toolsListChanged: true` 时自动调用本方法,\n * 业务方也可手动调用(如批量删除后只推送一次)。\n */\n notifyToolsListChanged(): void {\n this.broadcastNotificationToAllSessions('notifications/tools/list_changed');\n }\n\n /** 推送 `notifications/resources/list_changed` 到所有 session 的 SSE 订阅者 */\n notifyResourcesListChanged(): void {\n this.broadcastNotificationToAllSessions('notifications/resources/list_changed');\n }\n\n /** 推送 `notifications/prompts/list_changed` 到所有 session 的 SSE 订阅者 */\n notifyPromptsListChanged(): void {\n this.broadcastNotificationToAllSessions('notifications/prompts/list_changed');\n }\n\n /**\n * 向所有 session 的所有 SSE 订阅者广播通知(内部工具方法)\n *\n * 用于 list_changed 这种\"全局广播\"语义——所有 session 都应感知列表变化。\n */\n private broadcastNotificationToAllSessions(method: string, params?: unknown): void {\n const notification: { jsonrpc: '2.0'; method: string; params?: unknown } = {\n jsonrpc: '2.0',\n method,\n };\n if (params !== undefined) {\n notification.params = params;\n }\n const sseData = `data: ${JSON.stringify(notification)}\\n\\n`;\n for (const sessionId of this.sessions.allSessionIds()) {\n this.sessions.broadcastToSession(sessionId, sseData);\n }\n }\n\n /** 获取会话管理器 */\n getSessionManager(): SessionManager {\n return this.sessions;\n }\n\n /** 获取 GET SSE 流心跳间隔(毫秒) */\n getSseHeartbeatMs(): number {\n return this.options.sseHeartbeatMs ?? 30_000;\n }\n\n /**\n * 处理 JSON-RPC 请求,返回响应消息\n *\n * 通知(无 id)不返回响应,返回 null。\n */\n async handleJsonRpc(\n message: JsonRpcMessage,\n session: McpSession | undefined,\n ): Promise<JsonRpcMessage | null> {\n // 通知:无响应\n if (isNotification(message)) {\n return this.handleNotification(message, session);\n }\n\n // 请求:必须有 id\n if ('id' in message && 'method' in message && !('result' in message) && !('error' in message)) {\n return this.handleRequest(message, session);\n }\n\n // 其他消息类型(response 等):忽略\n return null;\n }\n\n private handleNotification(\n message: { method: string; params?: unknown },\n session: McpSession | undefined,\n ): null {\n switch (message.method) {\n case 'notifications/initialized':\n if (session) session.initialized = true;\n break;\n case 'notifications/cancelled':\n // 请求取消——v1 不实现取消逻辑,仅接收\n break;\n }\n return null;\n }\n\n private async handleRequest(\n request: JsonRpcRequest,\n session: McpSession | undefined,\n ): Promise<JsonRpcMessage> {\n try {\n switch (request.method) {\n case 'initialize':\n return this.handleInitialize(request, session);\n\n case 'ping':\n return createResultResponse(request.id, {});\n\n case 'tools/list':\n return this.handleToolsList(request);\n\n case 'tools/call':\n return await this.handleToolsCall(request, session);\n\n case 'resources/list':\n return this.handleResourcesList(request);\n\n case 'resources/read':\n return await this.handleResourcesRead(request, session);\n\n case 'prompts/list':\n return this.handlePromptsList(request);\n\n case 'prompts/get':\n return await this.handlePromptsGet(request, session);\n\n case 'logging/setLevel':\n return this.handleLoggingSetLevel(request, session);\n\n case 'resources/subscribe':\n return this.handleResourcesSubscribe(request, session);\n\n case 'resources/unsubscribe':\n return this.handleResourcesUnsubscribe(request, session);\n\n case 'resources/templates/list':\n return this.handleResourcesTemplatesList(request);\n\n case 'completion/complete':\n return await this.handleCompletionComplete(request);\n\n default:\n // 自定义方法分发(业务拓展)\n if (this.methods.has(request.method)) {\n return await this.handleCustomMethod(request, session);\n }\n return createErrorResponse(\n request.id,\n ErrorCode.MethodNotFound,\n `Method not found: ${request.method}`,\n );\n }\n } catch (err) {\n return createErrorResponse(\n request.id,\n ErrorCode.InternalError,\n err instanceof Error ? err.message : String(err),\n );\n }\n }\n\n // ─── initialize ──────────────────────────────────────\n\n private handleInitialize(\n request: JsonRpcRequest,\n session: McpSession | undefined,\n ): JsonRpcMessage {\n const params = (request.params ?? {}) as {\n protocolVersion?: string;\n clientInfo?: { name: string; version: string };\n };\n\n // 协议版本协商\n const requestedVersion = params.protocolVersion ?? PROTOCOL_VERSION;\n const protocolVersion = (SUPPORTED_PROTOCOL_VERSIONS as readonly string[]).includes(\n requestedVersion,\n )\n ? requestedVersion\n : PROTOCOL_VERSION;\n\n // 如果没有 session(直接调用 handleJsonRpc,非 transport 场景),创建一个\n // transport 层已创建 session 时则复用\n if (!session) {\n session = this.sessions.create();\n }\n session.protocolVersion = protocolVersion;\n session.clientInfo = params.clientInfo;\n\n // capability 根据实际注册情况动态生成\n const capabilities: Record<string, unknown> = {\n tools: { listChanged: this.toolsListChanged },\n // logging capability 始终声明——服务端内置日志推送能力\n logging: {},\n };\n if (this.resources.size > 0 || this.resourceTemplates.size > 0) {\n // 注册了 resource 或 resource template 时声明 resources capability + subscribe 子能力\n capabilities.resources = { listChanged: this.resourcesListChanged, subscribe: true };\n }\n if (this.prompts.size > 0) {\n capabilities.prompts = { listChanged: this.promptsListChanged };\n }\n\n const result = {\n protocolVersion,\n capabilities,\n serverInfo: {\n name: this.options.name,\n version: this.options.version,\n ...(this.options.title && { title: this.options.title }),\n },\n ...(this.options.instructions && { instructions: this.options.instructions }),\n };\n\n return createResultResponse(request.id, result);\n }\n\n // ─── tools/list ──────────────────────────────────────\n\n private handleToolsList(request: JsonRpcRequest): JsonRpcMessage {\n const params = (request.params ?? {}) as { cursor?: string };\n const allTools = Array.from(this.tools.values()).map((tool) => ({\n name: tool.name,\n ...(tool.definition.description && { description: tool.definition.description }),\n inputSchema: tool.jsonSchema ?? { type: 'object', properties: {} },\n ...(tool.definition.annotations && { annotations: tool.definition.annotations }),\n }));\n\n let paged: { items: typeof allTools; nextCursor?: string };\n try {\n paged = paginate(allTools, params.cursor, this.pageSize);\n } catch (err) {\n return createErrorResponse(\n request.id,\n ErrorCode.InvalidParams,\n err instanceof Error ? err.message : 'Invalid cursor',\n );\n }\n\n return createResultResponse(request.id, {\n tools: paged.items,\n ...(paged.nextCursor && { nextCursor: paged.nextCursor }),\n });\n }\n\n // ─── tools/call ──────────────────────────────────────\n\n private async handleToolsCall(\n request: JsonRpcRequest,\n session: McpSession | undefined,\n ): Promise<JsonRpcMessage> {\n const params = (request.params ?? {}) as {\n name?: string;\n arguments?: Record<string, unknown>;\n _meta?: { progressToken?: unknown };\n };\n\n if (!params.name) {\n return createErrorResponse(\n request.id,\n ErrorCode.InvalidParams,\n 'Missing required parameter: name',\n );\n }\n\n const tool = this.tools.get(params.name);\n if (!tool) {\n return createErrorResponse(\n request.id,\n ErrorCode.InvalidParams,\n `Unknown tool: ${params.name}`,\n );\n }\n\n // 校验输入参数\n const args = params.arguments ?? {};\n if (tool.inputSchema) {\n const parsed = tool.inputSchema.safeParse(args);\n if (!parsed.success) {\n return createErrorResponse(\n request.id,\n ErrorCode.InvalidParams,\n 'Invalid tool arguments',\n parsed.error.issues,\n );\n }\n // 使用解析后的值(含默认值、coerce 等)\n Object.assign(args, parsed.data);\n }\n\n // 从请求 _meta.progressToken 提取进度 token(任意 JSON 值)\n const progressToken = params._meta?.progressToken;\n\n // 调用 handler\n const extra: ToolCallExtra = {\n sessionId: session?.id ?? '',\n sendLogging: (level, data, logger) => {\n if (session) this.sendLogging(session.id, level, data, logger);\n },\n sendProgress: (progress, total) => {\n if (session) this.sendProgress(session.id, progressToken, progress, total);\n },\n };\n\n let result: McpToolResult;\n try {\n result = await tool.definition.handler(args as Record<string, unknown>, extra);\n } catch (err) {\n // tool 执行错误——返回 isError 而非协议错误\n result = {\n content: [\n {\n type: 'text',\n text: `Tool execution failed: ${err instanceof Error ? err.message : String(err)}`,\n },\n ],\n isError: true,\n };\n }\n\n return createResultResponse(request.id, result);\n }\n\n // ─── resources/list ─────────────────────────────────\n\n private handleResourcesList(request: JsonRpcRequest): JsonRpcMessage {\n const params = (request.params ?? {}) as { cursor?: string };\n const allResources = Array.from(this.resources.values()).map((r) => ({\n uri: r.uri,\n name: r.definition.name,\n ...(r.definition.description && { description: r.definition.description }),\n ...(r.definition.mimeType && { mimeType: r.definition.mimeType }),\n }));\n\n let paged: { items: typeof allResources; nextCursor?: string };\n try {\n paged = paginate(allResources, params.cursor, this.pageSize);\n } catch (err) {\n return createErrorResponse(\n request.id,\n ErrorCode.InvalidParams,\n err instanceof Error ? err.message : 'Invalid cursor',\n );\n }\n\n return createResultResponse(request.id, {\n resources: paged.items,\n ...(paged.nextCursor && { nextCursor: paged.nextCursor }),\n });\n }\n\n // ─── resources/read ─────────────────────────────────\n\n private async handleResourcesRead(\n request: JsonRpcRequest,\n session: McpSession | undefined,\n ): Promise<JsonRpcMessage> {\n const params = (request.params ?? {}) as {\n uri?: string;\n _meta?: { progressToken?: unknown };\n };\n\n if (!params.uri) {\n return createErrorResponse(\n request.id,\n ErrorCode.InvalidParams,\n 'Missing required parameter: uri',\n );\n }\n\n // 从请求 _meta.progressToken 提取进度 token(任意 JSON 值)\n const progressToken = params._meta?.progressToken;\n\n // sendProgress 闭包(精确匹配与模板匹配共用,捕获 progressToken)\n const sendProgressFn: SendProgressFn = (progress, total) => {\n if (session) this.sendProgress(session.id, progressToken, progress, total);\n };\n\n const extra: ResourceReadExtra = {\n sessionId: session?.id ?? '',\n sendLogging: (level, data, logger) => {\n if (session) this.sendLogging(session.id, level, data, logger);\n },\n sendProgress: sendProgressFn,\n };\n\n // 1. 先在 resources Map 中查找精确匹配\n const resource = this.resources.get(params.uri);\n if (resource) {\n const result = await resource.definition.read(params.uri, extra);\n return createResultResponse(request.id, result);\n }\n\n // 2. 找不到时,遍历 resourceTemplates 用 URI 模板匹配\n for (const tpl of this.resourceTemplates.values()) {\n const params2 = matchUriTemplate(tpl.regex, tpl.paramNames, params.uri);\n if (params2) {\n const tplExtra: ResourceTemplateReadExtra = {\n sessionId: session?.id ?? '',\n sendLogging: (level, data, logger) => {\n if (session) this.sendLogging(session.id, level, data, logger);\n },\n sendProgress: sendProgressFn,\n };\n const result = await tpl.definition.read(params.uri, params2, tplExtra);\n return createResultResponse(request.id, result);\n }\n }\n\n // 3. 都不匹配\n return createErrorResponse(\n request.id,\n ErrorCode.InvalidParams,\n `Unknown resource: ${params.uri}`,\n );\n }\n\n // ─── resources/templates/list ──────────────────────\n\n private handleResourcesTemplatesList(request: JsonRpcRequest): JsonRpcMessage {\n const params = (request.params ?? {}) as { cursor?: string };\n const allTemplates = Array.from(this.resourceTemplates.values()).map((t) => ({\n uriTemplate: t.uriTemplate,\n name: t.definition.name,\n ...(t.definition.description && { description: t.definition.description }),\n ...(t.definition.mimeType && { mimeType: t.definition.mimeType }),\n }));\n\n let paged: { items: typeof allTemplates; nextCursor?: string };\n try {\n paged = paginate(allTemplates, params.cursor, this.pageSize);\n } catch (err) {\n return createErrorResponse(\n request.id,\n ErrorCode.InvalidParams,\n err instanceof Error ? err.message : 'Invalid cursor',\n );\n }\n\n return createResultResponse(request.id, {\n resourceTemplates: paged.items,\n ...(paged.nextCursor && { nextCursor: paged.nextCursor }),\n });\n }\n\n // ─── prompts/list ───────────────────────────────────\n\n private handlePromptsList(request: JsonRpcRequest): JsonRpcMessage {\n const params = (request.params ?? {}) as { cursor?: string };\n const allPrompts = Array.from(this.prompts.values()).map((p) => ({\n name: p.name,\n ...(p.definition.description && { description: p.definition.description }),\n ...(p.definition.arguments && { arguments: p.definition.arguments }),\n }));\n\n let paged: { items: typeof allPrompts; nextCursor?: string };\n try {\n paged = paginate(allPrompts, params.cursor, this.pageSize);\n } catch (err) {\n return createErrorResponse(\n request.id,\n ErrorCode.InvalidParams,\n err instanceof Error ? err.message : 'Invalid cursor',\n );\n }\n\n return createResultResponse(request.id, {\n prompts: paged.items,\n ...(paged.nextCursor && { nextCursor: paged.nextCursor }),\n });\n }\n\n // ─── prompts/get ────────────────────────────────────\n\n private async handlePromptsGet(\n request: JsonRpcRequest,\n session: McpSession | undefined,\n ): Promise<JsonRpcMessage> {\n const params = (request.params ?? {}) as {\n name?: string;\n arguments?: Record<string, string>;\n _meta?: { progressToken?: unknown };\n };\n\n if (!params.name) {\n return createErrorResponse(\n request.id,\n ErrorCode.InvalidParams,\n 'Missing required parameter: name',\n );\n }\n\n const prompt = this.prompts.get(params.name);\n if (!prompt) {\n return createErrorResponse(\n request.id,\n ErrorCode.InvalidParams,\n `Unknown prompt: ${params.name}`,\n );\n }\n\n // 从请求 _meta.progressToken 提取进度 token(任意 JSON 值)\n const progressToken = params._meta?.progressToken;\n\n const extra: PromptGetExtra = {\n sessionId: session?.id ?? '',\n sendLogging: (level, data, logger) => {\n if (session) this.sendLogging(session.id, level, data, logger);\n },\n sendProgress: (progress, total) => {\n if (session) this.sendProgress(session.id, progressToken, progress, total);\n },\n };\n\n const args = params.arguments ?? {};\n const result = await prompt.definition.get(args, extra);\n return createResultResponse(request.id, result);\n }\n\n // ─── logging/setLevel ──────────────────────────────\n\n private handleLoggingSetLevel(\n request: JsonRpcRequest,\n session: McpSession | undefined,\n ): JsonRpcMessage {\n const params = (request.params ?? {}) as { level?: string };\n if (!params.level) {\n return createErrorResponse(\n request.id,\n ErrorCode.InvalidParams,\n 'Missing required parameter: level',\n );\n }\n const validLevels: readonly LoggingLevel[] = [\n 'debug',\n 'info',\n 'notice',\n 'warning',\n 'error',\n 'critical',\n 'alert',\n 'emergency',\n ];\n if (!validLevels.includes(params.level as LoggingLevel)) {\n return createErrorResponse(\n request.id,\n ErrorCode.InvalidParams,\n `Invalid logging level: ${params.level}`,\n );\n }\n if (session) {\n session.loggingLevel = params.level as LoggingLevel;\n }\n return createResultResponse(request.id, {});\n }\n\n // ─── resources/subscribe ───────────────────────────\n\n private handleResourcesSubscribe(\n request: JsonRpcRequest,\n session: McpSession | undefined,\n ): JsonRpcMessage {\n const params = (request.params ?? {}) as { uri?: string };\n if (!params.uri) {\n return createErrorResponse(\n request.id,\n ErrorCode.InvalidParams,\n 'Missing required parameter: uri',\n );\n }\n if (!session) {\n return createErrorResponse(request.id, ErrorCode.InvalidRequest, 'No session for subscribe');\n }\n this.sessions.subscribeResource(session.id, params.uri);\n return createResultResponse(request.id, {});\n }\n\n // ─── resources/unsubscribe ─────────────────────────\n\n private handleResourcesUnsubscribe(\n request: JsonRpcRequest,\n session: McpSession | undefined,\n ): JsonRpcMessage {\n const params = (request.params ?? {}) as { uri?: string };\n if (!params.uri) {\n return createErrorResponse(\n request.id,\n ErrorCode.InvalidParams,\n 'Missing required parameter: uri',\n );\n }\n if (!session) {\n return createErrorResponse(\n request.id,\n ErrorCode.InvalidRequest,\n 'No session for unsubscribe',\n );\n }\n this.sessions.unsubscribeResource(session.id, params.uri);\n return createResultResponse(request.id, {});\n }\n\n // ─── completion/complete ───────────────────────────\n\n private async handleCompletionComplete(request: JsonRpcRequest): Promise<JsonRpcMessage> {\n const params = (request.params ?? {}) as {\n ref?: { type: string; name?: string; uri?: string };\n argument?: { name?: string; value?: string };\n arguments?: Record<string, string>;\n };\n\n if (!params.ref || !params.argument) {\n return createErrorResponse(\n request.id,\n ErrorCode.InvalidParams,\n 'Missing required parameter: ref and argument',\n );\n }\n\n const ref = params.ref;\n let refType: 'ref/prompt' | 'ref/resource';\n let refId: string;\n if (ref.type === 'ref/prompt' && typeof ref.name === 'string') {\n refType = 'ref/prompt';\n refId = ref.name;\n } else if (ref.type === 'ref/resource' && typeof ref.uri === 'string') {\n refType = 'ref/resource';\n refId = ref.uri;\n } else {\n return createErrorResponse(\n request.id,\n ErrorCode.InvalidParams,\n `Invalid ref: ${JSON.stringify(ref)}`,\n );\n }\n\n if (typeof params.argument.name !== 'string') {\n return createErrorResponse(\n request.id,\n ErrorCode.InvalidParams,\n 'Missing required parameter: argument.name',\n );\n }\n\n const key = completionKey(refType, refId, params.argument.name);\n const completion = this.completions.get(key);\n if (!completion) {\n return createErrorResponse(\n request.id,\n ErrorCode.MethodNotFound,\n `No completion handler for ${refType} \"${refId}\" argument \"${params.argument.name}\"`,\n );\n }\n\n const value = params.argument.value ?? '';\n const context: CompletionContext = {\n arguments: params.arguments ?? {},\n };\n\n let result: CompletionResult;\n try {\n result = await completion.handler(value, context);\n } catch (err) {\n return createErrorResponse(\n request.id,\n ErrorCode.InternalError,\n err instanceof Error ? err.message : String(err),\n );\n }\n\n return createResultResponse(request.id, { completion: result });\n }\n\n // ─── 自定义方法分发(业务拓展) ───────────────────────\n\n private async handleCustomMethod(\n request: JsonRpcRequest,\n session: McpSession | undefined,\n ): Promise<JsonRpcMessage> {\n const registered = this.methods.get(request.method);\n if (!registered) {\n // 双重检查(并发场景下可能在 default 分支后已被 remove)\n return createErrorResponse(\n request.id,\n ErrorCode.MethodNotFound,\n `Method not found: ${request.method}`,\n );\n }\n\n const extra: RequestExtra = {\n sessionId: session?.id ?? '',\n sendLogging: (level, data, logger) => {\n if (session) this.sendLogging(session.id, level, data, logger);\n },\n sendProgress: (progress, total) => {\n // 自定义方法无 progressToken 来源,始终传 undefined(业务方可直接用 server.sendProgress)\n if (session) this.sendProgress(session.id, undefined, progress, total);\n },\n };\n\n let result: MethodHandlerResult;\n try {\n result = await registered.handler(request.params, session, extra);\n } catch (err) {\n return createErrorResponse(\n request.id,\n ErrorCode.InternalError,\n err instanceof Error ? err.message : String(err),\n );\n }\n\n // 返回 JsonRpcErrorResponse 表示业务错误\n if (\n result !== null &&\n typeof result === 'object' &&\n 'error' in result &&\n result.error !== null &&\n typeof result.error === 'object'\n ) {\n // 已是错误响应格式——补全 id 后返回\n const errResp = result as unknown as JsonRpcErrorResponse;\n return { ...errResp, jsonrpc: '2.0', id: request.id };\n }\n\n // 普通对象——作为 result 返回\n return createResultResponse(request.id, result);\n }\n\n // ─── sendLogging(应用级 + handler extra 共用) ─────\n\n /**\n * 推送 notifications/message 到 session 的所有 SSE 订阅者\n *\n * - 无 session 或无订阅者:静默丢弃\n * - level 低于 session.loggingLevel:静默丢弃\n * - SSE 行格式:`data: ${JSON.stringify(notification)}\\n\\n`\n */\n sendLogging(sessionId: string, level: LoggingLevel, data: unknown, logger?: string): void {\n if (!this.sessions.shouldLog(sessionId, level)) return;\n const notification: { jsonrpc: '2.0'; method: string; params: Record<string, unknown> } = {\n jsonrpc: '2.0',\n method: 'notifications/message',\n params: { level, data },\n };\n if (logger !== undefined) {\n notification.params.logger = logger;\n }\n const sseData = `data: ${JSON.stringify(notification)}\\n\\n`;\n this.sessions.broadcastToSession(sessionId, sseData);\n }\n\n /**\n * 推送 notifications/resources/updated 到所有订阅了该 URI 的 session\n *\n * - 找出所有 subscribedResources 包含该 URI 的 session\n * - 对每个 session 的所有 SSE 订阅者推送通知\n * - 无订阅者的 session 静默跳过\n */\n sendResourceUpdated(uri: string): void {\n const sessionIds = this.sessions.findSubscribersOfUri(uri);\n if (sessionIds.length === 0) return;\n const notification = {\n jsonrpc: '2.0' as const,\n method: 'notifications/resources/updated',\n params: { uri },\n };\n const sseData = `data: ${JSON.stringify(notification)}\\n\\n`;\n for (const sessionId of sessionIds) {\n this.sessions.broadcastToSession(sessionId, sseData);\n }\n }\n\n /**\n * 推送 notifications/progress 到 session 的所有 SSE 订阅者\n *\n * - 无 session 或无订阅者:静默丢弃\n * - progressToken 为 undefined/null:静默丢弃(无法关联进度与请求)\n *\n * @param sessionId 会话 ID\n * @param progressToken 客户端在请求 _meta.progressToken 中传入的 token(任意 JSON 值)\n * @param progress 当前进度(数值)\n * @param total 总数(可选)\n */\n sendProgress(sessionId: string, progressToken: unknown, progress: number, total?: number): void {\n if (progressToken === undefined || progressToken === null) return;\n const params: Record<string, unknown> = { progressToken, progress };\n if (total !== undefined) {\n params.total = total;\n }\n const notification = {\n jsonrpc: '2.0' as const,\n method: 'notifications/progress',\n params,\n };\n const sseData = `data: ${JSON.stringify(notification)}\\n\\n`;\n this.sessions.broadcastToSession(sessionId, sseData);\n }\n\n /**\n * 通用通知推送(业务拓展)——向指定 session 的所有 SSE 订阅者推送任意通知\n *\n * - 无 session 或无订阅者:静默丢弃\n * - 不校验 method 是否符合 MCP 规范——业务方自行负责\n * - SSE 行格式:`data: ${JSON.stringify(notification)}\\n\\n`\n *\n * @param sessionId 目标 session ID\n * @param method 通知方法名(如 `notifications/myapp/sync`)\n * @param params 通知参数(可选)\n */\n sendNotification(sessionId: string, method: string, params?: unknown): void {\n const notification: { jsonrpc: '2.0'; method: string; params?: unknown } = {\n jsonrpc: '2.0',\n method,\n };\n if (params !== undefined) {\n notification.params = params;\n }\n const sseData = `data: ${JSON.stringify(notification)}\\n\\n`;\n this.sessions.broadcastToSession(sessionId, sseData);\n }\n}\n\n// ─── 工具函数 ───────────────────────────────────────────\n\n/**\n * 将 raw shape({ key: z.ZodType })包装为 z.object\n */\nfunction buildZodObject(shape: Record<string, z.ZodType>): z.ZodObject<Record<string, z.ZodType>> {\n return z.object(shape);\n}\n\n/**\n * 生成 completion Map 的键\n *\n * 形如 `ref/prompt:greet:userName` 或 `ref/resource:file://docs/{path}:path`\n */\nfunction completionKey(\n refType: 'ref/prompt' | 'ref/resource',\n refId: string,\n argumentName: string,\n): string {\n return `${refType}:${refId}:${argumentName}`;\n}\n\n// ─── 工厂函数 ───────────────────────────────────────────\n\nexport function createMcpServer(options: McpServerOptions): McpServer {\n return new McpServer(options);\n}\n","/**\n * JSON-RPC 2.0 协议消息类型、解析和响应构建\n *\n * MCP 协议基于 JSON-RPC 2.0,所有通信都是 JSON-RPC 消息。\n * 本模块提供类型定义、消息判定函数和响应构建工具。\n */\n\n// ─── 消息类型 ───────────────────────────────────────────\n\nexport interface JsonRpcRequest {\n jsonrpc: '2.0';\n id: string | number;\n method: string;\n params?: unknown;\n}\n\nexport interface JsonRpcNotification {\n jsonrpc: '2.0';\n method: string;\n params?: unknown;\n}\n\nexport interface JsonRpcResultResponse {\n jsonrpc: '2.0';\n id: string | number;\n result: unknown;\n}\n\nexport interface JsonRpcErrorResponse {\n jsonrpc: '2.0';\n id: string | number | null;\n error: JsonRpcError;\n}\n\nexport interface JsonRpcError {\n code: number;\n message: string;\n data?: unknown;\n}\n\nexport type JsonRpcMessage =\n | JsonRpcRequest\n | JsonRpcNotification\n | JsonRpcResultResponse\n | JsonRpcErrorResponse;\n\n// ─── 错误码 ─────────────────────────────────────────────\n\nexport const ErrorCode = {\n // JSON-RPC 标准错误码\n ParseError: -32700,\n InvalidRequest: -32600,\n MethodNotFound: -32601,\n InvalidParams: -32602,\n InternalError: -32603,\n // MCP 扩展错误码\n ConnectionClosed: -32000,\n RequestTimeout: -32001,\n} as const;\n\n// ─── 消息判定 ───────────────────────────────────────────\n\nexport function isRequest(msg: JsonRpcMessage): msg is JsonRpcRequest {\n return 'method' in msg && 'id' in msg && !('result' in msg) && !('error' in msg);\n}\n\nexport function isNotification(msg: JsonRpcMessage): msg is JsonRpcNotification {\n return 'method' in msg && !('id' in msg);\n}\n\nexport function isResultResponse(msg: JsonRpcMessage): msg is JsonRpcResultResponse {\n return 'result' in msg && 'id' in msg;\n}\n\nexport function isErrorResponse(msg: JsonRpcMessage): msg is JsonRpcErrorResponse {\n return 'error' in msg && 'id' in msg;\n}\n\n// ─── 响应构建 ───────────────────────────────────────────\n\nexport function createResultResponse(id: string | number, result: unknown): JsonRpcResultResponse {\n return { jsonrpc: '2.0', id, result };\n}\n\nexport function createErrorResponse(\n id: string | number | null,\n code: number,\n message: string,\n data?: unknown,\n): JsonRpcErrorResponse {\n const error: JsonRpcError = { code, message };\n if (data !== undefined) error.data = data;\n return { jsonrpc: '2.0', id, error };\n}\n\n// ─── 消息解析 ───────────────────────────────────────────\n\n/**\n * 解析 JSON-RPC 消息(单条或批量)\n *\n * @throws ParseError(返回 Error 对象,不抛异常)\n * @returns 消息数组(单条也包装为数组)\n */\nexport function parseJsonRpcMessage(data: unknown): JsonRpcMessage[] {\n if (Array.isArray(data)) {\n if (data.length === 0) {\n throw new JsonRpcParseError('Invalid Request: empty batch');\n }\n return data.map((item) => parseSingleMessage(item));\n }\n return [parseSingleMessage(data)];\n}\n\nclass JsonRpcParseError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'JsonRpcParseError';\n }\n}\n\nexport { JsonRpcParseError };\n\nfunction parseSingleMessage(data: unknown): JsonRpcMessage {\n if (typeof data !== 'object' || data === null) {\n throw new JsonRpcParseError('Invalid Request: not an object');\n }\n const obj = data as Record<string, unknown>;\n if (obj.jsonrpc !== '2.0') {\n throw new JsonRpcParseError('Invalid Request: jsonrpc must be \"2.0\"');\n }\n // Request: has method + id\n if (\n typeof obj.method === 'string' &&\n (typeof obj.id === 'string' || typeof obj.id === 'number')\n ) {\n return {\n jsonrpc: '2.0',\n id: obj.id,\n method: obj.method,\n ...(obj.params !== undefined && { params: obj.params }),\n } as JsonRpcRequest;\n }\n // Notification: has method, no id\n if (typeof obj.method === 'string' && obj.id === undefined) {\n return {\n jsonrpc: '2.0',\n method: obj.method,\n ...(obj.params !== undefined && { params: obj.params }),\n } as JsonRpcNotification;\n }\n // Response: has result or error + id\n if ('result' in obj && (typeof obj.id === 'string' || typeof obj.id === 'number')) {\n return {\n jsonrpc: '2.0',\n id: obj.id,\n result: obj.result,\n } as JsonRpcResultResponse;\n }\n if ('error' in obj && obj.error !== null && typeof obj.error === 'object') {\n return {\n jsonrpc: '2.0',\n id: (obj.id as string | number | null) ?? null,\n error: obj.error as JsonRpcError,\n } as JsonRpcErrorResponse;\n }\n throw new JsonRpcParseError('Invalid Request: unknown message shape');\n}\n","/**\n * MCP 会话管理\n *\n * Streamable HTTP transport 通过 Mcp-Session-Id header 维持会话。\n * 会话在 initialize 请求时创建,在 DELETE 请求时销毁。\n *\n * 内置 TTL 机制:超过空闲时间的会话自动过期,防止内存泄漏。\n * 惰性清理:在 get/create 时检查过期会话,无需定时器。\n *\n * 每个 session 维护 SSE subscriber 集合,用于服务端主动推送\n * (logging/message, resources/updated, progress 等通知)。\n */\n\nimport { randomUUID } from 'node:crypto';\n\n/** 日志级别(syslog 严重度,从低到高) */\nexport type LoggingLevel =\n | 'debug'\n | 'info'\n | 'notice'\n | 'warning'\n | 'error'\n | 'critical'\n | 'alert'\n | 'emergency';\n\n/** 日志级别数值(越大越严重) */\nconst LOGGING_LEVEL_ORDER: Record<LoggingLevel, number> = {\n debug: 10,\n info: 20,\n notice: 30,\n warning: 40,\n error: 50,\n critical: 60,\n alert: 70,\n emergency: 80,\n};\n\n/** SSE 流订阅者(controller + 关联的 session id) */\nexport interface SseSubscriber {\n /** SSE 流控制器 */\n controller: ReadableStreamDefaultController<Uint8Array>;\n /** 关联的 session id */\n sessionId: string;\n}\n\nexport interface McpSession {\n /** 会话 ID(cryptographically secure UUID) */\n id: string;\n /** 是否已完成 initialize 握手 */\n initialized: boolean;\n /** 协商的协议版本 */\n protocolVersion: string;\n /** 客户端信息(来自 initialize 请求) */\n clientInfo?: { name: string; version: string };\n /** 创建时间戳 */\n createdAt: number;\n /** 最后活动时间戳(每次 get 时更新) */\n lastActivity: number;\n /** 当前日志级别(低于此级别的日志不推送),默认 info */\n loggingLevel: LoggingLevel;\n /** SSE 流订阅者集合(GET 流注册,用于服务端主动推送) */\n subscribers: Set<SseSubscriber>;\n /** 已订阅的资源 URI 集合(resources/subscribe 注册) */\n subscribedResources: Set<string>;\n}\n\n/** 默认会话空闲超时:30 分钟 */\nconst DEFAULT_TTL = 30 * 60 * 1000;\n\n/**\n * 内存会话管理器\n *\n * 生产环境如需多实例共享会话,可替换为 Redis 等外部存储实现。\n *\n * @param ttl 会话空闲超时(毫秒),超过此时间未活动的会话自动过期。默认 30 分钟。设为 0 表示永不过期。\n */\nexport class SessionManager {\n private sessions = new Map<string, McpSession>();\n private readonly ttl: number;\n\n constructor(ttl: number = DEFAULT_TTL) {\n this.ttl = ttl;\n }\n\n /** 是否启用 TTL 过期检查(ttl > 0) */\n private get ttlEnabled(): boolean {\n return this.ttl > 0;\n }\n\n /** 创建新会话,返回 session 对象 */\n create(): McpSession {\n // 惰性清理:创建新会话时顺便清理过期会话\n if (this.ttlEnabled) this.cleanupExpired();\n\n const now = Date.now();\n const session: McpSession = {\n id: randomUUID(),\n initialized: false,\n protocolVersion: '',\n createdAt: now,\n lastActivity: now,\n loggingLevel: 'info',\n subscribers: new Set(),\n subscribedResources: new Set(),\n };\n this.sessions.set(session.id, session);\n return session;\n }\n\n /** 按 ID 获取会话(更新最后活动时间,过期返回 undefined) */\n get(id: string): McpSession | undefined {\n const session = this.sessions.get(id);\n if (!session) return undefined;\n\n // 检查是否过期(ttl=0 时跳过)\n if (this.ttlEnabled && Date.now() - session.lastActivity > this.ttl) {\n this.closeSubscribers(session);\n this.sessions.delete(id);\n return undefined;\n }\n\n // 更新最后活动时间\n session.lastActivity = Date.now();\n return session;\n }\n\n /** 是否存在(不更新活动时间,过期会话返回 false) */\n has(id: string): boolean {\n const session = this.sessions.get(id);\n if (!session) return false;\n if (this.ttlEnabled && Date.now() - session.lastActivity > this.ttl) {\n this.closeSubscribers(session);\n this.sessions.delete(id);\n return false;\n }\n return true;\n }\n\n /** 销毁会话(关闭所有 SSE 订阅者) */\n delete(id: string): boolean {\n const session = this.sessions.get(id);\n if (session) {\n this.closeSubscribers(session);\n }\n return this.sessions.delete(id);\n }\n\n /** 当前会话数(含可能尚未清理的过期会话) */\n get size(): number {\n return this.sessions.size;\n }\n\n /** 获取所有 session ID 列表(用于全局广播通知) */\n allSessionIds(): string[] {\n return [...this.sessions.keys()];\n }\n\n /** 清空所有会话 */\n clear(): void {\n for (const session of this.sessions.values()) {\n this.closeSubscribers(session);\n }\n this.sessions.clear();\n }\n\n /** 注册 SSE 订阅者到 session */\n addSubscriber(\n sessionId: string,\n controller: ReadableStreamDefaultController<Uint8Array>,\n ): SseSubscriber | undefined {\n const session = this.get(sessionId);\n if (!session) return undefined;\n const subscriber: SseSubscriber = { controller, sessionId };\n session.subscribers.add(subscriber);\n return subscriber;\n }\n\n /** 注销 SSE 订阅者 */\n removeSubscriber(subscriber: SseSubscriber): void {\n const session = this.sessions.get(subscriber.sessionId);\n if (session) {\n session.subscribers.delete(subscriber);\n }\n }\n\n /** 向 session 的所有订阅者推送 SSE 数据 */\n broadcastToSession(sessionId: string, data: string): void {\n const session = this.sessions.get(sessionId);\n if (!session) return;\n const encoder = new TextEncoder();\n for (const sub of session.subscribers) {\n try {\n sub.controller.enqueue(encoder.encode(data));\n } catch {\n // controller 已关闭,移除订阅者\n session.subscribers.delete(sub);\n }\n }\n }\n\n /** 判断指定级别的日志是否应该推送(>= session.loggingLevel) */\n shouldLog(sessionId: string, level: LoggingLevel): boolean {\n const session = this.sessions.get(sessionId);\n if (!session) return false;\n return LOGGING_LEVEL_ORDER[level] >= LOGGING_LEVEL_ORDER[session.loggingLevel];\n }\n\n /** 添加资源订阅(将 uri 加入 session.subscribedResources) */\n subscribeResource(sessionId: string, uri: string): boolean {\n const session = this.sessions.get(sessionId);\n if (!session) return false;\n session.subscribedResources.add(uri);\n return true;\n }\n\n /** 取消资源订阅(从 session.subscribedResources 移除 uri) */\n unsubscribeResource(sessionId: string, uri: string): boolean {\n const session = this.sessions.get(sessionId);\n if (!session) return false;\n session.subscribedResources.delete(uri);\n return true;\n }\n\n /** 找出所有订阅了指定 URI 的 session id 列表 */\n findSubscribersOfUri(uri: string): string[] {\n const result: string[] = [];\n for (const session of this.sessions.values()) {\n if (session.subscribedResources.has(uri)) {\n result.push(session.id);\n }\n }\n return result;\n }\n\n /** 关闭 session 的所有订阅者(用于 session 销毁/过期) */\n private closeSubscribers(session: McpSession): void {\n for (const sub of session.subscribers) {\n try {\n sub.controller.close();\n } catch {\n // controller 已关闭,忽略\n }\n }\n session.subscribers.clear();\n }\n\n /** 清理所有过期会话 */\n private cleanupExpired(): void {\n if (!this.ttlEnabled) return;\n const now = Date.now();\n for (const [id, session] of this.sessions) {\n if (now - session.lastActivity > this.ttl) {\n this.closeSubscribers(session);\n this.sessions.delete(id);\n }\n }\n }\n}\n","/**\n * Streamable HTTP transport:Web Request → JSON-RPC → Response\n *\n * MCP Streamable HTTP transport 规范:\n * - POST:发送 JSON-RPC 消息,返回 JSON 响应或 SSE 流\n * - GET:打开 SSE 流接收服务端推送\n * - DELETE:终止会话\n *\n * 会话管理通过 Mcp-Session-Id header。\n * 实现:POST 返回 JSON,GET 返回 SSE 流(仅心跳,不推送业务消息),DELETE 销毁会话。\n */\n\nimport type { McpServer } from './mcpServer';\nimport {\n type JsonRpcMessage,\n isRequest,\n isNotification,\n createErrorResponse,\n ErrorCode,\n parseJsonRpcMessage,\n JsonRpcParseError,\n} from './jsonRpc';\n\n/** 默认 SSE 心跳间隔 */\nconst DEFAULT_SSE_HEARTBEAT_MS = 30_000;\n\n/**\n * 处理 MCP HTTP 请求\n *\n * 接收 Web API Request,返回 Web API Response。\n * 可直接在 faapi handler 中使用:\n * ```ts\n * export function POST(ctx) {\n * return mcp.handleWebRequest(ctx.request);\n * }\n * ```\n */\nexport async function handleMcpRequest(request: Request, server: McpServer): Promise<Response> {\n switch (request.method) {\n case 'POST':\n return handlePost(request, server);\n case 'GET':\n return handleGet(server, request);\n case 'DELETE':\n return handleDelete(request, server);\n default:\n return new Response(null, { status: 405 });\n }\n}\n\n/**\n * 处理 GET 请求:打开 SSE 流,定期推送心跳维持连接\n *\n * 若携带 Mcp-Session-Id 头,会在 stream start 时注册 SSE 订阅者,\n * 服务端 sendLogging 等推送方法可通过 broadcastToSession 推送到客户端。\n *\n * 客户端断开时 stream cancel 触发,清理定时器 + 注销订阅者避免泄漏。\n */\nfunction handleGet(server: McpServer, request: Request): Response {\n const heartbeatMs = server.getSseHeartbeatMs() ?? DEFAULT_SSE_HEARTBEAT_MS;\n const encoder = new TextEncoder();\n let interval: ReturnType<typeof setInterval> | undefined;\n let subscriber:\n | { controller: ReadableStreamDefaultController<Uint8Array>; sessionId: string }\n | undefined;\n\n const sessionId = request.headers.get('mcp-session-id') ?? undefined;\n\n const stream = new ReadableStream<Uint8Array>({\n start(controller) {\n // 初始连接确认\n controller.enqueue(encoder.encode(': connected\\n\\n'));\n\n // 若有 session id,注册订阅者(用于服务端推送)\n if (sessionId) {\n subscriber = server.getSessionManager().addSubscriber(sessionId, controller);\n }\n\n // 心跳定时器\n interval = setInterval(() => {\n try {\n controller.enqueue(encoder.encode(`: keepalive ${Date.now()}\\n\\n`));\n } catch {\n // controller 已关闭,清理定时器\n if (interval) clearInterval(interval);\n }\n }, heartbeatMs);\n },\n cancel() {\n // 客户端断开,清理定时器 + 注销订阅者避免泄漏\n if (interval) clearInterval(interval);\n if (subscriber) {\n server.getSessionManager().removeSubscriber(subscriber);\n }\n },\n });\n\n return new Response(stream, {\n status: 200,\n headers: {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n Connection: 'keep-alive',\n },\n });\n}\n\nasync function handlePost(request: Request, server: McpServer): Promise<Response> {\n // 解析请求体\n let body: unknown;\n try {\n body = await request.json();\n } catch {\n return jsonResponse(\n 400,\n createErrorResponse(null, ErrorCode.ParseError, 'Parse error: Invalid JSON'),\n );\n }\n\n // 解析 JSON-RPC 消息\n let messages: JsonRpcMessage[];\n try {\n messages = parseJsonRpcMessage(body);\n } catch (err) {\n const message = err instanceof JsonRpcParseError ? err.message : 'Invalid JSON-RPC message';\n return jsonResponse(400, createErrorResponse(null, ErrorCode.ParseError, message));\n }\n\n // 分离请求和通知\n const requests = messages.filter(isRequest);\n const notifications = messages.filter(isNotification);\n\n // initialize 请求豁免 Accept 头校验(首次握手)\n const hasInitialize = requests.some((r) => r.method === 'initialize');\n if (!hasInitialize) {\n // MCP 2025-06-18 规范:Accept 头必须同时包含 application/json 和 text/event-stream\n const acceptHeader = request.headers.get('accept') ?? '';\n const accepts = acceptHeader\n .split(',')\n .map((s) => s.trim().toLowerCase())\n .filter((s) => s.length > 0);\n const hasJson = accepts.some(\n (s) => s === 'application/json' || s.startsWith('application/json;'),\n );\n const hasSse = accepts.some(\n (s) => s === 'text/event-stream' || s.startsWith('text/event-stream;'),\n );\n if (!hasJson || !hasSse) {\n return jsonResponse(\n 400,\n createErrorResponse(\n null,\n ErrorCode.InvalidRequest,\n 'Accept header must include both application/json and text/event-stream',\n ),\n );\n }\n }\n\n // 查找 session(非 initialize 请求需要 session)\n const sessionId = request.headers.get('mcp-session-id') ?? undefined;\n const sessionManager = server.getSessionManager();\n let session = sessionId ? sessionManager.get(sessionId) : undefined;\n\n if (hasInitialize) {\n if (session) {\n // 已有 session 却再次 initialize\n return jsonResponse(\n 400,\n createErrorResponse(null, ErrorCode.InvalidRequest, 'Server already initialized'),\n );\n }\n // 先创建 session,handleJsonRpc 中会填充 protocolVersion 等信息\n session = sessionManager.create();\n } else if (requests.length > 0 && !session && sessionId) {\n // 有 session ID 但找不到\n return jsonResponse(\n 404,\n createErrorResponse(null, ErrorCode.RequestTimeout, 'Session not found'),\n );\n }\n\n // 处理通知(无响应)\n for (const notification of notifications) {\n await server.handleJsonRpc(notification, session);\n }\n\n // 处理请求\n const responses: JsonRpcMessage[] = [];\n for (const req of requests) {\n const response = await server.handleJsonRpc(req, session);\n if (response !== null) {\n responses.push(response);\n }\n }\n\n // 构建响应\n if (requests.length === 0) {\n // 全是通知 → 202 Accepted\n return new Response(null, { status: 202 });\n }\n\n const responseHeaders: Record<string, string> = {\n 'Content-Type': 'application/json',\n };\n\n // initialize 响应需带 Mcp-Session-Id header\n if (hasInitialize && session) {\n responseHeaders['Mcp-Session-Id'] = session.id;\n }\n\n const responseBody = responses.length === 1 ? responses[0] : responses;\n return new Response(JSON.stringify(responseBody), {\n status: 200,\n headers: responseHeaders,\n });\n}\n\nfunction handleDelete(request: Request, server: McpServer): Promise<Response> {\n const sessionId = request.headers.get('mcp-session-id');\n if (!sessionId) {\n return Promise.resolve(\n jsonResponse(\n 400,\n createErrorResponse(null, ErrorCode.InvalidRequest, 'Missing Mcp-Session-Id header'),\n ),\n );\n }\n\n const deleted = server.getSessionManager().delete(sessionId);\n if (!deleted) {\n return Promise.resolve(\n jsonResponse(404, createErrorResponse(null, ErrorCode.RequestTimeout, 'Session not found')),\n );\n }\n\n return Promise.resolve(new Response(null, { status: 200 }));\n}\n\nfunction jsonResponse(status: number, body: unknown): Response {\n return new Response(JSON.stringify(body), {\n status,\n headers: { 'Content-Type': 'application/json' },\n });\n}\n","/**\n * faapi 适配器:把 MCP Server 挂载到 faapi 路由\n *\n * 两种集成方式:\n *\n * 1. handler 风格(推荐)——在 handler.ts 中使用:\n * ```ts\n * // api/mcp/handler.ts\n * import { createMcpServer, createMcpHandler } from '@faapi/mcp';\n * const mcp = createMcpServer({ name: 'my-app', version: '1.0.0' });\n * mcp.tool('hello', { ... });\n * export const { POST, GET, DELETE } = createMcpHandler(mcp);\n * ```\n *\n * 2. 插件风格——在 faapi.config.ts 中声明:\n * ```ts\n * plugins: [['@faapi/mcp', { path: '/mcp' }]]\n * ```\n * 需配合 mcp.tool() 注册(通常在 lifecycle.onReady 中)。\n *\n * 函数即接口:MCP endpoint 就是 faapi 的一个路由。\n */\n\nimport { Readable } from 'node:stream';\nimport type { IncomingMessage, ServerResponse } from 'node:http';\nimport type { McpServer } from './mcpServer';\nimport { handleMcpRequest } from './streamableHttp';\n\n/**\n * 创建 faapi handler 函数\n *\n * 返回 { POST, GET, DELETE },可直接在 handler.ts 中导出。\n * faapi 按参数名注入 ctx,函数内通过 ctx.request 获取 Web Request。\n */\nexport function createMcpHandler(mcp: McpServer): {\n POST: (ctx: { request: Request }) => Promise<Response>;\n GET: (ctx: { request: Request }) => Promise<Response>;\n DELETE: (ctx: { request: Request }) => Promise<Response>;\n} {\n const handler = async (ctx: { request: Request }): Promise<Response> => {\n return handleMcpRequest(ctx.request, mcp);\n };\n return { POST: handler, GET: handler, DELETE: handler };\n}\n\n/**\n * 创建 Node.js 请求处理函数(供 wrapHandler 使用)\n *\n * 用于 faapi 插件场景:插件通过 wrapHandler 拦截指定路径,\n * 将 Node.js IncomingMessage/ServerResponse 转为 Web Request 处理。\n *\n * 使用 Node.js 原生 `Readable.toWeb(req)` 转换 body,正确处理 chunked transfer\n * (多 chunk 累积)、backpressure 和 stream error。\n */\nexport function createMcpNodeHandler(\n mcp: McpServer,\n): (req: IncomingMessage, res: ServerResponse) => Promise<void> {\n return async (req, res) => {\n const url = new URL(req.url ?? '/', 'http://localhost');\n const headers = new Headers();\n for (const [key, value] of Object.entries(req.headers)) {\n if (Array.isArray(value)) {\n for (const v of value) headers.set(key, v);\n } else if (value !== undefined) {\n headers.set(key, value);\n }\n }\n\n const method = req.method ?? 'GET';\n // GET/HEAD/DELETE 无 body(DELETE 可能有 body 但 MCP 协议中 DELETE 用于销毁会话,无 body)\n const hasBody = method !== 'GET' && method !== 'HEAD' && method !== 'DELETE';\n\n // 使用 Node.js 原生 Readable.toWeb 转换,正确处理多 chunk、backpressure、error\n const body = hasBody ? (Readable.toWeb(req) as ReadableStream<Uint8Array>) : undefined;\n\n const request = new Request(url, {\n method,\n headers,\n ...(body && { body, duplex: 'half' as const }),\n } as RequestInit);\n\n const response = await handleMcpRequest(request, mcp);\n\n res.statusCode = response.status;\n response.headers.forEach((value, key) => {\n res.setHeader(key, value);\n });\n\n if (response.body) {\n // 用 pipe 处理流式响应(SSE 流),避免 text() 阻塞\n // 注意:SSE 流不主动结束,监听 'close'(客户端断开或 res 销毁)而非仅 'finish'\n const nodeStream = Readable.fromWeb(response.body as never);\n await new Promise<void>((resolve, reject) => {\n let settled = false;\n const settle = (err?: Error) => {\n if (settled) return;\n settled = true;\n if (err) reject(err);\n else resolve();\n };\n nodeStream.on('error', (err) => settle(err));\n res.on('error', (err: Error) => settle(err));\n res.on('finish', () => settle());\n res.on('close', () => settle());\n nodeStream.pipe(res);\n });\n return;\n }\n\n res.end();\n };\n}\n"],"mappings":"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","names":[]}
package/package.json ADDED
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "@faapi/mcp",
3
+ "version": "0.0.0-canary.0",
4
+ "description": "MCP Server SDK for faapi — Streamable HTTP transport, zod-native tool definition",
5
+ "type": "module",
6
+ "main": "./src/index.ts",
7
+ "types": "./src/index.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./src/index.ts",
11
+ "import": "./src/index.ts"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist"
16
+ ],
17
+ "engines": {
18
+ "node": ">=24"
19
+ },
20
+ "scripts": {
21
+ "build": "tsup",
22
+ "test": "vitest run --passWithNoTests",
23
+ "typecheck": "tsc --noEmit"
24
+ },
25
+ "dependencies": {
26
+ "@faapi/faapi": "workspace:*",
27
+ "zod": "^4.4.3"
28
+ },
29
+ "devDependencies": {
30
+ "@types/node": "^22.15.0",
31
+ "@vitest/coverage-v8": "3",
32
+ "tsup": "^8.4.0",
33
+ "typescript": "^5.7.0",
34
+ "vitest": "^3.1.0"
35
+ },
36
+ "peerDependencies": {
37
+ "typescript": ">=5.7.0"
38
+ },
39
+ "peerDependenciesMeta": {
40
+ "typescript": {
41
+ "optional": true
42
+ }
43
+ },
44
+ "license": "MIT",
45
+ "repository": {
46
+ "type": "git",
47
+ "url": "https://github.com/faapi/faapi.git",
48
+ "directory": "packages/mcp"
49
+ },
50
+ "publishConfig": {
51
+ "access": "public",
52
+ "provenance": true,
53
+ "main": "./dist/index.js",
54
+ "types": "./dist/index.d.ts",
55
+ "exports": {
56
+ ".": {
57
+ "types": "./dist/index.d.ts",
58
+ "import": "./dist/index.js"
59
+ }
60
+ }
61
+ }
62
+ }