文章目录
- [构建自定义 MCP 服务器:从理论到实战](#构建自定义 MCP 服务器:从理论到实战)
-
- [一、目前 AI 想查个数据,有多难?](#一、目前 AI 想查个数据,有多难?)
- [二、我们现在的 AI 应用,到底是怎么用的?](#二、我们现在的 AI 应用,到底是怎么用的?)
-
- [2.1 三种主流使用方式](#2.1 三种主流使用方式)
- [2.2 AI Agent 到底是什么?](#2.2 AI Agent 到底是什么?)
- [2.3 工具调用:Agent 的"手"](#2.3 工具调用:Agent 的"手")
- [三、让模型用 API,有两种方式](#三、让模型用 API,有两种方式)
-
- [方案一:提示词硬塞(Prompt Engineering)](#方案一:提示词硬塞(Prompt Engineering))
- [方案二:MCP Server(正确方式)](#方案二:MCP Server(正确方式))
- [四、MCP 的三个角色,一台戏](#四、MCP 的三个角色,一台戏)
-
- [MCP 的工作流程,完整走一遍](#MCP 的工作流程,完整走一遍)
- [五、为什么国家统计局 API 特别需要 MCP?](#五、为什么国家统计局 API 特别需要 MCP?)
- [六、动手写:国家统计局 MCP Server](#六、动手写:国家统计局 MCP Server)
-
- [6.1 先把环境准备好](#6.1 先把环境准备好)
- [6.2 整体结构](#6.2 整体结构)
- [6.3 完整代码](#6.3 完整代码)
- [六、动手写:国家统计局 MCP Server](#六、动手写:国家统计局 MCP Server)
-
- [6.1 如何使用](#6.1 如何使用)
- [6.2 场景 A:在 Claude Desktop 中使用](#6.2 场景 A:在 Claude Desktop 中使用)
- [6.3 场景 B:在 Cursor 中使用](#6.3 场景 B:在 Cursor 中使用)
- [6.4 场景 C:在 HelloAgents 中用代码调用](#6.4 场景 C:在 HelloAgents 中用代码调用)
- [6.5 场景 D:在 OpenClaw 中可视化配置](#6.5 场景 D:在 OpenClaw 中可视化配置)
- [6.6 这个 Server 对外暴露了哪些工具?](#6.6 这个 Server 对外暴露了哪些工具?)
- [6.7 Server 内部做了什么?](#6.7 Server 内部做了什么?)
- [七、发布你的 MCP Server:让全世界都能用](#七、发布你的 MCP Server:让全世界都能用)
- [7.1 发布 Node.js 版本](#7.1 发布 Node.js 版本)
- [7.2 发布 Python 版本](#7.2 发布 Python 版本)
- [7.3 发布到 Smithery(两个版本通用)](#7.3 发布到 Smithery(两个版本通用))
-
- [第一步:准备 smithery.yaml](#第一步:准备 smithery.yaml)
- [第二步:准备 Dockerfile](#第二步:准备 Dockerfile)
- [第三步:提交到 Smithery](#第三步:提交到 Smithery)
- [7.4 两个版本怎么选?](#7.4 两个版本怎么选?)
构建自定义 MCP 服务器:从理论到实战
一、目前 AI 想查个数据,有多难?
想象这样一个场景:
你雇了一个超级聪明的助理(AI Agent),他博览群书、逻辑严密,能帮你分析任何问题。但有一天你问他:
"帮我查一下今年中国的 GDP 是多少?"
他可能会去搜索,然后给你输出一堆数据:
"据我了解,2019年的GDP是xxx。"
时间不是现在的,来源是不明朗的,这就是 AI Agent 的真实困境。聪明不等于万能,大模型的知识截止于训练数据,它无法实时访问外部系统。
二、我们现在的 AI 应用,到底是怎么用的?
在聊 MCP 之前,先退一步看看:今天大多数人在用 AI 做什么,AI 又是以什么形态存在的。
2.1 三种主流使用方式
① 对话式助手(最常见)
打开 豆包、千问、chatgpt,输入问题,得到回答。这是大多数人第一次接触 AI 的方式。用户提问,模型回答,完事。
这个阶段的 AI,本质上是一个极其博学的问答机。它能写代码、总结文章、翻译语言,但它不知道今天的天气,不知道你的日历上有什么,也不知道你的数据库里存着什么。
② 嵌入式 AI 功能
你用的 Notion AI、GitHub Copilot、Office 365 Copilot------这些是把 AI 能力嵌入到具体产品里。AI 在这里扮演的是一个功能增强插件,它能读到你当前文档的内容,但通常也仅限于此。
③ AI Agent(智能体)
这是最近两年真正让行业兴奋的方向。Agent 不只是"回答问题",而是主动完成任务。
你告诉它一个目标,它自己规划步骤、调用工具、处理结果、遇到问题自己想办法,直到任务完成。
比如你说:"帮我调研一下竞品的定价策略,整理成报告发到我邮箱。"
一个真正的 Agent 会:
- 自己去搜索引擎查资料
- 打开几个网页读内容
- 整理、归纳、写成报告
- 调用邮件 API 发送
全程不需要你盯着它,它自己跑完。
2.2 AI Agent 到底是什么?
"Agent"这个词被滥用得很厉害,各种产品都往上贴。我们用一个简单的标准来定义它:
AI Agent = 大模型 + 记忆 + 工具 + 自主规划
缺一不可。光有大模型,那叫聊天机器人。加上工具调用,那叫增强型助手。只有当它能自主拆解目标、决定下一步做什么、用工具执行、根据结果调整计划,才算得上 Agent。
用一个更接地气的比喻:
| 形态 | 类比 |
|---|---|
| 普通大模型 | 百科全书,你翻它才有用 |
| 带工具的模型 | 装了插件的百科全书,能帮你查实时信息 |
| AI Agent | 一个有手有脚的实习生,你给目标,他自己想办法完成 |
Agent 的核心能力循环长这样:
用户给目标
↓
Agent 思考:现在应该做什么?
↓
选择并调用合适的工具
↓
观察工具返回的结果
↓
再次思考:任务完成了吗?还需要做什么?
↓
重复,直到完成
现实中你已经见过很多 Agent 了------Cursor(写代码的 Agent)、Manus(通用任务 Agent)、各种公司内部的自动化流程机器人,本质上都是这套循环。
2.3 工具调用:Agent 的"手"
Agent 能做事,靠的是工具(Tool)。工具是 Agent 与外部世界交互的唯一通道。
没有工具,Agent 只能"说";有了工具,Agent 才能"做"。
工具可以是:
- 搜索引擎(让 Agent 能查实时信息)
- 代码执行器(让 Agent 能跑代码)
- 文件读写(让 Agent 能操作本地文件)
- 任意 API(让 Agent 能调用外部服务)
工具的调用机制,底层依赖的是大模型的 Function Calling 能力:模型不直接"运行"工具,而是生成一段结构化的"调用指令",由外部框架负责真正执行,再把结果塞回给模型。
用户:"今天北京天气怎么样?"
↓
模型思考后输出:
{ "tool": "get_weather", "args": { "city": "北京" } }
↓
框架执行 get_weather("北京"),拿到结果
↓
把结果交还给模型
↓
模型生成最终回答:"北京今天晴,气温 18°C......"
三、让模型用 API,有两种方式
现在回到我们的具体问题:你想让 AI 帮你查国家统计局的数据,怎么做?
主流方案有两种,看起来都能用,但本质上差距巨大。
方案一:提示词硬塞(Prompt Engineering)
最简单粗暴的方式:把 API 文档塞进系统提示词,让模型"自己学会"怎么调用。
系统提示词:
你是一个数据分析助手。你可以访问国家统计局 API。
提示词如下:
- 搜索接口:GET https://data.stats.gov.cn/search.htm?s={关键词}&m=searchdata
- 查询接口:GET https://data.stats.gov.cn/easyquery.htm?m=QueryData&dbcode={数据库代码}
&wds=[{"wdcode":"zb","valuecode":"{指标代码}"}]
&dfwds=[{"wdcode":"sj","valuecode":"{时间范围}"}]
&k1={当前时间戳}
...(几百行文档)...
当用户询问统计数据时,请构造正确的 URL 并告诉用户如何访问。
听起来可行,实际上一团糟。
我们来看看真实情况:
用户:"帮我查最近6个季度的 GDP 走势。"
模型输出:
您可以访问以下 URL 获取数据: https://data.stats.gov.cn/easyquery.htm?m=QueryData&dbcode=hgjd &wds=[{"wdcode":"zb","valuecode":"A010101"}] &dfwds=[{"wdcode":"sj","valuecode":"LAST6"}] &k1=1234567890请在浏览器中打开此链接。
问题来了:
- k1 时间戳是假的------模型不知道"现在"是几点,1234567890 是个固定值,服务器可能拒绝
- URL 编码没做 ------
[{"wdcode"...}]没有 encodeURIComponent,直接放进 URL 会报错 - 模型不能真正"执行"------它只是生成了一串文字,用户还得自己复制去浏览器跑
- 结果无法被模型处理------就算用户手动跑了,得到的 JSON 还得再粘回来让模型分析
这根本不是 Agent,这只是一个会写 URL 的聊天机器人。
提示词方案的硬伤:
| 问题 | 说明 |
|---|---|
| 模型无法真正执行 | 只能生成文本,不能发 HTTP 请求 |
| 状态依赖无法处理 | k1 时间戳、动态 token 等实时参数模型不知道 |
| 上下文窗口浪费 | 几百行 API 文档占满 context,还容易遗漏细节 |
| 错误无法自动恢复 | 请求失败了模型不知道,无法重试或调整 |
| 提示词越写越长 | API 文档一更新,提示词就得跟着改 |
方案二:MCP Server(正确方式)
MCP 的思路完全不同:把 API 的复杂性封装起来,对模型只暴露干净的工具接口。
模型不需要知道 wds 怎么编码,不需要知道 k1 是什么,不需要知道指标树怎么遍历。它只需要知道:
"我有一个工具叫
search_indicator,给它一个关键词,它会返回数据。"
整个过程变成这样:
用户:"帮我查最近6个季度的 GDP 走势。"
↓
模型决定调用工具:
search_indicator(keyword="GDP", time_range="LAST6")
↓
MCP Server 在后台:
调 search.htm 拿到指标 code(A010101)
构造正确的 wds/dfwds JSON
URL 编码
加上当前毫秒时间戳 k1
发送请求,处理响应
过滤 hasdata=false 的节点
整理成干净的数据结构
↓
返回给模型:
[
{ "时间": "2025年第四季度", "GDP": 387911.3, "单位": "亿元" },
{ "时间": "2025年第三季度", "GDP": 354106.2, "单位": "亿元" },
...
]
↓
模型生成分析:"近6个季度GDP整体呈上升趋势......"
模型全程只做它最擅长的事:理解意图、选择工具、分析结果、生成回答。脏活全扔给 MCP Server。
两种方案对比:
| 对比维度 | 提示词硬塞 | MCP Server |
|---|---|---|
| 模型是否真正执行 | ❌ 只生成文字 | ✅ 真实 HTTP 请求 |
| 参数处理 | ❌ 容易出错 | ✅ 封装好,不会出错 |
| 时间戳等动态参数 | ❌ 模型瞎猜 | ✅ Server 自动处理 |
| API 更新维护 | ❌ 改提示词 | ✅ 只改 Server 代码 |
| 错误处理 | ❌ 模型不知道失败 | ✅ Server 可以重试、报错 |
| 上下文占用 | ❌ 大量 token 浪费 | ✅ 只需简短工具描述 |
| 跨 Agent 复用 | ❌ 每个 Agent 重写 | ✅ 任何 MCP 客户端即插即用 |
四、MCP 的三个角色,一台戏
现在你理解了为什么需要 MCP。接下来搞清楚它的架构。
MCP 里有三个角色,用餐厅来理解最直观:
🍽️ 餐厅场景 🤖 MCP 场景
你(顾客) → 你(用户)
服务员(接单、传菜) → Host(Claude Desktop / OpenClaw / HelloAgents)
厨房(真正做菜的地方) → MCP Server(真正执行操作的服务)
-
Host(宿主):你直接打交道的 AI 应用。你跟它说话,它负责理解你的意图,决定要不要调用工具。可以是 Claude Desktop、你自己写的 HelloAgents 程序,或者 OpenClaw 这样的可视化平台。
-
Client(客户端):Host 内部的"传菜员",专门负责跟 Server 通信,按 MCP 协议发送请求、接收响应。你通常看不见他,但他一直在忙。
-
Server(服务器):真正干活的厨房。它接收工具调用请求,执行真实的操作(发 HTTP 请求、读数据库、写文件......),把结果整理好返回给 Client。
关键点:顾客不需要知道厨房用什么锅、几度油温。 你只需要点菜。这种分层设计让每个角色只关注自己该做的事,通过标准协议连接------这正是 MCP 能"一次开发,到处可用"的根本原因。
没有 MCP 的世界: 有 MCP 的世界:
Agent-A ──自定义适配──→ 统计局 API Agent-A ─┐
Agent-A ──自定义适配──→ 天气 API Agent-B ─┼──→ [MCP Server: 统计局]
Agent-A ──自定义适配──→ 数据库 Agent-C ─┘
↘
Agent-B ──重新写一遍──→ 统计局 API ──→ [MCP Server: 天气]
Agent-B ──重新写一遍──→ 天气 API ↗
Agent-B ──重新写一遍──→ 数据库 Agent-A ─┐
Agent-B ─┼──→ [MCP Server: 数据库]
(每个 Agent 都要重复造轮子) Agent-C ─┘
(Server 只写一次,所有 Agent 共用)
MCP 的工作流程,完整走一遍
还是用国家统计局的例子,完整演示一次 MCP 的调用过程:
① 你对 Host 说:"帮我分析一下近两年 GDP 的季度走势。"
② Host 里的大模型思考:
这个任务需要查统计数据,我有一个工具 search_gdp_trend 可以用。
③ Host 通过内置的 MCP Client,向 MCP Server 发送调用请求:
{
"tool": "search_gdp_trend",
"arguments": { "time_range": "LAST8" }
}
④ MCP Server(我们今天要写的那个)收到请求,在后台默默干活:
- 调用 search.htm 搜索 "GDP",拿到指标 code A010101
- 构造 wds/dfwds JSON 并 URL 编码
- 加上当前毫秒时间戳 k1
- 向 easyquery.htm 发送 QueryData 请求
- 解析响应,过滤 hasdata=false 的节点
- 从 wdnodes 里捞出单位"亿元"
- 整理成干净的列表
⑤ MCP Server 把结果返回给 MCP Client:
[
{ "quarter": "2025年第四季度", "value": 387911.3, "unit": "亿元" },
{ "quarter": "2025年第三季度", "value": 354106.2, "unit": "亿元" },
...
]
⑥ 大模型拿到数据,生成最终回答:
"近8个季度 GDP 整体呈上升趋势,2025年第四季度达到
387911亿元,环比增长约9.5%......"
⑦ 你看到结果,满意地点头。
整个过程里,你不知道有 MCP ,模型不知道 URL 怎么编码 ,MCP Server 不知道你问的是什么问题。每一层只做好自己的事,这就是协议分层的美妙之处。
五、为什么国家统计局 API 特别需要 MCP?
前面提到过,国统局 API 完全公开、无需鉴权,理论上任何人都能调。但如果你真的把 API 文档丢给大模型,让它自己去调,你会连续踩四个坑。
坑一:参数编码地狱
查询数据的核心接口长这样:
GET /easyquery.htm
?m=QueryData
&dbcode=hgjd
&rowcode=zb
&colcode=sj
&wds=%5B%7B%22wdcode%22%3A%22zb%22%2C%22valuecode%22%3A%22A010101%22%7D%5D
&dfwds=%5B%7B%22wdcode%22%3A%22sj%22%2C%22valuecode%22%3A%22LAST6%22%7D%5D
&k1=1749123456789
&h=1
wds 和 dfwds 是 JSON 数组先序列化、再 URL 编码的结果。解码后长这样:
json
[{"wdcode":"zb","valuecode":"A010101"}]
大模型生成这串参数时,极容易少个引号、多个空格、忘记编码------任何一个小错误都会导致请求失败,而且服务器返回的错误信息几乎没有任何指引。
坑二:你得先知道"A010101"是什么
valuecode=A010101 是"国内生产总值_当季值"的指标编码。问题是:你怎么知道 GDP 叫 A010101?
答案是:你得先调 getTree 接口,从根节点 zb 开始,递归遍历一棵多层指标树:
getTree(id="zb")
└─ A01 国民经济核算(isParent=true,继续下钻)
└─ getTree(id="A01")
└─ A0101(isParent=true,继续下钻)
└─ getTree(id="A0101")
├─ A010101 国内生产总值_当季值 ✅ 找到了
└─ A010102 国内生产总值_累计值
3 层递归,3 次 HTTP 请求,还要判断 isParent 字段决定要不要继续挖。让大模型实时做这件事,既慢又不可靠。
当然,国统局的搜索接口(
search.htm)可以绕过树遍历,直接返回指标 code------但你得知道这个捷径,还得正确解析report字段里的zb=A010101,再做一次cn=C01 → hgnd的数据库代码映射。对人类来说是小事,对模型来说是额外的出错概率。
坑三:时间戳不能造假
每个 GET 请求都必须带 k1 参数,值是当前毫秒级时间戳。
大模型没有"现在几点"的概念。它可能会生成一个看起来合理的数字,但那是它从训练数据里"猜"出来的------一个几年前的时间戳。服务器检测到时间戳异常,请求可能直接被拒,或者返回缓存的旧数据。
坑四:响应解析是个体力活
就算前三关都过了,拿到响应也还没完:
json
{
"returndata": {
"datanodes": [
{
"data": { "data": 387911.3, "strdata": "387911.3", "hasdata": true },
"wds": [
{ "wdcode": "zb", "valuecode": "A010101" },
{ "wdcode": "sj", "valuecode": "2025D" }
]
}
],
"wdnodes": [
{
"wdcode": "zb",
"nodes": [{ "code": "A010101", "name": "国内生产总值_当季值", "unit": "亿元" }]
},
{
"wdcode": "sj",
"nodes": [{ "code": "2025D", "name": "2025年第四季度" }]
}
]
}
}
你需要:
- 从
wdnodes里建立 code → 单位的映射表 - 从
wdnodes里建立 code → 时间名称的映射表 - 遍历
datanodes,过滤掉hasdata=false的空节点 - 交叉查表,把
A010101、2025D、387911.3拼装成人话
每一步单独看都不难,合在一起又要做正确,交给实时推理的模型,就是在赌运气。
结论很清晰:
国统局 API 的这四个特点------复杂编码、树形索引、时间戳校验、嵌套响应------凑在一起,完美构成了"不适合 LLM 直接调用"的典型案例。
我们需要一个中间层,把这四个坑全部填平,对外只暴露一个干净的工具接口。
这个中间层,就是我们接下来要亲手写的:国家统计局 MCP Server。
Agent 只需要说一句:
search_indicator(keyword="GDP", time_range="LAST6")
剩下的脏活,全交给 Server。
六、动手写:国家统计局 MCP Server
理论讲完了,开始写代码。
我们的目标是写一个 Python 脚本 nbs_mcp_server.py,它做两件事:
- 对内:封装国统局 API 的所有复杂性(编码、时间戳、解析......)
- 对外:通过 MCP 协议暴露几个干净的工具,让任何 Agent 都能直接调用
6.1 先把环境准备好
bash
pip install fastmcp httpx
fastmcp:MCP Server 的 Python 实现,帮我们处理协议层的所有细节httpx:比 requests 更现代的 HTTP 客户端,支持异步
6.2 整体结构
整个脚本分两层:
nbs_mcp_server.py
│
├── NBSClient 类 ← 负责跟国统局 API 打交道,吃掉所有复杂性
│ ├── search() ← 封装 search.htm
│ ├── query_series() ← 封装 easyquery.htm?m=QueryData
│ └── _工具方法们 ← URL编码、时间戳、响应解析
│
└── MCP 工具定义 ← 对 Agent 暴露的干净接口
├── search_indicator() ← 关键词搜索,返回最新值
├── get_trend() ← 查历史时间序列
└── list_databases() ← 查询支持哪些数据库
6.3 完整代码
六、动手写:国家统计局 MCP Server
如果你不想自己从头搭建,我已经把完整的 MCP Server 打包发布到了 npm,直接一行命令即可使用:
bashnpm i national-stats-mcp下面我们先讲怎么用,再聊它内部做了什么。
6.1 如何使用
这个 MCP Server 是 Node.js 实现的,通过标准的 stdio 传输协议运行。只要你的平台支持 MCP(Claude Desktop、Cursor、OpenClaw、HelloAgents......),接入方式都一样:
告诉平台:用这个命令启动我的 MCP Server
bash
npx national-stats-mcp
就这一句。平台会自动启动进程,建立 MCP 连接,发现所有可用工具。
6.2 场景 A:在 Claude Desktop 中使用
Claude Desktop 是目前 MCP 生态最成熟的 Host,配置方式是编辑一个 JSON 文件。
第一步:找到配置文件
| 系统 | 路径 |
|---|---|
| macOS | ~/Library/Application Support/Claude/claude_desktop_config.json |
| Windows | %APPDATA%\Claude\claude_desktop_config.json |
第二步:添加以下配置
json
{
"mcpServers": {
"national-stats": {
"command": "npx",
"args": ["-y", "national-stats-mcp"]
}
}
}
第三步:重启 Claude Desktop
重启后,你会在对话框左下角看到工具图标,点开能看到国统局相关的工具已经就绪。
第四步:直接对话
你:帮我查一下近6个季度 GDP 的走势,并分析趋势。
Claude:好的,我来查询国家统计局的数据......
[调用 search_indicator,关键词="GDP"]
[调用 get_trend,zb_code="A010101", dbcode="hgjd", time_range="LAST6"]
根据国家统计局数据,近6个季度 GDP 走势如下:
| 季度 | GDP(亿元)|
|------|-----------|
| 2025年第四季度 | 387,911.3 |
| 2025年第三季度 | 354,106.2 |
| ... | ... |
整体呈稳步上升趋势,环比增速维持在 8% 左右......
整个过程你不需要知道任何 API 细节,Claude 自动决定调用哪个工具、传什么参数。
6.3 场景 B:在 Cursor 中使用
Cursor 同样支持 MCP,适合在写代码的同时查阅宏观数据做分析。
编辑 ~/.cursor/mcp.json(没有就新建):
json
{
"mcpServers": {
"national-stats": {
"command": "npx",
"args": ["-y", "national-stats-mcp"]
}
}
}
重启 Cursor 后,在 Agent 模式下(Cmd+I 打开)即可直接提问:
你:用 Python 帮我写一个脚本,获取近10年的 CPI 数据并画出折线图。
Cursor:我先查一下 CPI 的指标代码......
[调用 search_indicator,keyword="CPI", database="年度数据"]
找到了,CPI 的指标代码是 A090101,数据库是 hgnd(年度数据)。
现在帮你写代码:
import matplotlib.pyplot as plt
# 数据来自国家统计局,CPI 2015-2024
years = [2015, 2016, ..., 2024]
cpi = [101.4, 102.0, ..., 100.3]
...
6.4 场景 C:在 HelloAgents 中用代码调用
如果你在用 HelloAgents 框架写 Agent,几行代码就能接入:
python
from hello_agents import SimpleAgent, HelloAgentsLLM
from hello_agents.tools import MCPTool
agent = SimpleAgent(
name="宏观经济分析师",
llm=HelloAgentsLLM(),
system_prompt="你是一位专业的宏观经济分析师,擅长解读中国统计数据。"
)
# 通过 npx 启动 national-stats-mcp,自动发现所有工具
stats_tool = MCPTool(
name="national_stats",
server_command=["npx", "-y", "national-stats-mcp"]
)
agent.add_tool(stats_tool)
# 直接提问,Agent 自动调用工具
response = agent.run("帮我分析一下近两年居民人均可支配收入的变化趋势。")
print(response)
运行后,你会看到 Agent 自动完成这个流程:
[Agent 思考] 需要查询居民人均可支配收入数据
[工具调用] national_stats_search_indicator(keyword="居民人均可支配收入", database="年度数据")
[工具返回] 指标:居民人均可支配收入(元),最新值:43377,时间:2024年,zb_code=A0A01,dbcode=hgnd
[工具调用] national_stats_get_trend(zb_code="A0A01", dbcode="hgnd", time_range="2022-2024")
[工具返回] [{"time_name":"2024年","value":43377},{"time_name":"2023年","value":39218},...]
[Agent 生成回答] 近两年居民人均可支配收入持续增长......
6.5 场景 D:在 OpenClaw 中可视化配置
OpenClaw 提供了图形界面来管理 MCP 连接,不需要手写配置文件。
方式一:通过界面添加
-
打开 OpenClaw,进入 Settings → MCP Servers
-
点击 Add Server
-
填写以下信息:
Name: 国家统计局数据
Command: npx
Args: -y national-stats-mcp -
点击 Save,OpenClaw 会自动连接并列出可用工具
方式二:直接编辑配置文件
OpenClaw 的配置文件通常位于:
~/.openclaw/config.json (macOS / Linux)
%APPDATA%\OpenClaw\config.json (Windows)
添加如下内容:
json
{
"mcpServers": {
"national-stats": {
"command": "npx",
"args": ["-y", "national-stats-mcp"],
"description": "国家统计局宏观经济数据查询"
}
}
}
配置好之后,在 OpenClaw 的对话界面里,你可以直接用自然语言查询:
你:2024年各季度 GDP 分别是多少?和 2023 年同期相比增长了多少?
OpenClaw Agent:正在查询国家统计局数据......
2024 年各季度 GDP 对比:
Q1:296,299 亿元(同比 +5.3%)
Q2:316,838 亿元(同比 +4.7%)
Q3:331,892 亿元(同比 +4.6%)
Q4:362,880 亿元(同比 +5.4%)
全年整体保持稳健增长,四季度增速有所回升......
6.6 这个 Server 对外暴露了哪些工具?
安装后,MCP 客户端会自动发现以下工具,你无需记忆,Agent 会自己选择:
| 工具名 | 作用 | 典型使用场景 |
|---|---|---|
search_indicator |
关键词搜索指标,返回最新值和指标 code | "CPI 最新是多少?" |
get_trend |
查询历史时间序列数据 | "近8个季度 GDP 走势" |
list_databases |
列出支持的数据库(年度/季度) | 不确定用哪个数据库时 |
一个完整的对话示例,展示 Agent 如何自动串联多个工具:
用户:"帮我分析 2024 年中国经济的几个核心指标"
Agent 内部流程:
第1步 → search_indicator("GDP", "季度数据")
拿到 zb_code=A010101, dbcode=hgjd
第2步 → get_trend("A010101", "hgjd", "LAST4")
拿到 2024 全年四个季度的 GDP 数据
第3步 → search_indicator("CPI", "年度数据")
拿到 zb_code=A090101, dbcode=hgnd
第4步 → get_trend("A090101", "hgnd", "2024")
拿到 2024 年 CPI 数据
第5步 → 综合以上数据,生成分析报告
用户看到:
一份包含 GDP 走势、CPI 变化的完整经济分析,
数据来源明确标注为国家统计局,数字准确可溯源。
6.7 Server 内部做了什么?
你不需要了解这些细节才能使用,但如果你好奇 MCP Server 是怎么把那些脏活吃掉的,这里做个简单说明。
每次 Agent 调用 get_trend("A010101", "hgjd", "LAST6"),Server 在后台依次完成:
① 把 zb_code 和 time_range 组装成 wds / dfwds JSON 数组
wds = [{"wdcode":"zb","valuecode":"A010101"}]
dfwds = [{"wdcode":"sj","valuecode":"LAST6"}]
② 对两个 JSON 数组做 URL 编码(两层处理)
%5B%7B%22wdcode%22%3A%22zb%22...%7D%5D
③ 生成当前毫秒时间戳
k1 = Date.now() // 如 1749123456789
④ 拼接完整请求 URL 并发送 GET 请求
⑤ 检查响应的 returncode 是否为 200
⑥ 从 wdnodes 建立 code → 单位 / 名称 的映射表
⑦ 遍历 datanodes,过滤 hasdata=false 的空节点
⑧ 把数据整理成干净的 JSON 数组,按时间倒序排列
⑨ 返回给 Agent
Agent 全程只看到步骤①的输入和步骤⑨的输出,中间七步对它完全透明。
这就是 MCP Server 存在的意义:让复杂的事情在正确的地方发生。
七、发布你的 MCP Server:让全世界都能用
写完 Server,下一步是把它发布出去。我们分两条路:
- Node.js 版本 → 发布到 npm + Smithery
- Python 版本 → 发布到 PyPI + Smithery
两条路最终都指向 Smithery------目前最主流的 MCP Server 发布和分发平台,类似于 MCP 生态的"应用商店"。
7.1 发布 Node.js 版本
第一步:项目结构
一个标准的 Node.js MCP Server 发布包,目录结构如下:
national-stats-mcp/
├── src/
│ └── index.ts ← Server 主文件
├── dist/ ← 编译后的 JS(发布时生成)
├── package.json ← npm 包配置(必需)
├── tsconfig.json ← TypeScript 配置
├── smithery.yaml ← Smithery 平台配置(必需)
├── Dockerfile ← 容器配置(Smithery 部署用)
└── README.md ← 说明文档
第二步:配置 package.json
json
{
"name": "national-stats-mcp",
"version": "1.0.0",
"description": "国家统计局宏观经济数据 MCP Server,支持 GDP、CPI、居民收入等指标查询",
"main": "dist/index.js",
"bin": {
"national-stats-mcp": "dist/index.js"
},
"scripts": {
"build": "tsc",
"start": "node dist/index.js",
"dev": "ts-node src/index.ts",
"prepare": "npm run build"
},
"keywords": [
"mcp",
"mcp-server",
"national-statistics",
"china-economy",
"gdp",
"statistics"
],
"author": "你的名字",
"license": "MIT",
"dependencies": {
"@modelcontextprotocol/sdk": "^1.0.0"
},
"devDependencies": {
"typescript": "^5.0.0",
"@types/node": "^20.0.0",
"ts-node": "^10.0.0"
},
"engines": {
"node": ">=18.0.0"
}
}
几个关键字段说明:
bin:让用户可以通过npx national-stats-mcp直接运行prepare:每次npm publish前自动执行编译engines:限制 Node.js 最低版本,MCP SDK 需要 18+
第三步:确保入口文件有 shebang
src/index.ts 第一行必须是:
typescript
#!/usr/bin/env node
这样 npx 才能正确执行它。
第四步:发布到 npm
bash
# 1. 登录 npm(没有账号先去 npmjs.com 注册)
npm login
# 2. 编译 TypeScript
npm run build
# 3. 检查一下会发布哪些文件
npm pack --dry-run
# 4. 发布
npm publish
# 如果包名已被占用,可以用 scope 发布
npm publish --access public
发布成功后,任何人都可以:
bash
# 直接运行(无需全局安装)
npx national-stats-mcp
# 或者全局安装
npm i -g national-stats-mcp
第五步:版本更新
后续迭代时:
bash
# 修复 bug:1.0.0 → 1.0.1
npm version patch
# 新增功能:1.0.0 → 1.1.0
npm version minor
# 破坏性变更:1.0.0 → 2.0.0
npm version major
# 发布新版本
npm publish
7.2 发布 Python 版本
第一步:项目结构
national-stats-mcp-py/
├── national_stats_mcp/
│ ├── __init__.py
│ └── server.py ← Server 主文件
├── pyproject.toml ← Python 包配置(必需)
├── smithery.yaml ← Smithery 平台配置(必需)
├── Dockerfile ← 容器配置(Smithery 部署用)
└── README.md
第二步:配置 pyproject.toml
toml
[build-system]
requires = ["setuptools>=61.0", "wheel"]
build-backend = "setuptools.build_meta"
[project]
name = "national-stats-mcp"
version = "1.0.0"
description = "国家统计局宏观经济数据 MCP Server,支持 GDP、CPI、居民收入等指标查询"
readme = "README.md"
license = { text = "MIT" }
authors = [
{ name = "你的名字", email = "你的邮箱" }
]
requires-python = ">=3.10"
keywords = ["mcp", "mcp-server", "statistics", "china", "gdp"]
classifiers = [
"Programming Language :: Python :: 3",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
]
dependencies = [
"fastmcp>=2.0.0",
"httpx>=0.27.0",
]
[project.urls]
Homepage = "https://github.com/你的用户名/national-stats-mcp-py"
Repository = "https://github.com/你的用户名/national-stats-mcp-py"
"Bug Tracker" = "https://github.com/你的用户名/national-stats-mcp-py/issues"
# 关键:让包可以通过命令行直接运行
[project.scripts]
national-stats-mcp = "national_stats_mcp.server:main"
[tool.setuptools.packages.find]
where = ["."]
include = ["national_stats_mcp*"]
[project.scripts] 这个配置让用户安装后可以直接在终端运行 national-stats-mcp,效果和 npx national-stats-mcp 类似。
第三步:server.py 入口
确保 server.py 里有 main() 函数作为入口:
python
#!/usr/bin/env python3
from fastmcp import FastMCP
mcp = FastMCP(name="nbs-stats-server")
# ... 工具定义 ...
def main():
mcp.run(transport="stdio")
if __name__ == "__main__":
main()
第四步:发布到 PyPI
bash
# 1. 安装发布工具
pip install build twine
# 2. 构建分发包
python -m build
# 会在 dist/ 目录生成 .whl 和 .tar.gz 两个文件
# 3. 先发布到测试环境验证一下(强烈建议)
twine upload --repository testpypi dist/*
# 测试安装
pip install --index-url https://test.pypi.org/simple/ national-stats-mcp
# 4. 确认没问题,发布到正式 PyPI
twine upload dist/*
发布成功后,用户可以:
bash
# 安装
pip install national-stats-mcp
# 运行
national-stats-mcp
# 或者通过 uvx 直接运行(无需手动安装,类似 npx)
uvx national-stats-mcp
第五步:版本更新
Python 版本没有 npm version 这样的快捷命令,需要手动改 pyproject.toml 里的 version 字段,然后重新 build 和 publish:
bash
# 改完版本号之后
python -m build
twine upload dist/*
或者用 bump2version 工具自动化:
bash
pip install bump2version
# 配置 .bumpversion.cfg 后
bump2version patch # 1.0.0 → 1.0.1
bump2version minor # 1.0.0 → 1.1.0
7.3 发布到 Smithery(两个版本通用)
npm 和 PyPI 解决了"怎么安装"的问题,Smithery 解决的是"怎么被发现"的问题。
Smithery 是 MCP 生态的核心分发平台,在这里发布后:
- 用户可以在 Smithery 网站搜索到你的 Server
- Claude Desktop、OpenClaw 等平台可以一键接入
- 你的 Server 会获得一个标准的接入 URL
第一步:准备 smithery.yaml
这是 Smithery 平台识别你的 Server 的核心配置文件,放在项目根目录。
Node.js 版本的 smithery.yaml:
yaml
name: national-stats-mcp
displayName: 国家统计局数据查询
description: >
查询中国国家统计局宏观经济数据,支持 GDP、CPI、居民人均可支配收入
等核心指标的搜索与历史走势分析。无需 API Key,数据实时来自官方数据库。
version: 1.0.0
author: 你的名字
license: MIT
homepage: https://github.com/你的用户名/national-stats-mcp
repository: https://github.com/你的用户名/national-stats-mcp
categories:
- data
- finance
- government
tags:
- china
- gdp
- economics
- statistics
- national-bureau-of-statistics
runtime: container
build:
dockerfile: Dockerfile
dockerBuildPath: .
startCommand:
type: http
tools:
- name: search_indicator
description: 通过关键词搜索指标,返回最新值和指标代码
- name: get_trend
description: 查询指定指标的历史时间序列数据
- name: list_databases
description: 列出支持查询的数据库类型
Python 版本的 smithery.yaml(几乎相同,name 区分一下):
yaml
name: national-stats-mcp-py
displayName: 国家统计局数据查询(Python版)
description: >
查询中国国家统计局宏观经济数据,支持 GDP、CPI、居民人均可支配收入
等核心指标的搜索与历史走势分析。无需 API Key,数据实时来自官方数据库。
version: 1.0.0
author: 你的名字
license: MIT
homepage: https://github.com/你的用户名/national-stats-mcp-py
repository: https://github.com/你的用户名/national-stats-mcp-py
categories:
- data
- finance
- government
tags:
- china
- gdp
- economics
- statistics
- python
runtime: container
build:
dockerfile: Dockerfile
dockerBuildPath: .
startCommand:
type: http
tools:
- name: search_indicator
description: 通过关键词搜索指标,返回最新值和指标代码
- name: get_trend
description: 查询指定指标的历史时间序列数据
- name: list_databases
description: 列出支持查询的数据库类型
第二步:准备 Dockerfile
Smithery 用 Docker 容器来部署你的 Server,两个版本分别准备。
Node.js 版本:
dockerfile
FROM node:20-slim
WORKDIR /app
# 先复制依赖文件,利用 Docker 层缓存
COPY package*.json ./
RUN npm ci --only=production
# 复制编译后的代码
COPY dist/ ./dist/
ENV NODE_ENV=production
ENV PORT=8081
EXPOSE 8081
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
CMD node -e "process.exit(0)"
CMD ["node", "dist/index.js"]
Python 版本:
dockerfile
FROM python:3.12-slim-bookworm
WORKDIR /app
# 先复制依赖,利用缓存
COPY pyproject.toml ./
COPY national_stats_mcp/ ./national_stats_mcp/
RUN pip install --no-cache-dir --upgrade pip && \
pip install --no-cache-dir .
ENV PYTHONUNBUFFERED=1
ENV PORT=8081
EXPOSE 8081
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
CMD python -c "import sys; sys.exit(0)"
CMD ["national-stats-mcp"]
第三步:提交到 Smithery
-
打开 smithery.ai,用 GitHub 账号登录
-
点击右上角 Publish Server
-
输入你的 GitHub 仓库地址,例如:
https://github.com/你的用户名/national-stats-mcp -
Smithery 会自动读取
smithery.yaml,展示预览信息 -
确认无误后点击 Publish,等待构建完成
构建成功后,你的 Server 页面会显示类似这样的接入信息:
✅ national-stats-mcp 已发布
接入方式:
# Claude Desktop / Cursor 配置
{
"mcpServers": {
"national-stats": {
"command": "npx",
"args": ["-y", "national-stats-mcp"]
}
}
}
# 或通过 Smithery 托管 URL 接入(无需本地安装)
https://server.smithery.ai/national-stats-mcp
7.4 两个版本怎么选?
发布了两个版本,用户该用哪个?
| 对比项 | Node.js 版本 | Python 版本 |
|---|---|---|
| 安装方式 | npx national-stats-mcp |
uvx national-stats-mcp |
| 环境依赖 | 需要 Node.js 18+ | 需要 Python 3.10+ |
| 冷启动速度 | 较快 | 略慢(首次下载依赖) |
| 适合人群 | 前端 / 全栈开发者 | Python / AI |