您的位置:首页 > 科技 > IT业 > 网站小程序app开发_上海装修公司排名49_福建seo优化_网络课程

网站小程序app开发_上海装修公司排名49_福建seo优化_网络课程

2025/7/6 13:11:36 来源:https://blog.csdn.net/qq837993702/article/details/147015563  浏览:    关键词:网站小程序app开发_上海装修公司排名49_福建seo优化_网络课程
网站小程序app开发_上海装修公司排名49_福建seo优化_网络课程

 三、 MCP天气查询服务器server与使用

1. MCP服务器概念介绍

根据MCP协议定义, Server可以提供三种类型的标准能力, Resources、 Tools、 Prompts,每个
Server可同时提供者三种类型能力或其中一种。

  • Resources: 资源,类似于文件数据读取,可以是文件资源或是API响应返回的内容。
  • Tools: 工具,第三方服务、功能函数,通过此可控制LLM可调用哪些函数。
  • Prompts: 提示词,为用户预先定义好的完成特定任务的模板。
     

2. MCP服务器通讯机制

Model Context Protocol(MCP)是一种由 Anthropic 开源的协议,旨在将大型语言模型直接连接
至数据源,实现无缝集成。根据 MCP 的规范,当前支持两种传输方式:标准输入输出(stdio)和基于HTTP 的服务器推送事件(SSE)。而近期,开发者在 MCP 的 GitHub 仓库中提交了一项提案,建议采用“可流式传输的 HTTP”来替代现有的 HTTP+SSE 方案。此举旨在解决当前远程 MCP 传输方式的关键限制,同时保留其优势。 HTTP 和 SSE(服务器推送事件)在数据传输方式上存在明显区别:

  • 通信方式:
    • HTTP:采用请求-响应模式,客户端发送请求,服务器返回响应,每次请求都是独立的。
    • SSE:允许服务器通过单个持久的 HTTP 连接,持续向客户端推送数据,实现实时更新。
  • 连接特性:
    • HTTP:每次请求通常建立新的连接,虽然在 HTTP/1.1 中引入了持久连接,但默认情况下仍是短连接。
    • SSE:基于长连接,客户端与服务器之间保持持续的连接,服务器可以在任意时间推送数据。
  • 适用场景:
    • HTTP:适用于传统的请求-响应场景,如网页加载、表单提交等。
    • SSE:适用于需要服务器主动向客户端推送数据的场景,如实时通知、股票行情更新等。
  • 需要注意的是, SSE 仅支持服务器向客户端的单向通信,而 WebSocket 则支持双向通信。

在 Model Context Protocol(MCP)中, 标准输入输出(stdio)模式是一种用于本地通信的传输方式。在这种模式下, MCP 客户端会将服务器程序作为子进程启动,双方通过标准输入(stdin)和标准输出(stdout)进行数据交换。这种方式适用于客户端和服务器在同一台机器上运行的场景,确保了高效、低延迟的通信。

具体而言,客户端通过标准输入发送请求,服务器通过标准输出返回响应。这种直接的数据传输方式减少了网络延迟和传输开销,适合需要快速响应的本地应用。

相比之下, MCP 还支持基于 HTTP 和服务器推送事件(SSE)的传输方式,适用于客户端和服务器位于不同物理位置的场景。在这种模式下,客户端和服务器通过 HTTP 协议进行通信,利用 SSE 实现服务器向客户端的实时数据推送。

总的来说, stdio 模式提供了一种简单、高效的本地通信方式,适用于客户端和服务器在同一环境下运行的情况。而对于分布式或远程部署的场景,基于 HTTP 和 SSE 的传输方式则更为合适。可流式传输的 HTTP PR: https://github.com/modelcontextprotocol/specification/pull/206

 具体来说, MCP定义了Client与Server进行通讯的协议与消息格式,其支持两种类型通讯机制:标准输入输出通讯、基于SSE的HTTP通讯,分别对应着本地与远程通讯。 Client与Server间使用JSON-RPC 2.0格式进行消息传输。

  • 本地通讯:使用了stdio传输数据,具体流程Client启动Server程序作为子进程,其消息通讯是通过stdin/stdout进行的,消息格式为JSON-RPC 2.0。
  • 远程通讯: Client与Server可以部署在任何地方, Client使用SSE与Server进行通讯,消息的格式为JSON-RPC 2.0, Server定义了/see与/messages接口用于推送与接收数据。

这里我们尝试一个入门级的示例,那就是创建一个天气查询的服务器。通过使用OpenWeather API,创建一个能够实时查询天气的服务器(server),并使用stdio方式进行通信。

OpenWeather官网: https://openweathermap.org/,更多API获取方法

测试查询效果

curl -s "https://api.openweathermap.org/data/2.5/weather?
q=Beijing&appid='YOUR_API_KEY'&units=metric&lang=zh_cn"

 

 测试无误后,接下来即可进入到创建server的环节中。

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

3.1 服务器依赖安装

由于我们需要使用http请求来查询天气,因此需要在当前虚拟环境中添加如下依赖

