Agents-SDK智能体开发[4]之集成MCP入门

文章目录

  • 说明
  • 一 Agents SDK接入MCP
    • 1.1 MCP技术回顾
    • 1.2 MCP基础实践流程
      • 1.2.1 天气查询服务器Server创建流程
      • 1.2.2 服务器依赖安装和代码编写
      • 1.2.3 环境配置文件
      • 1.2.4 客户端代码编写
    • 1.3 测试运行
  • 二 MCP+Agents SDK基础调用
    • 2.1 weather_server.py
    • 2.2 client_agent.py
    • 2.3 运行测试

说明

  • 本文学自赋范社区公开课,仅供学习和交流使用,不用作任何商业用途!

一 Agents SDK接入MCP

1.1 MCP技术回顾

  • 开篇:MCP理论理解和学习
  • 启程:MCP开发环境配置和旅游攻略案例体验
  • https://yuanyou.blog.csdn.net/article/details/148222368

1.2 MCP基础实践流程

  • 先尝试手动实现一遍MCP实践流程,再考虑将已经部署好的server带入Agents SDK中,作为tools进行调用。
  • 一个极简的天气查询MCP基本执行流程:
    在这里插入图片描述

1.2.1 天气查询服务器Server创建流程

  • 创建一个天气查询的服务器,通过openweather,创建一个能够实时查询天气的服务器(server)。
    curl -s "https://api.openweathermap.org/data/2.5/weather?q=Beijing&units=metric&appid=xxx"
    
  • 执行结果:
    {"coord": {"lon": 116.3972,"lat": 39.9075},"weather": [{"id": 804,"main": "Clouds","description": "阴,多云","icon": "04n"}],"base": "stations","main": {"temp": 22.36,"feels_like": 22.77,"temp_min": 22.36,"temp_max": 22.36,"pressure": 1007,"humidity": 81,"sea_level": 1007,"grnd_level": 1002},"visibility": 10000,"wind": {"speed": 1.42,"deg": 26,"gust": 3.23},"clouds": {"all": 100},"dt": 1753014180,"sys": {"country": "CN","sunrise": 1752958921,"sunset": 1753011546},"timezone": 28800,"id": 1816670,"name": "Beijing","cod": 200
    }
    

1.2.2 服务器依赖安装和代码编写

  1. 创建项目目录,创建并激活虚拟环境。
    uv init mcp-weather
    cd mcp-weather
    uv venv
    .venv\Scripts\activate
    
  2. 在当前虚拟环境中添加如下依赖:
    pip install mcp httpx openai python-dotenv pypinyin openai-agents
    
  3. 创建server服务器代码文件server.py
    import json
    import httpx
    from typing import Any
    from mcp.server.fastmcp import FastMCP# 初始化mcp服务器
    mcp=FastMCP("WeatherServer")#OpenWeather API 配置
    OPENWEATHER_API_BASE = "https://api.openweathermap.org/data/2.5/weather"
    API_KEY ="xxx"
    USER_AGENT = "weather-app/1.0"async def fetch_weather(city: str) -> dict[str, Any]|None:"""获取天气信息"""params={"q": city,"appid": API_KEY,"units": "metric","lang": "zh_cn"}headers={"User-Agent": USER_AGENT}async with httpx.AsyncClient() as client:response = await client.get(OPENWEATHER_API_BASE, params=params, headers=headers,timeout=1000)if response.status_code == 200:return response.json()else:return Nonedef format_weather(data: dict[str,Any] | str)->str:"""解析天气数据字典,提取关键信息并格式化输出。功能:对可能缺失的嵌套数据字段进行容错处理,确保返回内容完整。参数:data: 天气API返回的原始数据字典返回:格式化后的天气信息字符串"""# 基础位置信息(城市、国家)- 缺失时显示"未知"city = data.get("name", "未知")  # 城市名称(顶层字段)country = data.get("sys", {}).get("country", "未知")  # 国家代码(嵌套在sys字段中)# 天气核心指标 - 缺失时显示"N/A"(Not Available)main_data = data.get("main", {})  # 提取main字段(包含温度、湿度等)temperature = main_data.get("temp", "N/A")  # 温度humidity = main_data.get("humidity", "N/A")  # 湿度wind_data = data.get("wind", {})  # 提取wind字段(包含风速等)wind_speed = wind_data.get("speed", "N/A")  # 风速# 天气描述 - weather字段可能为空列表,默认返回第一个元素的描述weather_list = data.get("weather", [{}])  # 提取weather数组(默认空字典避免索引错误)weather_description = weather_list[0].get("description", "未知")  # 天气状况描述# 格式化输出字符串(使用f-string拼接,添加emoji直观展示)weather_info = (f"🌍 {city}, {country}\n"f"🌡️ 温度:{temperature}℃\n"f"💧 湿度:{humidity}%\n"f"💨 风速:{wind_speed} m/s\n"f"☁️ 天气:{weather_description}\n")return weather_info@mcp.tool()
    async def query_weather(city: str) -> str:"""查询天气信息并返回结果"""weather_data = await fetch_weather(city)if weather_data:return format_weather(weather_data)else:return "无法获取天气信息。请检查城市名称是否正确。"if __name__=="__main__":mcp.run(transport='stdio')
    

