在人工智能领域,模型上下文协议(Model Context Protocol,简称 MCP)作为一种标准化的协议,为大型语言模型(LLM)提供了丰富的上下文和工具支持。而 FastMCP 作为构建 MCP 服务器和客户端的 Python 框架,以其简洁的 API 设计、高效的开发体验以及强大的扩展能力,正逐渐成为开发者们的首选工具。
一、FastMCP 简介
FastMCP 是一个用于构建 MCP 服务器和客户端的 Python 框架,其目标是让开发者能够以更少的代码、更高的效率构建出功能强大的 MCP 应用。相比官方的 MCP Python SDK,FastMCP 在多个方面进行了优化和改进,提供了更简洁的 API 设计、更高效的开发体验以及更强大的扩展能力。
FastMCP 的核心优势主要体现在以下几个方面:
(一)简洁的 API 设计
FastMCP 采用了 Pythonic 的设计风格,通过装饰器(Decorator)即可轻松定义工具(Tools)、资源(Resources)和提示(Prompts)。这种设计方式极大地减少了开发过程中的样板代码,让开发者能够更加专注于业务逻辑的实现。
(二)高效的开发体验
FastMCP 提供了丰富的内置功能,如服务器组合、远程服务器代理、OpenAPI/FastAPI 集成等,这些功能不仅提高了开发效率,还为开发者提供了更多的灵活性。此外,FastMCP 还支持多种客户端/服务端传输模式,包括 Stdio、SSE 和内存传输,能够满足不同场景下的开发需求。
(三)强大的扩展能力
FastMCP 的设计具有高度的可扩展性,开发者可以根据自己的需求轻松添加新的功能和模块。无论是构建复杂的 AI 应用,还是进行简单的数据处理,FastMCP 都能够提供强大的支持。
二、FastMCP 与官方 SDK 的关系
FastMCP 1.0 的核心概念已经被纳入官方的 MCP Python SDK,而当前的 FastMCP 2.0 则是在此基础上进行的进一步扩展和优化。FastMCP 2.0 不仅继承了 1.0 版本的基础功能,还引入了完整的客户端支持、服务器组合、OpenAPI/FastAPI 集成、远程服务器代理以及内置测试工具等新功能,显著提升了开发效率和应用的灵活性。
三、开发示例
为了更好地理解 FastMCP 的强大功能和简洁的开发方式,我们以一个基于 FastMCP 的数学运算智能问答应用为例,详细介绍其开发过程。
(一)安装 FastMCP
首先,需要安装 FastMCP 框架。通过以下命令即可完成安装:
uv pip install fastmcp
(二)服务端实现
服务端的实现非常简单,只需要定义几个基本的数学运算工具即可。以下是服务端的代码示例:
from fastmcp import FastMCPmcp = FastMCP(name="MyAssistantServer")@mcp.tool()
def add(a: float, b: float) -> float:"""加法运算参数:a: 第一个数字b: 第二个数字返回:两数之和"""return a + b@mcp.tool()
def subtract(a: float, b: float) -> float:"""减法运算参数:a: 第一个数字b: 第二个数字返回:两数之差 (a - b)"""return a - b@mcp.tool()
def multiply(a: float, b: float) -> float:"""乘法运算参数:a: 第一个数字b: 第二个数字返回:两数之积"""return a * b@mcp.tool()
def divide(a: float, b: float) -> float:"""除法运算参数:a: 被除数b: 除数返回:两数之商 (a / b)异常:ValueError: 当除数为零时"""if b == 0:raise ValueError("除数不能为零")return a / bif __name__ == "__main__":mcp.run(transport='sse', host="127.0.0.1", port=8001)
在上述代码中,我们定义了四个基本的数学运算工具:加法、减法、乘法和除法。通过装饰器 @mcp.tool()
,这些函数被注册为 MCP 服务器的工具,可供客户端调用。最后,通过调用 mcp.run()
方法启动服务器,并指定使用 SSE 传输模式。
(三)客户端实现
客户端的实现同样简单。通过一行代码即可创建一个 MCP 客户端,并连接到服务端。以下是客户端的代码示例:
from fastmcp import Client
import asyncioasync def main():# 测试 mcp 客户端的功能async with Client("http://127.0.0.1:8001/sse") as mcp_client:tools = await mcp_client.list_tools()print(f"Available tools: {tools}")result = await mcp_client.call_tool("add", {"a": 5, "b": 3})print(f"Result: {result[0].text}")if __name__ == "__main__":asyncio.run(main())
在上述代码中,我们通过 Client
类创建了一个 MCP 客户端,并连接到服务端。通过调用 list_tools()
方法,我们可以获取服务端提供的所有工具列表。然后,通过调用 call_tool()
方法,我们可以调用服务端的工具并获取结果。
(四)数学运算智能问答应用
基于 FastMCP,我们还可以构建一个数学运算智能问答应用。该应用通过与大语言模型(LLM)进行交互,根据用户的输入调用相应的工具进行计算,并返回结果。以下是该应用的代码示例:
import asyncio
import json
import logging
import os
from typing import List, Dictfrom fastmcp import Client
from openai import OpenAIclass LLMClient:"""LLM客户端,负责与大语言模型API通信"""def __init__(self, model_name: str, url: str, api_key: str) -> None:self.model_name: str = model_nameself.url: str = urlself.client = OpenAI(api_key=api_key, base_url=url)def get_response(self, messages: List[Dict[str, str]]) -> str:"""发送消息给LLM并获取响应"""response = self.client.chat.completions.create(model=self.model_name,messages=messages,stream=False)return response.choices[0].message.contentclass ChatSession:"""聊天会话,处理用户输入和LLM响应,并与MCP工具交互"""def __init__(self, llm_client: LLMClient, mcp_client: Client) -> None:self.mcp_client: Client = mcp_clientself.llm_client: LLMClient = llm_clientasync def process_llm_response(self, llm_response: str) -> str:"""处理LLM响应,解析工具调用并执行"""try:# 尝试移除可能的markdown格式if llm_response.startswith('```json'):llm_response = llm_response.strip('```json').strip('```').strip()tool_call = json.loads(llm_response)if "tool" in tool_call and "arguments" in tool_call:# 检查工具是否可用tools = await self.mcp_client.list_tools()if any(tool.name == tool_call["tool"] for tool in tools):try:# 执行工具调用result = await self.mcp_client.call_tool(tool_call["tool"], tool_call["arguments"])return f"Tool execution result: {result}"except Exception as e:error_msg = f"Error executing tool: {str(e)}"logging.error(error_msg)return error_msgreturn f"No server found with tool: {tool_call['tool']}"return llm_responseexcept json.JSONDecodeError:# 如果不是JSON格式,直接返回原始响应return llm_responseasync def start(self, system_message: str) -> None:"""启动聊天会话的主循环"""messages = [{"role": "system", "content": system_message}]while True:try:# 获取用户输入user_input = input("用户: ").strip().lower()if user_input in ["quit", "exit", "退出"]:print('AI助手退出')breakmessages.append({"role": "user", "content": user_input})# 获取LLM的初始响应llm_response = self.llm_client.get_response(messages)print("助手: ", llm_response)# 处理可能的工具调用result = await self.process_llm_response(llm_response)# 如果处理结果与原始响应不同,说明执行了工具调用,需要进一步处理while result != llm_response:messages.append({"role": "assistant", "content": llm_response})messages.append({"role": "system", "content": result})# 将工具执行结果发送回LLM获取新响应llm_response = self.llm_client.get_response(messages)result = await self.process_llm_response(llm_response)print("助手: ", llm_response)messages.append({"role": "assistant", "content": llm_response})except KeyboardInterrupt:print('AI助手退出')breakasync def main():async with Client("http://127.0.0.1:8001/sse") as mcp_client:# 初始化LLM客户端,使用通义千问模型llm_client = LLMClient(model_name='qwen-plus-latest', api_key=os.getenv('DASHSCOPE_API_KEY'),url='https://dashscope.aliyuncs.com/compatible-mode/v1')# 获取可用工具列表并格式化为系统提示的一部分tools = await mcp_client.list_tools()dict_list = [tool.__dict__ for tool in tools]tools_description = json.dumps(dict_list, ensure_ascii=False)# 系统提示,指导LLM如何使用工具和返回响应system_message = f'''你是一个智能助手,严格遵循以下协议返回响应:可用工具:{tools_description}响应规则:1、当需要计算时,返回严格符合以下格式的纯净JSON:{{"tool": "tool-name","arguments": {{"argument-name": "value"}}}}2、禁止包含以下内容:- Markdown标记(如```json)- 自然语言解释(如"结果:")- 格式化数值(必须保持原始精度)- 单位符号(如元、kg)校验流程:✓ 参数数量与工具定义一致✓ 数值类型为number✓ JSON格式有效性检查正确示例:用户:单价88.5买235个多少钱?响应:{{"tool":"multiply","arguments":{{"a":88.5,"b":235}}}}错误示例:用户:总金额是多少?错误响应:总价500元 → 含自然语言错误响应:```json{{...}}```→ 含Markdown3、在收到工具的响应后:- 将原始数据转化为自然、对话式的回应- 保持回复简洁但信息丰富- 聚焦于最相关的信息- 使用用户问题中的适当上下文- 避免简单重复使用原始数据'''# 启动聊天会话chat_session = ChatSession(llm_client=llm_client, mcp_client=mcp_client)await chat_session.start(system_message=system_message)if __name__ == "__
__main__":asyncio.run(main())
(五)运行验证
运行服务端代码:
python fast_mcp_server.py
运行客户端代码:
python fast_mcp_client.py
在客户端中输入数学问题,例如:
用户: 现在要购买一批货,单价是 1034.32423,数量是 235326。商家后来又说,可以在这个基础上,打95折,折后总价是多少?
客户端会调用服务端的 multiply
工具进行计算,并返回结果:
助手: {"tool": "multiply","arguments": {"a": 1034.32423,"b": 235326}
}
助手: {"tool": "multiply","arguments": {"a": 243403383.74898,"b": 0.95}
}
助手: 折后总价是231233214.56。
四、FastMCP 的更多功能
除了上述提到的功能外,FastMCP 还提供了许多其他强大的功能,例如:
(一)服务器组合
通过 mcp.mount()
或 mcp.import_server()
方法,可以将多个 FastMCP
实例组合到一个父服务器中,从而构建出模块化的应用程序。这种方式不仅提高了代码的可维护性,还方便了功能的扩展。
(二)OpenAPI/FastAPI 集成
FastMCP 提供了从现有的 OpenAPI 规范或 FastAPI 应用程序生成 FastMCP
服务器的功能。通过这种方式,开发者可以轻松地将现有的 Web API 集成到 MCP 生态系统中,进一步扩展了 MCP 的应用场景。
(三)代理服务器
通过 FastMCP.as_proxy()
方法,可以创建一个代理服务器,该服务器可以作为本地或远程 MCP 服务器的中间层。这种方式特别适用于桥接不同的传输协议(例如,将远程 SSE 服务器代理到本地 Stdio 客户端)或为不受控制的服务器添加逻辑层。
(四)内置测试工具
FastMCP 提供了强大的内置测试工具,支持通过内存传输直接连接到 FastMCP
服务器实例,从而在测试过程中无需进行进程管理和网络调用。这种方式极大地提高了测试效率,降低了测试成本。
五、总结
FastMCP 作为一个高效、简洁且功能强大的 Python 框架,为构建 MCP 服务器和客户端提供了极大的便利。通过其简洁的 API 设计、高效的开发体验和强大的扩展能力,开发者可以快速构建出功能丰富的 MCP 应用。无论是简单的工具开发,还是复杂的 AI 应用构建,FastMCP 都能够满足开发者的需求。
如果你对 MCP 或 FastMCP 感兴趣,不妨尝试使用它来构建自己的应用。相信你一定会被其强大的功能和简洁的设计所吸引。同时,也欢迎关注我的后续文章,我将继续介绍更多关于 MCP 的内容,以及 FastMCP 的高级用法和实战案例。