MCP Client 示例(open ai 实现)

前提准备:server文件

环境准备

# Create project directory
uv init mcp-client
cd mcp-client

# Create virtual environment
uv venv

# Activate virtual environment
# On Windows:
.venv\Scripts\activate

# Install required packages
uv add mcp openai python-dotenv

# Create our main file
echo. >  client.py

.env文件
在这里插入图片描述

client.py 代码

import asyncio
from typing import Optional
from contextlib import AsyncExitStack
import os
import json

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

from openai import OpenAI
from dotenv import load_dotenv

load_dotenv()  # load environment variables from .env

api_key = os.environ["OPENAI_API_KEY"]
base_url = os.environ["OPENAI_API_BASE"]


# What are the weather alert in California
class MCPClient:
    def __init__(self):
        # Initialize session and client objects
        self.session: Optional[ClientSession] = None
        self.exit_stack = AsyncExitStack()

        self.openai = OpenAI(api_key=api_key, base_url=base_url)

    async def connect_to_server(self, server_script_path: str):
        """Connect to an MCP server

        Args:
            server_script_path: Path to the server script (.py or .js)
        """
        is_python = server_script_path.endswith(".py")
        is_js = server_script_path.endswith(".js")
        if not (is_python or is_js):
            raise ValueError("Server script must be a .py or .js file")

        command = (
            "D:\\llm\\MCP\\mcp-client\\.venv\\Scripts\\python.exe"
            if is_python
            else "node"
        )
        server_params = StdioServerParameters(
            command=command, args=[server_script_path], env=None
        )

        stdio_transport = await self.exit_stack.enter_async_context(
            stdio_client(server_params)
        )
        self.stdio, self.write = stdio_transport
        self.session = await self.exit_stack.enter_async_context(
            ClientSession(self.stdio, self.write)
        )

        await self.session.initialize()

        # List available tools
        response = await self.session.list_tools()
        tools = response.tools
        print(
            "\nConnected to server with tools:",
            [[tool.name, tool.description, tool.inputSchema] for tool in tools],
        )

    async def process_query(self, query: str) -> str:
        """Process a query using Claude and available tools"""
        messages = [{"role": "user", "content": query}]

        response = await self.session.list_tools()

        available_tools = []

        for tool in response.tools:
            tool_schema = getattr(
                tool,
                "inputSchema",
                {"type": "object", "properties": {}, "required": []},
            )

            openai_tool = {
                "type": "function",
                "function": {
                    "name": tool.name,
                    "description": tool.description,
                    "parameters": tool_schema,
                },
            }
            available_tools.append(openai_tool)

        # Initial Claude API call
        model_response = self.openai.chat.completions.create(
            model="GLM-4-Air-0111",
            max_tokens=1000,
            messages=messages,
            tools=available_tools,
        )

        # Process response and handle tool calls
        tool_results = []
        final_text = []

        messages.append(model_response.choices[0].message.model_dump())
        print(messages[-1])
        if model_response.choices[0].message.tool_calls:
            tool_call = model_response.choices[0].message.tool_calls[0]
            tool_args = json.loads(tool_call.function.arguments)

            tool_name = tool_call.function.name
            result = await self.session.call_tool(tool_name, tool_args)
            tool_results.append({"call": tool_name, "result": result})
            final_text.append(f"[Calling tool {tool_name} with args {tool_args}]")

            messages.append(
                {
                    "role": "tool",
                    "content": f"{result}",
                    "tool_call_id": tool_call.id,
                }
            )

            # Get next response from Claude
            response = self.openai.chat.completions.create(
                model="GLM-4-Air-0111",
                max_tokens=1000,
                messages=messages,
            )

            messages.append(response.choices[0].message.model_dump())
            print(messages[-1])

        return messages[-1]["content"]

    async def chat_loop(self):
        """Run an interactive chat loop"""
        print("\nMCP Client Started!")
        print("Type your queries or 'quit' to exit.")

        while True:
            try:
                query = input("\nQuery: ").strip()

                if query.lower() == "quit":
                    break

                response = await self.process_query(query)
                print("\n" + response)

            except Exception as e:
                print(f"\nError: {str(e)}")

    async def cleanup(self):
        """Clean up resources"""
        await self.exit_stack.aclose()


async def main():
    if len(sys.argv) < 2:
        print("Usage: python client.py <path_to_server_script>")
        sys.exit(1)

    client = MCPClient()
    try:
        await client.connect_to_server(sys.argv[1])
        await client.chat_loop()
    finally:
        await client.cleanup()


if __name__ == "__main__":
    import sys

    asyncio.run(main())


输出

(mcp-client) D:\llm\MCP\mcp-client>python client.py D:\llm\MCP\weather\weather.py
Processing request of type ListToolsRequest

Connected to server with tools: [['get_alerts', 'Get weather alerts for a US state.\n\n    Args:\n        state: Two-letter US state code (e.g. CA, NY)\n    ', {'properties': {'state': {'title': 'State', 'type': 'string'}}, 'required': ['state'], 'title': 'get_alertsArguments', 'type': 'object'}], ['get_forecast', 'Get weather forecast for a location.\n\n    Args:\n        latitude: Latitude of the location\n        longitude: Longitude of the location\n    ', {'properties': {'latitude': {'title': 'Latitude', 'type': 'number'}, 'longitude': {'title': 'Longitude', 'type': 'number'}}, 'required': ['latitude', 'longitude'], 'title': 'get_forecastArguments', 'type': 'object'}]]

MCP Client Started!
Type your queries or 'quit' to exit.

Query: What are the weather alert in California
Processing request of type ListToolsRequest
{'content': None, 'refusal': None, 'role': 'assistant', 'audio': None, 'function_call': None, 'tool_calls': [{'id': 'call_-8960025703641360364', 'function': {'arguments': '{"state": "CA"}', 'name': 'get_alerts'}, 'type': 'function', 'index': 0}]}
Processing request of type CallToolRequest
HTTP Request: GET https://api.weather.gov/alerts/active/area/CA "HTTP/1.1 200 OK"
{'content': 'Here are the current weather alerts for California:\n\n**1. Wind Advisory**\n\n*   **Area:** Mojave Desert Slopes\n*   **Severity:** Moderate\n*   **Description:** West winds 20 to 30 mph with gusts up to 50 mph are expected from noon Wednesday to 7 AM PST Thursday. Gusty winds can blow around unsecured objects, and tree limbs could be blown down, potentially causing power outages.\n*   **Instructions:** Use extra caution while driving, especially for high-profile vehicles.\n\n**2. Lake Wind Advisory**\n\n*   **Area:** Greater Lake Tahoe Area\n*   **Severity:** Moderate\n*   **Description:** Southwest winds 15 to 25 mph with gusts up to 40 mph and waves 2 to 4 feet are expected for Lake Tahoe from 8 AM to 6 PM PST Wednesday. Small boats, kayaks, and paddleboards will be prone to capsizing.\n*   **Instructions:** Check lake conditions before heading out and consider postponing boating activities until conditions improve.\n\n**3. Wind Advisory**\n\n*   **Area:** Coastal Del Norte, Del Norte Interior, Southwestern Humboldt, Northern Humboldt Interior, Southern Humboldt Interior\n*   **Severity:** Moderate\n*   **Description:** South-southeast winds 25 to 35 mph with gusts up to 50 mph (locally up to 60 mph over higher terrain) are expected from 2 AM to 9 AM PST Wednesday. Wind gusts will be particularly strong along windward ridges and exposed coastal headlands.\n*   **Instructions:** Use extra caution while driving, especially for high-profile vehicles.\n\n**4. High Surf Advisory**\n\n*   **Area:** San Luis Obispo County Beaches, Santa Barbara County Central Coast Beaches\n*   **Severity:** Minor\n*   **Description:** Large breaking waves of 8 to 12 feet with dangerous rip currents are expected until 3 AM PST Wednesday.\n*   **Instructions:** Remain out of the water, or stay near occupied lifeguard towers. Stay off rock jetties.\n\n**5. High Surf Advisory**\n\n*   **Area:** Ventura County Beaches\n*   **Severity:** Minor\n*   **Description:** Large breaking waves of 6 to 9 feet with dangerous rip currents are expected until 3 AM PST Wednesday.\n*   **Instructions:** Remain out of the water, or stay near occupied lifeguard towers. Stay off rock jetties.\n\n**6. Wind Advisory**\n\n*   **Area:** Central Siskiyou County (including Interstate 5 from Grenada south to Weed, and the cities of Grenada, Gazelle, and Weed)\n*   **Severity:** Moderate\n*   **Description:** South winds 35 to 45 mph with gusts up to 60 mph are expected from 1 AM to 7 AM PST Wednesday. Gusty winds can blow around unsecured objects, and tree limbs could be blown down, potentially causing power outages.\n*   **Instructions:** Use extra caution while driving, especially for high-profile vehicles.\n\nThese alerts highlight various weather hazards across California, including high winds and dangerous surf conditions. Please heed the instructions provided in each alert to ensure your safety.\n', 'refusal': None, 'role': 'assistant', 'audio': None, 'function_call': None, 'tool_calls': None}

