MCP实战

MCP

1、基础知识

协议介绍:modelcontextprotocol.io/docs/gettin...

  • MCP Host:集成并使用一个或多个 MCP Client 的AI应用
  • MCP ClientMCP Host中的一个组件,可以与 MCP Server建立通信
  • MCP Server:提供特定能力的工具集合,AI应用可以通过标准协议访问MCP Server提供的各种能力。

调用流程:

  1. MCP Host将用户的"自然语言"请求发送给MCP Client
  2. MCP Client传递用户的请求组装成 Prompt 并调用 LLM,然后获取需要执行的"指令(如,执行的工具+参数)"
  3. MCP Client根据指令请求MCP Server,并得到工具的执行结果
  4. MCP Client得到结果后传递给 LLM,生成自然语言响应

MCP 协议支持两种主要的通信机制:基于标准输入输出(STDIO)本地通信 和基于 HTTP远程通信 (2025 年 3 月 26 日,MCP协议更新:用 Streamable HTTP 替代原先的 HTTP + SSE )。

这两种机制都使用 JSON-RPC 2.0 格式进行消息传输,确保了通信的标准化和可扩展性。

  • 本地通信 :通过 STDIO 传输数据,适用于在同一台机器上运行的客户端和服务器之间的通信。
  • 远程通信 :利用 HTTP,实现跨网络的实时数据传输,适用于需要访问远程资源或分布式部署的场景。

2、实战

2.1 写在前面:调试工具 MCP Inspector

MCP Inspector 是一个用于测试和调试 MCP Server 的交互式开发工具。

启动: mcp dev hello_mcp_server.py

2.2 以 Streamable HTTP 为例

MCP Server
python 复制代码
# mcp_server.py
from mcp.server.fastmcp import FastMCP

# Initialize FastMCP server
mcp = FastMCP(name="mcp-server-demo"
              , host="0.0.0.0"
              , port=2222)


@mcp.tool(name="get_weather", description="获取指定城市的天气信息")
async def get_weather(city: str) -> str:
    weather_data = {
        "北京": "北京:晴,25°C",
        "深圳": "深圳:多云,27°C"
    }
    return weather_data.get(city, f"{city}:无法获取天气信息")


@mcp.tool(name="suggest_activity", description="根据天气推荐适合的活动")
async def suggest_activity(condition: str) -> str:
    if "晴" in condition:
        return "天气晴朗,推荐去户外散步或运动。"
    elif "多云" in condition:
        return "天气多云,适合逛公园或咖啡馆。"
    elif "雨" in condition:
        return "天气下雨,建议在家阅读或看电影。"
    else:
        return "建议进行室内活动。"


# Static resource
@mcp.resource("config://version")
def get_version():
    return "2.0.1"


# Dynamic resource template
@mcp.resource("users://{user_id}/profile")
def get_profile(user_id: int):
    # Fetch profile for user_id...
    return {"name": f"User {user_id}", "status": "active"}


def main():
    print("启动 MCP Server(Streamable HTTP): http://localhost:2222/mcp")
    mcp.run(transport="streamable-http")


if __name__ == "__main__":
    print("[begin]run mcp server")
    main()
    print("[end]run mcp server")
MCP Client
python 复制代码
# mcp_client.py
import asyncio
import os
from contextlib import AsyncExitStack
from datetime import timedelta

from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client

# [可选]避免因网络导致访问不通
os.environ["NO_PROXY"] = "localhost,127.0.0.1"

class WeatherMCPClient:
    def __init__(self, server_url="http://localhost:2222/mcp"):
        self.server_url = server_url
        self._sse_context = None
        self._session = None
        self.exit_stack = AsyncExitStack()

    async def __aenter__(self):
        print(f"[begin]connect to {self.server_url}")
        #  创建 transport 
        stream_transport = await self.exit_stack.enter_async_context(streamablehttp_client(
            url=self.server_url,
            timeout=timedelta(seconds=60),
        ))
        # 创建 session
        read_stream, write_stream, get_session_id = stream_transport
        self._session = await self.exit_stack.enter_async_context(ClientSession(read_stream, write_stream))
        # 初始化 connection
        await self._session.initialize()
        # 打印session_id
        session_id = get_session_id()
        if session_id:
            print(f"Session ID: {session_id}")

        print(f"[end]connect to {self.server_url}")
        return self

    async def __aexit__(self, exc_type, exc_val, exc_tb):
        if self.exit_stack:
            print("\n清理资源并断开连接")
            await self.exit_stack.aclose()

    async def list_tools(self):
        return await self._session.list_tools()

    async def list_resources(self):
        return await self._session.list_resources()

    async def call_tool(self, name, arguments):
        return await self._session.call_tool(name, arguments)


