当前位置: 首页 > news >正文

大语言模型 18 - MCP Model Context Protocol 基本项目 测试案例

MCP

基本介绍

官方地址:

  • https://modelcontextprotocol.io/introduction
    “MCP 是一种开放协议,旨在标准化应用程序向大型语言模型(LLM)提供上下文的方式。可以把 MCP 想象成 AI 应用程序的 USB-C 接口。就像 USB-C 提供了一种标准化的方式,让你的设备能够连接各种外设和配件一样,MCP 也提供了一种标准化的方式,让 AI 模型能够连接不同的数据源和工具。”

在这里插入图片描述
● MCP 主机(MCP Hosts):像 Claude Desktop、IDE 或 AI 工具等程序,它们希望通过 MCP 访问数据。
● MCP 客户端(MCP Clients):维护与服务器 1:1 连接的协议客户端。
● MCP 服务器(MCP Servers):轻量级程序,它们通过标准化的模型上下文协议(Model Context Protocol)公开特定的功能。
● 本地数据源(Local Data Sources):你的计算机上的文件、数据库和服务,MCP 服务器可以安全地访问这些数据。
● 远程服务(Remote Services):通过互联网可用的外部系统(例如 API),MCP 服务器可以与其连接。

https://www.anthropic.com/news/model-context-protocol

测试项目

服务端

使用刚才安装的 uv 创建一个新的项目,并启动虚拟环境

uv init weather
cd weatheruv venv
source .venv/bin/activate

操作结果如下:
在这里插入图片描述

安装依赖

uv add "mcp[cli]" httpx

对应如下:
在这里插入图片描述
编写一个 server:

from typing import Any
import httpx
from mcp.server.fastmcp import FastMCPmcp = FastMCP("weather")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 标识功能
# 根据 区域名称 进行查询
# 这里主要是拼接URL,并且对URL发起了请求make_nws_request
# 最后将返回结果放进format_alert格式化函数
@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 标识功能
# 根据 lng lat 进行查询
# 主要功能类似于 get_alerts
@mcp.tool()
async def get_forecast(latitude: float, longitude: float) -> str:"""Get weather forecast for a location.Args:latitude: Latitude of the locationlongitude: Longitude of the location"""# First get the forecast grid endpointpoints_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 responseforecast_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 forecastperiods = forecast_data["properties"]["periods"]forecasts = []for period in periods[:5]:  # Only show next 5 periodsforecast = f"""{period['name']}:Temperature: {period['temperature']}°{period['temperatureUnit']}Wind: {period['windSpeed']} {period['windDirection']}Forecast: {period['detailedForecast']}"""forecasts.append(forecast)return "\n---\n".join(forecasts)# 启动函数
if __name__ == "__main__":# Initialize and run the servermcp.run(transport='stdio')

客户端

继续新建一个项目:

uv init mcp-client
cd mcp-clientuv venv
source .venv/bin/activate
uv add mcp openai python-dotenv

对应结果如下:
在这里插入图片描述
编写一个 client 代码:

