MCP 实战:国家统计局数据查询 Server 从开发到发布

文章目录

  • [构建自定义 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 版本)
      • 第一步:项目结构
      • [第二步:配置 package.json](#第二步:配置 package.json)
      • [第三步:确保入口文件有 shebang](#第三步:确保入口文件有 shebang)
      • [第四步:发布到 npm](#第四步:发布到 npm)
      • 第五步:版本更新
    • [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 会:

  1. 自己去搜索引擎查资料
  2. 打开几个网页读内容
  3. 整理、归纳、写成报告
  4. 调用邮件 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

wdsdfwdsJSON 数组先序列化、再 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 的空节点
  • 交叉查表,把 A0101012025D387911.3 拼装成人话

每一步单独看都不难,合在一起又要做正确,交给实时推理的模型,就是在赌运气。


结论很清晰:

国统局 API 的这四个特点------复杂编码、树形索引、时间戳校验、嵌套响应------凑在一起,完美构成了"不适合 LLM 直接调用"的典型案例。

我们需要一个中间层,把这四个坑全部填平,对外只暴露一个干净的工具接口。

这个中间层,就是我们接下来要亲手写的:国家统计局 MCP Server

Agent 只需要说一句:

search_indicator(keyword="GDP", time_range="LAST6")

剩下的脏活,全交给 Server。


六、动手写:国家统计局 MCP Server

理论讲完了,开始写代码。

我们的目标是写一个 Python 脚本 nbs_mcp_server.py,它做两件事:

  1. 对内:封装国统局 API 的所有复杂性(编码、时间戳、解析......)
  2. 对外:通过 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,直接一行命令即可使用:

bash 复制代码
npm 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 连接,不需要手写配置文件。

方式一:通过界面添加

  1. 打开 OpenClaw,进入 Settings → MCP Servers

  2. 点击 Add Server

  3. 填写以下信息:

    Name: 国家统计局数据
    Command: npx
    Args: -y national-stats-mcp

  4. 点击 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

  1. 打开 smithery.ai,用 GitHub 账号登录

  2. 点击右上角 Publish Server

  3. 输入你的 GitHub 仓库地址,例如:

    复制代码
    https://github.com/你的用户名/national-stats-mcp
  4. Smithery 会自动读取 smithery.yaml,展示预览信息

  5. 确认无误后点击 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
相关推荐
开开心心就好1 小时前
Word批量转PDF工具,仅转换不合并很实用
java·前端·人工智能·edge·pdf·语音识别·模块测试
arvin_xiaoting1 小时前
OpenClaw 完全指南(03):飞书集成——打造团队 AI 助手
人工智能·飞书
孫治AllenSun2 小时前
【redis】redis重新创建集群
前端·javascript·redis
美狐美颜sdk2 小时前
实时美颜滤镜卡顿怎么办?美颜sdk滤镜特效开发优化方案
人工智能·深度学习·计算机视觉·音视频·美颜sdk·视频美颜sdk·美狐美颜sdk
zhensherlock2 小时前
Protocol Launcher 系列:一键唤起 VSCodium 智能 IDE
javascript·ide·vscode·typescript·开源·编辑器·github
Data_Journal2 小时前
如何将网站数据抓取到 Excel:一步步指南
大数据·开发语言·数据库·人工智能·php
HelloWorld1024!2 小时前
Pytorch1 PyTorch 官方 QuickStart 超详细笔记|
人工智能·pytorch·笔记
小程故事多_802 小时前
OpenClaw 实战|多 Agent 打通小红书:数据收集 + 笔记编写 + 自动发布一步到位
人工智能·笔记·aigc
Olafur_zbj2 小时前
【AI】深度解析OpenClaw智能体循环(Agentic Loop):底层运行机制、ReAct演进与多智能体协同架构
人工智能·react.js·架构·agent·openclaw