mcp协议实战:从0构建第一个mcp server,把本地工具接进AI工作流

发布时间:2026/10/7 19:36:55

mcp协议实战:从0构建第一个mcp server,把本地工具接进AI工作流 1. 从 function call 到 mcp 协议本地脚本为什么接不进 AI 工作流你可能已经用过大模型的 function call在请求里塞一段 JSON Schema模型返回一个函数名和参数你在自己的代码里判断、执行、再把结果拼回对话。这套流程跑一个脚本没问题但一旦工具多起来就乱了——每个客户端都要重新写一遍工具描述、参数校验、调用分发换个 AI 客户端就得推倒重来。mcp 协议Model Context Protocol想解决的就是这个中间层问题。它把「大模型要调用的能力」抽象成 mcp server把「发起调用的那一方」抽象成 mcp client也就是 host比如 Cline、Claude Code、各种 IDE 插件。server 负责暴露 tool、prompt、resourceclient 负责发现并调用它们。两边通过一套标准协议通信模型不需要知道你的脚本是 Python 还是 Node也不需要知道你查的是金价还是天气。一句话概括mcp 协议是 AI 客户端和本地工具之间的 USB 接口。你写一次 server所有支持 mcp 的客户端都能直接插上用。这篇文章面向零基础带你从 0 构建第一个 mcp server把本地脚本接进 AI 工作流。我会用一个「查询指定日期金价」的最小示例把注册、工具暴露、调用链路完整跑一遍最后接到 Cline 里做一次真实调用验证。全程可复制踩过的坑我也会标出来。适合谁看写过一点 Python、想让 AI 客户端调用自己本地脚本、但还没搞懂 mcp server 到底怎么落地的人。读完你应该能独立写出第二个、第三个 server。在动手前先说清楚调用链路这样后面每一步你都知道自己在干嘛本地脚本你的业务逻辑→ 被 mcp server 包装成 tool → server 通过 stdio 或 HTTP 暴露 → mcp clienthost读取 server 配置 → 模型决定调用哪个 tool → client 转发调用 → server 执行脚本 → 结果回传模型 → 模型组织成自然语言回答。整条链路里模型只负责「决定调什么」真正的执行永远在你的本地环境。这也是 mcp 协议在开发者里流行的原因数据不出本地能力却能被模型调度。2. 环境准备与 TaoToken 前置mcp server 开发环境搭建与 API Key 获取写 mcp server 之前先把两件事准备好Python 运行环境和模型 API Key。前者是 server 跑起来的基础后者是后面接客户端时模型调用的凭证。2.1 Python 环境与 mcp SDK 安装我建议用 conda 单独建一个环境避免和系统 Python 打架。Python 版本选 3.11 比较稳mcp SDK 对 3.10 支持都正常。conda create -n mcp-env python3.11 -y conda activate mcp-env激活后装 mcp SDK 和 httpx示例里要发 HTTP 请求pip install mcp[cli] httpxmcp[cli]里的 cli 很关键它自带一个mcp dev调试命令后面不用自己写测试客户端就能验证 tool 能不能跑。装完可以用下面这条确认版本pip show mcp如果输出里有 Name: mcp 和对应的 Version说明装好了。Node.js 不是必须的但如果你后面想用某些基于 Node 的 mcp client 或工具可以顺手装上这里不展开。2.2 获取模型 API Keymcp server 本身不依赖模型但你要把它接进 AI 客户端客户端得能调模型。这里我用 TaoToken 作为模型接入方它的接口兼容 OpenAI 风格配置起来省事。先到官网注册并进入控制台在 API Keys 页面创建一个 Key。地址是官网入口https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentAPI Keys 管理https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite创建后把 Key 复制下来形如sk-xxxx只显示一次丢了就重新建。这个 Key 后面填到 Cline 的模型设置里。Base URL 用https://taotoken.net/api注意这个地址不加 UTM 参数直接填就行。Model ID 按你实际要用的模型填比如claude-sonnet-4-5或gpt-4o这类具体以控制台模型列表为准。注意API Key 属于敏感凭证不要写进会提交到 Git 的代码里。本地测试可以用环境变量或者放在客户端的配置界面里。到这里前置就齐了一个能跑 Python 的 conda 环境一个可用的模型 Key。接下来写 server。3. 可复制配置编写第一个 mcp server 并暴露 tool这一节是核心。我们写一个main.py它做两件事定义一个查询金价的异步函数然后用mcp.tool()把它注册成 mcp tool。3.1 最小 server 代码把下面代码保存到d:/mcp-learn/main.py路径按你自己的来from typing import Any import httpx from mcp.server.fastmcp import FastMCP mcp FastMCP(gold-price) async def make_gold_price_request(date: str) - dict[str, Any] | None: url https://www.sge.com.cn/graph/Dailyhq payload {instid: Au99.99} headers { Accept: text/html, */*; q0.01, Content-Type: application/x-www-form-urlencoded; charsetUTF-8, Origin: https://www.sge.com.cn, Referer: https://www.sge.com.cn/sjzx/mrhq, User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36, X-Requested-With: XMLHttpRequest, } async with httpx.AsyncClient() as client: try: response await client.post(url, datapayload, headersheaders) response.raise_for_status() data_json response.json() data data_json[time] query_price None for d_price in data: if d_price[0] date: query_price d_price break if not query_price: return None cols [date, open, close, low, high] return {col: query_price[i] for i, col in enumerate(cols)} except Exception as e: print(e) return None mcp.tool() async def get_gold_price_of_date(date: str) - str | dict: 查询指定日期的黄金价格date 格式为 YYYY-MM-DD data await make_gold_price_request(date) if not data: return Unable to fetch gold price for this date. return data if __name__ __main__: mcp.run(transportstdio)几个关键点解释一下FastMCP(gold-price)创建了一个 server 实例名字叫 gold-price客户端里会看到这个名字。mcp.tool()是注册装饰器。被它装饰的函数会自动暴露成一个 tool函数名就是 tool 名docstring 就是 tool 描述——模型靠这个描述决定要不要调用。所以 docstring 一定要写清楚参数格式我这里标了YYYY-MM-DD。mcp.run(transportstdio)表示用标准输入输出通信。stdio 是最简单的传输方式客户端启动这个进程通过 stdin/stdout 交换 JSON-RPC 消息。本地开发基本都用它。3.2 用 mcp dev 调试写完先别急着接客户端用官方调试工具验证 tool 能不能被正确发现和调用d: cd mcp-learn conda activate mcp-env mcp dev main.py执行后它会启动一个本地调试界面默认在浏览器打开你能看到 Tools 列表里有get_gold_price_of_date点进去填个日期比如2024-11-01点 Run右侧会返回价格字典。这一步跑通说明 server 本身没问题。3.3 客户端配置片段接下来把 server 注册到支持 mcp 的客户端。以 Cline 为例它的 mcp 配置是一个 JSON 文件路径通常在 VS Code 的全局存储里你也可以在 Cline 的 MCP Servers 面板点「Configure MCP Servers」直接打开。配置内容如下{ mcpServers: { gold-price: { command: D:\\app\\anaconda3\\envs\\mcp-env\\python.exe, args: [ D:\\mcp-learn\\main.py ], disabled: false, autoApprove: [] } } }三件套对照一下command指向你 conda 环境里的 python.exe 绝对路径不是系统的 python。用conda activate mcp-env后where python可以查到。args你的 main.py 绝对路径。disabled / autoApprovedisabled 设 false 表示启用autoApprove 留空表示每次调用都要你手动批准安全起见先别自动批准。保存后回到 Cline 的 MCP Servers 面板能看到 gold-price 变成绿色已连接说明 server 启动成功。4. 验证请求一次完整的 mcp tool 调用链路配置好之后来跑一次真实调用把整条链路走通。4.1 在 Cline 里发起提问打开 Cline 对话框输入类似这样的问题帮我查一下 2024-11-01 的黄金价格模型会先判断需要调用工具然后 Cline 会弹出批准提示显示要调用的 tool 是get_gold_price_of_date参数是{date: 2024-11-01}。点 Approve。4.2 观察调用过程批准后你会看到几个阶段第一Cline 把调用请求通过 stdio 发给 server 进程。第二server 执行get_gold_price_of_date内部发 HTTP 请求到上金所接口拿到数据。第三server 把结果以 JSON-RPC 响应返回给 Cline。第四Cline 把结果喂给模型模型组织成自然语言回答。最终你会看到类似「2024-11-01 黄金 Au99.99 开盘价 xxx收盘价 xxx最高 xxx最低 xxx」的回答。如果接口当天没数据会返回「Unable to fetch gold price for this date.」。4.3 用 mcp dev 单独验证如果客户端里没跑通先用mcp dev main.py单独测 tool。在调试界面里点 Run看返回。这一步能排除是 server 逻辑问题还是客户端配置问题。4.4 换一个 tool 再验证为了确认注册机制是通用的你可以再加一个 tool比如返回当前服务器时间from datetime import datetime mcp.tool() async def get_server_time() - str: 返回当前服务器时间 return datetime.now().strftime(%Y-%m-%d %H:%M:%S)保存后重启 server在 Cline 面板点重启再问模型「现在服务器几点」它会调用get_server_time。两个 tool 都能被正确发现和调用说明你的 server 注册和暴露机制没问题。到这里从本地脚本到 AI 工作流的完整链路就跑通了。你会发现 mcp server 的实现和模型完全解耦——server 只管暴露能力模型只管决定调用中间靠协议对齐。5. 本篇常见错排查401、local proxy failed、reading choices 报错怎么解实际配置时最容易卡在几个报错上我按出现频率排一下。5.1 401 Unauthorized这个报错通常出现在客户端调模型时不是 mcp server 本身的问题。原因一般是 API Key 填错、过期或者 Base URL 写错。排查顺序先确认 Key 是完整的sk-开头字符串没有多余空格再确认 Base URL 是https://taotoken.net/api不要多加/v1或漏掉最后到控制台看 Key 是否被禁用或额度耗尽。改完保存重启客户端。5.2 local proxy failed / connection refused这个报错一般和 mcp server 进程启动失败有关。常见原因command 路径写错。比如你填了系统 python 而不是 conda 环境里的 python导致mcp模块找不到。用where python在激活环境后确认绝对路径。args 路径里有中文或空格没转义。Windows 下路径用双反斜杠\\或者用正斜杠/。server 代码有语法错误进程启动就崩了。先在命令行手动跑python main.py看有没有报错。stdio 模式下它不会输出东西但如果有异常会打印堆栈。5.3 reading choices / unexpected end of JSON这个报错通常出现在模型返回流被中断时。可能原因网络不稳定导致流式响应断开或者客户端配置的模型 ID 不存在服务端返回了非预期格式。先确认 Model ID 和控制台模型列表一致。再检查网络重试一次。如果持续出现换一个模型 ID 试试排除是单个模型的问题。5.4 OAuth 相关报错有些客户端在首次连接时会走 OAuth 流程。如果你看到 OAuth 报错通常是客户端缓存了旧的凭证。到客户端的账号设置里退出登录重新授权一次。mcp server 本身不涉及 OAuth这个报错和 server 无关。5.5 tool 列表为空配置显示已连接但模型说没有可用工具。检查两点server 代码里mcp.tool()装饰器有没有漏docstring 是不是空的。有些客户端对没有描述的 tool 会过滤掉。补上描述重启 server。5.6 调用返回 None 或空tool 被调用了但返回空。看 server 端日志mcp dev界面或命令行输出。示例里金价接口如果当天没数据会返回 None这是正常的。如果是其他异常print(e)会打出具体错误按错误改。排查的核心思路先分层确认是 server 问题还是客户端问题。mcp dev能跑通就是客户端配置问题跑不通就是 server 代码问题。分层之后问题范围就小很多。6. 把 mcp server 接进长期工作流从单次调用到 Coding Plan跑通第一个 server 之后你可能会想把它用得更重——比如让 AI 客户端在写代码时自动调用你的本地工具或者把多个 server 串起来做 Agent 流程。这时候单次调用就不够了需要考虑稳定性和额度。如果你打算长期把 mcp server 接进编码工作流可以了解下 Coding Planhttps://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite它适合需要持续调用模型、跑 Agent 任务的场景。配合你已经写好的 mcp server模型负责调度server 负责执行本地能力两边各司其职。另外两个常用入口也放这里按需取用模型对话体验https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentmodel-chatutm_campaignrewrite接入文档https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite回到 mcp server 本身给你几个继续深入的方向。第一把 tool 的返回值结构化比如返回 JSON 而不是字符串模型理解更准。第二用 resource 暴露本地文件让模型能读取你的项目文档。第三用 prompt 模板封装常用指令减少每次输入的重复。第四把多个 server 组合一个查数据、一个写文件、一个跑命令模型自己编排。我自己的经验是第一个 server 跑通后第二个会快很多因为注册、调试、配置这套流程是复用的。真正花时间的是想清楚「哪些本地能力值得暴露给模型」——暴露太多会干扰模型判断暴露太少又不够用。从高频、边界清晰的小工具开始比如查时间、读配置、跑测试比一上来就接复杂业务稳得多。最后提醒一句mcp server 跑在你本地权限就是你的权限。autoApprove 别乱开尤其是涉及文件写入和命令执行的 tool手动批准虽然麻烦但安全。
延伸阅读