1.2.3 环境配置文件

  • 创建.env文件
BASE_URL="https://api.siliconflow.cn/v1/chat/completions"
MODEL=deepseek-ai/DeepSeek-V3
OPENAI_API_KEY="sk-xxx"

1.2.4 客户端代码编写

  • 创建一个可以和server进行通信的客户端,需要注意的是,该客户端需要包含大模型调用的基础信息。我们需要编写一个client.py脚本。
    import asyncio
    import os
    import json
    import sys
    from typing import Optional
    from  contextlib import AsyncExitStack
    from openai.types.chat import ChatCompletionToolParam
    from openai import OpenAI
    from dotenv import load_dotenvfrom mcp import ClientSession,StdioServerParameters
    from mcp.client.stdio import stdio_clientfrom pypinyin import lazy_pinyin, Style# 加载env文件,确保配置正确
    load_dotenv()class MCPClient:def __init__(self):"""初始化MCP客户端"""self.write = Noneself.stdio = Noneself.exit_stack = AsyncExitStack()self.base_url=os.getenv("BASE_URL")self.model = os.getenv("MODEL")self.openai_api_key = os.getenv("OPENAI_API_KEY")if not self.openai_api_key:raise ValueError("OPENAI_API_KEY未设置")self.client=OpenAI(api_key=self.openai_api_key, base_url=self.base_url)self.session: Optional[ClientSession] = Noneself.exit_stack=AsyncExitStack()async def connect_to_server(self, server_script_path:str):"""连接MCP服务器并列出可用工具"""is_python=server_script_path.endswith(".py")is_js=server_script_path.endswith(".js")if not (is_python or is_js):raise ValueError("服务器脚本必须以.py或.js结尾")command="python" if is_python else "node"server_params=StdioServerParameters(command=command,args=[server_script_path],env=None)# 启动MCP服务器并建立通信stdio_transport=await self.exit_stack.enter_async_context(stdio_client(server_params))self.stdio,self.write=stdio_transportself.session= await self.exit_stack.enter_async_context(ClientSession(self.stdio,self.write))await self.session.initialize()# 列出MCP服务器上的工具response=await self.session.list_tools()tools=response.toolsprint("\n已连接到服务器,支持以下工具:",[tool.name for tool in tools])async def process_query(self, query:str)-> str:"""使用大模型处理查询并调用可用的MCP工具(Function Calling)"""messages=[{"role": "user","content": query}]response=await self.session.list_tools()available_tools = [ChatCompletionToolParam(type="function",function={"name": tool.name,"description": tool.description,"parameters": 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.nametool_args=json.loads(tool_call.function.arguments)# 如果调用的是 query_weather 工具,处理城市名称if tool_name == "query_weather" and "city" in tool_args:city = tool_args["city"]# 简单判断是否为中文城市名if any('\u4e00' <= c <= '\u9fff' for c in city):# 转换为拼音,首字母大写pinyin_city = ''.join([word.capitalize() for word in lazy_pinyin(city)])tool_args["city"] = pinyin_city# 执行工具result=await self.session.call_tool(tool_name, tool_args)print(f"\n\n[Calling Tool: {tool_name} with args: {tool_args}]")# 将工具调用和结果添加到消息历史中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.contentasync def chat_loop(self):"""运行交互式聊天循环"""print("\nMCP客户端已启动!输入'quit'退出")while True:try:query=input("\n you:").strip()if query.lower() == "quit":breakresponse=await self.process_query(query)print(f"\n ai: {response}")except Exception as e:print(f"\n Error: {e}")async def cleanup(self):"""清理资源"""await self.exit_stack.aclose()async def main():if len(sys.argv)<2:print("Usage: python client.py <server_address>")sys.exit(1)client=MCPClient()try:await client.connect_to_server(sys.argv[1])await client.chat_loop()finally:await client.cleanup()if __name__ == "__main__":asyncio.run(main())
    

