是不是总刷到各种高大上的 MCP 解读,名词满天飞,听着高深莫测,转头就一脸茫然?概念背了不少,却压根不知道这东西能干啥、怎么用?别再云里雾里看热闹了,跟着动手写个天气服务,瞬间吃透 MCP 全貌

一、摘要

Model Context Protocol(MCP,模型上下文协议)是 Anthropic 推出的开源标准化协议,旨在统一 AI 客户端与外部服务的通信规范,解决大模型上下文传递、工具调用、资源读取、提示词复用等场景的生态碎片化问题。当前主流本地 AI 客户端(Claude Code、Trea、Cursor 等)均已原生支持 MCP。

本文从原理 + 实战双维度切入:首先基于 Python 实现一个本地天气模拟 MCP Server,完整落地 MCP 五大核心组件(传输层、Tools 工具、Resources 资源、Prompts 提示词模板、Roots 根目录、Logging 日志);其次讲解 Claude Code、Trea 两大主流客户端的本地 MCP 服务配置流程;最后结合 Claude Code 独有 Skill 能力,演示 MCP + Skill 联动 的综合配置、业务编排与落地使用,帮助读者从零到一吃透 MCP 的设计思想与工程实践。


二、引言

2.1 什么是 MCP?

传统 AI 客户端扩展存在明显短板:不同工具的插件、外部能力、上下文交互逻辑互不兼容,开发者需要为每一款客户端单独开发适配插件,维护成本极高。

MCP 定义了一套基于 JSON-RPC 2.0 的标准化通信协议,架构分为 MCP Client(AI 客户端,如 Claude Code)和 MCP Server(外部能力服务)两层:

  • Client:大模型交互入口,负责接收用户指令、调用远端 MCP 服务、整合结果返回给用户;
  • Server:能力提供方,对外暴露工具、本地资源、预设提示词、目录权限等能力;
  • 通信基础:统一使用 JSON-RPC 2.0 编解码,支持 Stdio、HTTP、SSE、WebSocket 多种传输方式。

2.2 MCP 核心价值

  1. 标准化:一套 MCP Server 可对接所有兼容 MCP 的 AI 客户端;
  2. 能力解耦:大模型逻辑、外部工具、本地文件资源完全拆分;
  3. 权限可控:通过 Roots 目录隔离,限制服务端可访问的本地路径;
  4. 能力丰富:不止工具调用,还支持资源读取、提示词模板、日志推送等全场景。

2.3 本文实战目标

  1. 手写本地天气 MCP Server,全覆盖 MCP 所有核心组件
  2. 完成 Claude Code、Trea 客户端接入配置;
  3. 实现 MCP 能力 + Claude Code Skill 联动编排,落地真实业务场景。

三、MCP 整体架构与核心组件

在动手编码前,先理清 MCP 标准定义的核心模块,这是理解后续代码的关键。

3.1 整体架构

用户指令 → MCP Client(Claude Code/Trea) 
          ↓ JSON-RPC 2.0 + 传输层(Stdio/HTTP)
MCP Server(能力服务)
          ↓
返回工具结果/资源内容/日志 → Client 整合输出给用户

传输层选择:本地客户端(Claude Code/Trea)优先使用 Stdio 标准输入输出,无需端口、网络配置,通过子进程直接通信,是本地 MCP 服务的首选方案。

3.2 MCP 六大核心组件(本文重点演示)

组件 英文名称 核心作用 应用场景
传输层 Transport 定义 Client/Server 通信方式 Stdio(本地)、HTTP/SSE(远程)
工具调用 Tools 对外暴露可被大模型调用的外部函数 查天气、执行命令、数据库查询
资源读取 Resources 向模型提供本地 / 远程静态 / 动态资源 读取本地文档、配置文件、动态文本
提示词模板 Prompts 可复用的预设 Prompt 模板,支持参数渲染 固定话术、场景化提示词
根目录权限 Roots 声明服务端允许访问的本地根路径,做权限隔离 限制文件访问范围,保障本地安全
日志推送 Logging Server 主动向 Client 推送分级日志 服务调试、运行状态监控

