一文看懂什么是MCP(大模型上下文)?用来干什么的?怎么用它?

一文看懂什么是MCP协议,定义、原理、功能、怎么使用和开发

本文技术性比较强,适合从事技术人员阅读,非技术人员可以了解个大概。

最近cursor 0.45版本更新后支持了MCP Server,大大增强了Cursor的协作能力,比如在Composer里面能支持思维链、在线实时搜索、根据工作的上下文情况帮生成适合软件需要的图片等等。

那么,什么是MPC(Model Context Protocol)? 本文介绍下MCP的基本概念、功能价值、工作原理、能做什么以及怎么开发使用,文章最后附带一些相关的学习资料站,基本上学习MCP看这一文就足够了。

打个广告,我开发的这个mcp server插件开源地址:https://github.com/fengin/image-gen-server.git

对接国内的即梦平台,需要注册平台账号,一天一个账号可以免费调用88次,足够用了

无缝与cursor集成,你提你的任务需求,cursor会自动根据你项目的上下文,帮你生成好提示词和调用工具生成,大大提升软件开发效率。

想知道如何开发的?看这里:开发一个MCP Server与Cursor集成,给Cursor插上翅膀!

先看看在Cursor里面的使用效果:

一、什么是MCP(Model Context Protocol)

定义

MCP(Model Context Protocol,模型上下文协议) ,2024年11月底,由 Anthropic 推出的一种开放标准,旨在统一大型语言模型(LLM)与外部数据源和工具之间的通信协议。MCP 的主要目的在于解决当前 AI 模型因数据孤岛限制而无法充分发挥潜力的难题,MCP 使得 AI 应用能够安全地访问和操作本地及远程数据,为 AI 应用提供了连接万物的接口。

MCP 的价值

举个栗子,在过去,为了让大模型等 AI 应用使用我们的数据,要么复制粘贴,要么上传下载,非常麻烦。

即使是最强大模型也会受到数据隔离的限制,形成信息孤岛,要做出更强大的模型,每个新数据源都需要自己重新定制实现,使真正互联的系统难以扩展,存在很多的局限性。

现在,MCP 可以直接在 AI 与数据(包括本地数据和互联网数据)之间架起一座桥梁,通过 MCP 服务器和 MCP 客户端,大家只要都遵循这套协议,就能实现“万物互联”。

有了MCP,可以和数据和文件系统、开发工具、Web 和浏览器自动化、生产力和通信、各种社区生态能力全部集成,实现强大的协作工作能力,它的价值远不可估量。

MCP的价值

MCP 与 Function Calling 的区别

  • MCP(Model Context Protocol),模型上下文协议

  • Function Calling,函数调用

这两种技术都旨在增强 AI 模型与外部数据的交互能力,但 MCP 不止可以增强 AI 模型,还可以是其他的应用系统。

MCP和Function Calling的区别

数据安全性

这样一个理想的“万物互联”生态系统看着很让人着迷。

但是大家是不是担心通过 MCP Server 暴露出来的数据会泄露或被非法访问,这个头疼的问题 MCP 也考虑到了。

MCP 通过标准化的数据访问接口,大大减少了直接接触敏感数据的环节,降低了数据泄露的风险。

还有,MCP 内置了安全机制,确保只有经过验证的请求才能访问特定资源,相当于在数据安全又加上了一道防线。同时,MCP协议还支持多种加密算法,以确保数据在传输过程中的安全性。

例如,MCP 服务器自己控制资源,不需要将 API 密钥等敏感信息提供给 LLM 提供商。这样一来,即使 LLM 提供商受到攻击,攻击者也无法获取到这些敏感信息。

不过,MCP 这套协议/标准,需要大家一起来共建,这个生态才会繁荣,现在,只是测试阶段,一切才刚刚开始,当然,还会涌现出更多的问题。

工作原理

MCP 协议采用了一种独特的架构设计,它将 LLM 与资源之间的通信划分为三个主要部分:客户端、服务器和资源。

