MCP协议

1 什么是 MCP?

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

1.1 MCP 与functioncall

MCP是在OpenAI的Function call和GPTs之后出现的,那么它一定是看到了Function call的开发和使用的复杂性,而且看到了GPTs的封闭和不开放性。

Function call可以说是MCP的灵感的来源和基础功能,可以理解Function call等同于工具(tools)。大模型(LLM)能够理解工具的描述和参数的规定,然后,会从一堆工具中去选择一个和几个工具来解决用户提出的问题。没有LLM能自动选择和调用工具的能力,也没有MCP这个概念的可能。这是MCP的源头和基础,不得不说,这是OpenAI的巨大原始贡献。

但是,Function call,或者 Tools 使用,对很多开发者,就不用说一般用户了,尽管能用大模型来copilot,还是很不方便,网络访问,权限控制,流程控制,错误处理,可靠性,版本维护,升级改动,等等,一大堆事情都要去编程处理。而且,对不同的应用场景,可能还需要定制化。

既然Function call这么复杂不好用,那么OpenAI提出了GPTs的概念,说白的,GPTs就类似于微信的小程序,它的底层实现,依然是基于Function call,做好的一个一个GPTs,用户可以选择使用哪一个。这儿的问题是,GPTs相当于是已经包装好的闭源应用,只能在OpenAI平台上使用,不开放,不是生态玩法(可能只是OpenAI生态)。你给OpenAI做了个GPT,对别的平台,你还得做一个,这样,对服务商,开发者,依然不方便,不利于市场拓展。

由此看到,Function call太底层,GPTs太高层,这时,就有了MCP这样处于中间层的协议或产品出来了。

2 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协议_第1张图片

3 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 命令来运行。

3.1 Resources

3.1.1 resource类型

Resource可以是如下类型:
文件内容
数据库记录
API响应结果
图片等多媒体内容

Resources更多的是用于固定的资源获取,如果是一些更复杂的动态数据获取,还是需要使用Tools来实现。

协议内容
每个对象都有唯一的URI标识:[protocol]/[host]/[path],例如
file:///home/user/documents/report.pdf
postgres://database/customers/schema

3.1.2 客户端获取资源

客户端获取所有资源,共有两种方式:

  1. 获取direct resources
  2. 获取资源模板,一些动态资源可以通过这种方式返回
1. 获取direct resources
// Request
{
  method: "resources/list"
}
​
// Response
{
  uri: string;           // 唯一标识
  name: string;          // 资源名称
  description?: string;  // 描述
  mimeType?: string;     // 资源类型
}
2. 获取资源模板,一些动态资源可以通过这种方式返回

// Request
{
  method: "resources/templates/list"
}
​
// Response
{
  uriTemplate: string;   // RFC 6570 格式的uri,例如:/users/{userId} 
  name: string;          // 资源名称
  description?: string;  // 描述
  mimeType?: string;     // 资源类型
}

客户端读取指定资源,返回文本或base64后的内容

// Request
{
  method: "resources/get",
  params: {
      uri: uri
  }
}
​
// Response
{
  contents: [
    {
      uri: string;        // 资源uri
      mimeType?: string;  // 资源类型
​
      // 下面二选一:
      text?: string;      // 文本内容
      blob?: string;      // base64后的二进制内容
    }
  ]
}

3.2 Prompts

创建一个全局可复用的提示词模板,来标准化与LLM的交互,服务端只暴露这些prompts,供用户端选择使用。

3.1.1 协议内容

prompt的定义结构为:
客户端获取prompts列表, 只会包含prompt的唯一标识以及生成提示词需要的参数
客户端请求从服务端获取生成的prompt,需要传入要求的参数

{
  name: string;              // 唯一标识
  description?: string;      // 描述
  arguments?: [              // 参数列表
    {
      name: string;          // 参数唯一标识
      description?: string;  // 参数描述
      required?: boolean;    // 是否必填
    }
  ]
}