1.3 测试运行

  1. 进入项目目录,激活虚拟环境

    cd ./mcp-weather
    source .venv/bin/activate
    
  2. 运行MCP客户端和服务器

    uv run client.py server.py
    
    (mcp-weather) D:\Code\mcp-study\mcp-weather>uv run client.py server.py已连接到服务器,支持以下工具: ['query_weather']MCP客户端已启动!输入'quit'退出you:请问北京今天天气如何?[Calling Tool: query_weather with args: {'city': 'BeiJing'}]ai: 北京今天的天气情况如下:🌍 **北京,中国**
    🌡️ **温度**:22.85℃
    💧 **湿度**:74%
    💨 **风速**:2.14 m/s
    ☁️ **天气状况**:阴天,多云请根据实际需要增减衣物,出行注意安全!
    

二 MCP+Agents SDK基础调用

  • Agents SDK可以将某个对应的Agent封装为client与外部定义好的server进行通信。客户端为client_agent.py、服务端weather_server.py
    在这里插入图片描述

2.1 weather_server.py

import json
import httpx
from typing import Any
from mcp.server.fastmcp import FastMCP# 初始化mcp服务器
mcp=FastMCP("WeatherServer")#OpenWeather API 配置
OPENWEATHER_API_BASE = "https://api.openweathermap.org/data/2.5/weather"
API_KEY ="xxx"
USER_AGENT = "weather-app/1.0"async def fetch_weather(city: str) -> dict[str, Any]|None:"""获取天气信息"""params={"q": city,"appid": API_KEY,"units": "metric","lang": "zh_cn"}headers={"User-Agent": USER_AGENT}async with httpx.AsyncClient() as client:response = await client.get(OPENWEATHER_API_BASE, params=params, headers=headers,timeout=1000)if response.status_code == 200:return response.json()else:print(f"Error fetching weather data: {response.status_code}, {response.text}")  # 增加日志输return Nonedef format_weather(data: dict[str,Any] | str)->str:"""解析天气数据字典,提取关键信息并格式化输出。功能:对可能缺失的嵌套数据字段进行容错处理,确保返回内容完整。参数:data: 天气API返回的原始数据字典返回:格式化后的天气信息字符串"""# 基础位置信息(城市、国家)- 缺失时显示"未知"city = data.get("name", "未知")  # 城市名称(顶层字段)country = data.get("sys", {}).get("country", "未知")  # 国家代码(嵌套在sys字段中)# 天气核心指标 - 缺失时显示"N/A"(Not Available)main_data = data.get("main", {})  # 提取main字段(包含温度、湿度等)temperature = main_data.get("temp", "N/A")  # 温度humidity = main_data.get("humidity", "N/A")  # 湿度wind_data = data.get("wind", {})  # 提取wind字段(包含风速等)wind_speed = wind_data.get("speed", "N/A")  # 风速# 天气描述 - weather字段可能为空列表,默认返回第一个元素的描述weather_list = data.get("weather", [{}])  # 提取weather数组(默认空字典避免索引错误)weather_description = weather_list[0].get("description", "未知")  # 天气状况描述# 格式化输出字符串(使用f-string拼接,添加emoji直观展示)weather_info = (f"🌍 {city}, {country}\n"f"🌡️ 温度:{temperature}℃\n"f"💧 湿度:{humidity}%\n"f"💨 风速:{wind_speed} m/s\n"f"☁️ 天气:{weather_description}\n")return weather_info@mcp.tool()
async def query_weather(city: str) -> str:"""查询天气信息并返回结果"""weather_data = await fetch_weather(city)if weather_data:return format_weather(weather_data)else:return "无法获取天气信息。请检查城市名称是否正确。"if __name__=="__main__":mcp.run(transport='stdio')

2.2 client_agent.py

