Skip to content

stdio 模式下启动 banner 打到 stdout,污染 MCP 协议导致客户端加载失败 #1204

Description

@davidjackk571-hue

问题描述

mcp_server/server.pyrun_server() 在调用 mcp.run(transport='stdio') 之前,用 print()stdout 打印了约 60 行启动 banner(TrendRadar MCP Server - FastMCP 2.0 及工具列表)。

MCP over stdio 协议要求 stdout 只能承载 JSON-RPC 消息,任何非 JSON 输出都会破坏握手。实测 stdout 输出如下(banner 与响应混杂):

============================================================
  TrendRadar MCP Server - FastMCP 2.0
============================================================
  传输模式: STDIO
  ...
============================================================

{"jsonrpc":"2.0","id":1,"result":{...}}

结果:Claude Code 等严格遵循 stdio 协议的客户端无法解析 initialize 响应,MCP server 加载失败(工具列表里看不到 trendradar 的任何工具)。

根因

run_server() 中 banner 打印未区分传输模式,无条件写 stdout(server.py 约 1135–1201 行)。

附带问题:冷启动耗时约 26 秒

trendradar/ai/client.py 顶部 from litellm import completion 会在 import 阶段触发 litellm 从 raw.githubusercontent.com 拉取模型价格表。在无法直连 GitHub 的环境下,SSL 握手超时(约 25 秒)后才回退本地,导致 server 冷启动约 26 秒,进一步加剧客户端加载失败。建议在文档中提示设置 LITELLM_LOCAL_MODEL_COST_MAP=True,或将 litellm 改为延迟 import。

建议修复

stdio 模式下将 banner 重定向到 stderr(仅 4 行改动):

    # 打印启动信息(stdio 模式下 stdout 是 JSON-RPC 通道,banner 必须走 stderr)
    import sys
    _banner_stdout = sys.stdout
    if transport == 'stdio':
        sys.stdout = sys.stderr
    print()
    print("=" * 60)
    # ... 原有 banner ...
    print()
    sys.stdout = _banner_stdout

环境

  • TrendRadar v6.10.0(MCP server 上报 1.16.0)
  • Python 3.14(项目 .venv)
  • 客户端:Claude Code(stdio transport)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions