基于 MCP Http SSE模式的天气助手智能体开发实战(一文带你了解MCP两种开发模式)

一、MCP服务端通信方式

MCP(Model Context Protocol, 模型上下文协议)约定了AI Agent智能体的开发规范,AI Agent智能体由大模型客户端扩展大模型能力的服务端两部分构成。根据MCP协议定义,MCP服务端可以提供三种类型的标准能力:Resources, Tools, Prompts, 每个服务端可同时提供这三种类型能力或其中一种。

  • Resources:

    资源,类似于文件数据读取,可以是文件资源或是API响应返回的内容

  • Tools:

    工具,第三方服务、功能函数,通过此可控制大模型可调用哪些函数。

  • Prompts:

    提示词,为用户预先定义好的完成特定任务的模板。

目前MCP服务端常见的能力是Tools, 通过封装函数和外部请求,扩展大模型的能力。

img

MCP服务端当前支持两种与客户端的数据通信方式:标准输入输出(stdio)基于Http的服务器推送事件(http sse)

1.1 标准输入输出(stdio)

原理: 标准输入输出是一种用于本地通信的传输方式。在这种模式下,MCP 客户端会将服务器程序作为子进程启动,双方通过约定的标准输入和标准输出(可能是通过共享文件等方法)进行数据交换。具体而言,客户端通过标准输入发送请求,服务器通过标准输出返回响应。。

适用场景: 标准输入输出方式适用于客户端和服务器在同一台机器上运行的场景(本地自行编写服务端或将别人编写的服务端代码pull到本地执行),确保了高效、低延迟的通信。这种直接的数据传输方式减少了网络延迟和传输开销,适合需要快速响应的本地应用。

1.2 基于Http的服务器推送事件(http sse)

原理: 客户端和服务端通过 HTTP 协议进行通信,利用 SSE 实现服务端向客户端的实时数据推送,服务端定义了/see与/messages接口用于推送与接收数据。这里要注意SSE协议和WebSocket协议的区别,SSE协议是单向的,客户端和服务端建立连接后,只能由服务端向客户端进行消息推送。而WebSocket协议客户端和服务端建立连接后,客户端可以通过send向服务端发送数据,并通过onmessage事件接收服务端传过来的数据。

适用场景: 适用于客户端和服务端位于不同物理位置的场景,尤其是对于分布式或远程部署的场景,基于 HTTP 和 SSE 的传输方式更合适。

1.3 可流式传输的HTTP

虽然目前MCP协议的通信方式只有以上两种,但该协议还在不断的进步与完善。近期有开发者在MCP的Github仓库中提交了一项提案,建议采用“可流式传输的 HTTP”来替代现有的 HTTP+SSE 方案。此举旨在解决当前远程 MCP 传输方式的关键限制,同时保留其优势。目前该提案还未被正式采纳。

img

二、基于Http SSE模式的天气助手智能体开发实战

2.1 环境准备

1、使用deepseek-v3-0324作为大模型客户端,申请DeepSeek-V3的API Key。 获取当前的天气情况需要调用心知天气的API,申请心知天气API免费私钥。

2、 MCP开发要求借助uv进行虚拟环境创建和依赖管理。

  • (1)执行pip install uv命令安装uv

  • (2)执行uv init mcp-weather命令初始化项目。

  • (3)cd mcp-weather进行项目文件夹,执行uv venv命令创建虚拟环境, 执行.venv\Scripts\activate命令激活虚拟环境(Linux下使用source .venv/bin/activate激活)。

  • (4) 执行uv add mcp, uv add requests, uv add openai命令安装开发使用的python包。

    img

    img

    img

2.2 编写MCP服务端代码

  1. mcp-weather项目目录下新建server.py文件并编写如下代码:
import json
import requests
from typing import Any
from mcp.server.fastmcp import FastMCP

# 初始化MCP服务器
mcp = FastMCP("WeatherServer")


@mcp.tool()
async def get_weather(city: str):
     """
      输入指定城市的名称,返回当前天气情况
      :param city: 城市名称
    :return: json格式的天气信息
    """
     url="https://api.seniverse.com/v3/weather/now.json"
    params={
        "key": "你注册的心知天气私钥",
        "location": city,
        "language": "zh-Hans",
        "unit": "c"
    }
    response = requests.get(url, params=params)
    temperature = response.json()['results'][0]['now']
    return json.dumps(temperature)

if __name__ == "__main__":
    mcp.run(transport="sse")
  1. 再次体会MCP服务端开发的便捷性,使用Function Calling技术开发天气查询功能要编写description, json schema前后大约150行代码,使用MCP SDK开发只需要编写一个请求函数get_weather和函数注释,借助@mcp.tool()装饰器就可以快速添加天气查询功能。

  2. 注意使用http sse模式mcp服务端和使用stdio模式mcp服务端只有启动代码有差别。http sse的启动代码为mcp.run(transport="sse"), stdio的启动代码为mcp.run(transport="stdio")

2.3 编写MCP客户端代码

  1. mcp-weather项目目录下新建client.py文件, 编写如下代码:
import asyncio
import json
from typing import Optional
from contextlib import AsyncExitStack
from openai import OpenAI

from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
from mcp.client.sse import sse_client

class MCPClient:
    def __init__(self):
        """初始化MCP客户端"""
        self.exit_stack = AsyncExitStack()
        self.opanai_api_key = "这里填写你的deepseek-api" # 调用模型的api_key
        self.base_url = "https://api.deepseek.com" # 调用模型url, 这里以deepseek作演示
        self.model = "deepseek-chat" # 调用deepseek-v3模型
        self.client = OpenAI(api_key=self.opanai_api_key, base_url=self.base_url)
        self.session: Optional[ClientSession] = None # Optional提醒用户该属性是可选的,可能为None
        self.exit_stack = AsyncExitStack() # 用来存储和清楚对话中上下文的,提高异步资源利用率

    async def connect_to_sse_server(self, server_url): #连接sse服务端,因为是基于http协议的,需要传入url
        sse_transport = await self.exit_stack.enter_async_context(sse_client(server_url))
        self.write, self.read = sse_transport
        self.session = await self.exit_stack.enter_async_context(ClientSession(self.write, self.read))
        await self.session.initialize() # 与服务器建立sse连接
        # 列出MCP服务器上的工具
        response = await self.session.list_tools()
        tools = response.tools
        print("\n已连接到服务器,支持以下工具:", [tool.name for tool in tools])#打印服务端可用的工具

    async def process_query(self, query:str)->str:
        """使用大模型处理查询并调用MCP Server可用的MCP工具"""
        messages = [{"role":"user", "content":query}]
        response = await self.session.list_tools()

        available_tools = [{
            "type": "function",
            "function": {
                "name": tool.name,
                "description": tool.description,
                "input_schema": tool.inputSchema
            }
        } for tool in response.tools]

        response = self.client.chat.completions.create(
            model=self.model,
            messages=messages,
            tools=available_tools
        )

        # 处理返回内容
        content = response.choices[0]
        if content.finish_reason == "tool_calls":
            # 返回结果是使用工具的建议,就解析并调用工具
            tool_call = content.message.tool_calls[0]
            tool_name = tool_call.function.name
            tool_args = json.loads(tool_call.function.arguments)
            # 执行工具
            result = await self.session.call_tool(tool_name, tool_args)
            print(f"\n\n[Calling tool {tool_name} with args {tool_args}]\n\n")
            # 将模型返回的调用工具的对话记录保存在messages中
            messages.append(content.message.model_dump())
            messages.append({
                "role": "tool",
                "content": result.content[0].text,
                "tool_call_id": tool_call.id,
            })
            # 将上面的结果返回给大模型用于生产最终结果
            response = self.client.chat.completions.create(
                model=self.model,
                messages=messages
            )
            return response.choices[0].message.content
        return content.message.content

    async def chat_loop(self):
        """运行交互式聊天"""
        print("\n MCP客户端已启动!输入quit退出")

        while True:
            try:
                query = input("\n用户:").strip()
                if query.lower() == 'quit':
                    break
                response = await self.process_query(query)
                print(f"\nDeepSeek-V3-0324: {response}")
            except Exception as e:
                print(f"发生错误: {str(e)}")

    async def clean(self):
        """清理资源"""
        await self.exit_stack.aclose()

async def main():
    if len(sys.argv) < 2:
        print("使用方法是: python client.py server_url")
        sys.exit(1)

    client = MCPClient()
    try:
        await client.connect_to_sse_server(sys.argv[1])
        await client.chat_loop()
    finally:
        await client.clean()

