MCP协议解析

简介

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

Function CallingAI 模型调用函数的机制,而 AI agent 是一个自主运行的智能系统,利用 Function CallingMCP 来分析和执行任务,实现特定目标。

Function CallingMCP 的区别

  • MCP Model Context Protocol 模型上下文协议。
  • Function Calling 函数调用。

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

类别 MCP Model Context Protocol Function Calling
性质 协议 功能
范围 通用(多数据源、多功能) 特定场景(单一数据源或功能)
目标 统一接口,实现互操作 扩展模型能力
实现 基于标准协议 依赖于特定模型实现
开发复杂度 低:通过统一协议实现多源兼容 高:需要为每个任务单独开发函数
复用性 高:一次开发,可多场景使用 低:函数通常为特定任务设计
灵活性 高:支持动态适配和扩展 低:功能扩展需要额外开发
常见场景 复杂场景,如跨平台数据访问与整合 简单任务,如天气查询等

核心架构

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

  • MCP 主机(Host):发起请求的 LLM 应用程序。(例如 Claude DesktopIDEAI 工具)
  • MCP 客户端(MCP Client):在主机程序内部,与 MCP server 保持 1:1 的连接。
  • MCP 服务器(MCP Server):为 MCP 客户端提供上下文、工具和 prompt 信息。
  • 本地资源(Local Resource):本地计算机中可供 MCP 服务器安全访问的资源。(例如文件、数据库)
  • 远程资源(Remote Resource):MCP 服务器可以连接到的远程资源。(例如通过 API

MCP 的基本工作流程:
1.png

通信机制:
MCP 协议目前主要支持两种主要的通信机制:基于标准输入输出的本地通信和基于 SSEServer-Sent Events)的远程通信。
这两种通信机制都使用 JSON-RPC 2.0 格式进行消息传输,确保了通信的标准化和可扩展性。

  • 本地通信。通过 stdio 传输数据,适用于在同一台机器上运行的客户端和服务器之间的通信。
  • 远程通信。利用 SSEHTTP 结合,实现跨网络的实时数据传输,适用于需要访问远程资源和分布式部署的场景。

功能与应用

官方 MCP Server 支持列表:

  • 数据与文件系统:
    • 文件系统
    • PostgreSQL
    • SQLite
    • Google Drive
  • 开发工具
    • Git
    • Github
    • Gitlab
    • Sentry
  • 网络与浏览器自动化
    • Brave Search:利用 Brave 的搜索 API 进行网络和本地搜索。
    • Fetch:为 LLM 优化的网络内容获取和转换。
    • Puppeteer:提供浏览器自动化和网页抓取功能。
  • 生产力和通信
    • Slack
    • Google Maps
    • Memory
  • 专业工具
    • EverArt:使用多种模型进行 AI 图像生成。
    • Sequential Thinking:通过思维序列进行动态问题解决。
    • AWS KB Retrieval:使用 Bedrock Agent RuntimeAWS 知识库检索。

目前还有一些三方公司维护的的列表,有兴趣的可以自行了解。


如何开发 MCP Server

基于官方教程的核心内容,聚焦最小可用实现。

系统要求

  • Python 较新版本
  • maxOSWindows
  • uv

项目初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 创建项目目录
uv init mcp-client
cd mcp-client

# 创建虚拟环境
uv venv

# 激活虚拟环境(macOS/Linux)
source .venv/bin/activate

# 安装依赖
uv add mcp anthropic python-dotenv

# 清理样板并新建主文件
rm main.py
touch client.py

配置 API Key

1
2
echo "ANTHROPIC_API_KEY=<your key here>" > .env
echo ".env" >> .gitignore

客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import asyncio
from typing import Optional
from contextlib import AsyncExitStack

from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client

from anthropic import Anthropic
from dotenv import load_dotenv

load_dotenv() # load environment variables from .env

class MCPClient:
def __init__(self):
# Initialize session and client objects
self.session: Optional[ClientSession] = None
self.exit_stack = AsyncExitStack()
self.anthropic = Anthropic()
# methods will go here

服务端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
async def connect_to_server(self, server_script_path: str):
"""Connect to an MCP server

Args:
server_script_path: Path to the server script (.py or .js)
"""
is_python = server_script_path.endswith('.py')
is_js = server_script_path.endswith('.js')
if not (is_python or is_js):
raise ValueError("Server script must be a .py or .js file")

command = "python" if is_python else "node"
server_params = StdioServerParameters(
command=command,
args=[server_script_path],
env=None
)

stdio_transport = await self.exit_stack.enter_async_context(stdio_client(server_params))
self.stdio, self.write = stdio_transport
self.session = await self.exit_stack.enter_async_context(ClientSession(self.stdio, self.write))

await self.session.initialize()

# List available tools
response = await self.session.list_tools()
tools = response.tools
print("\nConnected to server with tools:", [tool.name for tool in tools])

主流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
async def process_query(self, query: str) -> str:
"""Process a query using Claude and available tools"""
messages = [
{
"role": "user",
"content": query
}
]

response = await self.session.list_tools()
available_tools = [{
"name": tool.name,
"description": tool.description,
"input_schema": tool.inputSchema
} for tool in response.tools]

# Initial Claude API call
response = self.anthropic.messages.create(
model="claude-3-5-sonnet-20241022",
max_tokens=1000,
messages=messages,
tools=available_tools
)

# 后续:解析响应、工具调用编排、聚合最终结果(参见官方教程完整代码)

有兴趣的话可以去研究下 larksuite 开源的 Agent,应该会给你一些开发思路。


使用

示例服务器作为配置参数

1
2
3
4
5
6
7
# 基于 TypeScript 的服务器可以直接使用 npx
npx -y @modelcontextprotocol/server-memory

# 基于 Python 的服务器可以直接使用 uvx 或者 pip
uvx mcp-server-git # Using uvx
pip install mcp-server-git # Using pip
python -m mcp_server_git

配置 Claude

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{
"mcpServers": {
"memory": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-memory"]
},
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/allowed/files"]
},
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "<YOUR_TOKEN>"
}
}
}
}

总结

MCP 协议是为模型服务,在开发过程中需要着重维护以下几点:

  • 标准化的 Tool 信息和描述文档。
  • 持续改进 prompt 信息。

个人备注

此博客内容均为作者学习所做笔记,侵删!
若转作其他用途,请注明来源!