MCP Protocol Complete Guide: Connecting AI Agents to Everything
Model Context Protocol(MCP)是 Anthropic 于 2024 年底推出的一项开放协议,旨在为 AI 模型与外部工具、数据源之间建立标准化的通信桥梁。本文将深入解析 MCP 的设计理念、技术架构和实践方法。
什么是 MCP
问题背景
在 MCP 出现之前,每个 AI 应用都需要为每种工具和数据源编写专用的集成代码。这意味着:
MCP 将这个问题简化为 N+M——每个 AI 应用只需实现一个 MCP 客户端,每个工具只需实现一个 MCP 服务器。
核心理念
MCP 基于一个简单但强大的理念:工具应该像 USB 设备一样即插即用。你不需要为每个应用重新编写驱动程序——只要遵循标准协议,任何设备都能在任何系统上工作。
MCP 架构详解
整体架构
┌─────────────────────────────────────────────────────────┐
│ MCP Host (AI 应用) │
│ ┌─────────────────────────────────────────────────┐ │
│ │ MCP Client │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
│ │ │Session 1 │ │Session 2 │ │Session 3 │ │ │
│ │ └────┬─────┘ └────┬─────┘ └────┬─────┘ │ │
│ └───────┼─────────────┼─────────────┼─────────────┘ │
│ │ │ │ │
└──────────┼─────────────┼─────────────┼───────────────────┘
│ │ │
┌─────┴───┐ ┌─────┴───┐ ┌────┴────┐
│MCP Server│ │MCP Server│ │MCP Server│
│ (文件系统) │ │ (GitHub) │ │ (数据库) │
└─────────┘ └─────────┘ └─────────┘
MCP 基于 JSON-RPC 2.0 协议,支持两种通信模式:
MCP 的四大核心概念
#### 1. Resources(资源)
Resources 允许服务器向客户端暴露数据。这些数据可以来自文件、数据库、API 等。
// 服务器端定义资源
server.setRequestHandler(ListResourcesRequestSchema, async () => {
return {
resources: [
{
uri: "file:///project/src/main.ts",
name: "Main Entry Point",
mimeType: "text/typescript",
description: "应用程序的主入口文件"
},
{
uri: "postgres://localhost/mydb/users",
name: "Users Table",
mimeType: "application/json",
description: "用户表数据"
}
]
};
});
// 读取资源
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
const { uri } = request.params;
const content = await readResource(uri);
return {
contents: [{ uri, mimeType: "text/plain", text: content }]
};
});
#### 2. Tools(工具)
Tools 允许服务器暴露可执行的函数,AI 模型可以调用这些函数执行操作。
// 定义工具
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: "create_issue",
description: "在 GitHub 上创建新的 Issue",
inputSchema: {
type: "object",
properties: {
title: { type: "string", description: "Issue 标题" },
body: { type: "string", description: "Issue 内容" },
labels: {
type: "array",
items: { type: "string" },
description: "标签列表"
}
},
required: ["title", "body"]
}
}
]
};
});
// 执行工具
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
if (name === "create_issue") {
const issue = await github.createIssue(args);
return {
content: [{ type: "text", text: Issue #${issue.number} 已创建 }]
};
}
throw new Error(未知工具: ${name});
});
#### 3. Prompts(提示模板)
Prompts 允许服务器提供预定义的提示模板,帮助用户完成常见任务。
server.setRequestHandler(ListPromptsRequestSchema, async () => {
return {
prompts: [
{
name: "review_code",
description: "代码审查提示模板",
arguments: [
{
name: "file_path",
description: "要审查的文件路径",
required: true
}
]
}
]
};
});
server.setRequestHandler(GetPromptRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
if (name === "review_code") {
const code = await readFile(args.file_path);
return {
messages: [
{
role: "user",
content: {
type: "text",
text: 请审查以下代码,关注安全性、性能和可维护性:\n\n\\\\n${code}\n\\\`
}
}
]
};
}
});
#### 4. Sampling(采样)
Sampling 允许服务器请求 AI 模型进行推理,实现服务器端的智能处理。
// 服务器请求客户端调用 AI 模型
const result = await client.request(
{
method: "sampling/createMessage",
params: {
messages: [
{
role: "user",
content: {
type: "text",
text: "分析这段日志中的异常模式"
}
}
],
maxTokens: 1000
}
},
CreateMessageResultSchema
);
构建 MCP 服务器实战
环境准备
初始化项目
mkdir my-mcp-server && cd my-mcp-server
npm init -y
npm install @modelcontextprotocol/sdk zod
TypeScript 配置
npm install -D typescript @types/node
完整的 MCP 服务器示例
以下是一个完整的数据库查询 MCP 服务器实现:
// src/server.tsimport { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
CallToolRequestSchema,
ListToolsRequestSchema,
ListResourcesRequestSchema,
ReadResourceRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
import { Pool } from "pg";
import { z } from "zod";
// 数据库连接池
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
});
// 定义工具的输入 Schema
const QuerySchema = z.object({
sql: z.string().describe("SQL 查询语句"),
params: z.array(z.string()).optional().describe("查询参数"),
});
const CreateTableSchema = z.object({
name: z.string().describe("表名"),
columns: z.array(z.object({
name: z.string(),
type: z.string(),
nullable: z.boolean().default(true),
})).describe("列定义"),
});
// 创建服务器实例
const server = new Server(
{ name: "postgres-mcp", version: "1.0.0" },
{ capabilities: { tools: {}, resources: {} } }
);
// 注册工具列表
server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: [
{
name: "query",
description: "执行只读 SQL 查询(SELECT 语句)",
inputSchema: QuerySchema,
},
{
name: "get_schema",
description: "获取数据库表结构信息",
inputSchema: z.object({
table: z.string().optional().describe("指定表名,不填则返回所有表"),
}),
},
{
name: "explain_query",
description: "分析 SQL 查询的执行计划",
inputSchema: QuerySchema,
},
],
}));
// 注册工具执行
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
switch (name) {
case "query": {
const { sql, params } = QuerySchema.parse(args);
// 安全检查:只允许 SELECT 语句
if (!sql.trim().toUpperCase().startsWith("SELECT")) {
throw new Error("安全限制:只允许执行 SELECT 查询");
}
const result = await pool.query(sql, params);
return {
content: [{
type: "text",
text: JSON.stringify(result.rows, null, 2),
}],
};
}
case "get_schema": {
const table = args?.table;
let sql =
SELECT table_name, column_name, data_type, is_nullable
FROM information_schema.columns
WHERE table_schema = 'public'
;if (table) sql += AND table_name = $1
;sql += ORDER BY table_name, ordinal_position
;const result = await pool.query(sql, table ? [table] : []);
return {
content: [{
type: "text",
text: JSON.stringify(result.rows, null, 2),
}],
};
}
case "explain_query": {
const { sql, params } = QuerySchema.parse(args);
const result = await pool.query(EXPLAIN (FORMAT JSON) ${sql}
, params);return {
content: [{
type: "text",
text: JSON.stringify(result.rows, null, 2),
}],
};
}
default:
throw new Error(未知工具: ${name}
);}
});
// 注册资源列表
server.setRequestHandler(ListResourcesRequestSchema, async () => ({
resources: [
{
uri: "postgres://schema",
name: "数据库 Schema",
mimeType: "application/json",
description: "当前数据库的完整表结构",
},
],
}));
// 注册资源读取
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
const { uri } = request.params;
if (uri === "postgres://schema") {
const result = await pool.query(
SELECT table_name, column_name, data_type, column_default, is_nullable
FROM information_schema.columns
WHERE table_schema = 'public'
ORDER BY table_name, ordinal_position
);return {
contents: [{
uri,
mimeType: "application/json",
text: JSON.stringify(result.rows, null, 2),
}],
};
}
throw new Error(未知资源: ${uri}
);});
// 启动服务器
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("PostgreSQL MCP 服务器已启动");
}
main().catch(console.error);
客户端配置
在 Claude Desktop 或其他 MCP 客户端中配置服务器:
{
"mcpServers": {
"postgres": {
"command": "node",
"args": ["dist/server.js"],
"env": {
"DATABASE_URL": "postgresql://user:pass@localhost:5432/mydb"
}
}
}
}
MCP vs Function Calling 对比
MCP 并非要取代 Function Calling,而是提供更高层次的抽象。实际上,许多 MCP 客户端在底层仍然使用 Function Calling 来实现工具调用。
真实世界应用场景
场景 1:企业知识库助手
┌─────────────────────────────────────────┐
│ Claude Desktop │
│ ┌──────────────────────────────────┐ │
│ │ MCP Client │ │
│ └──────┬──────┬──────┬─────────────┘ │
│ │ │ │ │
└─────────┼──────┼──────┼──────────────────┘
│ │ │
┌─────┴┐ ┌──┴──┐ ┌┴──────┐
│Conflu│ │Slack │ │Jira │
│ence │ │ │ │ │
└──────┘ └─────┘ └───────┘
用户可以自然地提问:"上周张三在 Confluence 上更新了哪些文档?" Claude 通过 MCP 自动查询 Confluence 和相关系统。
场景 2:全栈开发助手
{
"mcpServers": {
"github": { "command": "npx", "args": ["-y", "@anthropic/github-mcp"] },
"filesystem": { "command": "npx", "args": ["-y", "@anthropic/filesystem-mcp", "/home/user/project"] },
"postgres": { "command": "node", "args": ["./servers/postgres/dist/index.js"] },
"docker": { "command": "npx", "args": ["-y", "@anthropic/docker-mcp"] }
}
}
Claude 可以:读取代码 → 查询数据库结构 → 分析依赖关系 → 提交修复 PR,全部通过 MCP 自动完成。
场景 3:数据分析工作流
MCP 服务器可以封装复杂的数据处理逻辑:
server.tool(
"run_analysis",
{
dataset: z.string(),
analysis_type: z.enum(["correlation", "regression", "clustering"]),
parameters: z.record(z.any()).optional(),
},
async ({ dataset, analysis_type, parameters }) => {
// 执行数据分析并返回结果
const result = await executeAnalysis(dataset, analysis_type, parameters);
return { content: [{ type: "text", text: JSON.stringify(result) }] };
}
);
最佳实践
1. 工具设计原则
2. 安全考虑
// 始终验证和限制用户输入${sql} LIMIT 1000server.tool("query", QuerySchema, async ({ sql }) => {
// 防止 SQL 注入
if (containsDangerousPatterns(sql)) {
throw new Error("检测到潜在的危险 SQL 模式");
}
// 限制结果集大小
const limitedSql =
;// ...执行查询
});
3. 错误处理
try {操作失败: ${error.message}\n建议: 检查数据库连接或 SQL 语法`,const result = await executeOperation();
return { content: [{ type: "text", text: result }] };
} catch (error) {
// 返回结构化错误信息,帮助 AI 理解问题
return {
content: [{
type: "text",
text:
}],
isError: true,
};
}
总结
MCP 正在成为 AI Agent 生态系统的"USB 标准"。它解决了工具集成的碎片化问题,为 AI 应用提供了一个统一、可扩展的工具接入框架。
对于开发者来说,MCP 的价值在于:
随着 Anthropic、OpenAI 等主要 AI 厂商对 MCP 的支持,这一协议正在成为行业标准。现在是开始学习和使用 MCP 的最佳时机。