本文天气 Demo 会逐个实现以上所有组件,不做简化,完整还原标准 MCP 服务形态。


四、实战:从零编写本地天气 MCP Server

4.1 环境准备

1. 基础环境
  • Python 版本:3.10+(MCP SDK 最低要求)
  • 操作系统:Windows /macOS/ Linux 全支持
2. 安装依赖

使用 MCP 官方 Python SDK(封装了 JSON-RPC、传输层、协议解析,无需手写底层通信):

pip install mcp
3. 项目结构

创建独立文件夹 weather-mcp-server,目录结构极简:

weather-mcp-server/
├── main.py        # MCP 服务主程序(核心代码)
└── weather_doc.txt # 静态资源文件(用于演示 Resources 组件)

4.2 模拟业务数据

我们纯本地模拟天气数据(不调用第三方外网接口),保证服务离线可用。 预设城市天气字典:北京、上海、广州、深圳,包含温度、天气状况、风力。

4.3 完整 MCP Server 代码(main.py)

实现全部六大核心组件

from mcp.server import Server
from mcp.server.stdio import StdioServerTransport
from mcp.types import (
    Tool, TextContent,
    Resource, ResourceTemplate,
    Prompt, PromptArgument,
    LoggingLevel
)
import asyncio

# ===================== 1. 初始化MCP服务与基础数据 =====================
# 创建MCP Server实例,服务名称自定义
app = Server("local-weather-mcp-server")

# 本地模拟天气数据库(离线可用,无外网依赖)
WEATHER_DATA = {
    "北京": {"temp": "22℃", "status": "晴", "wind": "微风2级"},
    "上海": {"temp": "25℃", "status": "多云", "wind": "东风3级"},
    "广州": {"temp": "30℃", "status": "雷阵雨", "wind": "南风4级"},
    "深圳": {"temp": "29℃", "status": "阴", "wind": "无风"}
}

# 静态资源文件路径(用于Resources组件演示)
DOC_FILE_PATH = "./weather_doc.txt"

# ===================== 2. 核心组件1:Roots 根目录权限声明 =====================
# 声明服务端可访问的本地根目录,客户端会校验权限
@app.list_roots()
async def list_roots():
    return {
        "roots": [
            {
                "uri": f"file://{__file__.rsplit('/', 1)[0]}",
                "name": "天气服务根目录"
            }
        ]
    }

# ===================== 3. 核心组件2:Logging 分级日志推送 =====================
# 封装日志工具,向客户端推送日志(info/warn/error)
async def send_log(level: LoggingLevel, message: str):
    await app.send_log_message(
        level=level,
        logger_name="weather-mcp",
        message=message
    )

# ===================== 4. 核心组件3:Tools 工具调用(核心能力) =====================
# 注册工具列表:告诉客户端当前服务提供哪些可调用工具
@app.list_tools()
async def list_tools():
    return [
        Tool(
            name="query_weather",  # 工具名称(客户端调用标识)
            description="查询指定城市的实时天气,支持城市:北京、上海、广州、深圳",
            inputSchema={  # 入参JSON Schema(大模型自动解析参数)
                "type": "object",
                "properties": {
                    "city": {
                        "type": "string",
                        "description": "需要查询天气的城市名称"
                    }
                },
                "required": ["city"]  # 必传参数
            }
        )
    ]

# 工具执行逻辑:客户端触发工具调用时执行
@app.call_tool()
async def call_tool(name: str, arguments: dict):
    await send_log(LoggingLevel.INFO, f"收到工具调用请求:工具={name}, 参数={arguments}")

    if name != "query_weather":
        await send_log(LoggingLevel.ERROR, f"未知工具:{name}")
        return [TextContent(type="text", text="错误:不存在该工具")]

    city = arguments.get("city", "")
    if city not in WEATHER_DATA:
        await send_log(LoggingLevel.WARNING, f"查询未知城市:{city}")
        return [TextContent(type="text", text=f"暂不支持查询【{city}】的天气,仅支持:北京、上海、广州、深圳")]

    # 拼接天气结果
    weather = WEATHER_DATA[city]
    result = f"【{city}】今日天气:{weather['status']},气温{weather['temp']},风力{weather['wind']}"
    await send_log(LoggingLevel.INFO, f"天气查询成功:{result}")
    return [TextContent(type="text", text=result)]

