构建 MCP 客户端(核心版)

构建 MCP 客户端(核心版)

本页基于官方教程的核心内容,聚焦最小可用实现(方案A:先核心内容,后完整教程),示例与代码均来自官方文档源,便于快速上手与后续扩展。

建议先阅读:/docs/quickstart/server/(了解客户端与服务器的通信模型)

系统要求(Python)

  • macOS 或 Windows
  • 最新 Python 版本
  • 已安装 uv

初始化项目(Python)

# 创建项目目录
uv init mcp-client
cd mcp-client

# 创建虚拟环境
uv venv

# 激活虚拟环境(macOS/Linux)
source .venv/bin/activate

# 安装依赖
uv add mcp anthropic python-dotenv

# 清理样板并新建主文件
rm main.py
touch client.py

Windows PowerShell 等效命令与官方一致,可参考官方教程。

配置 API Key(Anthropic)

echo "ANTHROPIC_API_KEY=<your key here>" > .env
echo ".env" >> .gitignore

客户端骨架代码(来自官方)

import asyncio
from typing import Optional
from contextlib import AsyncExitStack

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

from anthropic import Anthropic
from dotenv import load_dotenv

load_dotenv()  # load environment variables from .env

class MCPClient:
    def __init__(self):
        # Initialize session and client objects
        self.session: Optional[ClientSession] = None
        self.exit_stack = AsyncExitStack()
        self.anthropic = Anthropic()
    # methods will go here

连接 MCP 服务器(官方示例)

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 = "python" 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 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 = [{
        "name": tool.name,
        "description": tool.description,
        "input_schema": tool.inputSchema
    } for tool in response.tools]

    # Initial Claude API call
    response = self.anthropic.messages.create(
        model="claude-3-5-sonnet-20241022",
        max_tokens=1000,
        messages=messages,
        tools=available_tools
    )

    # 后续:解析响应、工具调用编排、聚合最终结果(参见官方教程完整代码)

下一步

  • 补充工具调用执行与结果合并逻辑
  • 新增 TypeScript 版本(与官方教程保持一致)
  • 增加错误处理与重试策略
  • 与 /specification/draft/basic/authorization/ 对齐,接入 OAuth 令牌

完整代码与更多语言版本将分步补齐,保持与官方更新同步。