Here are the current weather alerts for California:

**1. Wind Advisory**

*   **Area:** Mojave Desert Slopes
*   **Severity:** Moderate
*   **Description:** West winds 20 to 30 mph with gusts up to 50 mph are expected from noon Wednesday to 7 AM PST Thursday. Gusty winds can blow around unsecured objects, and tree limbs could be blown down, potentially causing power outages.
*   **Instructions:** Use extra caution while driving, especially for high-profile vehicles.

**2. Lake Wind Advisory**

*   **Area:** Greater Lake Tahoe Area
*   **Severity:** Moderate
*   **Description:** Southwest winds 15 to 25 mph with gusts up to 40 mph and waves 2 to 4 feet are expected for Lake Tahoe from 8 AM to 6 PM PST Wednesday. Small boats, kayaks, and paddleboards will be prone to capsizing.
*   **Instructions:** Check lake conditions before heading out and consider postponing boating activities until conditions improve.

**3. Wind Advisory**

*   **Area:** Coastal Del Norte, Del Norte Interior, Southwestern Humboldt, Northern Humboldt Interior, Southern Humboldt Interior
*   **Severity:** Moderate
*   **Description:** South-southeast winds 25 to 35 mph with gusts up to 50 mph (locally up to 60 mph over higher terrain) are expected from 2 AM to 9 AM PST Wednesday. Wind gusts will be particularly strong along windward ridges and exposed coastal headlands.
*   **Instructions:** Use extra caution while driving, especially for high-profile vehicles.

**4. High Surf Advisory**

*   **Area:** San Luis Obispo County Beaches, Santa Barbara County Central Coast Beaches
*   **Severity:** Minor
*   **Description:** Large breaking waves of 8 to 12 feet with dangerous rip currents are expected until 3 AM PST Wednesday.
*   **Instructions:** Remain out of the water, or stay near occupied lifeguard towers. Stay off rock jetties.

**5. High Surf Advisory**

*   **Area:** Ventura County Beaches
*   **Severity:** Minor
*   **Description:** Large breaking waves of 6 to 9 feet with dangerous rip currents are expected until 3 AM PST Wednesday.
*   **Instructions:** Remain out of the water, or stay near occupied lifeguard towers. Stay off rock jetties.

**6. Wind Advisory**

*   **Area:** Central Siskiyou County (including Interstate 5 from Grenada south to Weed, and the cities of Grenada, Gazelle, and Weed)
*   **Severity:** Moderate
*   **Description:** South winds 35 to 45 mph with gusts up to 60 mph are expected from 1 AM to 7 AM PST Wednesday. Gusty winds can blow around unsecured objects, and tree limbs could be blown down, potentially causing power outages.
*   **Instructions:** Use extra caution while driving, especially for high-profile vehicles.

These alerts highlight various weather hazards across California, including high winds and dangerous surf conditions. Please heed the instructions provided in each alert to ensure your safety.

代码解释

代码功能概述

这是一个基于异步编程的MCP(可能是自定义协议)客户端程序,主要实现以下功能:

  1. 连接并控制通过Python/Node.js脚本实现的服务器
  2. 集成OpenAI API进行自然语言处理
  3. 支持工具扩展机制(通过服务器注册工具函数)
  4. 实现交互式聊天界面

关键组件解析

1. 类结构
class MCPClient:
    def __init__(self):
        self.session: Optional[ClientSession] = None  # 客户端会话
        self.exit_stack = AsyncExitStack()  # 异步资源管理器
        self.openai = OpenAI(...)  # OpenAI客户端
2. 核心方法

