如果你用过 Claude Desktop 或 Claude Code,可能见过"连接 GitHub""读取本地文件"这类能力。它们背后大多是一套开放协议:MCP(Model Context Protocol)。
简单说,MCP 解决的是"AI 助手如何安全、标准化地调用外部工具"的问题。这篇文章带你从概念到代码走一遍。
MCP 的架构:三个角色
- Host(宿主):用户直接面对的 AI 应用,比如 Claude Desktop。
- Client(客户端):宿主内部的连接器,一个服务器对应一个客户端。
- Server(服务器):你写的工具提供方,通过标准输入输出或 HTTP 与客户端通信。
宿主负责问模型"要不要用工具",服务器只负责"被调用时干活"。职责分得很干净。
服务器能提供三种能力
| 能力 | 说明 | 例子 |
|---|---|---|
| Tools | 可执行的动作 | 查数据库、发请求 |
| Resources | 可读取的数据 | 文件内容、日志 |
| Prompts | 预置的提示词模板 | "生成周报"模板 |
日常开发中 90% 的场景只需要 Tools。
动手:写一个查询 SQLite 的 MCP 服务器
下面是一个最小可用示例,基于官方 TypeScript SDK:
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
import Database from "better-sqlite3";
const db = new Database("app.db");
const server = new McpServer({ name: "sqlite-reader", version: "0.1.0" });
server.tool(
"list_tables",
"列出数据库中的所有表",
{},
async () => {
const rows = db
.prepare("SELECT name FROM sqlite_master WHERE type='table'")
.all();
return { content: [{ type: "text", text: JSON.stringify(rows) }] };
}
);
server.tool(
"query",
"执行只读 SQL 查询",
{ sql: z.string().describe("一条 SELECT 语句") },
async ({ sql }) => {
if (!/^\s*select/i.test(sql)) {
return { content: [{ type: "text", text: "只允许 SELECT 查询" }] };
}
const rows = db.prepare(sql).all();
return { content: [{ type: "text", text: JSON.stringify(rows, null, 2) }] };
}
);
const transport = new StdioServerTransport();
await server.connect(transport);
注意我们为 query 工具加了"只允许 SELECT"的护栏——AI 能调用工具,意味着提示词注入也能间接调用工具,写 MCP 服务器时要把每个工具都当成公开 API 来防御。
接入宿主
以 Claude Code 为例,一条命令即可注册:
claude mcp add sqlite-reader -- node ./server.js
之后在对话里就能直接说"查一下 users 表有多少行",模型会自己决定调用 query 工具。
什么时候值得自己写 MCP 服务器
- 团队内部系统(工单、监控、发布平台)想接入 AI 助手
- 反复把同一批数据复制粘贴给 AI 的场景
- 需要把"查一下再回答"固定成标准流程的场景
反之,一次性的数据查询,直接把 CSV 贴进对话框更快。MCP 是基础设施,不是银弹。