Skip to content

MCP Server

MCP(Model Context Protocol)是 Anthropic 推出的开放协议,用于标准化 AI 应用与外部系统的连接方式。它解决的问题很直接:不同 AI 工具(Claude、Cline、Cursor 等)各自实现工具调用机制,导致同一个工具需要为每个 AI 客户端单独适配。MCP 将"AI 调用外部能力"这件事抽象成统一的客户端-服务端架构——AI 工具作为 MCP Client,自定义的能力封装为 MCP Server,双方通过 JSON-RPC 2.0 通信。理解 MCP 的关键在于类比 USB-C 接口:USB-C 统一了设备之间的物理连接标准,MCP 统一了 AI 应用与外部工具之间的通信协议。

协议架构

MCP 采用客户端-服务端模型,通信基于 JSON-RPC 2.0。客户端是 AI 应用(Claude Desktop、Cline、Cursor 等),服务端是开发者自定义的工具服务。

协议定义了三种通信传输方式:stdio(标准输入输出流)Streamable HTTP(HTTP POST + SSE)、以及已废弃的纯 SSE。本地开发最常用的是 stdio——客户端直接启动服务端进程,通过 stdin/stdout 交换 JSON-RPC 消息,无需网络栈,零配置,适合单机场景。

MCP Server 可以暴露三种核心能力:Tools(可调用的函数)、Resources(可读取的数据资源)、Prompts(预定义的提示模板)。其中 Tools 是最常用的,它让 LLM 能够执行具体操作——查询数据库、调用 API、读写文件等。每个 Tool 通过 tools/list 请求被发现,通过 tools/call 请求被调用,服务端负责执行并返回结果。Client 收到工具定义后,将它们注入到 LLM 的上下文中,模型根据用户意图决定是否调用以及传什么参数。

一次完整的工具调用流程:用户在 Claude 中提问 → Claude 分析可用工具列表 → 决定调用 get_weather 并生成参数 → Client 通过 JSON-RPC 向 Server 发送 tools/call 请求 → Server 执行逻辑并返回结果 → Client 将结果反馈给 Claude → Claude 基于结果生成自然语言回答。整个过程对用户透明,用户只看到最终的回答和工具调用的摘要。

用 FastMCP 构建本地 Server

Python 生态下,mcp 官方 SDK 提供了 FastMCP 类,可以用装饰器快速定义工具。FastMCP 会自动从函数签名和 docstring 生成 JSON Schema,省去手动编写工具定义的繁琐。

python
# weather_server.py
from mcp.server.fastmcp import FastMCP
import httpx

mcp = FastMCP("weather")

@mcp.tool()
async def get_weather(city: str) -> str:
    """获取指定城市的天气信息

    Args:
        city: 城市名称,如 北京、上海、深圳
    """
    async with httpx.AsyncClient() as client:
        resp = await client.get(
            "https://wttr.in/" + city,
            params={"format": "j1"},
            timeout=10.0
        )
        data = resp.json()
        current = data["current_condition"][0]
        return (
            f"{city} 当前天气: {current['weatherDesc'][0]['value']}, "
            f"温度 {current['temp_C']}°C, "
            f"湿度 {current['humidity']}%"
        )

mcp.run(transport='stdio')

@mcp.tool() 装饰器将普通 async 函数注册为 MCP Tool。FastMCP 从函数名提取工具名(get_weather),从 docstring 和类型注解自动生成工具描述和参数 Schema。mcp.run(transport='stdio') 启动 stdio 传输模式的服务器,等待客户端连接。

stdio 模式下有一个关键注意点:绝不能向 stdout 写入任何非 JSON-RPC 内容。print() 函数会破坏 JSON-RPC 消息流,导致协议解析失败。日志输出应该使用 logging 模块(默认写入 stderr),或者写入文件。

更完整的 Server 示例

实际工程中,MCP Server 通常暴露多个工具,并需要处理错误、超时和参数校验。以下是一个同时暴露文件操作和系统信息查询的 Server:

python
# dev_tools_server.py
import os
import subprocess
import logging
from pathlib import Path
from mcp.server.fastmcp import FastMCP

logging.basicConfig(level=logging.INFO)
mcp = FastMCP("dev-tools")

@mcp.tool()
def list_files(directory: str, pattern: str = "*") -> str:
    """列出指定目录下的文件

    Args:
        directory: 目录路径,绝对路径或相对路径
        pattern: 文件匹配模式,默认匹配所有文件,如 "*.py" 只列出 Python 文件
    """
    path = Path(directory).expanduser().resolve()
    if not path.exists():
        return f"错误: 目录 {directory} 不存在"
    if not path.is_dir():
        return f"错误: {directory} 不是目录"

    matched = sorted(path.glob(pattern))
    if not matched:
        return f"目录 {directory} 中没有匹配 {pattern} 的文件"

    result = []
    for f in matched[:50]:  # 限制返回数量
        size = f.stat().st_size
        size_str = f"{size}B" if size < 1024 else f"{size/1024:.1f}KB"
        result.append(f"{'[D]' if f.is_dir() else '[F]'} {f.name}  {size_str}")
    return "\n".join(result)

