AI

人工智能相关文章

MCP协议深度解析:AI Agent如何通过标准接口调用外部工具

MCP协议深度解析:AI Agent如何通过标准接口调用外部工具

# MCP协议深度解析:AI Agent如何通过标准接口调用外部工具

## 摘要

Model Context Protocol(MCP)是Anthropic提出的开放标准,旨在解决AI Agent与外部工具之间的接口碎片化问题。本文深入解析MCP协议的架构设计、传输机制、资源管理,并实战构建MCP Server和Client。

## 一、为什么需要MCP?

### 1.1 现状:工具接入的碎片化

当前AI Agent调用外部工具的方式五花八门:

```

OpenAI → Function Calling(自定义JSON Schema)

Anthropic → Tool Use(另一种JSON Schema)

LangChain → Tool抽象层(Python函数包装)

自定义Agent → 硬编码API调用

```

每接入一个新工具,都需要:

- 适配不同LLM的函数调用格式

- 处理不同的认证方式

- 管理不同工具的错误处理逻辑

- 重复编写连接代码

### 1.2 MCP的解决方案

MCP的核心设计理念:**像USB-C统一接口一样,统一AI Agent与工具之间的连接标准**。

```

┌──────────────┐ MCP协议 ┌──────────────┐

│ AI Agent │ ←─────────────→ │ MCP Server │

│ (Client) │ 标准接口 │ (工具提供方) │

└──────────────┘ └──────┬───────┘

┌──────┴───────┐

│ 实际工具/资源 │

│ DB/API/文件等 │

└──────────────┘

```

## 二、MCP协议架构

### 2.1 核心概念

MCP定义了三个核心原语:

| 原语 | 方向 | 用途 |

|-----|------|------|

| **Tools** | Client→Server | Agent调用工具执行操作 |

| **Resources** | Server→Client | Server暴露可读取的数据/内容 |

| **Prompts** | Server→Client | Server提供预定义的Prompt模板 |

### 2.2 通信模型

MCP采用JSON-RPC 2.0协议,支持两种传输方式:

**Stdio传输**(本地进程间通信):

```

Agent进程 ← stdin/stdout → MCP Server进程

```

**SSE传输**(远程HTTP通信):

```

Agent ← HTTP POST → MCP Server

Agent ← SSE GET ← MCP Server(服务端推送)

```

### 2.3 消息类型

```json

// 请求

{

"jsonrpc": "2.0",

"id": 1,

"method": "tools/call",

"params": {

"name": "query_database",

"arguments": {

"sql": "SELECT * FROM articles WHERE article_type = 1 LIMIT 5"

}

}

}

// 响应

{

"jsonrpc": "2.0",

"id": 1,

"result": {

"content": [

{

"type": "text",

"text": "[{\"id\": 1, \"title\": \"...\", ...}]"

}

]

}

}

```

## 三、实战:构建MCP Server

### 3.1 安装MCP SDK

```bash

pip install mcp

```

### 3.2 创建数据库查询MCP Server

