MCP客户端开发——Python FastMCP

MCP是什么

MCP(Model Context Protocol,模型上下文协议)是由Anthropic提出的一项开放标准协议,旨在为大型语言模型(LLMs)与外部数据源及工具的交互建立统一接口 。其核心目标是通过标准化通信方式,使AI模型能够安全、便捷地访问外部资源,例如数据库、API或特定工具,从而提升应用灵活性与扩展性 。MCP的设计理念类似于“AI应用的USB-C接口”,通过模块化架构实现即插即用的集成模式,大幅降低开发复杂度 。该协议自2024年底推出以来,已逐渐成为企业级AI应用开发的重要基础,尤其在跨系统数据融合与工具链扩展场景中展现出显著优势 。相较于传统API,MCP通过统一的数据格式和交互规范,进一步简化了模型上下文的传递流程 。

准备工作

在开始之前,请先安装Python,如果之前安装了fastmcp确保版本<2.0.0

安装FastMCP

pip instasll fastmcp

客户端

导入Fastmcp

import asyncio
from fastmcp import Client

选择一个Transport

FastMCP提供了多种的MCP Transport客户端,包括sse(Server-Sent Events),StreamableHttp(流式HTTP),Studio(标准输入/输出)

Client类接受一个Transport,可以使用的如下

# .venv\Lib\site-packages\fastmcp\client\__init__.py line 15-27
__all__ = [
    "Client", # 客户端
    "ClientTransport", # Transport的父类
    "WSTransport", 
    "SSETransport", # SSE的Transport
    "StdioTransport", # Stdio的Transport
    "PythonStdioTransport", # Python的Transport
    "NodeStdioTransport", # Nodejs的Transport
    "UvxStdioTransport",
    "NpxStdioTransport",
    "FastMCPTransport",
    "StreamableHttpTransport", # StreamableHttp的Transport
]

SSE

import asyncio
from fastmcp import Client
from fastmcp.client import SSETransport # 使用SSETransport 

client = Client(SSETransport("http://localhost:8000/sse"))

参数如下

class SSETransport(ClientTransport):
    """Transport implementation that connects to an MCP server via Server-Sent Events."""

    def __init__(
        self,
        url: str | AnyUrl,
        headers: dict[str, str] | None = None,
        sse_read_timeout: datetime.timedelta | float | int | None = None,
    ):
        ...
参数名使用
urlMCP SSE服务器的
headers自定义请求头
sse_read_timeout连接TimeOut时间

Stdio

import asyncio
from fastmcp import Client
from fastmcp.client import StdioTransport

client = Client(StdioTransport("python" ,["mcp_server.py"])) # 假设mcp_server.py存在

参数如下

class StdioTransport(ClientTransport):
    """
    Base transport for connecting to an MCP server via subprocess with stdio.

    This is a base class that can be subclassed for specific command-based
    transports like Python, Node, Uvx, etc.
    """

    def __init__(
        self,
        command: str,
        args: list[str],
        env: dict[str, str] | None = None,
        cwd: str | None = None,
    ):
    ...
参数名说明示例
command执行命令需运行的可执行命令

python, node, uvx

args传递给命令的参数列表["main.py"],["test.js"]
env为子进程设置的环境变量{"ENV_NAME": "value"}
cwd子进程的当前工作目录/home/mcp_client

初始化

客户端异步运行,必须在块内使用。此上下文管理器处理建立连接、初始化 MCP 会话以及在退出时清理资源。async with

可以使用client.is_connected()判断是否连接

import asyncio
from fastmcp import Client
from fastmcp.client import SSETransport

client = Client(SSETransport("http://localhost:8000/sse"))

async def main():
    async with client:
        print(f"Client状态: {client.is_connected()}")
        # 在这里使用MCP
    print(f"Client状态: {client.is_connected()}")

if __name__ == "__main__":
    asyncio.run(main())

获取可用的工具

tools = await client.list_tools()

获取服务器上可用工具的列表

返回值:list[mcp.types.Tool]:一个包含 Tool 对象的列表。
 

import asyncio
from fastmcp import Client
from fastmcp.client import SSETransport

client = Client(SSETransport("http://localhost:8000/sse")) # Assumes my_mcp_server.py exists