import asyncio
import time
from openai import AsyncOpenAI
from agents import OpenAIChatCompletionsModel,Agent, Runner, gen_trace_id, trace, set_default_openai_client
from agents.mcp import MCPServer, MCPServerStdio
from agents.model_settings import ModelSettings
from agents import set_tracing_disabled  # or from your framework's module
OPENAI_API_KEY="hk-xxx"
OPENAI_API_BASE="https://api.openai-hk.com/v1"
MODEL="deepseek-v3"# 创建一个Agent对象并调用DeepSeek模型
external_client = AsyncOpenAI(base_url = OPENAI_API_BASE,api_key= OPENAI_API_KEY,
)set_default_openai_client(external_client)
set_tracing_disabled(True)
deepseek_model=OpenAIChatCompletionsModel(model=MODEL,openai_client=external_client)async def run(mcp_server: MCPServer):agent = Agent(name="Assistant",instructions="你是一名助人为乐的助手",mcp_servers=[mcp_server],model=deepseek_model)message = "请帮我查询Beijing天气如何?"print(f"Running: {message}")result = await Runner.run(starting_agent=agent, input=message)print(result.final_output)async def mcp_run():async with MCPServerStdio(name="Weather Server",cache_tools_list=True,params = {"command": "uv","args": ["run", "weather_server.py"]} ) as server:await run(server)if __name__ == "__main__":asyncio.run(mcp_run())

2.3 运行测试

(mcp-weather) D:\Code\mcp-study\mcp-weather>uv run client_agent.py
Running: 请帮我查询Beijing天气如何?
北京当前的天气情况如下:- **温度**34.66- **湿度**54%
- **风速**2.78 m/s
- **天气状况**:晴天气晴朗,但温度较高,请注意防晒和补水!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/91841.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/91841.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Camera相机人脸识别系列专题分析之十九:MTK ISP6S平台FDNode传递三方FFD到APP流程解析

【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了: 这一篇我们开始讲: Camera相机人脸识别系列专题分析之十九:MTK平台FDNode传递三方FFD到APP流程解析 目录 一、背景 二、:OcamMeta传递FFD到APP 2.1:OcamMeta 2.2 :OcamMeta::process更新FFD 2.…

【实时Linux实战系列】构建实时监测与报警系统

在实时系统中&#xff0c;监测与报警系统是确保系统正常运行和及时响应异常情况的关键组件。实时监测与报警系统能够实时收集系统数据&#xff0c;分析关键事件&#xff0c;并在检测到异常时发出警报。这种系统广泛应用于工业自动化、医疗设备监控、网络安全等领域。掌握实时监…

PHP入门及数据类型

PHP数据类型 PHP标记 //HTML风格 <?phpecho "hello world"; ?> //简短风格 <?echo "hello world"; ?>数据类型 PHP 最初源于 Perl 语言&#xff0c;与 Perl 类似&#xff0c;PHP 对数据类型采取较为宽松的态度。PHP 规定&#xff0c;变量数…

沸点 | 嬴图参加世界人工智能大会

2025 WAIC于 7 月 26 日至 28 日在上海举行。大会展览面积突破 7 万平方米&#xff0c;800 余家企业参展。嬴图作为图数据库领域的领先企业&#xff0c;携前沿技术与创新应用精彩亮相。​大会期间&#xff0c;嬴图创始人兼CEO孙宇熙与来自全球的顶尖学者、企业代表共同探讨人工…

2. 字符设备驱动

一、设备号 1.1. 什么是设备号 设备号是用来标记一类设备以及区分这类设备中具体个体的一组号码。 设备号由主设备号和次设备号组成。主设备号的作用为标记一类设备、用于标识设备驱动程序,而次设备号的作用是为了区分这类设备中的具体个体设备及用于标识同一驱动程序下的具…

uboot armv8 启动流程之 linker script

section 详细说明.text按如下顺序&#xff0c;中断向量表vectors, 启动入口代码start.o,普通text, glue &#xff08;arm thumb2 相互调用时自动生成的代码&#xff09;*(.vectors)CPUDIR/start.o (.text*)*(.text*)*(.glue*)__image_copy_start 标记为text 段入口&#xff0c;…

xxljob总结

XXL-Job 支持多种任务类型&#xff0c;以下是常见任务类型的示例 Demo&#xff0c;包含核心配置和代码片段&#xff0c;帮助快速理解用法&#xff1a;一、Bean模式任务&#xff08;最常用&#xff09;通过注解 XxlJob 定义任务方法&#xff0c;直接在 Spring 容器中管理&…

Python包安全工程实践:构建安全可靠的Python生态系统

在现代计算环境中&#xff0c;性能往往是Python包成功的关键因素。本文将深入探讨Python包的性能优化技术&#xff0c;包括并发编程模型、性能分析工具、内存优化策略以及原生代码集成等高级主题&#xff0c;帮助你构建高性能的Python组件。1. 性能分析基础1.1 性能分析工具矩阵…

kubernetes基础知识