客户端获取prompts列表, 只会包含prompt的唯一标识以及生成提示词需要的参数

// Request
{
  method: "prompts/list"
}
​
// Response
{
  prompts: [
    {
      name: "analyze-code",
      description: "Analyze code for potential improvements",
      arguments: [  // 这里表示prompt需要一个language参数ss
        {
          name: "language",
          description: "Programming language",
          required: true
        }
      ]
    }
  ]
}

客户端请求从服务端获取生成的prompt,需要传入要求的参数

// Request
{
  method: "prompts/get",
  params: {
    name: "analyze-code",
    arguments: {
      language: "python"
    }
  }
}
​
// Response
{
  description: "Analyze Python code for potential improvements",
  messages: [
    {
      role: "user",
      content: {
        type: "text",
        text: "Please analyze the following Python code for potential improvements:\n\n```python\ndef calculate_sum(numbers):\n    total = 0\n    for num in numbers:\n        total = total + num\n    return total\n\nresult = calculate_sum([1, 2, 3, 4, 5])\nprint(result)\n```"
      }
    }
  ]
}

这种设计的好处就是:prompt的生成可以由MCP服务端根据不同入参去做不同返回,而不仅仅只是字符串占位而已。

3.1.2 SDK注册tool示例

使用装饰器mcp.prompt可以自动生成prompts协议格式:

基于python的类型注解生成出prompt入参的schema
基于inspect工具提取函数描述作为prompt的描述
@mcp.prompt()
def echo_prompt(message: str) -> str:
“”“测试prompt”“”
return f"Please process this message: {message}"

3.3 tools

工具在MCP中被设计成通过模型来操控,是得LLM能与外部系统交互,能在现实世界执行动作。MCP Server需要将工具暴露给客户端,并由LLM决定如何执行,同时每个工具需要有一个唯一标识

3.3.1 协议内容

客户端获取服务端所有工具列表
// Request
{
method: “tools/list”
}

// Response
{
“tools”: [
{
“name”: “get_alerts”,
“description”: "获取天气预警信息\n Args:\n state: 州名\n ",
“inputSchema”: {
“properties”: {
“state”: {
“title”: “State”,
“type”: “string”
}
},
“required”: [
“state”
],
“title”: “get_alertsArguments”,
“type”: “object”
}
}
]
}
这里的schema协议用的json schema,openai的chat api中参数response_format也是支持使用该协议来规范大模型输出。

客户端调用tool执行
// Request
{
method: “tools/call”
}

// Response
{
“content”: “”
}

3.3.2 SDK注册tool示例

mcp协议规定工具定义的规范,是用实现的sdk的mcp.tool装饰器,不需要再额外去编写规范文档,能够自动生成工具定义:

基于python的类型注解生成出入参的schema
基于inspect工具提取函数描述
@mcp.tool()
async def tool_a(state: str) -> str:
“”“获取天气预警信息
Args:
state: 州名
“””

参考文档:https://zhuanlan.zhihu.com/p/19707405738

4 MCP Client

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

  • MCP client 首先从 MCP server 获取可用的工具列表。
  • 将用户的查询连同工具描述通过 function calling 一起发送给 LLM。
  • LLM 决定是否需要使用工具以及使用哪些工具。
  • 如果需要使用工具,MCP client 会通过 MCP server 执行相应的工具调用。
  • 工具调用的结果会被发送回 LLM。
  • LLM 基于所有信息生成自然语言响应。
  • 最后将响应展示给用户。

你可以在 Example Clients 找到当前支持 MCP 协议的客户端程序。
本文将会使用 Claude Desktop 作为 MCP client,你可以在此页面下载安装:https://claude.ai/download

5 使用 Claude Desktop 通过 PostgreSQL MCP Server 查询数据库信息

接下来演示通过 PostgreSQL MCP Server 使 LLM 能够基于 PostgreSQL 中的数据来回答问题。

5.1 准备 PostgreSQL 数据