import asyncio
from typing import Optional
from contextlib import AsyncExitStackfrom mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_clientfrom openai import OpenAI
from dotenv import load_dotenv
import jsonload_dotenv()class MCPClient:def __init__(self):# 初始化的参数配置在这里self.session: Optional[ClientSession] = Noneself.exit_stack = AsyncExitStack()self.openai = OpenAI()self.model = "gpt-4o-mini"# 连接到服务器async def connect_to_server(self, server_script_path: str):"""Connect to an MCP serverArgs:server_script_path: Path to the server script (.py or .js)"""# 为了兼容 py 和 jsis_python = server_script_path.endswith('.py')is_js = server_script_path.endswith('.js')if not (is_python or is_js):raise ValueError("Server script must be a .py or .js file")command = "python" if is_python else "node"server_params = StdioServerParameters(command=command,args=[server_script_path],env=None)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()# 从 Server 获取所有用的工具# List available toolsresponse = await self.session.list_tools()tools = response.toolsprint("\nConnected to server with tools:", [tool.name for tool in tools])# 执行查询async def process_query(self, query: str) -> str:"""Process a query using Claude and available tools"""messages = [{"role": "user","content": query}]# 1.从 Server 获取到所有可用的客户端后response = await self.session.list_tools()# 2.转换为 GPT 需要的格式available_tools = [{"type": "function","function": {"name": tool.name,"description": tool.description,"parameters": tool.inputSchema}} for tool in response.tools]# 3.在调用的时候 带着 toolsresponse = self.openai.chat.completions.create(model=self.model,max_tokens=1000,messages=messages,tools=available_tools)tool_results = []final_text = []for choice in response.choices:message = choice.messageis_function_call = message.tool_callsif not is_function_call:final_text.append(message.content)else:tool_name = message.tool_calls[0].function.nametool_args = json.loads(message.tool_calls[0].function.arguments)print(f"Tool Call: {tool_name}")print(f"Tool Call Param: {json.dumps(tool_args, ensure_ascii=False, indent=2)}")result = await self.session.call_tool(tool_name, tool_args)tool_results.append({"call": tool_name, "result": result})final_text.append(f"[Calling tool {tool_name} with args {tool_args}]")if message.content and hasattr(message.content, 'text'):messages.append({"role": "assistant","content": message.content})messages.append({"role": "user","content": result.content})response = self.openai.chat.completions.create(model=self.model,max_tokens=1000,messages=messages,tools=available_tools)final_text.append(response.choices[0].message.content)return "\\n".join(final_text)async def chat_loop(self):"""Run an interactive chat loop"""print("\nMCP Client Started!")print("Type your queries or 'quit' to exit.")while True:try:query = input("\nQuery: ").strip()if query.lower() == 'quit':breakresponse = await self.process_query(query)print("\n" + response)except Exception as e:print(f"\nError: {str(e)}")async def cleanup(self):"""Clean up resources"""await self.exit_stack.aclose()async def main():if len(sys.argv) < 2:print("Usage: python client.py <path_to_server_script>")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__":import sysasyncio.run(main())

测试项目

这里我们启动 Client 端、Server 端。
在这里插入图片描述
第一个参数是 Client 端,第二个是 Server 端:

uv run main.py ../weather/main.py

启动之后,可以看到从 Server 端获取到了目前有的工具:
在这里插入图片描述
我们提问:“What are the weather alerts in California”。
PS:注意,这里需要是美国地址,我们 Server 端中的URL是美国的。
在下面的日志中,我们可以看到 Client 中输出的:

Tool Call: get_alerts
Tool Call Param: {"state": "CA"
}

全部的内容如下所示:

