AIHero
    04 / 06模型上下文协议教程 · 阅读约 3 分钟

    日志记录:MCP 中一个巨大的隐患

    避免在 MCP Server 中使用 console.log,以免客户端出问题。请使用自定义 logger 或 `sse` Transport,在不干扰协议的情况下记录日志。

    Matt Pocock
    Matt Pocock
    源代码下一课
    本页目录

    使用 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 的实现,这可能导致崩溃;至少日志会被消费这些消息的程序吞掉。

    为什么 sse 没有这个问题?

    sse Transport 没有这个问题,因为它不使用 stdio 传输消息:

    这意味着可以自由使用 stdout 记录日志。

    在本地完全可以使用 sse ;如果控制台访问对你很重要,可能会更喜欢这种方式。

    如何记录日志

    我更喜欢创建一个把日志写入本地文件的自定义 logger,例如 mcp-server.log。下面是我的实现:

    // 1. appendFileSync
    import { appendFileSync } from "fs";
    import { join } from "path";
    // 2. LOG_FILE
    const LOG_FILE = join(
    import.meta.dirname,
    "mcp-server.log",
    );
    // 3. formatMessage
    function 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. logger
    export const logger = {
    log(message: string, data?: unknown) {
    const logMessage = formatMessage(
    "INFO",
    message,
    data,
    );
    appendFileSync(LOG_FILE, logMessage);
    },
    // ...
    };
    1. 我们使用 appendFileSync 同步写入文件。
    2. 定义日志文件路径。
    3. 定义格式化消息的函数。
    4. 导出一个 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 文件。
    登录以保存进度。