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

相关推荐
一百天成为python专家31 分钟前
Python循环语句 从入门到精通
开发语言·人工智能·python·opencv·支持向量机·计算机视觉
Sunhen_Qiletian34 分钟前
朝花夕拾(五)--------Python 中函数、库及接口的详解
开发语言·python
三年呀1 小时前
标题:移动端安全加固:发散创新,筑牢安全防线引言:随着移动互联网
网络·python·安全
悠哉悠哉愿意2 小时前
【Python语法基础学习笔记】if语句
笔记·python·学习
Q_Q19632884753 小时前
python的电影院座位管理可视化数据分析系统
开发语言·spring boot·python·django·flask·node.js·php
BYSJMG3 小时前
计算机大数据毕业设计推荐:基于Hadoop+Spark的食物口味差异分析可视化系统【源码+文档+调试】
大数据·hadoop·分布式·python·spark·django·课程设计
杜子不疼.3 小时前
《Python学习之第三方库:开启无限可能》
开发语言·python·学习
青衫客364 小时前
用 Python 实现一个“小型 ReAct 智能体”:思维链 + 工具调用 + 环境交互
python·大模型·llm·react
带刺的坐椅4 小时前
Java MCP 的鉴权?好简单的啦
java·鉴权·mcp·solon-ai