首先使用 Docker 启动 PostgreSQL 服务。

docker run -d --name postgres \
  -e POSTGRES_PASSWORD=postgres -p 5432:5432 \
  postgres

在 PostgreSQL 中创建数据库和表,并插入数据。

-- 登录 PostgreSQL
docker exec -it postgres psql -U postgres

-- 创建数据库
CREATE DATABASE shopdb;

-- 连接到新创建的数据库
\c shopdb;

-- 创建 users 表
CREATE TABLE users (
    user_id SERIAL PRIMARY KEY,
    first_name VARCHAR(50) NOT NULL,
    last_name VARCHAR(50) NOT NULL,
    email VARCHAR(100) UNIQUE NOT NULL
);

-- 创建 orders 表
CREATE TABLE orders (
    order_id SERIAL PRIMARY KEY,
    order_date TIMESTAMP NOT NULL,
    total_amount DECIMAL(10, 2) NOT NULL,
    user_id INT REFERENCES users(user_id)
);

-- 插入示例数据
INSERT INTO users (first_name, last_name, email) VALUES
('John', 'Doe', '[email protected]'),
('Jane', 'Smith', '[email protected]'),
('Alice', 'Johnson', '[email protected]');

INSERT INTO orders (order_date, total_amount, user_id) VALUES
('2025-01-05 10:30:00', 150.75, 1),
('2025-01-06 11:00:00', 200.50, 2),
('2025-01-07 12:45:00', 120.25, 1);

5.2 配置连接 PostgreSQL MCP Server

在 Claude Desktop 中配置 PostgreSQL MCP Server 的连接信息,具体内容可以参考:For Claude Desktop Users。最终是在 claude_desktop_config.json 文件中添加如下内容:

{
  "mcpServers": {
    "postgres": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-postgres",
        "postgresql://postgres:[email protected]/shopdb"
      ]
    }
  }
}

配置完毕后,重启 Claude Desktop。一切正常的话,你应该能在输入框的右下角看到一个锤子图标。点击锤子图标,可以看到 PostgreSQL MCP Server 提供的工具信息。

5.3 根据 PostgreSQL 的数据进行提问

首先来问一个简短的问题:数据库中有哪些表? Claude 会判断出需要调用 MCP server 来查询 PostgreSQL 中的数据。这里会弹出一个窗口,需要用户授权。
点击 Allow 后,Claude 成功返回了结果。
接下来我们可以增加一点难度:查询金额最高的订单信息。在数据库中有两张表 users 和 orders,要想得到完整的订单信息,需要先去查询 orders 表中金额最高的一条记录,然后根据 user_id 这个外键再去查询 users 表中对应的用户信息。
从下面的输出可以发现 Claude 一开始是不知道数据库中的表结构的,因此先发送请求分别确定 orders 表和 users 表中相应的字段,然后再对两张表进行 join 查询。

点击 View Result from query from postgres 可以看到 Claude Desktop 向 MCP server 发送的请求以及得到的响应,说明这个结果确实是从 PostgreSQL 数据库中查询得到的。

你也可以复制这条 SQL 语句到数据库中查询进行确认。

总结
本文带领读者快速入门了 MCP(模型上下文协议),介绍了其架构、核心概念以及实际应用场景。通过演示 Claude Desktop 结合 PostgreSQL MCP Server 查询数据库的场景,展示了 MCP 如何增强 LLM 与外部数据源的交互能力。后续文章还会继续分享 MCP server 和 MCP client 开发的相关内容,欢迎持续关注。

参考资料
Model Context Protocol 官方文档:https://modelcontextprotocol.io/introduction
深度解析:Anthropic MCP 协议:https://mp.weixin.qq.com/s/ASmcjW53HKokdYt1m-xyXA
欢迎关注

http://weixin.qq.com/r/_hKehkDEUR0urQTl90fo (二维码自动识别)

你可能感兴趣的:(入口集锦,人工智能,自然语言处理)