MCP终极指南(进阶篇)知识点框架与内容

MCP终极指南(进阶篇)知识点框架与内容

一、视频概述

  • 是MCP终极指南系列的进阶篇,承接基础篇内容
  • 进阶篇分为三个部分:
    1. 动手编写MCP server
    2. 截获MCP server的输入和输出并逐行分析,演示不借助MCP host和编程语言直接与MCP server沟通
    3. 探讨MCP(模型上下文协议)的含义及在大模型相关应用中的角色

在这里插入图片描述

二、编写第一个MCP server

(一)开发准备

  • 开发语言选择:可使用Python、Node、Java、C#等,本次选择Python(考虑使用人数和编程难度)
  • 安装Python:
    • macOS用户:系统自带Python,需确保版本为3.10及以上
    • Windows用户:需到Python官方网站下载安装
  • 所需工具:
    • UV:Python的包管理器
    • Vs Code:代码编写软件
    • Client:Vs Code的插件
    • (以上工具在基础篇已提及,需自行安装)

(二)具体开发步骤

  1. 打开终端,使用uv init weather新建名为weather的项目
  2. 进入项目目录,执行uv venv新建虚拟环境(防止依赖影响系统环境)
  3. 执行source .venv/bin/activate(windows中VSCODE终端输入: .\.venv\Scripts\activate.ps1 进入虚拟环境)进入虚拟环境(终端显示括号内的weather表示已进入)
  4. 执行uv add “mcp[cli]" httpx安装开发MCP必备的依赖:
    • mcp[cli]:开发MCP的核心依赖
    • httpx:用于调用HTTP接口(查询天气需调用HTTP)
  5. 用Vs Code打开weather项目目录,新建weather.py文件,在该文件中完成主要工作:

这里代码和上一篇一样(每一个带有@mcp.tool()的函数都会被仍为是工具函数,如:get_alerts中的注释 都会转换为tool的信息,传递给大模型

     """Get weather alerts for a US state.

    Args:
        state: Two-letter US state code (e.g. CA, NY)
    """)
from typing import Any
import httpx
from mcp.server.fastmcp import FastMCP


# Initialize FastMCP server
mcp = FastMCP("weather", log_level="ERROR")


# Constants
NWS_API_BASE = "https://api.weather.gov"
USER_AGENT = "weather-app/1.0"


async def make_nws_request(url: str) -> dict[str, Any] | None:
    """Make a request to the NWS API with proper error handling."""
    headers = {
        "User-Agent": USER_AGENT,
        "Accept": "application/geo+json"
    }
    async with httpx.AsyncClient() as client:
        try:
            response = await client.get(url, headers=headers, timeout=30.0)
            response.raise_for_status()
            return response.json()
        except Exception:
            return None


def format_alert(feature: dict) -> str:
    """Format an alert feature into a readable string."""
    props = feature["properties"]
    return f"""
Event: {props.get('event', 'Unknown')}
Area: {props.get('areaDesc', 'Unknown')}
Severity: {props.get('severity', 'Unknown')}
Description: {props.get('description', 'No description available')}
Instructions: {props.get('instruction', 'No specific instructions provided')}
"""


@mcp.tool()
async def get_alerts(state: str) -> str:
    """Get weather alerts for a US state.

    Args:
        state: Two-letter US state code (e.g. CA, NY)
    """
    url = f"{NWS_API_BASE}/alerts/active/area/{state}"
    data = await make_nws_request(url)

    if not data or "features" not in data:
        return "Unable to fetch alerts or no alerts found."

    if not data["features"]:
        return "No active alerts for this state."

    alerts = [format_alert(feature) for feature in data["features"]]
    return "\n---\n".join(alerts)


@mcp.tool()
async def get_forecast(latitude: float, longitude: float) -> str:
    """Get weather forecast for a location.

    Args:
        latitude: Latitude of the location
        longitude: Longitude of the location
    """
    # First get the forecast grid endpoint
    points_url = f"{NWS_API_BASE}/points/{latitude},{longitude}"
    points_data = await make_nws_request(points_url)

    if not points_data:
        return "Unable to fetch forecast data for this location."

    # Get the forecast URL from the points response
    forecast_url = points_data["properties"]["forecast"]
    forecast_data = await make_nws_request(forecast_url)

    if not forecast_data:
        return "Unable to fetch detailed forecast."

    # Format the periods into a readable forecast
    periods = forecast_data["properties"]["periods"]
    forecasts = []
    for period in periods[:5]:  # Only show next 5 periods
        forecast = f"""
{period['name']}:
Temperature: {period['temperature']}°{period['temperatureUnit']}
Wind: {period['windSpeed']} {period['windDirection']}
Forecast: {period['detailedForecast']}
"""
        forecasts.append(forecast)

    return "\n---\n".join(forecasts)
import os
import time

@mcp.tool()
def take_screenshots() -> str:
    """每隔5秒截图一次,保存到当前目录的 pick 文件夹,累计10张后停止。"""
    try:
        import pyautogui
    except ImportError:
        return "请先安装 pyautogui 库:pip install pyautogui"

    save_dir = os.path.join(os.getcwd(), "pick")
    os.makedirs(save_dir, exist_ok=True)
    for i in range(1, 11):
        img = pyautogui.screenshot()
        filename = os.path.join(save_dir, f"screenshot_{i:02d}.png")
        img.save(filename)
        time.sleep(5)
    return "截图已完成,已保存10张图片到 pick 文件夹。"

