MCP Explained: How Modern AI Agents Connect to the Real World

MCP Explained: How Modern AI Agents Connect to the Real World

MCP 详解:现代 AI 智能体如何连接现实世界

In my latest posts, we’ve talked a lot about tool calling, exploring how AI agents decide which tool to use and how to use it. We saw how the model generates a tool call, our code executes it, and the result gets fed back to the model. This works well enough, but there’s a problem we kind of glossed over. That is, where do the tools come from? 在我最近的文章中,我们讨论了很多关于“工具调用”(tool calling)的内容,探讨了 AI 智能体如何决定使用哪个工具以及如何使用它。我们了解了模型如何生成工具调用,我们的代码如何执行它,以及结果如何反馈给模型。这虽然运行良好,但我们忽略了一个问题:这些工具究竟从何而来?

In all of the previously presented examples, we defined the tools ourselves, by hand, in the same Python script as the agent. Apparently, for a tutorial intended to help us understand how all these work, that is fine, but for a real application, this approach quickly falls apart. And that is because every tool needs a custom integration, every new model-tool pair requires its own connector, and so on. 在之前展示的所有示例中,我们都是在智能体所在的同一个 Python 脚本中手动定义工具的。显然,对于旨在帮助我们理解其工作原理的教程来说,这样做没问题,但对于实际应用而言,这种方法很快就会失效。这是因为每个工具都需要定制集成,每一对新的“模型-工具”组合都需要自己的连接器,以此类推。

Think, for instance, that for a setup using three AI models and ten tools, we are already potentially maintaining thirty integrations, and every time one of those elements changes, something may break. In other words, as good as this approach may work for a simple model and tool setup, it doesn’t scale at all. 🤷‍♀️ This is not a niche problem, but rather a major challenge of the agentic AI era. And it is exactly what the Model Context Protocol (MCP) was designed to solve. So, let’s take a look! 🍨 试想一下,如果一个系统使用了三个 AI 模型和十个工具,我们可能就需要维护三十个集成,而且每当其中一个元素发生变化时,系统就可能崩溃。换句话说,这种方法虽然适用于简单的模型和工具配置,但完全无法扩展。🤷‍♀️ 这不是一个小众问题,而是智能体 AI 时代面临的一个重大挑战。而这正是模型上下文协议(Model Context Protocol, MCP)旨在解决的问题。让我们一探究竟吧!🍨

What about MCP?

什么是 MCP?

Before MCP, connecting an AI model to an external tool (like a database, a file system, a Slack workspace, or a GitHub repository) meant writing a custom integration every time. The model needed to know how to call the tool in its specific format, and on the other side, the tool needed to know how to respond in a format the model could understand. If the model changed, we would need to rewrite the integration, and if there was a new tool, we would write another integration from scratch. 在 MCP 出现之前,将 AI 模型连接到外部工具(如数据库、文件系统、Slack 工作区或 GitHub 仓库)意味着每次都要编写定制的集成。模型需要知道如何以特定格式调用工具,而工具端也需要知道如何以模型能理解的格式进行响应。如果模型更换了,我们就需要重写集成;如果有了新工具,我们就得从零开始编写另一个集成。

This is sometimes referred to as the M×N problem, meaning we have M models and N tools, creating the need for M×N custom integrations. As you may imagine, as the number of models and tools that need to be used gets larger, this doesn’t scale very well. 这有时被称为 M×N 问题,意味着如果我们有 M 个模型和 N 个工具,就需要 M×N 个定制集成。可以想象,随着所需模型和工具数量的增加,这种方式的扩展性非常差。

A useful metaphor for understanding this is the evolution and standardization of computer hardware. In the early days of computer peripherals, every printer, every mouse, every keyboard had its own proprietary connector. Eventually, this was resolved by the use of USB as the single, standard connector, and any device that supports it works with any computer that supports it. We can imagine MCP as the USB for AI agents. One standard protocol, and any agent that supports it can connect to any tool that supports it, regardless of which company built them. 理解这一点的一个好比喻是计算机硬件的演进与标准化。在计算机外设的早期,每台打印机、鼠标和键盘都有自己专有的连接器。最终,USB 作为单一标准连接器的出现解决了这个问题,任何支持 USB 的设备都能与任何支持 USB 的计算机配合使用。我们可以把 MCP 想象成 AI 智能体的 USB。通过这一标准协议,任何支持它的智能体都可以连接到任何支持它的工具,无论它们是由哪家公司开发的。