客户端负责发送请求给 MCP 服务器,服务器则将这些请求转发给相应的资源。这种分层的设计使得 MCP 协议能够更好地控制访问权限,确保只有经过授权的用户才能访问特定的资源。

工作流程

以下是 MCP 的基本工作流程:

  • 初始化连接:客户端向服务器发送连接请求,建立通信通道。

  • 发送请求:客户端根据需求构建请求消息,并发送给服务器。

  • 处理请求:服务器接收到请求后,解析请求内容,执行相应的操作(如查询数据库、读取文件等)。

  • 返回结果:服务器将处理结果封装成响应消息,发送回客户端。

  • 断开连接:任务完成后,客户端可以主动关闭连接或等待服务器超时关闭。

MCP的工作流程

核心架构

MCP 遵循客户端-服务器架构(client-server),其中包含以下几个核心概念:

  • MCP 主机(MCP Hosts):发起请求的 LLM 应用程序(例如 Claude Desktop、IDE 或 AI 工具)。

  • MCP 客户端(MCP Clients):在主机程序内部,与 MCP server 保持 1:1 的连接。

  • MCP 服务器(MCP Servers):为 MCP client 提供上下文、工具和 prompt 信息。

  • 本地资源(Local Resources):本地计算机中可供 MCP server 安全访问的资源(例如文件、数据库)。

  • 远程资源(Remote Resources):MCP server 可以连接到的远程资源(例如通过 API)。

MCP核心架构

MCP Client

MCP client 充当 LLM 和 MCP server 之间的桥梁,MCP client 的工作流程如下:

  • MCP client 首先从 MCP server 获取可用的工具列表。

  • 将用户的查询连同工具描述通过 function calling 一起发送给 LLM。

  • LLM 决定是否需要使用工具以及使用哪些工具。

  • 如果需要使用工具,MCP client 会通过 MCP server 执行相应的工具调用。

  • 工具调用的结果会被发送回 LLM。

  • LLM 基于所有信息生成自然语言响应。

  • 最后将响应展示给用户。

Claude Desktop 和Cursor都支持了MCP Server接入能力,它们就是作为 MCP client来连接某个MCP Server感知和实现调用。

MCP Server

MCP server 是 MCP 架构中的关键组件,它可以提供 3 种主要类型的功能:

  • 资源(Resources):类似文件的数据,可以被客户端读取,如 API 响应或文件内容。

  • 工具(Tools):可以被 LLM 调用的函数(需要用户批准)。

  • 提示(Prompts):预先编写的模板,帮助用户完成特定任务。

这些功能使 MCP server 能够为 AI 应用提供丰富的上下文信息和操作能力,从而增强 LLM 的实用性和灵活性。

你可以在 MCP Servers Repository 和 Awesome MCP Servers 这两个 repo 中找到许多由社区实现的 MCP server。使用 TypeScript 编写的 MCP server 可以通过 npx 命令来运行,使用 Python 编写的 MCP server 可以通过 uvx 命令来运行。

通信机制

MCP 协议支持两种主要的通信机制:基于标准输入输出的本地通信和基于SSE(Server-Sent Events)的远程通信。

这两种机制都使用 JSON-RPC 2.0 格式进行消息传输,确保了通信的标准化和可扩展性。

  • 本地通信通过 stdio 传输数据,适用于在同一台机器上运行的客户端和服务器之间的通信。

  • 远程通信利用 SSE 与 HTTP 结合,实现跨网络的实时数据传输,适用于需要访问远程资源或分布式部署的场景。

二、MCP能做什么?

引入各种各样的MCP Sever能力,可以大大扩展一些AI工具的能力,比如我们常用的Cursor和Claude

这些官方参考服务器展示了 MCP 核心功能和 SDK 的使用:

