自定义MCP服务器:让LLM安全接入私有数据与工具

MCP以客户端-服务器架构解决AI接入外部工具的N×M集成难题,并给出自定义服务器的构建与安全实践。
文章系统介绍了模型上下文协议(MCP)如何让大语言模型安全接入私有数据与工具。MCP由Anthropic于2024年底推出、现由Linux基金会治理,通过客户端-服务器架构解决了模型与外部系统集成时的N×M问题,实现“构建一次、处处可用”。每个MCP服务器由工具、资源、提示三大原语构成,多数场景从少量工具起步即可。文章以TypeScript为例,演示了从项目初始化、定义服务器、注册工具、暴露资源到连接stdio传输的完整流程,并对比了本地stdio与远程HTTP/SSE两种部署方式的适用边界。在生产实践部分,作者强调工具职责收窄、严格schema校验、结构化最小输出、清晰工具描述、优雅错误处理以及日志限流等要点,最后列举了接入CRM、私有仓库、专有数据库等典型场景,认为构建自定义MCP服务器对反复为不同AI工具接入同一数据源的团队是一项划算投资。
自定义MCP服务器:让LLM安全接入私有数据与工具
大语言模型的价值上限,取决于它能触及的上下文边界。开箱即用的LLM对你的内部数据库、工单系统或笔记本电脑上的CSV文件一无所知。Anthropic于2024年底推出、现由Linux基金会治理的开源标准——模型上下文协议(Model Context Protocol,MCP),正是为了解决这个问题:它给模型提供了一种统一的标准化方式,去连接外部工具与数据源。