async def main():
    # Connection is established here
    async with client:
        print(f"Client connected: {client.is_connected()}")

        # Make MCP calls within the context
        tools = await client.list_tools()
        print(f"Available tools: {tools}")

    # Connection is closed automatically here
    print(f"Client connected: {client.is_connected()}")

if __name__ == "__main__":
    asyncio.run(main())

输出:

Client connected: True
Available tools: [Tool(name='add', description='计算两个整数的和', inputSchema={'properties': {'a': {'title': 'A', 'type': 'integer'}, 'b': {'title': 'B', 'type': 'integer'}}, 'required': ['a', 'b'], 'title': 'addArguments', 'type': 'object'}, annotations=None), Tool(name='sub', description='计算两个整数的差', inputSchema={'properties': {'a': {'title': 'A', 'type': 'integer'}, 'b': {'title': 'B', 'type': 'integer'}}, 'required': ['a', 'b'], 'title': 'subArguments', 'type': 'object'}, annotations=None), Tool(name='mul', description='计算两个整数的积', inputSchema={'properties': {'a': {'title': 'A', 'type': 'integer'}, 'b': {'title': 'B', 'type': 'integer'}}, 'required': ['a', 'b'], 'title': 'mulArguments', 'type': 'object'}, annotations=None), Tool(name='div', description='计算两个整数的商', inputSchema={'properties': {'a': {'title': 'A', 'type': 'integer'}, 'b': {'title': 'B', 'type': 'integer'}}, 'required': ['a', 'b'], 'title': 'divArguments', 'type': 'object'}, annotations=None), Tool(name='mod', description='计算两个整数的余数', inputSchema={'properties': {'a': {'title': 'A', 'type': 'integer'}, 'b': {'title': 'B', 'type': 'integer'}}, 'required': ['a', 'b'], 'title': 'modArguments', 'type': 'object'}, annotations=None), Tool(name='pow', description='计算两个整数的幂', inputSchema={'properties': {'a': {'title': 'A', 'type': 'integer'}, 'b': {'title': 'B', 'type': 'integer'}}, 'required': ['a', 'b'], 'title': 'powArguments', 'type': 'object'}, annotations=None)]
Client connected: False

调用工具

result = await client.call_tool("add", {"a": 1, "b": 2})

在服务器上调用一个工具。与 call_tool_mcp 不同,如果工具调用导致错误,此方法会引发 ToolError 异常。

参数:
name(str):要调用的工具名称。
arguments(dict[str, Any] | None,可选):传递给工具的参数。默认为 None。

添加一点功能

简单的一个调用Demo

import asyncio
from fastmcp import Client
from fastmcp.client import SSETransport
sse_url = "http://localhost:8000/sse"
client = Client(SSETransport(sse_url))
print("MCP客户端Demo",f"SSE客户端连接地址:{sse_url}")
async def main():
    # Connection is established here
    async with client:
        print(f"Client connected: {client.is_connected()}")

        tools = await client.list_tools()
        for tool in tools:
            print("-"* 20)
            print(f"工具名称: {tool.name}")
            print(f"工具描述: {tool.description}")
            print(f"工具参数: {tool.inputSchema["required"]}")
            print("-"*20)
        use = input("请输入要使用的工具名称: ") # 输入工具名称
        tools = await client.list_tools()
        if any(tool.name == use for tool in tools): # 判断add工具是否存在
            for tool in tools:
                if tool.name == use:
                    required = tool.inputSchema["required"]
                    break
            input_required = {}
            for i in required:
                input_required[i] = input(f"请输入{i}的值: ")
                if tool.inputSchema["properties"][i]["type"] == "int":
                    input_required[i] = int(input_required[i])
                elif tool.inputSchema["properties"][i]["type"] == "boolean":
                    input_required[i] = bool(input_required[i])
                elif tool.inputSchema["properties"][i]["type"] == "number":
                    input_required[i] = float(input_required[i])
                elif tool.inputSchema["properties"][i]["type"] == "string":
                    pass
                else:
                    print(f"未知类型:{tool.inputSchema['properties'][i]['type']}")
            result = await client.call_tool(tool.name, input_required)
            print(f"返回结果: {result}")

    # Connection is closed automatically here
    print(f"Client状态: {client.is_connected()}")

