使用模型上下文协议 (MCP) 标准化 AI 集成
关于构建和保护自定义模型上下文协议 (MCP) 服务器以安全地将企业数据连接到 AI 开发人员代理的实用指南。

在过去,将大型语言模型(LLM)连接到内部数据源和系统是一项零散的、临时性的工作。每个 AI 工程项目通常都从编写自定义 API 包装器、映射 JSON 模式或在协调器运行时内编写专有粘合代码以处理工具调用开始。
如果您从 OpenAI 切换到 Anthropic,或者您的开发人员从一个 AI 辅助 IDE 迁移到另一个,您通常必须重写集成层。
这种摩擦正是由 Anthropic 主导的开放标准 模型上下文协议 (Model Context Protocol, MCP) 迅速获得关注的原因。就像语言服务器协议 (LSP) 标准化了编译器与代码编辑器的通信方式一样,MCP 标准化了 AI 模型与数据源及开发人员工具的通信方式。
这是一份关于构建、结构化和保护自定义 MCP 服务器的实用指南,以安全地将企业数据暴露给您的开发人员代理。
架构:解耦客户端和服务器
MCP 的核心设计原则是解耦。MCP 引入了客户端-服务器架构,而不是将 API 集成直接硬编码到代理运行时中:
[ AI Agent / IDE ] (MCP Client)
│
│ (JSON-RPC 2.0 over Stdio or SSE)
▼
[ Custom MCP Server ]
│
├─► Secure Database (PostgreSQL / BigQuery)
├─► Internal Microservices
└─► Local Development Tools- MCP 客户端:协调器(例如 Cursor、Windsurf 或自定义 LangChain 协调器)。它管理 LLM 推理,保存用户上下文并启动工具请求。
- MCP 服务器:一个轻量级进程或服务,暴露三个核心基元:
- Prompts(提示):用于引导模型交互的可重用模板。
- Resources(资源):只读数据源(文件内容、数据库行、API 响应)。
- Tools(工具):可以执行操作或调用外部 API 的可执行函数。
在 TypeScript 中构建自定义 MCP 服务器
让我们使用官方 TypeScript SDK 构建一个可用于生产环境的 Node.js MCP 服务器。该服务器将暴露一个安全工具,用于搜索内部数据库记录(例如候选人或案例研究),并具有内置的运行时参数验证。
1. 项目初始化
首先,设置一个 TypeScript 项目并安装必要的依赖项:
npm init -y
npm install @modelcontextprotocol/sdk zod
npm install --save-dev typescript @types/node
npx tsc --init2. 实现服务器
以下是基于 stdio 的安全 MCP 服务器的代码。我们注册了一个搜索工具,并使用 zod 对传入的负载强制执行严格的模式验证:
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 { z } from "zod";
// 1. Initialize the MCP Server
const server = new Server(
{
name: "enterprise-search-service",
version: "1.0.0",
},
{
capabilities: {
tools: {}, // Advertise tool capabilities to the client
},
}
);
// 2. Define the Search Schema using Zod
const CandidateSearchSchema = z.object({
query: z.string().min(2),
limit: z.number().optional().default(5),
department: z.enum(["Engineering", "Design", "Product", "Sales"]).optional(),
});
// 3. Register Available Tools
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: "search_candidates",
description: "Search internal database for candidates matching specific skills and departments.",
inputSchema: {
type: "object",
properties: {
query: { type: "string", description: "Search term or required skill" },
limit: { type: "number", description: "Maximum records to return" },
department: { type: "string", enum: ["Engineering", "Design", "Product", "Sales"] },
},
required: ["query"],
},
},
],
};
});
// Mock database resolver
async function queryDatabase(query: string, limit: number, dept?: string) {
// Real implementation would connect to Cloud SQL / BigQuery
return [
{ id: 101, name: "Sarah Connor", role: "Staff Platform Engineer", tags: ["Kubernetes", "Go", "MACH"] },
{ id: 102, name: "Marcus Wright", role: "Solutions Architect", tags: ["Next.js", "React", "AI Agents"] }
];
}
// 4. Handle Tool Executions
server.setRequestHandler(CallToolRequestSchema, async (request) => {
if (request.params.name !== "search_candidates") {
throw new Error(`Tool ${request.params.name} not found`);
}
try {
// Validate the arguments at runtime
const args = CandidateSearchSchema.parse(request.params.arguments);
// Fetch secure records
const results = await queryDatabase(args.query, args.limit, args.department);
return {
content: [
{
type: "text",
text: JSON.stringify(results, null, 2),
},
],
};
} catch (error: any) {
return {
content: [
{
type: "text",
text: `Error validating arguments: ${error.message}`,
},
],
isError: true,
};
}
});
// 5. Start Server Transport (stdio is standard for local IDE integrations)
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("Enterprise Search MCP Server running on stdio");强化企业使用安全性
虽然编写 TypeScript 逻辑非常简单,但将内部生产数据暴露给 LLM 需要严格的运营安全防线。AI 模型容易出现幻觉、提示注入和意外的工具执行循环。
以下是企业 MCP 安全性的四个支柱:
1. 模式验证和输入清理
绝不信任 LLM 生成的参数。始终使用 Zod 等库验证参数,并清理字符串以防止数据库风险:
- 使用参数化查询或 ORM 来防止 SQL 注入。
- 如果您的工具读取本地文件,请验证目录路径以防止目录遍历漏洞。
2. 身份验证和 OAuth 上下文传递
在企业网络中运行时,您必须验证代理背后的用户的授权级别。
- 通过 服务器发送事件 (SSE) 而不是 stdio 暴露 MCP。这允许将 MCP 服务器作为 API 网关背后的独立微服务运行。
- 在请求头中转发用户的身份令牌 (JWT),允许您的 MCP 服务器在目标数据库中实施行级安全 (RLS)。
3. 人在环路 (HITL) 把关
暴露读取工具(如 search_candidates)风险较低。然而,暴露写入工具(如 update_records 或 deploy_service)是危险的。
- 对写入操作实施明确的批准。MCP 客户端应拦截写入请求,并向开发人员显示一个 diff,展示代理想要提交的更改。
[ Agent Tool Request ] ──► [ Security Middleware ] ──► (Diff Check / UI Popup)
│
┌──────────────────────────────────────────┘
▼
[ User Approves? ] ──(Yes)──► [ Execute Write on Server ]4. 速率限制和防线
代理可能会进入递归推理循环,在几秒钟内调用一个工具数十次,从而导致重大的数据库负载或高额的代币成本。
- 强制执行每个会话的请求速率限制。
- 限制最大结果负载以防止代币溢出。
展望未来:将遗留系统暴露为 AI 基元
模型上下文协议的力量在于它将遗留软件接口转化为干净、可发现的功能。
通过将内部数据库、部署脚本和 API 封装在标准化的 MCP 层中,您可以确保任何 AI 工具(无论是像 Cursor 这样的编辑器、终端伴侣还是自主部署代理)都能够安全、可预测且以零翻译成本与您的业务逻辑进行交互。