数据和文件系统

  • 文件系统 - 具有可配置访问控制的安全文件操作

  • PostgreSQL - 具有架构检查功能的只读数据库访问

  • SQLite - 数据库交互和商业智能功能

  • Google Drive - Google Drive 的文件访问和搜索功能

开发工具

  • Git - 用于读取、搜索和操作 Git 仓库的工具

  • GitHub - 仓库管理、文件操作和 GitHub API 集成

  • GitLab - 支持项目管理的 GitLab API 集成

  • Sentry - 从 Sentry.io 获取和分析问题

Web 和浏览器自动化

  • Brave Search - 使用 Brave 的搜索 API 进行网络和本地搜索

  • Fetch - 为 LLM 使用优化的网络内容获取和转换

  • Puppeteer - 浏览器自动化和网页抓取功能

生产力和通信

  • Slack - 频道管理和消息功能

  • Google Maps - 位置服务、路线和地点详情

  • Memory - 基于知识图谱的持久记忆系统

AI 和专业工具

官方集成的工具

这些 MCP 服务器由公司维护,用于其平台:

  • Axiom - 使用自然语言查询和分析日志、跟踪和事件数据

  • Browserbase - 在云端自动化浏览器交互

  • Cloudflare - 在 Cloudflare 开发者平台上部署和管理资源

  • E2B - 在安全的云沙箱中执行代码

  • Neon - 与 Neon 无服务器 Postgres 平台交互

  • Obsidian Markdown Notes - 读取和搜索 Obsidian 知识库中的 Markdown 笔记

  • Qdrant - 使用 Qdrant 向量搜索引擎实现语义记忆

  • Raygun - 访问崩溃报告和监控数据

  • Search1API - 用于搜索、爬虫和网站地图的统一 API

  • Tinybird - 与 Tinybird 无服务器 ClickHouse 平台交互

社区的一些工具

不断发展的社区开发服务器生态系统扩展了 MCP 的功能:

  • Docker - 管理容器、镜像、卷和网络

  • Kubernetes - 管理 pod、部署和服务

  • Linear - 项目管理和问题跟踪

  • Snowflake - 与 Snowflake 数据库交互

  • Spotify - 控制 Spotify 播放和管理播放列表

  • Todoist - 任务管理集成

更多的可以查看社区服务器列表: MCP Servers Repository

三、怎么使用和开发MCP Server

使用

目前支持的部分工具列表(更多见这里):

客户端

资源

提示

工具

采样

根目录

备注

Claude 桌面应用

所有MCP 功能

Zed

提示以斜杠命令形式出现

Sourcegraph Cody

通过OpenCTX 支持资源

Firebase Genkit

⚠️

支持资源列表和查找

Continue

支持所有MCP功能

GenAIScript

支持工具

Cursor

支持工具

Claude Desktop 使用示例

以 Claude Desktop 为例,配置 MCP 客户端的步骤如下:

  1. 安装 Claude Desktop: 确保已在 macOS 或 Windows 系统上安装最新版本的 Claude Desktop。

  2. 配置 MCP 服务器: 在 Claude Desktop 的配置文件中,配置入口Claude Desktop—>菜单—>Settings—>Developer—>Edit Config:

    Claude Desktop里面配置MCP Server

    添加所需的 MCP 服务器信息,例如:

{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/allowed/files"]
    },
    "git": {
      "command": "uvx",
      "args": ["mcp-server-git", "--repository", "path/to/git/repo"]
    }
  }
}

这里的@modelcontextprotocol/server-filesystem、mcp-server-git是对应的一些MCP Server,可以是开源找来的,也可以是你自己开发的。

配置完后,在主界面对话题右下角就有个锤子出现了,有几个锤子就是配置几个,然后对话中如果涉及使用该工具的,claude就会自动调用

Claude Desktop里面使用MCP Server

Cursor中 使用示例

Cursor工具中集成mcp server功能对开发增加效率非常明显,配置入口在:文件—>首选项—>Cursor Settings—>Features—>MCP Server—>Add new MCP Server

Cursor里面配置MCP Server

配置完后,你需要画图的地方给它提要求就行了,它会自动感知,按上下文生成prompt并调用工具生成图片:

Cursor里面使用MCP Server

生成的图片质量还不错,符合开发需要的图片

Cursor里面使用MCP Server生成图片

开发MCP Server

MCP只是一个协议,只要符合这个协议,理论上所有的语言都可以开发,这里展示用python构建一个简单的 MCP 天气服务器并将其连接到宿主程序 Claude for Desktop的示例:

以下示例如果获取天气接口比较麻烦,具体的实现业务可以不写,你仅写一个hello world返回也可以。主要server.py实现的功能为三步:

  • 注册服务名:server = Server("weather")

  • 注册工具列表描述:@server.list_tools() 注解的方法,注意出入参规范要求

  • 实现具体的工具方法:@server.call_tool()注解的方法,注意出入参规范要求

前置知识

本快速入门假设你熟悉:

  • Python

  • LLM(如 Claude)

系统要求

对于 Python,请确保你安装了 Python 3.9 或更高版本。

配置环境

首先,让我们安装 uv 并设置 Python 项目和环境:

curl -LsSf https://astral.sh/uv/install.sh | sh

安装完成后请重启终端,以确保 uv 命令可以被正确识别。

现在,让我们创建并设置项目:

# 为项目创建新目录
uv init weather
cd weather

# 创建虚拟环境并激活
uv venv
# 实测windows下命令打.\.venv\Scripts\activate 
source .venv/bin/activate

# 安装依赖
uv add mcp httpx 

# 删除模板文件,windows下手动吧
rm hello.py

# 创建我们的文件,windows下手动吧
mkdir -p src/weather
touch src/weather/__init__.py
touch src/weather/server.py

将以下代码添加到 pyproject.toml

...rest of config

[build-system]
requires = [ "hatchling",]
build-backend = "hatchling.build"

[tool.hatch.build.targets.wheel]
packages = ["src/weather"]

[project.scripts]
weather = "weather:main"

将以下代码添加到 __init__.py

from . import server
import asyncio

def main():
    """包的主入口点。"""
    asyncio.run(server.main())

# 可选:在包级别暴露其他重要项
__all__ = ['main', 'server']

现在让我们开始构建服务器。

构建服务器

1. 导入包

将以下内容添加到 server.py 的顶部:

from typing import Any
import asyncio
import httpx
from mcp.server.models import InitializationOptions
import mcp.types as types
from mcp.server import NotificationOptions, Server
import mcp.server.stdio

2. 设置实例

然后初始化服务器实例和 NWS API 的基础 URL:

# mcp核心协议源码对unicode编码处理还有bug,需手动指定为utf-8

stdin.reconfigure(encoding='utf-8')
stdout.reconfigure(encoding='utf-8')

NWS_API_BASE = "https://api.weather.gov"
USER_AGENT = "weather-app/1.0"

server = Server("weather")

3. 实现工具列表

我们需要告诉客户端有哪些工具可用。list_tools() 装饰器会注册这个处理程序:

@server.list_tools()
async def handle_list_tools() -> list[types.Tool]:
    """
    列出可用的工具。
    每个工具使用 JSON Schema 验证来指定其参数。
    """
    return [
        types.Tool(
            name="get-alerts",
            description="获取指定州的天气预警",
            inputSchema={
                "type": "object",
                "properties": {
                    "state": {
                        "type": "string",
                        "description": "两字母州代码(例如 CA、NY)",
                    },
                },
                "required": ["state"],
            },
        ),
        types.Tool(
            name="get-forecast",
            description="获取指定位置的天气预报",
            inputSchema={
                "type": "object",
                "properties": {
                    "latitude": {
                        "type": "number",
                        "description": "位置的纬度",
                    },
                    "longitude": {
                        "type": "number",
                        "description": "位置的经度",
                    },
                },
                "required": ["latitude", "longitude"],
            },
        ),
    ]