个人博客站—运维鹿: http://www.kervin24.top CSDN博客—做个超努力的小奚&#xff1a; https://blog.csdn.net/qq_52914969?typeblog一、kubernetes介绍Kubernetes本质是一组服务器集群&#xff0c;它可以在集群的每个节点上运行特定的程序&#xff0c;来对节点中的容器进行…

winntsetup安装驱动和光驱安装F6功能一样----NT5.2.3790源代码分析

D:\drv>dir驱动器 D 中的卷是 新加卷卷的序列号是 443D-D64BD:\drv 的目录2025-08-03 23:57 <DIR> . 2025-08-03 23:57 <DIR> .. 2008-05-27 10:01 119,068 yk51x86.cat 2008-05-20 10:01 969,380 yk51x86.inf…

Web 开发 11

今天完成了workshop2&#xff0c;进度有点慢&#xff0c;但是记录一下极为愚蠢的一轮轮问答和思考~&#xff01;&#xff08;还是有点成就感的&#xff09;ps&#xff1a;【】内为我的提问1 导入语句&#xff08;ES6 模块导入语法&#xff09;【import CatHappiness from "…

写作路上的迷茫与突破

曾经&#xff0c;我也是那个在写作面前踌躇不前的人。每次提笔&#xff0c;满心都是“我写不好”“我没什么可写的”“我达不到别人的高度”……这些念头像藤蔓一样&#xff0c;紧紧缠绕着我&#xff0c;让我寸步难行。我看着群里的小伙伴们一个个妙笔生花&#xff0c;自己却只…

23 Active Directory攻击与防护策略解析

引言 Active Directory&#xff08;AD&#xff09;是企业IT环境中用户认证、访问控制和身份管理的核心。因其掌握整个网络的"钥匙"&#xff0c;AD常成为攻击者的首要目标。 从凭证转储到隐蔽侦察&#xff0c;攻击者通过多种手段控制AD。无论您是网络安全分析师、红…

【内容规范】关于标题中【】标记的使用说明

【内容规范】关于标题中【】标记的使用说明 在信息爆炸的时代&#xff0c;如何让内容更易识别、更具条理性&#xff0c;成为内容创作者和平台运营者共同关注的问题。标题中【】标记的使用&#xff0c;正是在这种需求下形成的一种实用规范。 这种规范的核心作用在于建立统一的内…

centos 9 安装docker教程

拉取相关依赖 dnf -y install dnf-plugins-core设置阿里云镜像库 dnf config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo安装docker dnf install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plu…

关闭Jetbrains Mono字体连写、连字功能

所谓的关闭Jetbrains Mono字体连写&#xff0c;其实就是更换为Jetbrains Mono NL字体二者的区别就是符号间距的大小不同&#xff0c;也就是有无连字功能。 下图以Visutal Studio为例&#xff1a;

漫花软件集合分享

漫花软件集合分享的各种apk 1、磁盘漫画【推荐】 2、你搜 3、皮皮喵 4、泼辣漫画 5、趣漫画 6、异次元&图源 7、漫 8、再漫画X 9、章鱼漫画 10、芝士漫画&图源 通过网盘分享的文件&#xff1a;漫画软件 链接: https://pan.baidu.com/s/1dlGl50MNzzVOdTP38_…

DB-GPT 0.7.3 版本更新:支持Qwen3 Embedding和Reranker模型、支持知识库自定义检索策略等

V0.7.3版本主要新增、增强了以下核心特性 &#x1f340; 支持Qwen3 Embedding和Reranker模型 &#x1f340; 支持知识库自定义检索策略&#xff1a;语义检索、全文检索、树形检索、混合检索等 &#x1f340; 新增GaussDB数据源支持 &#x1f340; 支持GLM-4.1V多模态模型 …

Django常见模型字段

AutoField:数据库中的自动增长类型&#xff0c;相当于ID自动增长的IntegerField类型字段&#xff0c;对应mysql的Int类型 BooleanField:真/假的布尔类型字段&#xff0c;对应mysql的Tinyint类型 CharField:字符类型字段&#xff0c;对应mysql的varChar类型 DateField:日期字段&…

前端列表封面图如何自不同图片比例不变形

设置图片宽度100%时&#xff0c;若不设置高度&#xff0c;可能导致高度不足导致空白区域。如何实现图片高度自适应填充&#xff0c;避免空白区域&#xff1f;解决方式&#xff1a;加上height&#xff1a;100%&#xff1b;object-fit:cover&#xff1b;就可以始终剪切铺满&#…