本页目录
使用 stdio Transport 连接 MCP Server 时,很容易踩到一个大坑。
问题就是:console log 无法正常使用。
原因 console.log 为什么不可用
MCP Server 本质上只是标准 Node 应用。Client 运行 MCP Server,并监听 Server 的 stdout 以接收 MCP 消息,再把 MCP 消息发送回 Server 的 stdin.
然而,Node 应用还会把 stdio 用于日志记录。向控制台写日志时,写入的正是 MCP Server 与 Client 通信所使用的数据流。
因此,如果在 Server 中向控制台记录日志,就会把不符合 MCP 格式的消息发送给 Client。根据 Client 的实现,这可能导致崩溃;至少日志会被消费这些消息的程序吞掉。
想继续深入: 加入“面向真正工程师的 AI 编码”候补名单
为什么 sse 没有这个问题?
而 sse Transport 没有这个问题,因为它不使用 stdio 传输消息:
这意味着可以自由使用 stdout 记录日志。
在本地完全可以使用 sse ;如果控制台访问对你很重要,可能会更喜欢这种方式。
如何记录日志
我更喜欢创建一个把日志写入本地文件的自定义 logger,例如 mcp-server.log。下面是我的实现:
// 1. appendFileSyncimport { appendFileSync } from "fs";import { join } from "path";// 2. LOG_FILEconst LOG_FILE = join(import.meta.dirname,"mcp-server.log",);// 3. formatMessagefunction formatMessage(level: string,message: string,data?: unknown,): string {const timestamp = new Date().toISOString();const dataStr = data? `\n${JSON.stringify(data, null, 2)}`: "";return `[${timestamp}] [${level}] ${message}${dataStr}\n`;}// 4. loggerexport const logger = {log(message: string, data?: unknown) {const logMessage = formatMessage("INFO",message,data,);appendFileSync(LOG_FILE, logMessage);},// ...};
- 我们使用
appendFileSync同步写入文件。 - 定义日志文件路径。
- 定义格式化消息的函数。
- 导出一个 logger 对象,其中包含
log方法,用于写入日志文件。还可以导出其他方法,例如error,warn等。
这样就能把日志写入文件,而不会干扰 MCP 协议。
一种可能的替代方案:Notifications
一位读者提醒我,MCP 确实存在 notifications 概念,只是它藏在 documentation.
理论上,这允许 Server 向 Client 发送消息。
不过具体实现取决于 Client,因此能否利用这套机制记录日志仍是开放问题。
如果有人使用过 notifications 记录日志,欢迎在 Discord.
另一种可能的替代方案: stderr
有人告诉我,把日志写入 stderr ——也就是使用 console.error ——不会被 MCP Client 读取。
这意味着可以把运行 MCP Server 的进程 tee 运行 MCP Server 的进程,并把日志输出到文件。
我很快会更深入地介绍这一点,暂时把它视为 TODO。
总结
在 MCP Server 中记录日志时,有两种选择:
- 使用不会干扰
stdout的 Transport,例如sse. - 写入
.log文件。