CATS
138.50M · 2026-02-04
最近在 Hacker News 上,有个讨论热度居高不下:"MCP is the HTTP of AI"。
如果你还没听过 MCP,别慌。简单说,它解决的是一个很现实的问题:
怎么让 AI 模型安全、标准化地调用外部工具?
以前每家的实现都不一样。OpenAI 有 Function Calling,LangChain 有自己的 Tool 抽象,各种 Agent 框架也各搞一套。这就导致生态碎片化——你在 ChatGPT 里定义的工具,换到 Claude 就得重写。
MCP 的目标就是统一这件事。
MCP 全称 Model Context Protocol,由 Anthropic 在2024年底开源。
它定义了一套标准化的通信协议,让 AI 应用(Client)可以与外部能力提供方(Server)进行交互。这些能力可以是:
架构很简单:
┌─────────────────┐ MCP Protocol ┌─────────────────┐
│ │ ◄─────────────────► │ │
│ AI Client │ (JSON-RPC) │ MCP Server │
│ (Claude, etc.) │ │ (你来实现) │
│ │ │ │
└─────────────────┘ └─────────────────┘
通信基于 JSON-RPC 2.0,可以跑在 stdio、HTTP SSE 等传输层上。
说再多不如写代码。我们来实现一个最简单的 MCP Server,提供两个能力:
pip install mcp
创建 file_server.py:
import os
from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp.types import Tool, TextContent
# 初始化 MCP Server
app = Server("file-manager")
# 定义工具:列出目录文件
@app.tool()
async def list_files(directory: str) -> list[TextContent]:
"""
列出指定目录下的所有文件和文件夹。
Args:
directory: 要列出的目录路径
"""
try:
items = os.listdir(directory)
result = "n".join(items) if items else "目录为空"
return [TextContent(type="text", text=result)]
except FileNotFoundError:
return [TextContent(type="text", text=f"错误:目录 {directory} 不存在")]
except PermissionError:
return [TextContent(type="text", text=f"错误:无权限访问 {directory}")]
# 定义工具:读取文件内容
@app.tool()
async def read_file(file_path: str) -> list[TextContent]:
"""
读取指定文件的文本内容。
Args:
file_path: 要读取的文件路径
"""
try:
with open(file_path, "r", encoding="utf-8") as f:
content = f.read()
# 限制返回长度,避免 token 爆炸
if len(content) > 10000:
content = content[:10000] + "n...[内容已截断]"
return [TextContent(type="text", text=content)]
except FileNotFoundError:
return [TextContent(type="text", text=f"错误:文件 {file_path} 不存在")]
except Exception as e:
return [TextContent(type="text", text=f"错误:{str(e)}")]
# 启动 Server
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())
如果你用的是 Claude Desktop,在配置文件 claude_desktop_config.json 中添加:
{
"mcpServers": {
"file-manager": {
"command": "python",
"args": ["/path/to/file_server.py"]
}
}
}
重启 Claude Desktop,你会在对话框里看到一个新的工具图标。
现在你可以直接对 Claude 说:
Claude 会自动调用你写的 list_files 工具,返回结果。
读取不够?加个写入功能:
@app.tool()
async def write_file(file_path: str, content: str) -> list[TextContent]:
"""
将内容写入指定文件。如果文件不存在会创建。
Args:
file_path: 目标文件路径
content: 要写入的内容
"""
try:
# 安全检查:限制只能写入特定目录
allowed_dirs = ["/tmp", os.path.expanduser("~/mcp-sandbox")]
if not any(file_path.startswith(d) for d in allowed_dirs):
return [TextContent(
type="text",
text=f"安全限制:只能写入 {allowed_dirs} 目录"
)]
os.makedirs(os.path.dirname(file_path), exist_ok=True)
with open(file_path, "w", encoding="utf-8") as f:
f.write(content)
return [TextContent(type="text", text=f"成功写入 {file_path}")]
except Exception as e:
return [TextContent(type="text", text=f"写入失败:{str(e)}")]
注意那个安全检查。永远不要让 AI 无限制地写入文件系统——这是最基本的安全原则。
几个原因:
调试用 MCP Inspector:官方提供了 npx @modelcontextprotocol/inspector 工具,可以可视化测试你的 Server。
错误处理要充分:AI 会以各种意想不到的方式调用你的工具。边界情况一定要处理好。
限制 token 消耗:返回结果太长会浪费 token。像上面代码里一样做截断。
考虑并发:如果你的 Server 要支持多个 Client 同时调用,记得处理好异步和锁。
不想从零写?这些官方和社区的 Server 可以直接用:
| Server | 功能 | 安装 |
|---|---|---|
@modelcontextprotocol/server-filesystem | 文件系统读写 | npx 直接跑 |
@modelcontextprotocol/server-github | GitHub 操作 | 需要 Token |
@modelcontextprotocol/server-postgres | PostgreSQL 查询 | 需要连接串 |
mcp-server-sqlite | SQLite 操作 | 社区实现 |
MCP 现在还很年轻,协议本身也在快速迭代。
但它代表的方向是确定的:AI 应用需要一个标准化的方式接入外部世界。
如果你正在做 AI 相关的开发,现在花半天时间了解 MCP,绝对不亏。
代码就这么几十行,周末可以玩起来。
Reference: