人工智能助手是否常常让你感到受限于一个数字沙箱?你希望它能总结桌面上的文档,却被告知无法访问本地文件;或者你希望强大的大模型不仅仅是聊天,而是能执行脚本或从私有 API 获取数据。这些限制如今可以通过 模型-语境-协议 (MCP) 来解决。

MCP(Model-Context-Protocol)是由 Anthropic 创建的开源协议,旨在安全有效地为你的大模型提供其一直缺失的语境和工具。 就像 USB-C 为设备连接各种外围设备和配件提供标准化方式一样,MCP 提供了一种标准化方式,将 AI 模型连接到不同的数据源和工具。它将你的 AI 从被动的对话者转变为工作流程中的积极参与者,是时候打破 AI 的枷锁了!

MCP:AI 的通用接口

MCP 的核心在于其作为“通用协议”的角色。 想象一下,你的大模型就像一位拥有强大脑力的专家,但却缺乏实际操作工具和对周边环境的感知。MCP 就像一个通用的适配器,允许这个专家与各种工具和数据源进行交互。

具体来说,MCP 采用标准的客户端-服务器架构。 你正在使用的应用程序(例如文本编辑器或桌面应用程序)充当客户端,该客户端可以连接到一个或多个专用服务器。 这些服务器提供 LLM 可以使用的“工具”或“上下文”。例如,你可以将 VS Code 或 Cursor 这样的文本编辑器作为 MCP Host,通过 MCP Client 管理与 MCP Server 的连接,将 LLM 的意图转化为服务器能够理解的请求。

例如,假设你想让你的大模型阅读并分析一份本地的 CSV 文件。如果没有 MCP大模型只能依赖你手动复制粘贴文件内容,这既繁琐又容易出错。有了 MCP,你就可以创建一个 MCP Server,专门负责读取文件,并将文件内容以结构化的方式传递给大模型。 这样,大模型就能够直接处理原始数据,进行更深入的分析和更准确的回答。

构建 MCP Server:让你的大模型“读懂”文件

理解 MCP 的最佳方式是动手构建一个简单的服务器。 让我们使用 Python 创建一个 MCP Server,该服务器可以读取本地文件的内容。 这将使我们的大模型能够在我们需要时从我们的机器读取文件,这是一项基本且非常有用的技能。

根据文章中的示例代码,我们可以创建一个名为 file_reader.py 的 Python 文件,并添加以下代码:

import os
from pathlib import Path
from typing import Optional
from mcp.server.fastmcp import FastMCP, Context

# Initialize FastMCP server
mcp = FastMCP("file_reader")

@mcp.tool()
async def get_file_content(
    file_path: str,
    encoding: str = "utf-8",
    max_size_mb: int = 10,
    ctx: Optional[Context] = None
) -> str:
    """
    Read and return the content of a file from the specified path.

    Args:
        file_path: The absolute or relative path to the file to read
        encoding: Text encoding to use when reading the file (default: utf-8)
        max_size_mb: Maximum file size allowed in megabytes (default: 10MB)
        ctx: FastMCP context for logging and progress reporting

    Returns:
        The content of the file as a string

    Raises:
        FileNotFoundError: If the file doesn't exist
        PermissionError: If there are insufficient permissions to read the file
        ValueError: If file is too large or other validation errors
    """
    if ctx:
        await ctx.info(f"Reading file: {file_path}")
    try:
        # Convert to Path object for better path handling
        path = Path(file_path)

        # Check if file exists
        if not path.exists():
            error_msg = f"File not found: {file_path}"
            if ctx:
                await ctx.error(error_msg)
            raise FileNotFoundError(error_msg)

        # Check if it's actually a file (not a directory)
        if not path.is_file():
            error_msg = f"Path is not a file: {file_path}"
            if ctx:
                await ctx.error(error_msg)
            raise ValueError(error_msg)

        # Check file size
        file_size_bytes = path.stat().st_size
        max_size_bytes = max_size_mb * 1024 * 1024

        if file_size_bytes > max_size_bytes:
            error_msg = f"File too large: {file_size_bytes / (1024*1024):.2f}MB exceeds limit of {max_size_mb}MB"
            if ctx:
                await ctx.error(error_msg)
            raise ValueError(error_msg)

        if ctx:
            await ctx.info(f"File size: {file_size_bytes / 1024:.1f} KB")

        # Read the file content
        try:
            with open(path, 'r', encoding=encoding) as file:
                content = file.read()

                if ctx:
                    lines_count = content.count('\n') + 1
                    chars_count = len(content)
                    await ctx.info(f"Successfully read file: {lines_count} lines, {chars_count} characters")

                return content

        except UnicodeDecodeError as e:
            error_msg = f"Failed to decode file with encoding '{encoding}': {str(e)}"
            if ctx:
                await ctx.error(error_msg)
            raise ValueError(error_msg)

        except PermissionError as e:
            error_msg = f"Permission denied reading file: {file_path}"
            if ctx:
                await ctx.error(error_msg)
            raise PermissionError(error_msg)
    except Exception as e:
        error_msg = f"Unexpected error reading file: {str(e)}"
        if ctx:
            await ctx.error(error_msg)
        raise