更多相关文章

2026/10/7 20:26:59

VMware虚拟机连接PLC全攻略:有线/无线桥接设置与网络排查

做自动化调试这些年,碰到最多的问题之一,就是同事抱着笔记本跑到现场,打开VMware虚拟机里的博途,在线扫描半天,设备列表空空如也。很多人第一反应是PLC挂了,其实绝大多数情况下,是虚拟机的网络方…

2026/10/7 20:26:59

AI Agent技能体系实战:从设计到GKE部署的完整指南

1. 从“skills”这个标题说起:它到底在解决什么问题第一次看到“skills”这个标题,很多人会以为是某个招聘网站上的技能标签,或者是一份简历里的能力清单。但结合热搜词里反复出现的 Agent Skills、Google Cloud、GKE、Genkit、codex skills、…

2026/10/5 6:32:56

Jev+Agent接管浏览器:browser-use实战与jev-ultrafast性能优化

1. 从“Jev”说起:为什么我要把Agent接进浏览器“Jev”这个词最近在圈子里出现的频率越来越高,很多人第一次听到会以为是某个新模型的名字,其实它更像是一种思路——把Jev模型的能力当作底座,通过Agent的方式去接管浏览器&#xf…

2026/10/7 8:18:33

多智能体集群实战:DeepAgents编排、MCP与A2A协议及Skills体系

1. 从"单兵作战"到"集群协同":多智能体编排到底在解决什么问题如果你最近在折腾 Agent 相关的东西,大概率会有一种感觉:单个 Agent 能做的事情,其实很快就摸到天花板了。你给它一个提示词,挂几个工…

2026/10/6 17:46:51

无源低通滤波器设计实战:从RC到LC,手把手教你避开那些坑

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/7 1:05:03

ESP32免重刷固件:浏览器直接修改NVS键值实现WiFi配置更新

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/7 1:05:03

SAP HANA查询结果导出CSV:避开乱码、性能与权限的实用指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/7 1:05:03

数字后端Placement阶段Density与Congestion控制实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