a. 服务器连接 (connect_to_server)

  • 功能:通过标准输入输出与服务器建立连接
  • 实现细节:
    command = "python.exe" if Python脚本 else "node"  # 根据脚本类型选择解释器
    server_params = StdioServerParameters(...)  # 配置服务器启动参数
    stdio_transport = 建立标准输入输出管道
    self.session = 创建客户端会话
    

b. 查询处理 (process_query)

  • 工作流程:
    1. 获取服务器注册的工具列表
    2. 将工具信息转换为OpenAI兼容格式
    3. 调用语言模型(示例中使用GLM-4模型)
    4. 处理模型返回的工具调用请求
    5. 整合工具调用结果生成最终响应

c. 交互循环 (chat_loop)

  • 实现简单的REPL(Read-Eval-Print Loop)交互界面
  • 支持输入"quit"退出

关键技术点

1. 异步架构
  • 使用asyncio库实现非阻塞IO
  • AsyncExitStack管理异步资源生命周期
  • 协程(coroutine)贯穿整个程序
2. 工具调用机制
response = await self.session.list_tools()  # 获取工具列表
available_tools = [...]  # 转换为OpenAI工具格式
model_response = openai.chat.completions.create(tools=available_tools)  # 带工具调用能力的模型请求
3. 服务集成
  • 通过标准输入输出与子进程通信
  • 支持Python和Node.js服务器脚本
  • 示例服务器路径参数:python client.py path/to/server.py

执行流程

  1. 启动时加载环境变量(OPENAI_API_KEY等)
  2. 通过命令行参数指定服务器脚本
  3. 建立与服务器的连接
  4. 进入交互式聊天循环:
    Query: 今天天气如何?
    → 模型判断需要调用天气查询工具
    → 调用服务器注册的天气工具
    → 整合工具结果生成最终响应
    

该代码展示了现代AI应用开发的典型模式:结合大语言模型与自定义工具扩展,通过异步架构实现高效交互。

注意事项:

 command = (
            "D:\\llm\\MCP\\mcp-client\\.venv\\Scripts\\python.exe"
            if is_python
            else "node"
        )

"D:\\llm\\MCP\\mcp-client\\.venv\\Scripts\\python.exe"MCP Server代码解释器的路径

参考链接:https://modelcontextprotocol.io/quickstart/client

MCP(Model Context Protocol,模型上下文协议)是一种旨在促进 AI 大模型与外部数据源、工具和服务之间高效协作的标准协议。尽管当前引用材料并未具体提及 MCP 支持的 AI 大模型列表[^1],但从其设计目标来看,MCP 的开放性和灵活性使其能够适配多种主流的大规模语言模型以及多模态模型。 通常情况下,支持 MCP 的大模型可能包括但不限于以下几类: ### 常见的支持类别 #### 1. 开放平台上的大规模语言模型 (LLMs) 这些模型通常是开源社区或商业公司开发的语言处理引擎,例如: - **OpenAI 系列**: 如 GPT-3, GPT-3.5 Turbo 和 GPT-4。 - **Anthropic 系列**: Claude 等闭源高性能 LLMs。 - **Meta 系列**: LLama 及其变体版本,如 LLama2[^3]。 #### 2. 跨模态任务优化模型 为了实现更广泛的场景覆盖,部分专注于图像识别、语音转换等领域的大模型也被纳入支持范围之内。比如: - CLIP: 结合视觉理解功能的文字描述生成器; - DALL·E: 文本驱动的艺术创作框架; 需要注意的是,虽然理论上任何遵循 MCP 接口定义规范的大模型都可以接入该体系,但实际上每种特定实现可能会依据自身需求有所取舍。因此,在选用前建议查阅对应 SDK 或服务文档获取最新兼容清单[^2]。 此外,随着技术不断进步,未来还会有更多新型号加入到这个生态系统当中来扩展应用场景边界。 ```java // 示例代码展示如何通过 Spring AI MCP 查询支持模型列表 import org.springframework.ai.mcp.McpClient; public class McpSupportedModelsExample { public static void main(String[] args){ try{ McpClient client = new McpClient("your_api_key"); List<String> models = client.getSupportedModels(); System.out.println("The following models are supported by MCP:"); for(String model : models){ System.out.println("- "+model); } }catch(Exception e){ System.err.println(e.getMessage()); } } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值