uv add mcp httpx

3.2 服务器代码编写

接下来尝试创建服务器代码,此时MCP基本执行流程如下:

对应server服务器代码如下:

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 = "YOUR_API_KEY" # 请替换为你自己的 OpenWeather API Key
USER_AGENT = "weather-app/1.0"
async def fetch_weather(city: str) -> dict[str, Any] | None:
"""
从 OpenWeather API 获取天气信息。
:param city: 城市名称(需使用英文, 如 Beijing)
:return: 天气数据字典; 若出错返回包含 error 信息的字典
"""
params = {
"q": city,
"appid": API_KEY,
"units": "metric",
"lang": "zh_cn"
} h
eaders = {"User-Agent": USER_AGENT}
async with httpx.AsyncClient() as client:try:
response = await client.get(OPENWEATHER_API_BASE, params=params,
headers=headers, timeout=30.0)
response.raise_for_status()
return response.json() # 返回字典类型
except httpx.HTTPStatusError as e:
return {"error": f"HTTP 错误: {e.response.status_code}"}
except Exception as e:
return {"error": f"请求失败: {str(e)}"}
def format_weather(data: dict[str, Any] | str) -> str:
"""
将天气数据格式化为易读文本。
:param data: 天气数据(可以是字典或 JSON 字符串)
:return: 格式化后的天气信息字符串
"""
# 如果传入的是字符串, 则先转换为字典
if isinstance(data, str):
try:
data = json.loads(data)
except Exception as e:
return f"无法解析天气数据: {e}"
# 如果数据中包含错误信息, 直接返回错误提示
if "error" in data:
return f"⚠ {data['error']}"
# 提取数据时做容错处理
city = data.get("name", "未知")
country = data.get("sys", {}).get("country", "未知")
temp = data.get("main", {}).get("temp", "N/A")
humidity = data.get("main", {}).get("humidity", "N/A")
wind_speed = data.get("wind", {}).get("speed", "N/A")
# weather 可能为空列表, 因此用 [0] 前先提供默认字典
weather_list = data.get("weather", [{}])
description = weather_list[0].get("description", "未知")
return (
f"🌍 {city}, {country}\n"
f"🌡 温度: {temp}°C\n"
f"💧 湿度: {humidity}%\n"
f"🌬 风速: {wind_speed} m/s\n"
f"⛅ 天气: {description}\n"
)
@mcp.tool()
async def query_weather(city: str) -> str:
"""
输入指定城市的英文名称, 返回今日天气查询结果。
:param city: 城市名称(需使用英文)
:return: 格式化后的天气信息
"""
data = await fetch_weather(city)
return format_weather(data)'''
代码解释如下:
Part 1. 异步获取天气数据
函数 fetch_weather(city: str)
使用 httpx.AsyncClient() 发送异步 GET 请求到 OpenWeather API。
如果请求成功,则调用 response.json() 返回一个字典。
出现异常时,返回包含错误信息的字典。
Part 2. 格式化天气数据
函数 format_weather(data: dict | str)
首先检查传入的数据是否为字符串,如果是,则使用 json.loads 将其转换为字典。
检查数据中是否包含 "error" 字段,如果有,直接返回错误提示。
使用 .get() 方法提取 name 、 sys.country 、 main.temp 、 main.humidity 、
wind.speed 和 weather[0].description 等数据,并为可能缺失的字段提供默认值。
将提取的信息拼接成一个格式化字符串,方便阅读。
Part 3. MCP 工具 query_weather(city: str)
函数 query_weather
通过 @mcp.tool() 装饰器注册为 MCP 服务器的工具,使其能够被客户端调用。
调用 fetch_weather(city) 获取天气数据,然后用 format_weather(data) 将数据格式化
为易读文本,最后返回该字符串。
Part 4. 运行服务器
'''
if __name__ == "__main__":
# 以标准 I/O 方式运行 MCP 服务器
mcp.run(transport='stdio')

 此外,上述代码有两个注意事项,

1. query_weather函数的函数说明至关重要,相当于是此后客户端对函数进行识别的基本依据,因此需要谨慎编写;

2. 当指定 transport='stdio' 运行 MCP 服务器时,客户端必须在启动时同时启动当前这个脚本,
否则无法顺利通信。这是因为 stdio 模式是一种本地进程间通信(IPC, Inter-Process
Communication)方式,它需要服务器作为子进程运行,并通过标准输入输出
( stdin / stdout )进行数据交换。

因此,当我们编写完服务器后,并不能直接调用这个服务器,而是需要创建一个对应的能够进行stdio的客户端,才能顺利进行通信。

4. 天气查询客户端client创建流程

4.1 代码编写

