構建 MCP 客戶端(核心版)

構建 MCP 客戶端(核心版)

本頁基於官方教程的核心內容,聚焦最小可用實作(方案A:先核心內容,後完整教程),示例與代碼均來自官方文檔源,便於快速上手與後續擴展。

建議先閱讀:/docs/quickstart/server/(了解客戶端與服務器的通信模型)

系統要求(Python)

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

初始化專案(Python)

uv init mcp-client
cd mcp-client
uv venv
source .venv/bin/activate
uv add mcp anthropic python-dotenv
rm main.py
touch client.py

配置 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()

class MCPClient:
    def __init__(self):
        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):
    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()

    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:
    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]
    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 令牌