if __name__ == "__main__":
    # Initialize and run the server
    mcp.run(transport='stdio')
    mcp.run(transport='stdio')

这里mcp是下面构建的mcp对象,这里代表对象开始工作,传输方式为stdio

mcp = FastMCP("weather", log_level="ERROR")

(三)功能测试

注册mcpserver,可以参考上一篇流程,这里也贴出注册代码

{
  "mcpServers": {
    "weather": {
      "disabled": false,
      "timeout": 60,
      "type": "stdio",
      "command": "uv",
      "args": [
        "--directory",
        "D:/work/test1_weather/weather",
        "run",
        "weather.py"
      ]
    }
  }
}
  • 新建对话,输入问题“纽约明天的天气怎么样”
  • 模型会找到对应的MCP server及其中的get_forecast tool,点击approve同意调用
  • 模型会拿到get_forecast的调用结果并整理成答案返回,说明MCP server编写成功

三、MCP协议分析

在这里插入图片描述

(一)获取MCP server输入输出的方法

  • 大部分MCP server通过输入和输出与client沟通,若在终端启动可直接看到,但由client启动时用户无法直接看到
  • 解决方案:编写mcp_log.py脚本,该脚本的参数为启动MCP server的命令,功能是截取MCP server的输入和输出并写入外部文件
  • 操作方式:在client的MCP server配置中修改启动参数,在原启动命令前加上python mcp_log.py,输入输出会写入与mcp_log.py同目录的mcpiolog.log文件
    在这里插入图片描述
    这个不是重点,主要是要明白他们之间是怎么交互的

(二)MCP server与client交互内容分析

在这里插入图片描述
第一个工具:
在这里插入图片描述
在这里插入图片描述

  • 日志内容说明:每行最前面的“输入”“输出”及后面的冒号是mcp_log.py脚本添加的,不属于交互内容,交互内容为后面的JSON,标识输入输出是为了方便查看数据流向(输入是client到MCP server的数据,输出是MCP server到client的数据)
  • 具体交互过程及内容:
    1. client向MCP server打招呼:告知自身是client,软件版本,使用的MCP协议版本(2024年11月5号出品)
    2. MCP server回复:表示使用相同的协议版本,说明自身不支持的能力,告知名称(weather)和版本号(1.6.0)
    3. client回复收到
    4. client询问MCP server包含的tool:MCP server返回两个tool(get_alertsget_forecast),其定义遵循同一套格式,以get_forecast为例:
      • 功能:获取某个地区的天气预告

      • 包含参数信息(纬度latitude和经度longitude,类型为number)

      • 描述信息来自函数注释(Python中称为doc string),由@mcp.tool装饰器提取并放在description字段

      • 在这里插入图片描述

      • input_schema:定义了参数规范,由@mcp.tool装饰器从参数定义中提取,遵循JSON schema规范(本身是一段JSON,用于描述另一个JSON的结构),模型会根据此规范提取参数,以确保调用成功

    5. client询问MCP server是否有资源和资源模板:MCP server回复均为无(空列表)
    6. 等待合适时机使用MCP server:当用户再次询问“纽约明天的天气怎么样”并允许调用后,client通知MCP server使用get_forecast tool,参数为纽约的纬度(40.7128)和经度(-74.006),符合input_schema规范
    7. MCP server执行对应函数后输出结果:核心是text字段的值,包含未来几天的天气信息(由get_forecast函数返回)
    8. client拿到执行结果后,与MCP server的交互结束,将结果发给模型总结,最终展示模型总结的结果(在client中可找到每次tool的请求参数和结果,与日志内容一致)

四、直接与MCP server沟通(不经过client)

  • 条件:理解MCP协议细节,保证发给MCP server的数据符合格式

  • 在这里插入图片描述

  • 操作步骤:

    1. 在终端运行MCP server(使用配置中的命令,不加mcp_log.py
    2. 直接在终端输入符合格式的信息与MCP server沟通:
      • 发送打招呼信息(可修改名称和版本号),MCP server会回复
      • 发送表示收到消息可以开始工作的信息,MCP server不回复(与日志表现一致)
      • 发送请求工具列表的信息,MCP server会返回工具列表
      • 发送调用工具的信息,MCP server会返回工具调用结果
  • 结论:无需MCP host也可直接与MCP server交互,此时用户自己就是MCP host

五、MCP协议的本质与定位

在这里插入图片描述

  • MCP协议规定的交互环节不涉及模型,主要规定两部分内容:

    1. 每个MCP server有哪些函数可以用
    2. 如何调用这些函数(可总结为函数的注册与使用,暂忽略MCP server内部的资源)
  • MCP协议脱离大模型也能使用(只是实际中无人如此使用),本身不规定与模型的交互方式

  • 不同的MCP host与模型的交互存在差异(注意:这里不是和mcp和cline的交互,是右边和大模型的交互,注意看图和注意区分):例如client用XML与模型沟通,cherry studio用OpenAI提出的function calling格式与模型沟通

  • 在这里插入图片描述

  • MCP(模型上下文协议)的含义:让模型感知外部环境(周围可调用的用于获取外界信息的函数,如获取天气、网络、文件信息等)的协议

  • 对MCP名称的评价:

    • 有误导性,易让人以为规定了与模型的交互内容,实际最多是给模型服务
    • 过于玄妙,初看难以理解

下一篇整理HOST和大模型之间的交互流程和细节

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值