if __name__ == "__main__":
    import sys
    asyncio.run(main())
  1. 对比sse客户端代码和stdio客户端代码的区别,发现只是在连接服务函数层面有变化。sse是基于http sse协议的,需要服务端url地址作为参数。
async def connect_to_sse_server(self, server_url):
    sse_transport = await self.exit_stack.enter_async_context(sse_client(server_url)) #sse_client初始化sse连接参数, 包括读,写流
    self.write, self.read = sse_transport
    self.session = await self.exit_stack.enter_async_context(ClientSession(self.write, self.read)) #依据读写流初始化sesssion
    await self.session.initialize() # 与服务器建立sse连接

stdio将服务端代码作为子进程执行,需要设置启动参数:

async def connect_to_server(self, server_script_path):
        """连接到MCP服务器并列出MCP服务器的可用工具函数"""
        server_params = StdioServerParameters(
        command="python",
            args=[server_script_path],
            env=None
        ) # 设置启动服务器的参数, 这里是要用python执行server.py文件

        # 启动MCP服务器并建立通信
        stdio_transport = await self.exit_stack.enter_async_context(stdio_client(server_params))
        self.stdio, self.write = stdio_transport
        self.session = await self.exit_stack.enter_async_context(ClientSession(self.stdio, self.write))

        await self.session.initialize() # 与服务器建立stdio连接

2.4 启动服务端和客户端

stdio模式下,服务端作为客户端子进程启动,只需要执行uv run client.py server.py命令同时启动客户端和服务端。但在http sse模式下,MCP 服务端不再作为客户端的子进程,而是独立的服务提供,需要分两步启动。

  1. 激活虚拟环境的mcp-weather目录下执行uv run server.py命令,可以看到服务端开启了8000端口,在浏览器中输入http://localhost:8000/sse进行测试, 当客户端访问该url会触发服务端处理sse连接,同时服务端也不断的ping维持长连接。

img

img

  1. 执行uv run client.py http://localhost:8000/sse命令,第二个参数传入服务端sse的url, 用来建立客户端和服务端的连接,连接成功并返回正确结果,我们基于http sse模式的天气助手智能体就开发完成啦!

img

以上就是我们本篇文章的项目内容,希望大家与上篇文章结合,深刻理解MCP两种通信方式的异同点~

三、加餐:MCP Inspector——MCP服务端测试调用工具

Http Sse开发模式让我们能够访问远程部署的例如高德地图,百度地图,高德天气等各种各样MCP 服务端,不过每次编写相应的客户端程序进行测试访问还是比较麻烦的。

为了让开发者可以快速调用测试MCP服务端,Anthropic提供了一个非常便捷的debug工具:MCP Inspector。下面就来简单看一下MCP Inspector的用法:

3.1 环境配置

使用MCP Inspector需要node.js环境,从 Node.js官网中下载.msi安装包,安装过程中注意将node添加到环境变量中,一路install即可。

img

执行npx -v命令查看node.js是否安装成功:

img

执行如下命令运行MCP Inspector, 即可在本地浏览器查看当前工具运行情况,我这里的地址是http://127.0.0.1:6274

npx -y @modelcontextprotocol/inspector uv run server.py

img

3.2 MCP Inspector基本使用

使用浏览器打开http://127.0.0.1:6274, 选择 Transport Type为SSE, 输入MCP Server的url, 我们这里使用开发的天气智能体服务端作为测试, 输入http://localhost:8000/sse, 点击connect成功连接。

img

天气智能体的服务端类别是Tools, 我们点击Tools标签,并点击List Tools按钮,可以看到列出了天气智能体服务端的方法get_weather()及其注释。

img

点击get_weather()方法,在右侧输入该方法的参数,这里输入北京, 点击Run Tool, 可以看到服务端运行成功返回结果。

img

除了可以测试sse模式, MCP Inspector还可以测试stdio模式,只需在一开始选择 Transport Type为Stdio, 同时command输入uv, args输入run server.py就可以啦,大家可以使用上篇文章的例子尝试一下~

img

以上就是MCP Inspector软件的基本使用方法,其它使用技巧就需要屏幕前聪明的你自行探索了~

四、总结