```python

# db_mcp_server.py

from mcp.server import Server

from mcp.server.stdio import stdio_server

from mcp.types import Tool, TextContent

import mysql.connector

app = Server("db-query-server")

DB_CONFIG = {

'host': '59.110.223.195',

'port': 7889,

'user': 'root',

'password': 'Renjnet@1',

'database': 'info',

'charset': 'utf8mb4'

}

@app.list_tools()

async def list_tools() -> list[Tool]:

return [

Tool(

name="query_articles",

description="查询info数据库中的文章,支持按分类、关键词筛选",

inputSchema={

"type": "object",

"properties": {

"article_type": {

"type": "integer",

"description": "文章类型:1=AI, 2=运维, 3=开发, 5=短视频和直播, 6=其他科技",

"enum": [1, 2, 3, 5, 6]

},

"keyword": {

"type": "string",

"description": "搜索关键词"

},

"limit": {

"type": "integer",

"description": "返回条数,默认5",

"default": 5

}

},

"required": []

}

),

Tool(

name="get_article_detail",

description="根据文章GUID获取完整文章内容",

inputSchema={

"type": "object",

"properties": {

"guid": {

"type": "string",

"description": "文章唯一标识GUID"

}

},

"required": ["guid"]

}

)

]

@app.call_tool()

async def call_tool(name: str, arguments: dict) -> list[TextContent]:

conn = mysql.connector.connect(**DB_CONFIG)

cursor = conn.cursor(dictionary=True)

try:

if name == "query_articles":

sql = "SELECT guid, title, excerpt, article_type, pub_time FROM articles WHERE 1=1"

params = []

if "article_type" in arguments:

sql += " AND article_type = %s"

params.append(arguments["article_type"])

if "keyword" in arguments:

sql += " AND (title LIKE %s OR keywords LIKE %s)"

kw = f"%{arguments['keyword']}%"

params.extend([kw, kw])

sql += " ORDER BY pub_time DESC LIMIT %s"

params.append(arguments.get("limit", 5))

cursor.execute(sql, params)

results = cursor.fetchall()

return [TextContent(type="text", text=str(results))]

elif name == "get_article_detail":

cursor.execute(

"SELECT * FROM articles WHERE guid = %s",

(arguments["guid"],)

)

result = cursor.fetchone()

return [TextContent(type="text", text=str(result))]

finally:

cursor.close()

conn.close()

async def main():

async with stdio_server() as (read_stream, write_stream):

await app.run(read_stream, write_stream, app.create_initialization_options())

if __name__ == "__main__":

import asyncio

asyncio.run(main())

```

### 3.3 MCP Server配置

在Claude Desktop或支持MCP的客户端中配置:

```json

{

"mcpServers": {

"db-query": {

"command": "python",

"args": ["D:/work/ai/codes/mcp_servers/db_mcp_server.py"]

}

}

}

```

## 四、实战:构建MCP Client

```python

# mcp_client.py

from mcp import ClientSession, StdioServerParameters

from mcp.client.stdio import stdio_client

server_params = StdioServerParameters(

command="python",

args=["db_mcp_server.py"]

)

async def query_via_mcp():

async with stdio_client(server_params) as (read, write):

async with ClientSession(read, write) as session:

await session.initialize()

# 列出可用工具

tools = await session.list_tools()

print("可用工具:", [t.name for t in tools.tools])

# 调用工具

result = await session.call_tool(

"query_articles",

arguments={"article_type": 1, "limit": 3}

)

print("查询结果:", result.content[0].text)

import asyncio

asyncio.run(query_via_mcp())

```

## 五、MCP vs Function Calling

| 维度 | Function Calling | MCP |

|-----|-----------------|-----|

| 接口标准 | 厂商私有(OpenAI/Anthropic各自定义) | 开放标准 |

| 工具发现 | 需硬编码在Prompt中 | 动态发现(list_tools) |

| 运行方式 | 同步,嵌入LLM调用 | 独立进程/服务 |

| 可复用性 | 低(每个Agent重新定义) | 高(一次开发,多Agent复用) |

| 安全控制 | 依赖LLM方 | Server端独立控制权限 |

| 生态成熟度 | 高(广泛支持) | 快速增长中 |

## 六、MCP生态现状(2026年)

| 类别 | 示例 |

|------|------|

| 数据库 | PostgreSQL、MySQL、SQLite、MongoDB |

| 文件系统 | 本地文件、S3、GCS |

| 开发工具 | GitHub、GitLab、Jira |

| 通信 | Slack、Email、企业微信 |

| 搜索 | Brave Search、Tavily |

| 创作工具 | Figma、Notion |

## 总结

MCP通过定义AI Agent与外部工具之间的标准通信协议,解决了工具接入的碎片化问题。虽然生态仍在发展中,但其"一次开发、多Agent复用"的理念代表了AI工具集成的未来方向。对于企业内部AI应用,构建MCP Server是提升工具可复用性和安全性的有效途径。

---

*本文由北科信息日采集系统自动生成,发布日期:2026-05-05*