python之fastmcp2 调用的四种方式
【代码】python之fastmcp2。
·
一、http方式运行服务和客户端
1.1 服务端
# coding=utf-8
'''
@File :demo_basic.py.py
@Author :juxuan2
@Date :2025/12/8 09:20
'''
from fastmcp import FastMCP
from typing import Literal, List
import httpx
# 1. 初始化 FastMCP 服务器(配置元数据 + FastAPI 特性)
mcp = FastMCP(
name="demo_mcp_server",
instructions="FastMCP 2.0 演示服务器:天气查询 + 计算器 + 城市资源",
version="1.0.0"
)
# 2. 定义工具:天气查询(对接 Open-Meteo 公开 API)
@mcp.tool(
name="get_weather_forecast", # 自定义工具名(默认取函数名)
description="查询指定城市7天天气预报"
)
def get_weather_forecast(
city: str,
units: Literal["celsius", "fahrenheit"] = "celsius"
) -> str:
"""
查询指定城市的7天天气预报
:param city: 城市名称(中文/英文)
:param units: 温度单位(摄氏度/华氏度)
:return: 格式化天气预报
"""
# 模拟城市坐标映射(实际场景可对接地理编码 API)
city_coords = {
"北京": (39.9042, 116.4074),
"上海": (31.2304, 121.4737),
"广州": (23.1291, 113.2644),
"New York": (40.7128, -74.0060)
}
if city not in city_coords:
return f"错误:暂不支持{city},支持城市:{list(city_coords.keys())}"
lat, lon = city_coords[city]
# 调用 Open-Meteo 天气 API
try:
response = httpx.get(
"https://api.open-meteo.com/v1/forecast",
params={
"latitude": lat,
"longitude": lon,
"daily": "temperature_2m_max,temperature_2m_min",
"temperature_unit": units,
"timezone": "Asia/Shanghai" if city in ["北京", "上海", "广州"] else "America/New_York"
}
)
response.raise_for_status()
data = response.json()
# 格式化结果
forecast = [f"{city} 7天天气预报({units}):"]
for date, max_temp, min_temp in zip(
data["daily"]["time"],
data["daily"]["temperature_2m_max"],
data["daily"]["temperature_2m_min"]
):
forecast.append(f"{date}:最低 {min_temp}°,最高 {max_temp}°")
return "\n".join(forecast)
except Exception as e:
return f"查询失败:{str(e)}"
# 3. 定义工具:简单计算器(支持加减乘除)
@mcp.tool()
def calculator(
a: float,
b: float,
operation: Literal["add", "subtract", "multiply", "divide"]
) -> str:
"""
数学计算器
:param a: 第一个数值
:param b: 第二个数值
:param operation: 运算类型(add/减/subtract/乘/multiply/除/divide)
:return: 运算结果
"""
if operation == "add":
result = a + b
elif operation == "subtract":
result = a - b
elif operation == "multiply":
result = a * b
elif operation == "divide":
if b == 0:
return "错误:除数不能为0"
result = a / b
else:
return "错误:不支持的运算类型"
return f"{a} {operation} {b} = {result:.2f}"
# 4. 定义资源:向 LLM 提供结构化数据(支持的城市列表)
@mcp.resource(
"resource://supported_cities",
name="supported_cities",
description="天气查询工具支持的城市列表",
mime_type="application/json" # 使用mime_type代替type参数
)
def get_supported_cities() -> List[str]:
"""返回天气服务支持的城市列表"""
return ["北京", "上海", "广州", "New York"]
# 5. 定义提示模板:指导 LLM 正确调用工具
@mcp.prompt(
name="weather_query_guide",
description="LLM 调用天气工具的指导模板"
)
def weather_query_guide() -> str:
return """
协助用户查询天气的规则:
1. 先通过 supported_cities 资源确认用户查询的城市是否支持;
2. 若支持,调用 get_weather_forecast 工具,指定 city 和 units 参数;
3. 若不支持,告知用户并列出支持的城市;
4. 格式化返回结果,确保清晰易读。
"""
# 6. 运行服务器(支持热重载、指定端口/主机)
if __name__ == "__main__":
mcp.run(
transport="http", # 使用HTTP传输
host="0.0.0.0", # 允许外部访问
port=8000 # 端口
)
1.2 客户端
# coding=utf-8
'''
@File :demo_client.py
@Author :juxuan2
@Date :2025/12/8 09:32
'''
import asyncio
import fastmcp
async def load_mcp():
client = fastmcp.Client("http://127.0.0.1:8000/mcp")
async with client:
print(await client.list_tools())
if __name__ == "__main__":
asyncio.run(load_mcp())
二、stdio方式运行服务和客户端
2.1 服务端
from fastmcp import FastMCP
# 创建MCP实例
mcp = FastMCP(
instructions="这是一个简单的天气查询服务",
)
# 注册资源
@mcp.resource("resource://supported_cities", mime_type="application/json")
async def supported_cities():
return ["北京", "上海", "广州", "深圳", "成都", "杭州"]
# 注册工具
@mcp.tool(
name="weather_check",
description="查询指定城市的天气信息",
output_schema={
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "查询的城市名称"
},
"temperature": {
"type": "integer",
"description": "当前温度,单位摄氏度"
},
"condition": {
"type": "string",
"description": "天气状况"
}
}
}
)
async def weather_check(location: str) -> dict:
# 模拟天气数据
weather_data = {
"北京": {"temperature": 22, "condition": "晴朗"},
"上海": {"temperature": 25, "condition": "多云"},
"广州": {"temperature": 28, "condition": "小雨"},
"深圳": {"temperature": 29, "condition": "晴天"},
"成都": {"temperature": 20, "condition": "阴天"},
"杭州": {"temperature": 24, "condition": "多云"}
}
# 检查城市是否支持
if location not in weather_data:
return {
"location": location,
"temperature": None,
"condition": "未知城市"
}
data = weather_data[location]
return {
"location": location,
"temperature": data["temperature"],
"condition": data["condition"]
}
# 运行服务器(stdio模式是默认的,无需指定transport)
mcp.run()
2.2 客户端
import asyncio
import sys
import traceback
from pathlib import Path
from fastmcp import Client
from fastmcp.client.transports import PythonStdioTransport
async def main():
# 通过stdio方式连接到Python脚本服务器
# 这里的"demo_stdio_server.py"是要运行的服务器脚本路径
print(f"使用Python解释器: {sys.executable}")
print(f"当前工作目录: {sys.path[0]}")
try:
# 直接使用PythonStdioTransport来连接,这样可以更清楚地看到错误
transport = PythonStdioTransport(
script_path="demo_stdio_server.py",
log_file=Path("stdio_server.log")
)
client = Client(transport)
print("尝试连接到服务器...")
# 使用上下文管理器建立连接
async with client:
print("已连接到服务器")
# 调用工具
print("调用weather_check工具...")
result = await client.call_tool("weather_check", {
"location": "北京"
})
print(f"天气查询结果: {result}")
# 获取资源
print("获取supported_cities资源...")
resource = await client.read_resource("resource://supported_cities")
print(f"支持的城市列表: {resource}")
# 调用另一个工具
print("调用weather_check工具(上海)...")
result2 = await client.call_tool("weather_check", {
"location": "上海"
})
print(f"天气查询结果: {result2}")
except Exception as e:
print(f"连接或调用失败: {e}")
traceback.print_exc()
if __name__ == "__main__":
asyncio.run(main())
或者
import asyncio
from fastmcp import Client
async def main():
"""通过stdio方式连接FastMCP服务器并调用工具示例"""
# 方式1:直接传入脚本路径,Client会自动推断为stdio传输
client = Client("demo_stdio_server.py")
# 方式2:显式指定stdio传输(更灵活)
# from fastmcp.client.transports import PythonStdioTransport
# transport = PythonStdioTransport(script_path="demo_stdio_server.py")
# client = Client(transport)
try:
# 建立连接
async with client:
print("✅ 已通过stdio方式连接到服务器")
# 调用工具
print("\n📡 调用weather_check工具...")
result = await client.call_tool("weather_check", {
"location": "北京"
})
# 处理结果
if not result.is_error:
print(f"✅ 工具调用成功:")
print(f" 城市:{result.structured_content['location']}")
print(f" 温度:{result.structured_content['temperature']}°C")
print(f" 天气:{result.structured_content['condition']}")
# 读取资源
print("\n📁 读取supported_cities资源...")
resource = await client.read_resource("resource://supported_cities")
print(f"✅ 资源获取成功:")
print(f" 支持的城市:{resource[0].text}")
except Exception as e:
print(f"❌ 连接或调用失败: {e}")
if __name__ == "__main__":
asyncio.run(main())
三、sse方式运行服务和客户端
3.1 服务端
from fastmcp import FastMCP
# 创建MCP实例
mcp = FastMCP(
instructions="这是一个支持SSE传输的天气查询服务",
)
# 注册资源
@mcp.resource("resource://supported_cities", mime_type="application/json")
async def supported_cities():
return ["北京", "上海", "广州", "深圳", "成都", "杭州"]
# 注册工具
@mcp.tool(
name="weather_check",
description="查询指定城市的天气信息",
output_schema={
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "查询的城市名称"
},
"temperature": {
"type": "integer",
"description": "当前温度,单位摄氏度"
},
"condition": {
"type": "string",
"description": "天气状况"
}
}
}
)
async def weather_check(location: str) -> dict:
# 模拟天气数据
weather_data = {
"北京": {"temperature": 22, "condition": "晴朗"},
"上海": {"temperature": 25, "condition": "多云"},
"广州": {"temperature": 28, "condition": "小雨"},
"深圳": {"temperature": 29, "condition": "晴天"},
"成都": {"temperature": 20, "condition": "阴天"},
"杭州": {"temperature": 24, "condition": "多云"}
}
# 检查城市是否支持
if location not in weather_data:
return {
"location": location,
"temperature": None,
"condition": "未知城市"
}
data = weather_data[location]
return {
"location": location,
"temperature": data["temperature"],
"condition": data["condition"]
}
# 运行服务器,使用SSE传输
mcp.run(
transport="sse",
host="0.0.0.0",
port=8001
)
3.2 客户端
import asyncio
from fastmcp import Client
async def main():
# 使用SSE方式连接FastMCP服务器
print("=== 使用SSE方式连接FastMCP服务器 ===")
try:
# 服务器URL(注意必须包含/sse路径)
sse_url = "http://127.0.0.1:8001/sse"
# 创建客户端实例(通过URL中的/sse路径自动推断SSE传输)
print("创建FastMCP客户端实例...")
client = Client(sse_url)
# 建立连接
print("尝试连接到服务器...")
async with client:
print("✅ 客户端连接成功!")
# 读取资源
print("\n📁 读取支持的城市列表...")
resource = await client.read_resource("resource://supported_cities")
print(f"✅ 资源获取成功:")
print(f" 支持的城市:{resource[0].text}")
# 调用工具
print("\n📡 调用weather_check工具(北京)...")
result = await client.call_tool("weather_check", {
"location": "北京"
})
# 处理结果
if not result.is_error:
print(f"✅ 工具调用成功:")
print(f" 城市:{result.structured_content['location']}")
print(f" 温度:{result.structured_content['temperature']}°C")
print(f" 天气:{result.structured_content['condition']}")
else:
print(f"❌ 工具调用失败:{result.error_message}")
except Exception as e:
print(f"❌ 连接或调用失败: {e}")
import traceback
traceback.print_exc()
if __name__ == "__main__":
asyncio.run(main())
四、streamable-http方式运行服务和客户端
4.1 服务端
from fastmcp import FastMCP
# 创建FastMCP实例
mcp = FastMCP(
name="StreamableHttpDemoServer"
)
# 注册资源示例
@mcp.resource("resource://supported_cities")
def get_supported_cities():
"""获取支持的城市列表"""
return ["北京", "上海", "广州", "深圳", "成都", "杭州"]
# 注册工具示例
@mcp.tool
async def weather_check(city: str) -> dict:
"""获取指定城市的天气信息"""
# 模拟天气数据
weather_data = {
"北京": {"temperature": 22, "weather": "晴朗"},
"上海": {"temperature": 25, "weather": "多云"},
"广州": {"temperature": 30, "weather": "阵雨"},
"深圳": {"temperature": 29, "weather": "多云"},
"成都": {"temperature": 19, "weather": "阴天"},
"杭州": {"temperature": 23, "weather": "晴朗"}
}
if city in weather_data:
data = weather_data[city]
return {
"city": city,
"temperature": data["temperature"],
"weather": data["weather"]
}
else:
return {
"city": city,
"temperature": 0,
"weather": "未知城市"
}
# 注册另一个工具示例
@mcp.tool
async def time_check() -> dict:
"""获取当前时间"""
import datetime
now = datetime.datetime.now()
return {
"time": now.strftime("%Y-%m-%d %H:%M:%S"),
"timestamp": now.timestamp()
}
if __name__ == "__main__":
# 使用streamable-http传输方式启动服务器
mcp.run(
transport="streamable-http",
host="0.0.0.0",
port=8002
)
4.2 客户端
import asyncio
from fastmcp import Client
from fastmcp.client.transports import StreamableHttpTransport
async def main():
"""使用streamable-http方式连接FastMCP服务器并演示功能"""
# 服务器URL(streamable-http通常使用普通HTTP路径)
server_url = "http://127.0.0.1:8002/mcp"
try:
print("=== 使用streamable-http方式连接FastMCP服务器 ===")
# 方式1:直接传入URL,Client会自动处理传输方式
# 注意:streamable-http不需要特殊的URL路径标识
print("\n1. 创建客户端实例...")
client = Client(server_url)
# 方式2:显式创建StreamableHttpTransport
# client = Client(StreamableHttpTransport(url=server_url))
# 建立连接
print("2. 尝试连接到服务器...")
async with client:
print("✅ 客户端连接成功!")
# 获取所有可用工具
print("\n3. 获取所有可用工具...")
tools = await client.list_tools()
print(f"✅ 发现 {len(tools)} 个可用工具:")
for i, tool in enumerate(tools, 1):
print(f" {i}. {tool.name} - {tool.description}")
# 打印工具的输入输出模式(如果有)
if hasattr(tool, 'inputSchema') and tool.inputSchema:
print(f" 输入模式: {tool.inputSchema.type if hasattr(tool.inputSchema, 'type') else 'object'}")
if hasattr(tool, 'outputSchema') and tool.outputSchema:
print(f" 输出模式: {tool.outputSchema.type if hasattr(tool.outputSchema, 'type') else 'object'}")
# 读取资源示例
print("\n4. 读取支持的城市列表...")
resource_contents = await client.read_resource("resource://supported_cities")
print(f"✅ 资源获取成功:")
# 处理资源内容
if hasattr(resource_contents, '__iter__') and not isinstance(resource_contents, str):
# 如果是多个资源项
city_list = []
for item in resource_contents:
if hasattr(item, 'text'):
city_list.append(item.text)
else:
city_list.append(str(item))
print(f" 支持的城市:{', '.join(city_list)}")
elif hasattr(resource_contents, 'text'):
# 如果是单个资源项
print(f" 支持的城市:{resource_contents.text}")
else:
# 如果是直接的字符串或列表
print(f" 支持的城市:{resource_contents}")
# 调用天气查询工具
print("\n5. 调用天气查询工具(北京)...")
result = await client.call_tool("weather_check", {
"city": "北京"
})
if not result.is_error:
print(f"✅ 工具调用成功:")
print(f" 城市:{result.structured_content['city']}")
print(f" 温度:{result.structured_content['temperature']}°C")
print(f" 天气:{result.structured_content['weather']}")
else:
print(f"❌ 工具调用失败:{result.error_message}")
# 调用时间查询工具
print("\n6. 调用时间查询工具...")
result = await client.call_tool("time_check", {})
if not result.is_error:
print(f"✅ 工具调用成功:")
print(f" 当前时间:{result.structured_content['time']}")
print(f" 时间戳:{result.structured_content['timestamp']}")
else:
print(f"❌ 工具调用失败:{result.error_message}")
print("\n🎉 所有操作完成!")
except Exception as e:
print(f"❌ 操作失败: {e}")
import traceback
traceback.print_exc()
# 运行主函数
if __name__ == "__main__":
asyncio.run(main())
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐


所有评论(0)