# ===================== 5. 核心组件4:Resources 资源读取(静态+动态) =====================
# 1. 静态资源:读取本地 weather_doc.txt 文件
# 2. 动态资源:根据城市动态生成天气简介(ResourceTemplate)
@app.list_resources()
async def list_resources():
    return [
        # 静态文件资源
        Resource(
            uri=f"file://{DOC_FILE_PATH}",
            name="天气服务说明文档",
            description="MCP天气服务使用规则说明"
        ),
        # 动态资源模板(支持参数渲染)
        ResourceTemplate(
            uriTemplate="mcp://weather/intro/{city}",
            name="城市天气动态简介",
            description="根据城市动态生成天气温馨提示"
        )
    ]

# 读取资源内容
@app.read_resource()
async def read_resource(uri: str):
    await send_log(LoggingLevel.INFO, f"读取资源请求:{uri}")

    # 处理静态文件资源
    if uri.startswith("file://"):
        file_path = uri.replace("file://", "")
        try:
            with open(file_path, "r", encoding="utf-8") as f:
                content = f.read()
            return content
        except Exception as e:
            return f"读取文件失败:{str(e)}"

    # 处理动态资源 mcp://weather/intro/{city}
    if uri.startswith("mcp://weather/intro/"):
        city = uri.split("/")[-1]
        if city in WEATHER_DATA:
            return f"温馨提示:{city}今日{WEATHER_DATA[city]['status']},出行注意合理穿搭。"
        else:
            return f"暂无【{city}】的天气提示"

    return "未知资源URI"

# ===================== 6. 核心组件5:Prompts 提示词模板 =====================
# 注册预设提示词模板(客户端可直接拉取使用,支持参数)
@app.list_prompts()
async def list_prompts():
    return [
        Prompt(
            name="weather_ask_template",
            description="通用天气查询话术模板",
            arguments=[
                PromptArgument(
                    name="user_question",
                    description="用户原始提问",
                    required=True
                )
            ]
        )
    ]

# 渲染提示词模板
@app.get_prompt()
async def get_prompt(name: str, arguments: dict | None = None):
    if name == "weather_ask_template" and arguments:
        user_q = arguments.get("user_question", "")
        prompt_text = f"""
你是专业天气助手,请根据用户提问调用天气工具并友好回答。
用户提问:{user_q}
要求:语言简洁、通俗易懂,补充出行建议。
        """.strip()
        return {"description": "天气查询模板", "messages": [{"role": "user", "content": prompt_text}]}
    return {"description": "无效模板", "messages": []}

# ===================== 7. 传输层:Stdio 启动服务(本地通信核心) =====================
async def main():
    # 使用Stdio传输层:标准输入输出,本地客户端默认通信方式
    transport = StdioServerTransport()
    await app.connect(transport)
    await send_log(LoggingLevel.INFO, "天气MCP Server 已启动,等待客户端连接...")

if __name__ == "__main__":
    asyncio.run(main())

4.4 补充静态资源文件

在同目录创建 weather_doc.txt,写入内容(用于测试 Resources 静态文件读取):

===== 本地天气MCP服务使用说明 =====
1. 支持查询城市:北京、上海、广州、深圳
2. 调用工具:query_weather
3. 可读取资源:服务说明文档、城市动态天气提示
4. 可使用预设提示词模板:weather_ask_template

4.5 核心组件逐模块解析