这里定义了我们的两个工具:get-alertsget-forecast

4. 辅助函数

接下来,让我们添加用于查询和格式化国家气象服务 API 数据的辅助函数:

async def make_nws_request(client: httpx.AsyncClient, url: str) -> dict[str, Any] | None:
    """向 NWS API 发送请求并进行适当的错误处理。"""
    headers = {
        "User-Agent": USER_AGENT,
        "Accept": "application/geo+json"
    }

    try:
        response = await client.get(url, headers=headers, timeout=30.0)
        response.raise_for_status()
        return response.json()
    except Exception:
        return None

def format_alert(feature: dict) -> str:
    """将预警特征格式化为简洁的字符串。"""
    props = feature["properties"]
    return (
        f"事件:{props.get('event', '未知')}\n"
        f"区域:{props.get('areaDesc', '未知')}\n"
        f"严重程度:{props.get('severity', '未知')}\n"
        f"状态:{props.get('status', '未知')}\n"
        f"标题:{props.get('headline', '无标题')}\n"
        "---"
    )

5. 实现工具执行

工具执行处理程序负责实际执行每个工具的逻辑。让我们添加它:

@server.call_tool()
async def handle_call_tool(
    name: str, arguments: dict | None
) -> list[types.TextContent | types.ImageContent | types.EmbeddedResource]:
    """
    处理工具执行请求。
    工具可以获取天气数据并通知客户端变化。
    """
    if not arguments:
        raise ValueError("缺少参数")
  
    if name == "get-alerts":
        state = arguments.get("state")
        if not state:
            raise ValueError("缺少州参数")

        # 将州代码转换为大写以确保格式一致
        state = state.upper()
        if len(state) != 2:
            raise ValueError("州代码必须是两位字母(例如 CA, NY)")

        async with httpx.AsyncClient() as client:
            alerts_url = f"{NWS_API_BASE}/alerts?area={state}"
            alerts_data = await make_nws_request(client, alerts_url)

            if not alerts_data:
                return [types.TextContent(type="text", text="获取预警数据失败")]

            features = alerts_data.get("features", [])
            if not features:
                return [types.TextContent(type="text", text=f"{state} 没有活跃的预警")]

            # 将每个预警格式化为简洁的字符串
            formatted_alerts = [format_alert(feature) for feature in features[:20]] # 仅取前20个预警
            alerts_text = f"{state} 的活跃预警:\n\n" + "\n".join(formatted_alerts)

            return [
                types.TextContent(
                    type="text",
                    text=alerts_text
                )
            ]
    elif name == "get-forecast":
        try:
            latitude = float(arguments.get("latitude"))
            longitude = float(arguments.get("longitude"))
        except (TypeError, ValueError):
            return [types.TextContent(
                type="text",
                text="无效的坐标。请提供有效的纬度和经度数字。"
            )]
            
        # 基本坐标验证
        if not (-90 <= latitude <= 90) or not (-180 <= longitude <= 180):
            return [types.TextContent(
                type="text",
                text="无效的坐标。纬度必须在 -90 到 90 之间,经度在 -180 到 180 之间。"
            )]

        async with httpx.AsyncClient() as client:
            # 首先获取网格点
            lat_str = f"{latitude}"
            lon_str = f"{longitude}"
            points_url = f"{NWS_API_BASE}/points/{lat_str},{lon_str}"
            points_data = await make_nws_request(client, points_url)

            if not points_data:
                return [types.TextContent(type="text", text=f"获取坐标 {latitude}, {longitude} 的网格点数据失败。此位置可能不受 NWS API 支持(仅支持美国位置)。")]

            # 从响应中提取预报 URL
            properties = points_data.get("properties", {})
            forecast_url = properties.get("forecast")
            
            if not forecast_url:
                return [types.TextContent(type="text", text="从网格点数据获取预报 URL 失败")]

            # 获取预报
            forecast_data = await make_nws_request(client, forecast_url)
            
            if not forecast_data:
                return [types.TextContent(type="text", text="获取预报数据失败")]

            # 格式化预报周期
            periods = forecast_data.get("properties", {}).get("periods", [])
            if not periods:
                return [types.TextContent(type="text", text="没有可用的预报周期")]

            # 将每个周期格式化为简洁的字符串
            formatted_forecast = []
            for period in periods:
                forecast_text = (
                    f"{period.get('name', '未知')}:\n"
                    f"温度: {period.get('temperature', '未知')}°{period.get('temperatureUnit', 'F')}\n"
                    f"风: {period.get('windSpeed', '未知')} {period.get('windDirection', '')}\n"
                    f"{period.get('shortForecast', '无可用预报')}\n"
                    "---"
                )
                formatted_forecast.append(forecast_text)

            forecast_text = f"{latitude}, {longitude} 的预报:\n\n" + "\n".join(formatted_forecast)

            return [types.TextContent(
                type="text",
                text=forecast_text
            )]
    else:
        raise ValueError(f"未知工具: {name}")