本次分享我们深入浅出地介绍了MCP(模型上下文协议)的两种通信方式:标准输入输出(stdio)和基于HTTP的服务器推送事件(SSE)。通过开发一个天气助手智能体的实战案例,生动展示了两种模式的异同——stdio适合本地高效通信,而SSE则适用于远程分布式场景。本次分享我还着重对比了代码差异,比如SSE需要URL参数,而stdio直接调用子进程。最后,还为大家安利了调试神器MCP Inspector,能一键测试服务端功能,堪称“懒人福音”。

如何学习大模型 AI ?

由于新岗位的生产效率,要优于被取代岗位的生产效率,所以实际上整个社会的生产效率是提升的。

但是具体到个人,只能说是:

“最先掌握AI的人,将会比较晚掌握AI的人有竞争优势”。

这句话,放在计算机、互联网、移动互联网的开局时期,都是一样的道理。

我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。

我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在人工智能学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。但苦于知识传播途径有限,很多互联网行业朋友无法获得正确的资料得到学习提升,故此将并将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。

这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

https://img-blog.csdnimg.cn/img_convert/05840567e2912bcdcdda7b15cba33d93.jpeg

在这里插入图片描述

第一阶段(10天):初阶应用

该阶段让大家对大模型 AI有一个最前沿的认识,对大模型 AI 的理解超过 95% 的人,可以在相关讨论时发表高级、不跟风、又接地气的见解,别人只会和 AI 聊天,而你能调教 AI,并能用代码将大模型和业务衔接。

  • 大模型 AI 能干什么?
  • 大模型是怎样获得「智能」的?
  • 用好 AI 的核心心法
  • 大模型应用业务架构
  • 大模型应用技术架构
  • 代码示例:向 GPT-3.5 灌入新知识
  • 提示工程的意义和核心思想
  • Prompt 典型构成
  • 指令调优方法论
  • 思维链和思维树
  • Prompt 攻击和防范

第二阶段(30天):高阶应用

该阶段我们正式进入大模型 AI 进阶实战学习,学会构造私有知识库,扩展 AI 的能力。快速开发一个完整的基于 agent 对话机器人。掌握功能最强的大模型开发框架,抓住最新的技术进展,适合 Python 和 JavaScript 程序员。

  • 为什么要做 RAG
  • 搭建一个简单的 ChatPDF
  • 检索的基础概念
  • 什么是向量表示(Embeddings)
  • 向量数据库与向量检索
  • 基于向量检索的 RAG
  • 搭建 RAG 系统的扩展知识
  • 混合检索与 RAG-Fusion 简介
  • 向量模型本地部署

第三阶段(30天):模型训练

恭喜你,如果学到这里,你基本可以找到一份大模型 AI相关的工作,自己也能训练 GPT 了!通过微调,训练自己的垂直大模型,能独立训练开源多模态大模型,掌握更多技术方案。

到此为止,大概2个月的时间。你已经成为了一名“AI小子”。那么你还想往下探索吗?

  • 为什么要做 RAG
  • 什么是模型
  • 什么是模型训练
  • 求解器 & 损失函数简介
  • 小实验2:手写一个简单的神经网络并训练它
  • 什么是训练/预训练/微调/轻量化微调
  • Transformer结构简介
  • 轻量化微调
  • 实验数据集的构建

第四阶段(20天):商业闭环

对全球大模型从性能、吞吐量、成本等方面有一定的认知,可以在云端和本地等多种环境下部署大模型,找到适合自己的项目/创业方向,做一名被 AI 武装的产品经理。

  • 硬件选型
  • 带你了解全球大模型
  • 使用国产大模型服务
  • 搭建 OpenAI 代理
  • 热身:基于阿里云 PAI 部署 Stable Diffusion
  • 在本地计算机运行大模型
  • 大模型的私有化部署
  • 基于 vLLM 部署大模型
  • 案例:如何优雅地在阿里云私有部署开源大模型
  • 部署一套开源 LLM 项目
  • 内容安全
  • 互联网信息服务算法备案

学习是一个过程,只要学习就会有挑战。天道酬勤,你越努力,就会成为越优秀的自己。

如果你能在15天内完成所有的任务,那你堪称天才。然而,如果你能完成 60-70% 的内容,你就已经开始具备成为一名大模型 AI 的正确特征了。

这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

https://img-blog.csdnimg.cn/img_convert/05840567e2912bcdcdda7b15cba33d93.jpeg

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值