➜ uv run main.py ../weather/main.pyConnected to server with tools: ['get_alerts', 'get_forecast']MCP Client Started!
Type your queries or 'quit' to exit.Query: What are the weather alerts in California
Tool Call: get_alerts
Tool Call Param: {"state": "CA"
}[Calling tool get_alerts with args {'state': 'CA'}]\nHere are the current weather alerts in California:1. **Lake Wind Advisory**- **Area**: Greater Lake Tahoe Area- **Severity**: Moderate- **Description**: Southwest winds 15 to 25 mph with gusts up to 45 mph and waves 1 to 4 feet.- **When**: Until 5 AM PDT Thursday.- **Impacts**: Small boats, kayaks, and paddle boards will be prone to capsizing and should stay off lake waters until conditions improve.- **Instructions**: Check lake conditions before heading out and consider postponing boating activities until a day with less wind.2. **Frost Advisory**- **Area**: Southeastern Mendocino Interior; Southern Lake County- **Severity**: Minor- **Description**: Temperatures as low as 33 will result in frost formation.- **When**: From 2 AM to 10 AM PDT Thursday.- **Impacts**: Frost could harm sensitive outdoor vegetation.- **Instructions**: Take steps now to protect tender plants from the cold.3. **Freeze Warning**- **Area**: Northeastern Mendocino Interior- **Severity**: Moderate- **Description**: Sub-freezing temperatures as low as 30 expected.- **When**: From 3 AM to 10 AM PDT Thursday.- **Impacts**: Frost/Freeze damage to crops.- **Instructions**: Take steps now to protect tender plants from the cold.4. **Freeze Warning**- **Area**: Northwestern Mendocino Interior- **Severity**: Moderate- **Description**: Sub-freezing temperatures as low as 29 expected.- **When**: From 3 AM to 10 AM PDT Thursday.- **Impacts**: Frost/Freeze damage to crops.- **Instructions**: Take steps now to protect tender plants from the cold.5. **Freeze Warning**- **Area**: Northern Lake County- **Severity**: Moderate- **Description**: Sub-freezing temperatures as low as 29 expected.- **When**: From 3 AM to 10 AM PDT Thursday.- **Impacts**: Frost/Freeze damage to crops.- **Instructions**: Take steps now to protect tender plants from the cold.6. **Winter Weather Advisory**- **Area**: Northern Trinity- **Severity**: Moderate- **Description**: Snow above 4000 feet, with additional snow accumulations up to one inch.- **When**: Until 1 AM PDT Thursday.- **Impacts**: Plan on slippery road conditions.- **Instructions**: Slow down and use caution while traveling.7. **Winter Weather Advisory**- **Area**: Western Siskiyou County- **Severity**: Moderate- **Description**: Snow expected, with total accumulations between 6 and 8 inches and up to 12 inches over high remote terrain. Winds gusting as high as 55 mph.- **When**: Until 11 AM PDT Thursday.- **Impacts**: Travel could be difficult, affecting commutes.- **Instructions**: Slow down and use caution while traveling. Call 511 or visit quickmap.dot.ca.gov for road information.Please take necessary precautions based on these alerts!Query:

对应的截图如下所示:
在这里插入图片描述

相关文章:

  • 技术篇-2.3.Golang应用场景及开发工具安装
  • 数巅智能亮相中国石油石化企业信息技术交流大会 以大模型能力驱动能源行业数智化升级
  • AIGC消除软件概览:优化内容创作的新工具
  • 嵌入式STM32学习——串口USART 2.3(串口发送数据控制LED灯)
  • [初阶--使用milvus向量数据库实现简单RAG]
  • 云曦25年春季期中考核复现
  • 滚珠导轨:重构精密仪器传动架构,开启微纳世界
  • MacBookPro上macOS安装第三方应用报错解决方案:遇到:“无法打开“XXX”,因为Apple无法检查其是否包含恶意软件 问题如何解决
  • python学习打卡day33
  • Mysql刷题之正则表达式专题
  • MA网络笔记
  • leetcode2261. 含最多 K 个可整除元素的子数组-medium
  • 关于Python编程语言的详细介绍,结合其核心特性、应用领域和发展现状,以结构化方式呈现:
  • 网络编程 之 从BIO到 NIO加多线程高性能网络编程实战
  • JMeter 教程:响应断言
  • 融合蛋白质语言模型和图像修复模型,麻省理工与哈佛联手提出PUPS ,实现单细胞级蛋白质定位
  • recurrent neural network(rnn)
  • 记录Pycharm断点调试的一个BUG
  • Java的列表、集合、数组的添加一个元素各自用的什么方法?
  • 蜂鸣器模块
  • 网站设计分析/今日热点事件
  • 石景山广州网站建设/百度推广官网
  • 找网络公司建网站每年收维护费/必应搜索推广
  • 装修公司加盟哪个好/seo的中文是什么
  • 哪个做砍价活动的网站好/aso关键词优化计划
  • 做电影网站被告版权/百度top排行榜