import asyncio
import os
import json
from typing import Optional
from contextlib import AsyncExitStack
from openai import OpenAI
from dotenv import load_dotenv
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
# 加载 .env 文件, 确保 API Key 受到保护
load_dotenv()
class MCPClient:
def __init__(self):
"""初始化 MCP 客户端"""
self.exit_stack = AsyncExitStack()
self.openai_api_key = os.getenv("OPENAI_API_KEY") # 读取 OpenAI API Key
self.base_url = os.getenv("BASE_URL") # 读取 BASE YRL
self.model = os.getenv("MODEL") # 读取 model
if not self.openai_api_key:
raise ValueError("❌ 未找到 OpenAI API Key, 请在 .env 文件中设置
OPENAI_API_KEY")
self.client = OpenAI(api_key=self.openai_api_key, base_url=self.base_url)
# 创建OpenAI client
self.session: Optional[ClientSession] = None
self.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_transport
self.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.tools
print("\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 = [{
"type": "function",
"function": {
"name": tool.name,
"description": tool.description,
"input_schema": tool.inputSchema
}
} for tool in response.tools]
# print(available_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,
) r
eturn 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) # 发送用户输入到 OpenAI
API
print(f"\n🤖 OpenAI: {response}")
except Exception as e:
print(f"\n⚠ 发生错误: {str(e)}")
async def cleanup(self):
"""清理资源"""
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 sys4.2 测试运行
直接提问 请问北京今天天气如何? 运行结果如下所示:
asyncio.run(main())

 4.2 测试运行

# 确认进入到项目目录
cd /root/autodl-tmp/MCP/mcp-client
# 确认激活虚拟环境
source .venv/bin/activate

 

uv run client.py server.py 

直接提问 请问北京今天天气如何? 运行结果如下所示:

 

QwQ-32B推理类模型问答效果如下:


 

4.3 代码解释

MCPClient 类创建过程

1. self.exit_stack = AsyncExitStack()
用于 统一管理异步上下文(如 MCP 连接)的生命周期。
可以在退出( cleanup )时自动关闭。

2. 读取环境变量
openai_api_key : OpenAI API Key
base_url :模型请求的 Base URL(如你自建的反代地址)
model : OpenAI 模型名称

3. 初始化 OpenAI 客户端
OpenAI(api_key=self.openai_api_key, base_url=self.base_url)
你自定义的 OpenAI 客户端,用来与 OpenAI Chat Completion API 通信。

4. self.session
用于保存 MCP 的客户端会话,默认是 None ,稍后通过 connect_to_server 进行连接。

5. 再次声明 self.exit_stack = AsyncExitStack()
这里两次赋值其实有点冗余(前面已赋值过一次)。不过并不影响功能,等同于覆盖掉前面的
对象。可能是手误或调试时多写了一次
 

5.MCP Inspector功能介绍

在实际开发MCP服务器的过程中, Anthropic提供了一个非常便捷的debug工具: Inspector。借助
Inspector,我们能够非常快捷的调用各类server,并测试其功能。 Inspector具体功能实现流程如下。
安装nodejs

curl -fsSL https://deb.nodesource.com/setup_20.x | sudo bash -
sudo apt install -y nodejs

 

 

npx -v

 

运行Inspector

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

 

然后即可在本地浏览器查看当前工具运行情况: http://127.0.0.1:5173/#resources

注,若是使用AutoDL进行本地映射,则需要将5173和3000两个端口映射到本地
 

此时浏览器内容如下:

 

 然后即可查看当前服务器运行状况:


 

四、 MCP更多进阶使用

基于我们当前介绍的MCP开发入门, MCP还有诸多待探索的进阶功能
 

1. MCP服务器Server进阶功能

  • 基于SSE传输的MCP服务器功能实现

        除了stdio连接模式外, MCP还提供了可以服务器、客户端异地运行的SSE传输模式,以适用于更加通用的开发情况。若要实现SSE的MCP服务器通信,需要同时修改客户端和服务器代码。

  • Resources、 Prompt类功能MCP服务器

        除了Tools功能的服务器外, MCP还支持Resources类服务器和Prompt类服务器,其中Resources服务器主要负责提供更多的资源接口,如调用本地文件、数据等,而Prompt类服务器则
是用于设置Agent开发过程中各环节的提示词模板。

  • 更多通用公开&在线服务器调用指南

        MCP标准通信协议带来的最大价值之一,就是让广大Agent开发者能够基于此进行协作。在
MCP推出后的若干时间,已经诞生了数以千计的MCP服务器,允许用户直接下载并进行调用。几个有名的MCP服务器合集(导航站)地址:

MCP官方服务器合集: https://github.com/modelcontextprotocol/servers

MCP Github热门导航: https://github.com/punkpeye/awesome-mcp-servers

MCP集合: https://github.com/ahujasid/blender-mcp

MCP导航: https://mcp.so/

2. MCP客户端Client进阶功能


此外,除了能在命令行中创建MCP客户端外,还支持各类客户端的调用: https://modelcontextprotocol.io/clients

其中借助对话类客户端,如Claude Destop,我们能够轻易的将各类服务器进行集成,从而拓展Claude Destop的性能:



而在一些IDE客户端里,如cline或者Cursor,我们能够直接调用服务器进行开发:

此外,还有一些为MCP量身定制的Agent开发框架,通过集成MCP来提高Agent开发进度:
https://github.com/lastmile-ai/mcp-agent

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com