So, the Model Context Protocol is an open standard that enables developers to build secure, two-way connections between their data sources and AI-powered tools. It was created by Anthropic and released as open source in November 2024. Essentially, it replaces custom point-to-point integrations with a single client-server protocol, enabling any MCP-compatible AI host to discover and use any MCP-compatible tools and data resources. 因此,模型上下文协议(MCP)是一个开放标准,使开发者能够在数据源和 AI 工具之间建立安全的双向连接。它由 Anthropic 创建,并于 2024 年 11 月开源。本质上,它用单一的客户端-服务器协议取代了定制的点对点集成,使任何兼容 MCP 的 AI 主机都能发现并使用任何兼容 MCP 的工具和数据资源。

The MCP Architecture

MCP 架构

More specifically, the MCP architecture consists of three main participants: 具体来说,MCP 架构由三个主要参与者组成:

  • The Host: The AI application the user interacts with (e.g., Claude Desktop, VS Code extension). The host manages the model’s context window, decides when to invoke tools, and routes tool outputs back into the conversation. 主机 (Host):用户与之交互的 AI 应用程序(例如 Claude Desktop、VS Code 插件)。主机管理模型的上下文窗口,决定何时调用工具,并将工具输出路由回对话中。
  • The Client: Lives inside the host and manages the connection to one or more MCP servers. It is the part of the app that manages the MCP protocol. 客户端 (Client):存在于主机内部,管理与一个或多个 MCP 服务器的连接。它是应用程序中负责管理 MCP 协议的部分。
  • The Server: Where the actual tools and data live. An MCP server exposes capabilities through a standardised interface. The server never communicates directly with the LLM; all interaction is mediated by the client. 服务器 (Server):实际工具和数据所在的地方。MCP 服务器通过标准化接口公开功能。服务器从不直接与大语言模型(LLM)通信;所有交互都由客户端中介。

Regarding the capabilities exposed by the MCP server, these can be of three types: 关于 MCP 服务器公开的功能,主要有三种类型:

  1. Tools: Executable operations that return output to the AI model (e.g., querying a database, sending an email). 工具 (Tools):可执行的操作,将输出返回给 AI 模型(例如查询数据库、发送电子邮件)。
  2. Resources: Read-only access to data (e.g., file contents, database records, API responses). 资源 (Resources):对数据的只读访问(例如文件内容、数据库记录、API 响应)。
  3. Prompts: Reusable prompt templates that define structured interaction patterns. 提示词 (Prompts):可重用的提示词模板,定义了结构化的交互模式。

A simple MCP server in Python

Python 中的简单 MCP 服务器

So, let’s try all of these in action. Here is what a minimal MCP server looks like in Python, using the official MCP SDK: 让我们付诸实践。以下是使用官方 MCP SDK 在 Python 中构建的最简 MCP 服务器示例:

from mcp.server.fastmcp import FastMCP
import requests

# create an MCP server
mcp = FastMCP("weather-server")

@mcp.tool()
def get_current_weather(city: str, unit: str = "celsius") -> dict:
    """Get the current weather for a given city using Open-Meteo."""
    # geocode the city
    geo = requests.get(
        "https://geocoding-api.open-meteo.com/v1/search", 
        params={"name": city, "count": 1}
    ).json()
    lat = geo["results"][0]["latitude"]
    lon = geo["results"][0]["longitude"]
    
    # fetch weather
    weather = requests.get(
        "https://api.open-meteo.com/v1/forecast", 
        params={
            "latitude": lat, 
            "longitude": lon, 
            "current": "temperature_2m,weather_code", 
            "temperature_unit": unit
        }
    ).json()
    return {"city": city, "data": weather}