MCP解决了什么根本问题?
在MCP出现之前,把AI模型接入外部系统意味着为每一对“模型-工具”组合编写定制集成。五个模型配上十个数据源,最多可能产生五十个定制集成——这就是经典的“N×M问题”。
MCP用简洁的客户端-服务器架构化解了这一困境:
- MCP客户端:发起连接的AI应用,如Claude Desktop、Claude Code、Cursor、VS Code或自建智能体
- MCP服务器:暴露特定能力的轻量级程序,包括工具、资源和提示模板
- 传输层:通过stdio(本地进程)或HTTP/SSE(远程服务器)通信
为你的数据库构建一个MCP服务器,所有兼容MCP的客户端都能立即使用,无需针对每个模型重新开发。这种“构建一次、处处可用”的特性,是MCP最核心的杠杆效应。
N×M问题中的数字具体指什么:这里的 N 是接入方(AI 客户端或模型)的数量,M 是被接入方(数据源、工具、内部系统)的数量。在没有统一协议时,每个客户端要调用每个工具,就必须单独写一套连接代码与数据格式转换逻辑,因此集成数量随两者相乘增长。MCP 的客户端-服务器架构把这一乘积关系拆成了加法:每个客户端只需实现一份 MCP 客户端逻辑,每个数据源只需实现一个 MCP 服务器,集成总工作量近似变成 N+M。这一区别也是 MCP 与函数调用(function calling)的关键差异——后者只规定模型如何“表达”一次调用意图,并不规定工具如何被发现、描述和托管,MCP 则把发现、调用与传输都纳入了标准。
MCP服务器的三大核心构件
每个MCP服务器都由三种原语构成:
- 工具(Tools):模型可以调用的函数,用于执行动作,例如
create_ticket、run_query、send_email - 资源(Resources):模型可以读取的数据,例如文件、数据库记录、文档
- 提示(Prompts):服务器向客户端暴露的可复用、带参数的提示模板
并非三者都需要实现。大多数自定义服务器从少量工具起步即可满足需求。
原语(Primitive)一词的含义:在 MCP 规范中,原语指协议层面预先定义、由服务器向客户端声明并可被标准化处理的能力单元。工具、资源、提示之所以被称为三种原语,是因为它们各自对应不同的控制主体和交互方式:工具由模型决定何时调用,资源由客户端或用户选择读取,提示通常由用户显式触发。这种划分直接影响权限设计——如果希望某类操作必须经过用户确认,把它实现为资源读或触发式提示,而非可被模型自主调用的工具,往往更安全。理解这一点,有助于在后续实践中判断一项能力应暴露为哪种原语,而不是所有功能都塞进工具列表。
实战:从零构建一个基础MCP服务器
以下是一个使用TypeScript的最小化示例(Python SDK同样可行),展示了构建MCP服务器的完整流程。
第一步:初始化项目
mkdir my-mcp-server && cd my-mcp-server
npm init -y
npm install @modelcontextprotocol/sdk zod
第二步:定义服务器实例
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
const server = new McpServer({
name: "my-custom-data-server",
version: "1.0.0",
});
第三步:注册一个工具
工具是扩展LLM能力最常见的方式,让模型能够按需查询你的数据。
server.tool(
"get_customer_orders",
"Fetch recent orders for a given customer ID",
{ customerId: z.string() },
async ({ customerId }) => {
const orders = await db.query(
"SELECT * FROM orders WHERE customer_id = ?",
[customerId]
);
return {
content: [{ type: "text", text: JSON.stringify(orders) }],
};
}
);
第四步:暴露一个资源
资源让客户端无需调用工具即可读取数据,适合文档、配置等静态或半静态内容。
server.resource(
"product-catalog",
"catalog://products",
async () => ({
contents: [
{
uri: "catalog://products",
text: await fetchProductCatalog(),
},
],
})
);
第五步:连接传输层
const transport = new StdioServerTransport();
await server.connect(transport);
至此,一个能工作的服务器就完成了。将Claude Desktop、Claude Code或任何兼容客户端指向它,模型便可以直接调用get_customer_orders或读取你的产品目录。
stdio 传输的工作方式:StdioServerTransport 让 MCP 服务器作为一个普通子进程被客户端启动,双方通过标准输入输出交换 JSON-RPC 消息,标准错误则用于日志。这意味着服务器不需要监听端口、不需要网络配置,也不需要单独管理进程生命周期,客户端退出时子进程随之结束,因此非常适合本机原型与个人工具。代价是进程与客户端一一绑定,无法被多个用户共享,也无法跨机器访问。此外,使用 stdio 时务必避免向标准输出打印调试信息,否则会污染消息流导致协议解析失败;调试输出应统一走标准错误。
本地服务器与远程服务器的选择
- stdio(本地):适合个人工具、本地数据库或文件访问,构建和调试都简单
- HTTP/SSE(远程):适合团队或生产环境,多个用户或智能体需要共享访问,需要处理认证(通常是OAuth)和托管
合理的路径是:原型阶段先用本地模式,等到需要多用户访问或生产级可靠性时,再迁移到远程部署。
生产级MCP服务器的最佳实践
原文给出了一套颇具实操价值的清单,这里结合分析展开:
- 工具职责收窄:一个接受任意查询的
run_sql工具是安全隐患。应优先使用get_order_status这类目的明确的专用工具。攻击面与工具粒度直接相关。 - 严格校验输入:对每个工具参数使用schema校验(Zod、Pydantic),绝不盲目信任模型生成的输入
- 返回结构化、最小化的输出:模型只需要三个字段时,不要倾倒整行数据库记录。更小的响应意味着更低的延迟和token成本
- 写好工具描述:模型依据描述来选择调用哪个工具,模糊的描述会导致误用或漏调
- 优雅处理错误:返回模型能够推理并从中恢复的描述性错误信息,而非原始堆栈跟踪
- 日志与限流:尤其是远程服务器,需跟踪使用情况并防范失控的工具调用循环
- 用真实客户端测试:Claude Code和Claude Desktop都开箱支持本地MCP服务器,是快速反馈的开发闭环
schema 校验为何是安全边界:模型生成的工具参数在本质上是不可信输入,可能包含类型错误、超长字符串、注入式片段或越界值。Zod(TypeScript)和 Pydantic(Python)这类 schema 库不仅做类型检查,还能约束取值范围、格式与必填项,并在校验失败时给出结构化错误。把校验放在工具处理函数的最前端,可以在任何业务逻辑或数据库操作之前拦截非法输入,避免参数被直接拼接进查询语句。同样重要的是,校验规则应显式声明而非依赖默认值,对于字符串型 ID 这类参数,最好再配合正则限定格式,从源头压缩攻击面。
自定义MCP服务器的典型场景
- 将LLM接入内部CRM或工单系统
- 为编码助手开放私有仓库或文档的访问权限
- 让智能体用自然语言查询专有数据库
- 将内部API(计费、库存、分析)暴露为可调用工具
- 把没有现代API的遗留系统桥接进智能体工作流
最后的判断
MCP把“将AI接入我的数据”从一项定制工程项目,转变为一种标准化、可复用的模式。一旦构建了第一个服务器,扩展它或构建下一个的速度会大幅提升。如果团队正在反复将同一数据源接入不同的AI工具,那么花一个下午构建自定义MCP服务器,很可能是一笔划算的投资。
相关推荐

WorkBuddy全流程教程:从零搭建AI办公自动化智能体
WorkBuddy 全流程教程精讲:从下载安装、三种工作模式到多模态绘本视频实战,再到专家团搭建智能体与工作流配置,帮你用低成本 AI Agent 实现办公自动化。

WorkBuddy智能体全攻略:7天从入门到自动化实战
基于B站256集WorkBuddy全套精讲课程,系统拆解腾讯AI办公工作台的核心能力:Agent原理、Skill封装、连接器跨平台、定时自动化、知识库与零代码开发,附学习路径建议。

8个AI账号翻车7个:我用AI干活的真实复盘
B站8个AI运营账号仅1个跑通。本文拆解"演AI"与"用AI干活"的本质区别,分析5条视频217万播放背后的产能控制、评论区运营和交付节奏策略。