金句:MCP 让 AI 从"会说话的建议者"变成了"会动手的执行者"——它不再只告诉你怎么查数据库,而是直接帮你查。
一、MCP 是什么?为什么重要?
Model Context Protocol(MCP),由 Anthropic 于 2024 年底发布,是一个开放协议,让 AI 模型可以安全地连接外部工具、数据源和服务。
在 MCP 之前,AI 只能处理你粘贴给它的文本。
在 MCP 之后,AI 可以主动查询数据库、调用 API、读写文件系统、执行代码。
这是 AI 编程工具能力的重大跃升。
二、MCP 架构原理
┌─────────────────────────────────────────────────────────────┐
│ MCP 架构 │
│ │
│ ┌─────────────┐ MCP Protocol ┌──────────────────┐ │
│ │ AI 客户端 │ ←───────────────→ │ MCP Server │ │
│ │ (Cursor/ │ │ │ │
│ │ Claude) │ │ 提供: │ │
│ └─────────────┘ │ • Tools(工具) │ │
│ │ • Resources │ │
│ │ • Prompts │ │
│ └──────────────────┘ │
│ ↓ │
│ ┌──────────────────┐ │
│ │ 外部系统 │ │
│ │ • 数据库 │ │
│ │ • REST API │ │
│ │ • 文件系统 │ │
│ │ • 第三方服务 │ │
│ └──────────────────┘ │
└─────────────────────────────────────────────────────────────┘
核心概念:
- MCP Client:AI 工具(Cursor、Claude Desktop)
- MCP Server:提供特定功能的服务器(可以是本地进程)
- Tools:AI 可以调用的函数(如 query_database、call_api)
- Resources:AI 可以读取的数据(如文件、数据库记录)
三、实战:构建数据库 MCP Server
场景:让 AI 直接查询你的 PostgreSQL 数据库
安装依赖:
npm init -y
npm install @modelcontextprotocol/sdk pg
npm install -D typescript @types/pg
mcp-postgres-server.ts:
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import {
CallToolRequestSchema,
ListToolsRequestSchema,
} from '@modelcontextprotocol/sdk/types.js';
import { Pool } from 'pg';
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
max: 5,
});
const server = new Server(
{
name: 'postgres-mcp-server',
version: '1.0.0',
},
{
capabilities: {
tools: {},
},
}
);
// 注册可用工具
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: 'query_database',
description: '执行 SQL 查询并返回结果。只允许 SELECT 语句。',
inputSchema: {
type: 'object',
properties: {
sql: {
type: 'string',
description: '要执行的 SQL SELECT 语句',
},
limit: {
type: 'number',
description: '最大返回行数(默认100)',
default: 100,
},
},
required: ['sql'],
},
},
{
name: 'list_tables',
description: '列出数据库中的所有表及其结构',
inputSchema: {
type: 'object',
properties: {},
},
},
{
name: 'describe_table',
description: '获取指定表的详细结构(列名、类型、约束)',
inputSchema: {
type: 'object',
properties: {
table_name: {
type: 'string',
description: '表名',
},
},
required: ['table_name'],
},
},
],
};
});
// 处理工具调用
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
switch (name) {
case 'query_database': {
const sql = args?.sql as string;
// 安全检查:只允许 SELECT 语句
if (!sql.trim().toUpperCase().startsWith('SELECT')) {
return {
content: [{ type: 'text', text: '错误:只允许 SELECT 查询' }],
isError: true,
};
}
const limit = (args?.limit as number) || 100;
const safeSql = `SELECT * FROM (${sql}) AS subquery LIMIT ${limit}`;
try {
const result = await pool.query(safeSql);
return {
content: [
{
type: 'text',
text: JSON.stringify({
rowCount: result.rowCount,
columns: result.fields.map(f => f.name),
rows: result.rows,
}, null, 2),
},
],
};
} catch (error) {
return {
content: [{ type: 'text', text: `查询失败:${error}` }],
isError: true,
};
}
}
case 'list_tables': {
const result = await pool.query(`
SELECT
table_name,
pg_size_pretty(pg_total_relation_size(quote_ident(table_name))) as size,
(SELECT count(*) FROM information_schema.columns
WHERE table_name = t.table_name) as column_count
FROM information_schema.tables t
WHERE table_schema = 'public'
ORDER BY table_name
`);
return {
content: [
{
type: 'text',
text: JSON.stringify(result.rows, null, 2),
},
],
};
}
case 'describe_table': {
const tableName = args?.table_name as string;
const result = await pool.query(`
SELECT
column_name,
data_type,
is_nullable,
column_default,
character_maximum_length
FROM information_schema.columns
WHERE table_name = $1 AND table_schema = 'public'
ORDER BY ordinal_position
`, [tableName]);
return {
content: [
{
type: 'text',
text: JSON.stringify(result.rows, null, 2),
},
],
};
}
default:
return {
content: [{ type: 'text', text: `未知工具:${name}` }],
isError: true,
};
}
});
// 启动服务器
const transport = new StdioServerTransport();
await server.connect(transport);
在 Cursor 中配置
~/.cursor/mcp.json:
{
"mcpServers": {
"postgres": {
"command": "node",
"args": ["/path/to/mcp-postgres-server.js"],
"env": {
"DATABASE_URL": "postgresql://user:password@localhost:5432/mydb"
}
}
}
}
使用效果
配置完成后,在 Cursor 中你可以:
你:帮我分析一下过去30天的用户注册趋势,
看看每周的新增用户数量变化
Cursor(调用 MCP):
→ list_tables()
→ describe_table("users")
→ query_database("SELECT DATE_TRUNC('week', created_at) as week,
COUNT(*) as new_users
FROM users
WHERE created_at > NOW() - INTERVAL '30 days'
GROUP BY week ORDER BY week")
Cursor:根据查询结果,过去30天用户注册趋势如下:
第1周:234人,第2周:312人...(增长35%)
主要增长出现在周三和周五...
四、其他实用 MCP Server
官方 MCP Servers 生态
# 文件系统操作
npx @modelcontextprotocol/server-filesystem /path/to/workspace
# GitHub 集成
npx @modelcontextprotocol/server-github
# Google Drive
npx @modelcontextprotocol/server-gdrive
# Slack
npx @modelcontextprotocol/server-slack
# Puppeteer(浏览器自动化)
npx @modelcontextprotocol/server-puppeteer
社区热门 MCP Servers
| 名称 | 功能 |
|---|---|
| mcp-server-sqlite | SQLite 数据库操作 |
| mcp-server-redis | Redis 缓存读写 |
| mcp-server-jira | Jira 任务管理 |
| mcp-server-notion | Notion 文档操作 |
| mcp-server-aws | AWS 服务操作 |
五、MCP 安全最佳实践
MCP 给了 AI 强大的能力,也带来了安全风险:
✅ 安全配置原则
1. 最小权限原则
- 数据库 MCP:只允许 SELECT,禁止 INSERT/UPDATE/DELETE
- 文件系统 MCP:限制可访问的目录范围
- API MCP:只开放必要的端点
2. 敏感数据保护
- 数据库连接信息用环境变量,不硬编码
- 个人信息字段在返回前脱敏
3. 审计日志
- 记录所有 MCP 工具调用
- 异常访问模式告警
4. 沙箱隔离
- 生产环境不暴露 MCP 接口
- 使用只读账号进行数据查询
章节小结:MCP 是 AI 编程工具的"手脚"——让 AI 从"说教者"变成"行动者"。通过构建数据库 MCP Server,你可以让 AI 直接分析你的真实数据,提供更精准的业务洞察和代码建议。这是 Vibe Coding 迈向企业级应用的关键一步。