结合代码,对应前文的 MCP 组件,讲清作用 + 协议逻辑

  1. Transport 传输层 代码中 StdioServerTransport() 是本地 MCP 标配,服务启动后通过标准输入 / 输出和客户端通信,无需开放端口,安全性高、配置简单。

  2. Roots 根目录 list_roots 声明服务端仅能访问当前项目目录,客户端会做路径校验,防止 MCP 服务越权读取本地文件,是 MCP 的安全机制。

  3. Logging 日志 通过 send_log_message 向客户端推送分级日志(INFO/WARN/ERROR),在 Claude Code/Trea 中可直接看到服务运行日志,方便调试。

  4. Tools 工具调用

    • list_tools:向客户端声明工具列表 + 参数规则(JSON Schema),大模型会自动识别工具能力;
    • call_tool:客户端触发工具后执行业务逻辑,返回结构化文本结果; 这是 MCP 最常用的能力,也是大模型 “联网 / 调用外部能力” 的核心。
  5. Resources 资源 分为静态资源(本地文件)动态资源(模板 URI),作用是为大模型补充上下文信息,比如读取配置、文档、动态生成提示文本。

  6. Prompts 提示词模板 复用固定提示词,支持动态参数渲染,避免客户端重复编写 Prompt,统一交互话术。

4.6 本地单独测试服务

直接运行 main.py

python main.py

服务会进入阻塞状态(等待客户端连接),说明 MCP Server 启动正常。


五、主流本地 AI 客户端配置 MCP Server

我们已经完成 MCP 服务开发,接下来分别配置 Claude CodeTrea 两大客户端,接入本地天气 MCP。

5.1 配置 Claude Code(Anthropic 官方终端 / VS Code 客户端)

Claude Code 支持全局 MCP 配置项目局部配置,优先级:项目配置 > 全局配置。

步骤 1:找到配置文件路径
  • 全局配置(所有项目生效): macOS/Linux: ~/.claude/mcp.json Windows: C:\Users\你的用户名\.claude\mcp.json
  • 项目局部配置(仅当前文件夹生效): 在 weather-mcp-server 目录下创建 .claude/mcp.json

若目录 / 文件不存在,手动新建即可。

步骤 2:编写 MCP 配置文件(mcp.json)

核心字段说明:

  • command:Python 解释器绝对路径(必须写绝对路径,防止环境变量问题);
  • args:MCP 服务脚本的绝对路径;
  • env:可选,环境变量配置。

配置模板(通用)

{
  "mcpServers": {
    "local-weather-server": {
      "command": "/usr/bin/python3",  # macOS/Linux 绝对路径
      "args": ["/你的项目路径/weather-mcp-server/main.py"],
      "env": {}
    }
  }
}

Windows 示例

{
  "mcpServers": {
    "local-weather-server": {
      "command": "D:\\Python311\\python.exe",
      "args": ["D:\\weather-mcp-server\\main.py"],
      "env": {}
    }
  }
}
步骤 3:验证接入
  1. 打开终端,进入任意目录,执行 claude 启动 Claude Code;
  2. 输入指令:帮我查北京的天气
  3. Claude Code 会自动发现 MCP 工具,调用 query_weather 并返回结果,同时终端会打印 MCP 服务推送的日志。

5.2 配置 Trea 客户端

Trea 是轻量化本地 AI 客户端,原生兼容 MCP 协议,配置方式分为图形界面配置配置文件配置

方式 1:图形界面配置(推荐新手)
  1. 打开 Trea,进入 设置 → MCP 服务;
  2. 点击「添加服务」,服务名称填写 weather-mcp
  3. 传输类型选择 Stdio
  4. 执行命令:填写 Python 绝对路径;
  5. 启动参数:填写 main.py 绝对路径;
  6. 保存并启用服务,重启 Trea。
方式 2:配置文件配置

Trea MCP 配置文件路径:

  • macOS/Linux: ~/.trea/config.json 配置内容和 Claude Code 格式基本一致,填入 mcpServers 节点即可,保存后重启客户端生效。
验证

在 Trea 对话框输入:查询上海天气,客户端会自动调用 MCP 工具,返回结果。


六、进阶:Claude Code 中 MCP + Skill 综合配置与实战

6.1 先理解:Claude Code Skill 是什么

Skill 是 Claude Code 独有的自定义技能 / 工作流编排能力,本质是可复用的指令脚本 + 交互逻辑

  • MCP:负责底层能力(工具、资源、提示词、日志);
  • Skill:负责上层业务编排(指令拦截、流程串联、话术封装、多能力组合);

二者组合可以实现:用户指令 → Skill 预处理 → 调用 MCP 工具/读取 MCP 资源/使用 MCP 模板 → 整合结果输出

6.2 Skill 目录规范