6. 运行服务器

最后,实现主函数来运行服务器:

async def main():
    # 使用标准输入/输出流运行服务器
    async with mcp.server.stdio.stdio_server() as (read_stream, write_stream):
        await server.run(
            read_stream,
            write_stream,
            InitializationOptions(
                server_name="weather",
                server_version="0.1.0",
                capabilities=server.get_capabilities(
                    notification_options=NotificationOptions(),
                    experimental_capabilities={},
                ),
            ),
        )

# 如果你想连接到自定义客户端,这是必需的
if __name__ == "__main__":
    asyncio.run(main())

你的服务器已经完成!运行 uv run src/weather/server.py 以确认一切正常。

让我们现在测试你的服务器,从现有的 MCP 宿主程序,Claude for Desktop。

测试你的服务器与 Claude for Desktop

首先,确保你已经安装了 Claude for Desktop。你可以在这里安装最新版本。

接下来,在Claude for Desktop中配置你的MCP服务器,这个在“Claude Desktop 使用示例”章节中有说明。

Windows配置

{
    "mcpServers": {
        "weather": {
            "command": "uv",
            "args": [
                "--directory",
                "C:\\ABSOLUTE\PATH\TO\PARENT\FOLDER\weather",
                "run",
                "weather"
            ]
        }
    }
}

MacOS/Linux配置

{
    "mcpServers": {
        "weather": {
            "command": "uv",
            "args": [
                "--directory",
                "/ABSOLUTE/PATH/TO/PARENT/FOLDER/weather",
                "run",
                "weather"
            ]
        }
    }
}

这告诉 Claude for Desktop:

  1. 有一个名为 “weather” 的 MCP 服务器

  2. 通过运行 uv --directory /ABSOLUTE/PATH/TO/PARENT/FOLDER/weather run weather 来启动它

保存文件,并重新启动 Claude for Desktop

现在你可以通过在 Claude for Desktop 中运行以下命令来测试你的服务器:

  • Sacramento 的天气怎么样?

  • Texas 有什么活跃的天气预警?

幕后原理

当你提出一个问题时:

  1. 客户端将你的问题发送给 Claude

  2. Claude 分析可用的工具并决定使用哪个工具

  3. 客户端通过 MCP 服务器执行选定的工具

  4. 结果返回给 Claude

  5. Claude 组织一个自然语言响应

  6. 响应显示给你!

四、核心的MCP 学习资料

作为AI全书布道者,刚接触MCP也是一头雾水,MCP在2024年年底左右才出来,为了开发一个MCP服务,找过很多资料学习,我把这些其中比较好的学习资料挑选了下,分享给大家,方便大家阅读,也免得大家去网上找零散的资料了。

官方资料

中文学习

框架和实践

其他实践

License:  CC BY 4.0

©2025 AI全书. Some rights reserved.

    备案号: 浙ICP备06043869号-8