19 · MCP Server把 N×M 变成 NM第四周我做了个 MCP Server把我那套 API 文档检索包成了两个 tool。做完之后我最想讲的不是它怎么用而是它解决的那个连接问题以及我在 Windows 上被一个 print 语句坑了半小时的事。一、MCP 到底解决什么一句话把 N×M 的连接问题变成 NM。没有 MCP 的时候有 N 个 AI 应用Claude Desktop、Cursor、你自己写的壳有 M 个数据源 / 工具数据库、文档库、内部 API每个应用要接每个数据源得写 N×M 个适配器。有了 MCP大家都说同一套协议应用只需要实现一次clientN 次数据源只需要暴露一次serverM 次总共 NM。这不是什么新思想——USB、LSP语言服务器协议都是同一个套路。标准化接口的价值不在接口本身在它把组合爆炸变成了线性增长。二、三个角色很多人搞混MCP 有三个角色搞清楚它们一半的困惑就没了角色是什么我这儿的对应Host面向用户的应用内嵌 client 做编排没有Claude Desktop / Cursor 才是Client跑在 Host 内部连 server 的那层scripts/mcp_smoke.py验证用Server暴露 tool / resource 的进程mcp_server/常见误解以为自己写了个 Agent 就是 Host。不是——我的app/里那个 Agent 是另一条链路工具是硬编码的根本没走 MCP。所以严格说我本地只有 Server 和一个用来验证的 Client没有 Host。Host 是「谁拉起我的 server谁就是」。我用官方 SDK 写的验证客户端长这样frommcpimportClientSession,StdioServerParametersfrommcp.client.stdioimportstdio_clientasyncwithstdio_client(params)as(read,write):asyncwithClientSession(read,write)assession:awaitsession.initialize()awaitsession.list_tools()awaitsession.call_tool(search_api_docs,{...})这跟 Claude Desktop 内部那个 client 用的是同一套 API。所以它能跑通就证明我的 server 能被真实 Host 装上——不需要我真的去装一个 Claude Desktop。三、stdio 下stdout 是协议独占通道这是我踩的最实在的一个坑。MCP 的 stdio 传输client 起一个子进程通过stdin/stdout说 JSON-RPC。所以 server 的 stdout 不能再干别的事。而我的检索链路里有print()调试输出。在 WindowsGBK 编码下这些输出混进 JSON-RPC 流client 直接解析失败。我盯着「server 起不来」查了半天最后发现是自己的 print 污染了协议流。修法是加一个shield_stdout()把sys.stdout重定向到 stderr让所有 print 走错误流。defshield_stdout():sys.stdoutsys.stderr# 协议流独占print 一律走 stderr这个坑的本质当你选了 stdio 作为传输层你就放弃了 stdout 的使用权。这不是 bug是协议设计的约束——只是文档不会用大字提醒你。四、Tools 和 Resources 的区别在「谁发起」这是我读完规范后觉得最值得记的一条Tools模型决定要不要调模型发起Resources应用决定要不要读应用发起比如用户选中了一段文本区分它们的意义在于权限模型不一样。Tools 是「让模型干活」风险更高所以要标readOnlyHint让 Host 知道它安不安全。我这两个 tool 都是只读检索所以都标了readOnlyHintTrue。这不是装饰—— Host 可以据此决定要不要弹确认。五、发布时发现的真问题准备把 server 发到 GitHub 的时候我发现一件事# mcp_server/server.pyfromapp.ragimportAskPipelinefromapp.retrieval.pipelineimportRetrievalPipeline它依赖主项目的检索链路。这意味着我不能只把mcp_server/单独发成一个仓库——别人 clone 下来装完依赖照样跑不起来缺app/和向量库数据。这个发现让我改了发布方案整仓发布而不是单独发 server 目录。顺带说一句我对工具数量的取舍只暴露2 个 tool 1 个 resource。不是能力不够是刻意收窄。工具越多模型越容易选错第 17 篇里「工具选择错误」那类失败。在 MCP 这种「别人来装」的场景里宁可少而准不要多而全。六、一句话MCP 的技术门槛不高——它就是一个 JSON-RPC 加一层约定。它的价值在生态位你把自己的能力包成一个标准 server就等于让所有支持 MCP 的 Host 都能直接装。一次实现到处可用。而它的坑也都在工程细节里stdout 归协议、Python SDK 是 snake_caseserver_info不是serverInfo、入口不能依赖工作目录Host 拉起子进程时 cwd 不由你控制。这些细节只有真正跑一遍才会遇到。上一篇18 · 四道闸门怎么让 Agent 别乱来下一篇20 · trace 是 Agent 时代的迭代曲线