Claude Code Skill 存放路径:

  1. 全局 Skill(所有项目生效)~/.claude/skills/
  2. 项目局部 Skill:项目目录下 .claude/skills/

新建文件 weather_helper.md(Skill 以 Markdown 格式编写)。

6.3 编写联动 Skill(MCP + Skill 完整编排)

该 Skill 实现逻辑:

  1. 拦截用户「查天气」相关指令;
  2. 加载 MCP 预设 Prompt 模板;
  3. 调用 MCP 天气工具;
  4. 读取 MCP 静态说明文档 + 动态资源;
  5. 整合所有内容,输出格式化回答。

weather_helper.md 完整代码

---
name: 天气助手
description: 联动本地MCP服务查询天气,整合资源与提示词
trigger: ["查天气", "天气怎么样", "今日天气"]
---

## 执行流程
1. 调用MCP服务的 weather_ask_template 提示词模板,优化回答话术;
2. 识别用户查询的城市,调用MCP工具 query_weather 获取天气数据;
3. 读取MCP静态资源【天气服务说明文档】;
4. 读取对应城市的MCP动态资源【天气温馨提示】;
5. 整合所有信息,分模块友好输出。

## 输出格式
### 天气查询结果
{工具返回的天气数据}

### 出行提示
{动态资源内容}

### 服务说明
{静态文档内容}

6.4 联合使用实操演示

  1. 确保 MCP Server 已在 Claude Code 中正常配置、Skill 文件放入对应目录;
  2. 终端执行 claude 启动客户端;
  3. 输入触发指令:帮我查广州天气
完整执行链路拆解
  1. Skill 拦截:检测到触发词「查天气」,启动预设工作流;
  2. 加载 MCP Prompt:拉取 weather_ask_template 模板,规范回答风格;
  3. 调用 MCP Tool:执行 query_weather,获取广州天气数据;
  4. 读取 MCP Resources
    • 读取静态文件 weather_doc.txt
    • 读取动态资源 mcp://weather/intro/广州
  5. 结果整合:Skill 按照预设格式拼接所有内容,输出给用户;
  6. 日志回显:MCP 服务推送的 INFO/WARN 日志在终端同步展示。

6.5 最佳实践总结

  1. 能力分层:底层通用能力(工具、资源)交给 MCP,上层业务流程、交互逻辑交给 Skill;
  2. 权限隔离:通过 MCP Roots 限制文件访问范围,避免安全风险;
  3. 复用优先:高频话术、固定规则抽离为 MCP Prompts,减少 Skill 冗余代码;
  4. 日志调试:利用 MCP Logging 排查工具调用、资源读取异常。

七、总结与拓展

7.1 本文核心收获

  1. MCP 本质:一套基于 JSON-RPC + 多传输层的能力标准化协议,核心是解耦 AI 客户端与外部服务;
  2. 核心组件全覆盖:掌握 Transport、Tools、Resources、Prompts、Roots、Logging 六大模块的设计与编码;
  3. 落地流程:MCP Server 开发 → 客户端配置(Claude Code/Trea)→ MCP + Skill 业务编排,完整闭环。

7.2 拓展方向

  1. 传输层升级:将 Stdio 改为 HTTP/SSE,实现远程 MCP 服务,多客户端共享;
  2. 复杂工具开发:基于 MCP 实现代码执行、数据库操作、本地文件管理等高级工具;
  3. 生态对接:对接 Cursor、IDE 插件、企业内部 AI 平台,复用同一套 MCP 服务;
  4. 权限增强:结合 MCP Roots + 身份校验,实现多用户权限管控。

7.3 学习建议

MCP 现在是本地大模型扩展的事实标准,从简单 Demo 入手理解组件,再结合业务场景做复杂服务开发,是快速掌握该协议的最优路径。本文的天气 Demo 可直接改造为文件管理、接口测试、运维工具等通用 MCP 服务。


互动话题

上手 MCP 之后,你第一个想基于它开发什么自定义工具?我是阿宇,欢迎大家在评论区留言讨论!

Logo

欢迎加入 MCP 技术社区!与志同道合者携手前行,一同解锁 MCP 技术的无限可能!

更多推荐