async def main():
    async with WeatherMCPClient() as client:
        print("连接 MCP Server")

        print("\n可用工具:")
        tools = await client.list_tools()
        print(tools)

        print("\n可用资源:")
        resources = await client.list_resources()
        print(resources)

        print("\n调用工具(city=北京)...")
        result = await client.call_tool("get_weather", {"city": "北京"})

        print("\n工具返回:")
        for item in result.content:
            print(" -", item.text)


if __name__ == "__main__":
    print("[begin]run mcp client")
    asyncio.run(main())
    print("[end]run mcp client")
实战
  1. 启动 MCP Server
    python mcp_server.py

  2. 【可选】启动 MCP Inspector ,测试和调试 MCP Server

  • 启动
    mcp dev mcp_server.py
  • 配置Connect
    Transport Type: Streamable HTTP
    URL: http://localhost:2222/mcp
  • 点击"Connect/Disconnect"
  1. 启动 MCP Client python mcp_client.py

2.3 以 STDIO 为例

MCP Server
python 复制代码
# mcp_server.py
from mcp.server.fastmcp import FastMCP

# Initialize FastMCP server
mcp = FastMCP(name="mcp-server-demo")


@mcp.tool(name="get_weather", description="获取指定城市的天气信息")
async def get_weather(city: str) -> str:
    # 同上,略...


@mcp.tool(name="suggest_activity", description="根据天气推荐适合的活动")
async def suggest_activity(condition: str) -> str:
    # 同上,略...


# Static resource
@mcp.resource("config://version")
def get_version():
    # 同上,略...


# Dynamic resource template
@mcp.resource("users://{user_id}/profile")
def get_profile(user_id: int):
    # 同上,略...


def main():
    # 以标准 I/O 方式运行 MCP 服务器
    print("启动 MCP Server(stdio)")
    mcp.run(transport='stdio')


if __name__ == "__main__":
    main()
MCP Client
python 复制代码
# mcp_client.py
import asyncio
from contextlib import AsyncExitStack

from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client


class WeatherMCPClient:
    def __init__(self, server_url="mcp_server.py"):
        # 略...

    async def __aenter__(self):
        print(f"[begin]connect to {self.server_url}")
        # 准备参数
        server_params = StdioServerParameters(
            # 用于启动 MCP Server 的配置
            command='python', args=[self.server_url], env=None
        )
        #  创建 transport 
        stdio_transport = await self.exit_stack.enter_async_context(
            stdio_client(server_params)
        )
        # 创建 session
        read_stream, write_stream = stdio_transport
        self._session = await self.exit_stack.enter_async_context(ClientSession(read_stream, write_stream))
        # 初始化 connection
        await self._session.initialize()
        print(f"[end]connect to {self.server_url}")
        return self

    async def __aexit__(self, exc_type, exc_val, exc_tb):
        if self.exit_stack:
            print("\n清理资源并断开连接")
            await self.exit_stack.aclose()

    async def list_tools(self):
        # 略...

    async def list_resources(self):
        # 略...

    async def call_tool(self, name, arguments):
        # 略...


async def main():
    async with WeatherMCPClient() as client:
        # 略...


if __name__ == "__main__":
    print("[begin]run mcp client")
    asyncio.run(main())
    print("[end]run mcp client")

实战

启动 MCP Client python mcp_client.py

MCP Client 启动后,会去拉起 MCP Server,所以无需手动启动 MCP Server

相关推荐
weixin_462446232 分钟前
Python+React 专为儿童打造的汉字学习平台:从学前到小学的智能汉字教育解决方案
python·学习·react.js
河码匠6 分钟前
Django rest framework 自定义url
后端·python·django
cnxy1887 分钟前
Python Web开发新时代:FastAPI vs Django性能对比
前端·python·fastapi
weixin_4624462312 分钟前
【原创实践】Windows 和 Linux 下使用 Python 3.10 搭建 PaddleOCRVL 识别图片并100%还原表格
linux·windows·python·飞浆
ID_1800790547312 分钟前
除了Python,还有哪些语言可以解析淘宝商品详情API返回的JSON数据?
开发语言·python·json
Irene.ll1 小时前
DAY23
python
专注于大数据技术栈1 小时前
java学习--Collection的迭代器
java·python·学习
梨落秋霜9 小时前
Python入门篇【文件处理】
android·java·python
Java 码农9 小时前
RabbitMQ集群部署方案及配置指南03
java·python·rabbitmq
张登杰踩10 小时前
VIA标注格式转Labelme标注格式
python