@mcp.tool()
def read_file(filepath: str, max_lines: int = 100) -> str:
    """读取文件内容

    Args:
        filepath: 文件路径
        max_lines: 最多读取的行数,默认 100 行
    """
    path = Path(filepath).expanduser().resolve()
    if not path.exists():
        return f"错误: 文件 {filepath} 不存在"

    try:
        with open(path, "r", encoding="utf-8") as f:
            lines = f.readlines()[:max_lines]
        return "".join(lines)
    except UnicodeDecodeError:
        return "错误: 无法以 UTF-8 编码读取该文件,可能是二进制文件"

@mcp.tool()
def git_status(project_path: str) -> str:
    """获取 Git 仓库的状态信息

    Args:
        project_path: Git 仓库的根目录路径
    """
    path = Path(project_path).expanduser().resolve()
    if not (path / ".git").exists():
        return f"错误: {project_path} 不是一个 Git 仓库"

    result = subprocess.run(
        ["git", "-C", str(path), "status", "--short"],
        capture_output=True, text=True, timeout=10
    )
    if result.returncode != 0:
        return f"Git 执行错误: {result.stderr}"
    if not result.stdout.strip():
        return "工作区干净,没有未提交的更改"
    return result.stdout.strip()

if __name__ == "__main__":
    mcp.run(transport='stdio')

这个 Server 暴露了三个工具:文件列表、文件读取、Git 状态查询。每个工具都做了参数校验和错误处理,返回结构化的文本结果供 LLM 解析。工具粒度按业务语义划分,而非按底层 API 划分——LLM 理解"列出文件"比理解"调用 os.listdir"更容易做出正确决策。

接入 Claude Code

Claude Code 通过配置文件注册 MCP Server。在项目根目录的 .claude/settings.json 中添加:

json
{
  "mcpServers": {
    "dev-tools": {
      "command": "uv",
      "args": ["run", "python", "/absolute/path/to/dev_tools_server.py"]
    }
  }
}

command 是启动 Server 进程的命令,args 是参数列表。Claude Code 启动时会执行这个命令,通过 stdio 与 Server 进程通信。也可以使用全局配置 ~/.claude/settings.json,让所有项目都能使用该 Server。

更常见的做法是用 uvx 直接运行 Python 包形式的 Server,无需指定绝对路径:

json
{
  "mcpServers": {
    "dev-tools": {
      "command": "uvx",
      "args": ["dev-tools-mcp"]
    }
  }
}

这要求 Server 已经打包发布到 PyPI,或者通过 --from 参数指定本地路径。配置完成后重启 Claude Code,新工具会出现在可用工具列表中。可以通过 /mcp 命令查看已连接的 Server 状态。

接入 Claude Desktop

Claude Desktop 的配置文件位于 ~/Library/Application Support/Claude/claude_desktop_config.json(macOS)或 %APPDATA%\Claude\claude_desktop_config.json(Windows)。配置格式与 Claude Code 类似:

json
{
  "mcpServers": {
    "weather": {
      "command": "uv",
      "args": ["--directory", "/absolute/path/to/weather", "run", "weather_server.py"]
    }
  }
}

配置完成后重启 Claude Desktop,对话界面会出现工具图标,点击可以查看已加载的工具列表。直接向 Claude 提问触发工具调用,如"北京今天天气怎么样",Claude 会自动调用 get_weather 工具获取实时数据。

接入 Cline

Cline(原 Claude Dev)是 VS Code 中的 AI 编程助手插件,同样支持 MCP。在 VS Code 设置中搜索 cline.mcpServers,或直接编辑 settings.json

json
{
  "cline.mcpServers": {
    "dev-tools": {
      "command": "uvx",
      "args": ["dev-tools-mcp"]
    }
  }
}

Cline 的 MCP 配置与其他客户端格式一致,但配置入口在 VS Code 的设置文件而非独立配置文件。配置后在 Cline 的对话面板中可以看到新加载的工具。Cline 的特点是面向代码开发场景,因此文件操作、Git 操作类的 MCP Server 与它的契合度最高。

接入 Cursor

Cursor 从 0.40+ 版本开始支持 MCP。配置入口在 Settings → MCP,或者编辑 .cursor/mcp.json 文件:

json
{
  "mcpServers": {
    "dev-tools": {
      "command": "uvx",
      "args": ["dev-tools-mcp"]
    }
  }
}

Cursor 的 MCP 工具会集成到 Agent 模式中,在 @ 符号触发的上下文菜单中选择 MCP 工具。由于 Cursor 本身已经有强大的代码索引和编辑能力,MCP Server 更适合提供 Cursor 不擅长的能力:外部 API 调用、数据库查询、自定义业务逻辑等。