MCP详解:为Claude构建自然语言驱动的PostgreSQL助手
通过项目讲解MCP:模型上下文协议如何将N x M的集成方式转换为N + M的形式,进而让Claude Desktop能够查询只读的PostgreSQL服务器。
来源: MCP Explained: The Protocol That Finally Gives AI a Standard Way to Talk to the World
粘合代码问题
每个开发人工智能产品的开发者最终都会遇到同样的难题。模型功能完备,数据库、文件系统或某些API中也存有有用数据,但缺少一种简洁标准的方法将二者结合起来。
于是各种粘合代码应运而生:这里一个适配器,那里一个脆弱的封装层。这种方案在模型发生变化、出现新的数据源,或是新同事需要反编译整个数据处理层之前还能勉强维持。
Anthropic在2024年11月提出了解决方案,即模型上下文协议(MCP)。大约两年后,它就从一个小众实验发展为主流智能体基础设施:到2026年中,每月的SDK下载量已达9700万次,官方注册表中活跃的公共服务器数量接近10000台。
设想这样一种产品:用户用通俗的英语提出关于公司数据的问题。思路很简单,但实现起来却十分困难。系统必须先理解问题,将其转化为数据库查询语句并执行,然后将查询结果传递给模型,最后格式化出回复。如果再加上人工智能需要使用的各种工具,比如日历、GitHub 仓库或 Slack 工作空间,那么每个工具都需要单独进行集成,且每种集成都有其特定的 API 接口格式、认证流程和错误处理方式。
有些工程师将这种状况称为“意大利面式集成”。假设模型数量为 N,工具数量为 M,那么每一种模型与工具的组合都需要编写专属代码。一旦新增一个模型,所有工具都需要重新开发;而新增一个工具,则意味着要更新每个模型的集成代码。
MCP 是什么
MCP是一种基于JSON-RPC 2.0的开放标准,它为模型提供了统一的词汇表,以便连接外部工具和数据。由于单个服务器即可为所有遵循该协议的客户端提供服务,原本复杂的N×M架构简化为N+M的结构。
人们常将其比作USB-C接口。过去,笔记本电脑、手机、相机和耳机等设备所需的充电器各不相同,每类设备都需要专属的充电线。USB-C通过统一接口标准而非改变电力规格,让一根充电线就能满足所有设备的充电需求。MCP在人工智能领域扮演着类似的角色:只要模型遵循该协议,就能使用任何提供相应接口的工具,因此只需编写一次服务器代码,就能与所有兼容的模型配合使用。
治理机制让2026年成为了一个转折点。2025年12月,Anthropic将MCP交给了Agentic AI基金会,该基金会是Linux基金会旗下的专项基金,由Anthropic、Block和OpenAI共同创立,这一举措表明该协议不再仅属于Anthropic所有。随后获得了公众的支持:OpenAI的首席执行官表示支持,并宣布将在各类智能体SDK及ChatGPT中提供支持;谷歌DeepMind也在几天内确认Gemini将会使用MCP来调用各类工具。如今,该协议已成为模型连接外部工具、数据及服务的标准途径。
三个组成部分
主机指的是用户实际使用的应用程序:Claude Desktop、VS Code插件或企业自建的聊天机器人。
MCP客户端运行在主机内部。它保持与一个或多个MCP服务器的连接畅通,并在模型与这些服务器之间传递消息,因此当模型决定调用某个工具时,客户端会负责传递请求。
MCP服务器是功能所在之处。每个服务器都会将某个工具或数据源封装在标准接口之后,并能提供三类内容:
- 工具是指可被调用的函数,例如
run_sql_query、search_web或send_email。模型可以利用这些工具来执行操作或获取数据。 - 资源是可供读取的数据,比如文件、数据库记录或文档,模型可以将它们引入自身的上下文窗口中。
- 提示词是服务器提供给主机的可重复使用的提示词模板。
消息以 JSON-RPC 2.0 格式编码,并通过两种传输方式之一发送。stdio 适用于在客户端机器上作为本地进程运行的服务器。Streamable HTTP 则针对远程服务器和云部署环境,使用普通的 HTTP 请求,必要时结合 Server-Sent Events (SSE) 实现流式响应及服务器到客户端的通知功能。由于这种分工,一种协议即可同时满足本地开发与生产级系统的需求。
一个问题,逐步解析
以下是用户输入问题到获得答案之间的完整流程。
- 用户提问:“上周我们收到了多少订单?”
- 模型在启动时从 MCP 服务器获取可用工具列表,随后看到该问题。
- 它判断需要使用
query_database功能,于是发出结构化的工具调用请求。 - MCP客户端捕获该请求并将其发送到相应的服务器。
- 服务器执行查询并以JSON格式返回结果。
- 模型读取该结果后生成通俗易懂的答案。
模型从不直接接触数据库,也不需要预先获取连接字符串,因为这些工作都由MCP服务器处理。
项目内容:PostgreSQL的聊天界面
先不说理论,来看个实际案例。某个团队将订单数据存储在PostgreSQL中,而那些不懂技术的同事总是向唯一懂SQL的人索要报表。我们的目标是创建一个聊天界面,让他们用通俗的英语提问,即可立即获得答案,无需编写任何SQL代码。
该方案是在 PostgreSQL 数据库前端部署一个 MCP 服务器,提供一个 query_database 工具,并与 Claude 相连。团队中的任何人都可以用日常语言提出问题,从而获得真实数据。
设置
首先创建一个新项目文件夹,然后安装所需的依赖项。
mkdir nl-db-assistant
cd nl-db-assistant
npm init -y
npm install @modelcontextprotocol/sdk pg dotenv zod
这些包分别承担不同的功能。@modelcontextprotocol/sdk 是 Anthropic 为 MCP 服务器提供的官方 JavaScript 和 TypeScript 工具包,pg 是常用的 Node.js PostgreSQL 客户端,而 dotenv 则用于防止数据库凭证出现在源代码中。zod 会在运行时验证数据结构,MCP 依赖它来生成 JSON 规范,模型通过该规范学习如何调用工具。
在项目根目录下创建一个 .env 文件,用于存放连接字符串。
DATABASE_URL=postgresql://your_user:your_password@localhost:5432/your_database
请立即将 .env 添加到 .gitignore 中,因为凭证绝不能被提交。
服务器框架
接下来是 server.js,它以导入语句、服务器名称与版本以及数据库连接池作为开头。
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
import pg from "pg";
import dotenv from "dotenv";
dotenv.config();
// Set up the PostgreSQL connection pool
const pool = new pg.Pool({
connectionString: process.env.DATABASE_URL,
});
// Create the MCP server instance
const server = new McpServer({
name: "postgres-assistant",
version: "1.0.0",
});
在客户端连接并进行功能协商时,会向其告知名称和版本信息。连接池只需创建一次,即可为每次查询重复使用,这比每次都建立新连接要高效得多。
暴露模式结构
为了让模型能够编写出有用的查询语句,它必须知道存在哪些表和列。实时模式结构会以可读取的MCP资源形式提供,模型可将其引入上下文中使用。
server.resource(
"database-schema",
"schema://main",
async (uri) => {
const result = await pool.query(`
SELECT
table_name,
column_name,
data_type
FROM information_schema.columns
WHERE table_schema = 'public'
ORDER BY table_name, ordinal_position
`);
const schema = result.rows.reduce((acc, row) => {
if (!acc[row.table_name]) acc[row.table_name] = [];
acc[row.table_name].push(`${row.column_name} (${row.data_type})`);
return acc;
}, {});
const schemaText = Object.entries(schema)
.map(([table, cols]) => `${table}:\n ${cols.join("\n ")}`)
.join("\n\n");
return {
contents: [{
uri: uri.href,
text: schemaText,
}],
};
}
);
information_schema.columns 是 PostgreSQL 内置的视图,用于描述所有的表和列。该代码会查询该视图,将行数据转换为可读的文本形式,并将其作为结果返回。模型在决定如何编写查询之前会先读取这些信息,这样就能掌握完整的表结构,而无需猜测有效的 SQL 语句。
查询工具
这是服务器的核心,也是模型用来对数据库执行 SQL 查询的工具。
server.tool(
"query_database",
"Run a read-only SQL query against the PostgreSQL database. Use this to answer questions about data, counts, trends, or summaries.",
{
sql: z.string().describe(
"A valid PostgreSQL SELECT query. Only SELECT statements are allowed."
),
},
async ({ sql }) => {
// Safety gate: only allow SELECT statements
const trimmed = sql.trim().toUpperCase();
if (!trimmed.startsWith("SELECT")) {
return {
content: [{
type: "text",
text: "Error: only SELECT queries are permitted through this interface.",
}],
isError: true,
};
}
try {
const result = await pool.query(sql);
const output = JSON.stringify(result.rows, null, 2);
return {
content: [{
type: "text",
text: `Query returned ${result.rowCount} row(s):\n\n${output}`,
}],
};
} catch (err) {
return {
content: [{
type: "text",
text: `Query failed: ${err.message}`,
}],
isError: true,
};
}
}
);
请务必仔细留意描述字符串,也就是第二个参数,因为模型在决定是否以及如何使用该工具时会读取它。撰写时需像给从未接触过数据库的实习生讲解指令一样清晰明了。Zod为sql参数生成的架构会自动转换为模型所看到的JSON架构,从而明确指定参数的格式。顶部的校验机制仅允许SELECT语句通过,因此无论是故意还是无意,都无法执行写入操作。
启动服务器
最终,服务器会在stdio传输协议上启动。
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("PostgreSQL MCP server is running");
通过 stdio,MCP 客户端会将脚本作为子进程启动,并通过标准输入输出与它进行通信。这是本地开发中最简单且最可靠的传输方式。日志行特意使用了 console.error,这样就不会污染 MCP 用于传输协议消息的 stdout 通道。
连接 Claude Desktop
打开 Claude Desktop 的配置文件。在 macOS 上,该文件位于此处:
~/Library/Application Support/Claude/claude_desktop_config.json
在 Windows 系统中,路径为:
%APPDATA%\Claude\claude_desktop_config.json
为新服务器添加一条记录:
{
"mcpServers": {
"postgres-assistant": {
"command": "node",
"args": ["/absolute/path/to/nl-db-assistant/server.js"]
}
}
}
重新启动 Claude Desktop 后,界面中会出现一个小型工具图标,表明 MCP 服务器已连接并处于可用状态。
实际试用
日常用语即可使用:比如过去一周收到了多少订单、本月哪个产品类别带来的收入最高,或是按订单总价值计算的五大客户是谁。
Claude 会读取实时的模式资源,编写相应的 SQL 语句,调用 query_database 函数,获取结果后将其转化为清晰的答案。非技术背景的同事根本看不到查询过程,只会看到问题与答案而已。
大约80行JavaScript代码就能构建出一个服务器:它能显示与服务器连接的模型所使用的实时PostgreSQL数据库结构,将自然语言问题转换为SQL语句,确保访问为只读模式,并返回结构化输出以便模型进行汇总。该代码只需编写一次,任何支持MCP协议的模型,无论是现在的Claude还是未来的其他模型,都无需修改服务器即可使用它。这正是共享协议的优势所在。
采用情况
其采用速度极为迅速。自发布之初每月的SDK下载量仅为10万次,到2026年3月已上升至9700万次,18个月内增长了约970倍。相比之下,React的npm包则花了大约三年时间才达到每月1亿次的下载量。
实际应用场景包括Block、Bloomberg、Amazon以及数百家《财富》500强企业。Pinterest在2026年4月介绍了其生产环境中的MCP架构:为Presto、Spark和Airflow配备专用服务器,同时由人工审核敏感操作。据称,844名活跃用户每月约发起66,000次工具调用,可节省约7,000小时的工程工作时间。
目前已有官方或社区维护的MCP服务器,适用于Slack、GitHub、Google、Salesforce和Stripe,以及HubSpot、Shopify、Notion、Linear、Sentry、Figma、Webflow、Cloudflare和Postman。
2026年的发展路线图以企业适配为核心,主要内容包括与企业身份提供商绑定的OAuth 2.1登录机制、多代理协调功能(其中一个代理可像工具服务器一样被调用),以及包含安全评级信息的经过筛选的服务器注册表。
常见问题
MCP仅仅是在函数调用基础上增加了额外步骤吗?并非如此,因为二者处于不同的层级。函数调用是模型选择调用某个工具的行为,而MCP则是连接模型与工具的协议。函数调用负责决定是否调用工具,MCP则处理如何连接该工具以及如何与其交互。现代的典型架构会将二者结合使用。
它只适用于Claude吗?当然不是,这正是它的优点之一。OpenAI、Google DeepMind和Microsoft都采用了MCP,还有数千个开发团队也在使用它。只要拥有兼容MCP的客户端,无论模型或服务器由谁开发,都可以使用它们。
2026年时它已经具备生产环境使用条件了吗?鉴于上述大规模的应用场景,对于大多数用途而言答案是肯定的。不过对于实时交易这类对延迟要求极高的系统,或是需要低于100毫秒响应时间的场景,这种抽象层会带来一定的成本,直接使用API连接可能比通过MCP中介的连接更高效。
它的安全性是否足以满足企业级使用需求?正在逐步完善中。2025年3月的规范更新加入了基于OAuth 2.1的完整授权框架,2026年的发展路线图还计划实现与Okta和Azure AD等身份提供商的SAML及OIDC集成。目前,金融或医疗保健等高度受监管的行业仍需要额外的合规保障措施。
谁来管理它?Anthropic 能改变其发展方向吗?自2025年12月起,该协议由Linux基金会的Agentic AI基金会负责管理。这使其成为一种与HTTP或TCP/IP类似的、由社区共同管理的、对供应商中立的共享基础设施,任何单一公司都无法单方面改变其走向。
工具与资源有何区别?工具是模型选择执行的操作,比如发起查询、发送消息或创建文件。而资源则是模型被动读取的数据,如文件、架构或文档。资源会被加载到上下文中,但工具则会在对话过程中按需执行。
一台服务器能否同时承载多个数据库或服务?可以。服务器可以根据需求提供尽可能多的工具和资源,常见的设计是构建一个数据平台服务器,为多个数据库提供读取权限,每个数据库都作为独立的工具或资源呈现。
相关阅读
- 实用笔记:模型上下文协议(MCP)详解——初学者指南 — 该指南详细介绍了模型上下文协议(MCP)的实现方式,包括合同定义、校验规则以及供采用该模式的团队直接使用的代码模板。