# Main execution block
if __name__ == "__main__":
    mcp.run(transport="stdio")

这段代码定义了一个名为 get_file_content 的工具,它接收文件路径作为输入,并返回文件内容。 通过使用 FastMCP 库,我们可以轻松地将此函数转换为 MCP Server

测试与集成:让你的大模型“用起来”

在将 MCP Server 集成到你的大模型之前,对其进行测试至关重要。 MCP SDK 提供了 MCP Inspector 来测试 MCP 服务器上的所有功能是否正常工作。通过 MCP Inspector,您可以列出工具、输入所需的参数,并验证结果是否符合预期。

完成测试后,您可以将 MCP Server 添加到您喜欢的 AI 助手(确保它支持 MCP)。 对于 VS Code,您可以在 settings.json 文件中添加以下配置:

"mcp": {
  "file-reader": {
    "command": "uv",
    "args":[
      "run",
      "--with",
      "mcp[cli]",
      "mcp",
      "run",
      "your-full-path/file_reader.py"
    ]
  }
}

配置完成后,您就可以在 GitHub Copilot chat 部分(使用 agent mode)中使用该服务器。 例如,您可以要求 Copilot 读取一个文件并进行总结,它将能够通过 MCP Server 读取文件内容并完成任务。

MCP 生态系统:无限的可能性

你无需从头开始构建每个工具。 作为一个开放标准,MCP 鼓励开发者社区构建和共享服务器。 这意味着你可以利用现有的 MCP Server,快速扩展你的大模型的能力。

例如,目前已经存在一些流行的 MCP Server,包括:

  • 文件系统工具:允许 大模型 列出目录、创建文件和搜索整个项目。
  • GitHub:允许 大模型 管理您的存储库、审查 PR 等。
  • Context7:你的文档 LLM 伙伴,允许你的 LLM 使用更新的文档。
  • Memory:允许 LLM 记住所有聊天历史记录或上下文。
  • Sequential Thinking: 通过思维序列进行动态问题解决。

这些 MCP Server大模型 提供了访问各种数据源和工具的能力,从而解锁了新的应用场景。

例如,借助 GitHub MCP Server,你可以让 大模型 帮你审查代码,并根据代码库的风格和最佳实践提出修改建议。 或者,你可以使用文件系统工具,让 大模型 在你的项目文件中查找特定的信息,从而加速开发过程。

MCP 的技术细节:传输层与 JSON-RPC

MCP 具有灵活性,并支持两种主要的传输方法:

  • Stdio 传输:使用程序的标准输入 (stdin) 和标准输出 (stdout) 进行通信。 它简单、高效,非常适合在本地机器上运行工具。
  • 可流式 HTTP 传输:使用 HTTP Server-Sent Events (SSE) 从服务器向客户端流式传输数据,并使用标准 HTTP POST 请求进行客户端到服务器的消息传递。 这非常适合需要通过网络访问的工具。

无论使用哪种传输方式,所有通信都使用 JSON-RPC 2.0 标准,确保消息结构化、可靠且通用。JSON-RPC 确保客户端和服务器可以以标准化的方式进行通信,而无需关心底层的传输细节。这简化了 MCP Server 的开发和集成过程。

MCP 的未来:交互式 AI 的新时代

模型-语境-协议不仅仅是另一个工具;它是人机交互未来的蓝图。 它弥合了 大模型 的抽象智能与我们的个人数据和应用程序的具体、语境丰富的世界之间的关键差距。

通过为模型提供安全和标准化的工具访问方式,MCP 开启了一类新的功能。 你的 大模型 可以成为真正的助手——它不仅提供信息,还积极帮助你在自己的环境中完成工作。

下一次你希望你的 AI 可以做更多的事情时,请记住 MCP。 提升你最喜欢的 LLM 的力量,从字面上看,就在你手中。