ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

自己动手写一个 MCP 服务器:给 ZCode 造专属工具,5 步上线(附可抄代码)

自己动手写一个 MCP 服务器:给 ZCode 造专属工具,5 步上线(附可抄代码) 看完你能带走:判断该不该自己写的三个问题、一个 40 行就能跑通的 MCP 服务器完整代码(新旧两代 SDK 写法都实测通过)、接入 ZCode 的配置模板、验收对话、调试五步清单,以及自写服务器的 4 条安全红线。6 个模板全部可直接照抄,建议先收藏再看。 开写之前:三个问题,决定你要不要自己动手本系列早前写过 MCP 接入:装现成服务器,填配置,就能让 AI 查数据库、开浏览器。那为什么还要自己写?因为最值钱的工具,往往是你自己业务里那个——内部系统、私有接口、团队里重复了八百遍的固定流程,官方仓库里永远不会有。但能写不等于该写。动手前先过三问(模板 1):问题一:要连的东西,有现成的 MCP 服务器吗? 官方仓库 modelcontextprotocol/servers 和社区先找一遍, 有 → 直接用,别重复造轮子。 问题二:ZCode 的内置能力(读写文件、跑命令、浏览器)够不够? 够 → 这就是一句提示词的事,封装纯属浪费。 问题三:这件事高频、重复、流程固定吗? 是 → 值得封装成工具,一次封装,处处调用。三问过后仍然要写,再往下看。恰好,第三问命中的场景最多:统计表格、查内部 wiki、发布登记、日志巡检……这些活儿天天出现、步骤固定,正是造个按钮给 AI的最佳对象。 五分钟看穿本质:服务器就是个翻译官程序很多人被MCP 服务器这个名字吓住,以为要懂什么框架。拆开看,它就是一个普通程序:ZCode 把它当子进程启动,俩人隔着一根管道用 JSON-RPC 对话。它上报我会哪些工具,AI 决定什么时候调,它执行,把结果还回来。仅此而已。每个工具由四件套组成,而其中三件是自动生成的:工具名和描述:告诉 AI “我是谁、什么时候找我”;参数表:规定 AI 该按什么格式传参;执行函数:你写的业务逻辑——四件套里你唯一要写的。名字、描述、参数表全部由装饰器从代码里自动生成,这就是几十行就能起步的底气。接入之后,一次完整的调用长这样:会话启动时握手一次、把工具清单报上来;之后你说人话,AI 判断该调哪个工具、填什么参数,服务器执行、返回结果,由 AI 转述给你。⚠️版本提醒,先看再写:MCP 官方 Python SDK 迭代很快,写法只差导入两行——旧版(1.26 及更早)用from mcp.server.fastmcp import FastMCP,现行正式版(2.x)用from mcp.server import MCPServer,装饰器用法完全一致。动笔前先pip show mcp确认版本;本文两种版本都实测跑通,代码里两行都给你标出来了。️ 实战:40 行写一个 csv_summary 工具选个真实的场景:团队里天天有人喊帮我统计一下这个表。我们就把CSV 摘要统计封装成工具,以后对 ZCode 说一句话就出结果。按五步节奏走:第 1 步,装环境:pip install mcp[cli] # 官方 SDK,带命令行调试工具 pip show mcp # 看清版本号,决定下一节的导入行第 2 步,写最小实现。完整代码如下,一个文件搞定(模板 2):# server.py —— 最小但完整的 MCP 服务器# 按安装的 SDK 版本二选一(本文两种都实测跑通):frommcp.serverimportMCPServer# SDK 2.x(现行正式版)# from mcp.server.fastmcp import FastMCP # SDK 1.x(旧版)importcsvfrompathlibimportPath mcpMCPServer(csv-tools)# 1.x 用:mcp FastMCP(csv-tools)mcp.tool()defcsv_summary(path:str,column:str)-str:统计 CSV 文件的行数,以及指定数值列的最小/最大/平均值。 Args: path: CSV 文件的路径(建议绝对路径) column: 要统计的数值列名,必须出现在表头里 withPath(path).open(encodingutf-8-sig,newline)asf:rowslist(csv.DictReader(f))ifnotrows:return文件没有数据行ifcolumnnotinrows[0]:returnf列{column}不存在,现有列:{list(rows[0])}values[float(r[column])forrinrows]return(f共{len(rows)}行;{column}列:f最小{min(values):.2f},最大{max(values):.2f},f平均{sum(values)/len(values):.2f})if__name____main__:mcp.run()# stdio 传输:由 AI 客户端以子进程方式启动三个看点:docstring 不是注释,是简历:它会被自动提取成工具描述,AI 靠它决定这个活儿该不该找我。实测里,协议返回的描述就是 docstring 第一行,一字不差;类型注解自动变成参数表:path: str, column: str会被转成 JSON Schema,AI 按格式传参,不用你写一行校验协议的代码;mcp.run()是总开关:stdio 模式下程序自己不带界面,等着 ZCode 来启动和对话。第 3 步,自测——这一步新手最容易跳过,却最能救命。不用接任何 AI,直接把函数当普通函数调(实测输出):python -c from server import csv_summary; print(csv_summary(demo.csv,amount)) 共 6 行;amount 列:最小 39.90,最大 1099.00,平均 337.57函数逻辑错了在这一步就暴露,排错不用两头猜。装饰器返回的还是原函数,所以可以这么直接调——这也是后面所有迭代的基本功:改一行,测一行。 工具设计三原则:描述是写给 AI 看的简历第一个工具跑通后,你会想加第二个、第三个。这时设计水平开始拉开差距:工具名是按钮:动词 名词,一眼能懂。csv_summary通过,handler2别碰运气——AI 选工具靠的就是名字和描述的第一印象;描述决定调用率:写清何时用、何时不用、参数什么含义。描述空泛的工具,AI 永远想不起来调——吃灰的最大原因不在代码,在 docstring;参数少而明确:能用类型注解表达的就别造字符串协议;非法输入在函数开头就拒绝,并返回人话错误信息(上面列不存在,现有列……就是示范,错误信息也会被 AI 读走、用来自我纠正)。 接入 ZCode:三分钟(模板 3、4)配置和接入现成服务器一模一样——毕竟在 ZCode 眼里,自己写的和别人的没有区别。用户级~/.zcode/cli/config.json(全项目可用)或工作区级.zcode/config.json(随 Git 共享给全队)的mcp.servers里加一段(模板 3):{mcp:{servers:{csv-tools:{command:D:/Programs/Python/Python313/python.exe,args:[D:/mcp_server_demo/server.py],env:{}}}}}两个细节,都是实测踩出来的:command必须指向装了 mcp 包的那个解释器。装在虚拟环境里,就指到 venv 里的 python;这里写绝对路径是最稳的写法;脚本路径同样用绝对路径,Windows 下用正斜杠D:/...。然后新开一个会话(配置在会话启动时加载),到设置 → MCP状态页确认 csv-tools 已连接。接着做验收(模板 4):用 csv_summary 工具,统计 D:/mcp_server_demo/demo.csv 的 amount 列AI 会列工具、选中你的 csv_summary、按 schema 填参、调用、转述结果——第一次看到自己写的函数被 AI 当工具使,那个瞬间值得截图留念。验收别只测一次:换个列名、换个不存在的列、换个空文件,把边界都过一遍,再开始日常使用。 调试五步:连不上、调不动,按顺序查(模板 5)自己写的服务器,坑基本都坑在这五处。按顺序查,九成问题五分钟内定位(模板 5):第 1 步:打开 设置 → MCP 状态页,先看它给的错误信息 第 2 步:核对 command——是不是装了 mcp 的那个解释器 (虚拟环境里装的,就指到 venv 的 python,别用全局的) 第 3 步:核对路径——脚本绝对路径,Windows 用正斜杠 第 4 步:自查 stdout 纪律——代码里有没有 print? 调试输出一律走 stderr 或日志文件 第 5 步:改完代码,新开会话再验证(配置与代码都是会话启动时加载)第 4 步值得单独展开,这是 MCP 开发最独特的一个坑:stdout 是协议专线。JSON-RPC 的每一行都从 stdout 走,你随手一句print(调试),等于往专线里塞了私货。更险恶的是,我实测(1.26.0)它不会立刻报错——调试文本悄悄消失在缓冲区里,问题像是随机出现的,排查难度直线上升。正确姿势现成的:FastMCP 的日志本来就写 stderr(实测如此,带时间戳和级别),跟着用就好。官方还备了一个可视化调试器:MCP Inspector,命令mcp dev server.py,会在本地起一个网页调试台,能手动调用工具看原始返回(需要 Node.js 环境,用法以官方文档为准)。适合调试复杂工具时开着用。 安全四条:自己写服务器,你就是守门人接现成服务器时,安全是选型问题;自己写时,安全是手艺问题。四条红线(模板 6 覆盖第二条):最小暴露:工具是给 AI 的按钮,按钮越多,AI 的操作面越大。别把执行任意命令读写任意文件封装成工具——哪怕你自己用着方便;校验输入:凡是接路径的工具,必须防路径穿越。攻击长什么样?传../../secret.txt就能跳出数据目录读到别处文件。防御只要六行,见下面的模板 6(实测拦截);限时限幅:慢操作设超时,大结果先截断或落盘——一次性给 AI 塞十兆文本,撑爆的是你自己的对话窗口;密钥走 env:配置里的env字段就是干这个的,凭据不进代码、不进会提交 Git 的文件,日志记得脱敏。模板 6:路径穿越防御,六行,实测拦截../越界:frompathlibimportPathdefsafe_path(base_dir:str,user_path:str)-Path:把用户传入的路径锁在 base_dir 里面,越界一律拒绝。basePath(base_dir).resolve()target(base/user_path).resolve()ifnottarget.is_relative_to(base):raiseValueError(越界访问被拒绝)returntarget# 用法:path 参数先过这道闸,再去读文件# p safe_path(D:/data, path)工具以你的身份运行,它能做什么,取决于你给它封了什么。❓ 快问快答Q:用 Python 还是 TypeScript SDK?两个都是官方维护,写法风格接近(装饰器注册工具)。团队主栈是什么用什么;纯内部工具用 Python 上手最快。Q:写好的服务器能分享给团队吗?能,而且这正是它比提示词模板强的地方:脚本提交进 Git,配置放进工作区级.zcode/config.json,队友拉完代码新开会话就能用。更正式的做法是发到内部 PyPI 或起一个 HTTP 传输的共享实例。Q:resources 和 prompts 是什么?MCP 服务器的另外两类能力:资源(把文件/数据暴露给 AI 读)和提示词模板(预置常用问法)。两代 SDK 里都有同名装饰器。先玩明白工具,这两个需要时再看,不冲突。Q:不想让 AI 用某个工具,怎么办?按作用域处理:自己写的,从配置里删掉这段即可;项目共享的服务器,你可以在用户级配置里写一个同名服务器覆盖它(用户级优先于工作区级),或干脆与项目维护者沟通下掉。另一个现实约束要记住:工作区配置声明的服务器会随打开项目自动连接——来路不明的项目别随便打开。Q:什么时候用 HTTP 传输?stdio 是本地子进程,最简单,默认选它;当工具要跨机器共享、或连接云端服务时,再考虑 HTTP。本文的本地工具用 stdio 就够。 写在最后从会用工具到会造工具,是 AI 编程的一道分水岭。造完这个 40 行的小东西,你会发现:AI 的能力边界,从此由你的业务定义——内部系统、私有流程、祖传脚本,都可以变成 AI 手里顺手的工具。按老规矩,三个动作起步:用三问筛出你业务里最值得封装的那件事;把 40 行最小服务器跑通;接入 ZCode 做一次真对话验收。跑通第一个之后,第二、第三个工具就是复制粘贴改函数的事了。️ 声明:本文为个人使用经验总结,属第三方独立教程,非 ZCode 官方文档;“ZCode”MCP相关名称与商标归其权利人所有;SDK 版本迭代较快,API 以你安装版本的官方文档为准;全部插图与示例代码均为本文原创,代码在新旧两代 SDK(1.26 / 2.3)上实测通过。 你的团队里,哪个重复流程最该被封装成 MCP 工具?评论区聊聊,我帮你看看边界怎么划。系列下一篇,回到开发环境方向,写「IDEA 装完必改的 10 个设置」。
返回列表