if __name__ == "__main__":
    asyncio.run(main())

服务端

先写代码,下次再介绍。。。

from fastmcp import FastMCP

# 创建一个 FastMCP 服务器实例
mcp = FastMCP("Calculator", instructions="这是一个简单的计算器,包含了加法、减法、乘法、除法、取余、幂运算")

# 定义加法工具
@mcp.tool()
def add(a: int, b: int) -> int:
    """计算两个整数的和"""
    return a + b
@mcp.tool()
def sub(a: int, b: int) -> int:
    """计算两个整数的差"""
    return a -b

@mcp.tool()
def mul(a: int, b: int) -> int:
    """计算两个整数的积"""
    return a * b

@mcp.tool()
def div(a: int, b: int) -> float:
    """计算两个整数的商"""
    return a / b

@mcp.tool()
def mod(a: int, b: int) -> int:
    """计算两个整数的余数"""
    return a % b

@mcp.tool()
def pow(a: int, b: int) -> int:
    """计算两个整数的幂"""
    return a ** b
if __name__ == "__main__":
    # 启动服务器
    mcp.run(transport='sse')

### 使用Python开发MCP服务的核心步骤 #### 环境准备 为了成功运行MCP服务,开发者需要确保已安装必要的软件和依赖项。以下是所需的主要组件及其安装方法: - **Python 3.8+**: MCP服务要求使用较新版本的Python来提供更好的兼容性和性能支持[^1]。 - **pip**: 这是Python的标准包管理工具,用于安装其他所需的库。 - **mcp-sdk-python**: 官方提供的SDK,可以通过以下命令安装: ```bash pip install mcp-sdk-python ``` - **FastAPI 和 Uvicorn**: FastAPI是一个现代、快速(高性能)的Web框架,而Uvicorn则是其推荐的ASGI服务器。两者可以配合使用以构建高效的API服务。安装命令如下: ```bash pip install fastapi uvicorn ``` - **Pydantic**: 数据验证和设置管理工具,能够帮助定义清晰的数据结构并自动处理输入校验。同样可通过`pip`安装: ```bash pip install pydantic ``` --- #### 核心代码实现 以下是一份基于上述技术栈的简单示例代码,展示如何使用Python开发一个基础的MCP服务。 ```python from fastapi import FastAPI, Body from pydantic import BaseModel import mcp_sdk_python as mcp app = FastAPI() class ModelContext(BaseModel): model_id: str context_data: dict @app.post("/execute/") async def execute_model(context: ModelContext = Body(...)): """ 接收来自客户端的请求,并执行相应的逻辑。 :param context: 包含模型ID和其他上下文数据的对象。 :return: 返回执行结果或错误信息。 """ try: # 调用MCP SDK中的功能 result = mcp.execute(model_id=context.model_id, data=context.context_data) return {"status": "success", "result": result} except Exception as e: return {"status": "error", "message": str(e)} if __name__ == "__main__": import uvicorn uvicorn.run(app, host="0.0.0.0", port=8000) ``` 此代码片段展示了如何通过FastAPI接收POST请求并将接收到的数据传递给MCP SDK进行进一步处理。 --- #### 测试与调试 完成基本的服务搭建后,可借助MCP Inspector工具对其进行测试和调试。假设您已经编写了一个名为`server.py`的脚本文件作为您的MCP服务入口点,则可以通过以下方式启动调试模式: ```bash npx @modelcontextprotocol/inspector python /path/to/server.py ``` 这一步骤允许开发者实时监控服务状态以及捕获潜在异常[^3]。 另外,在客户端侧也可以模拟发送请求至该服务端口来进行交互式测试。例如,创建一个简单的Client程序并与之建立连接[^4]: ```python from mcp.client.stdio_server_parameters import StdioServerParameters from mcp.client.mcp_client import McpClient def main(): server_params = StdioServerParameters( command="python", args=["/Users/ser/server.py"], env=None ) with McpClient(server_params) as client: response = client.send({"model_id": "test_model", "data": {}}) print(response) if __name__ == "__main__": main() ``` 以上即为完整的从环境配置到实际编码再到最终部署的一整套流程说明。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值