name: mcp-development description: MCP服务器开发,包括工具设计、资源端点、提示模板和传输配置
MCP开发
带工具的MCP服务器
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: "project-tools",
version: "1.0.0",
});
server.tool(
"search_files",
"在项目目录中搜索匹配glob模式的文件",
{
pattern: z.string().describe("Glob模式(例如,'**/*.ts')"),
directory: z.string().optional().describe("搜索的基目录"),
},
async ({ pattern, directory }) => {
const files = await glob(pattern, { cwd: directory ?? process.cwd() });
return {
content: [
{
type: "text",
text: files.length > 0
? files.join("
")
: `未找到匹配 ${pattern} 的文件`,
},
],
};
}
);
server.tool(
"run_query",
"在应用数据库上执行只读SQL查询",
{
query: z.string().describe("要执行的SQL SELECT查询"),
limit: z.number().default(100).describe("最大返回行数"),
},
async ({ query, limit }) => {
if (!query.trim().toUpperCase().startsWith("SELECT")) {
return {
content: [{ type: "text", text: "只允许SELECT查询" }],
isError: true,
};
}
const rows = await db.query(`${query} LIMIT ${limit}`);
return {
content: [{ type: "text", text: JSON.stringify(rows, null, 2) }],
};
}
);
资源
server.resource(
"schema",
"db://schema",
"当前数据库模式,包含所有表、列和关系",
async () => {
const schema = await db.query(`
SELECT table_name, column_name, data_type, is_nullable
FROM information_schema.columns
WHERE table_schema = 'public'
ORDER BY table_name, ordinal_position
`);
return {
contents: [
{
uri: "db://schema",
mimeType: "application/json",
text: JSON.stringify(schema, null, 2),
},
],
};
}
);
server.resource(
"config",
"config://app",
"应用配置(秘密信息已脱敏)",
async () => {
const config = await loadConfig();
const safe = redactSecrets(config);
return {
contents: [
{
uri: "config://app",
mimeType: "application/json",
text: JSON.stringify(safe, null, 2),
},
],
};
}
);
提示模板
server.prompt(
"review-code",
"审查代码变更中的错误、安全问题和风格",
{
diff: z.string().describe("Git差异或要审查的代码"),
focus: z.enum(["security", "performance", "style", "all"]).default("all"),
},
async ({ diff, focus }) => ({
messages: [
{
role: "user",
content: {
type: "text",
text: `审查此代码差异。焦点:${focus}
${diff}`,
},
},
],
})
);
客户端配置
{
"mcpServers": {
"project-tools": {
"command": "node",
"args": ["./mcp-server/dist/index.js"],
"env": {
"DATABASE_URL": "postgres://localhost:5432/app"
}
},
"remote-server": {
"url": "https://mcp.example.com/sse",
"headers": {
"Authorization": "Bearer ${MCP_TOKEN}"
}
}
}
}
传输设置
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
const transport = new StdioServerTransport();
await server.connect(transport);
对于基于HTTP的服务器,使用SSE传输以流式响应客户端。
反模式
- 创建描述模糊的工具,不解释何时使用
- 在处理前未使用Zod模式验证输入
- 向客户端返回原始错误堆栈跟踪
- 错误响应中缺少
isError: true标志 - 创建太多细粒度工具而不是可组合的工具
- 在资源响应中未脱敏秘密信息
检查表
- [ ] 每个工具都有清晰的描述,说明何时及为何使用
- [ ] 输入参数使用Zod模式和描述性消息进行验证
- [ ] 错误响应包括
isError: true和用户友好的消息 - [ ] 资源暴露只读数据,秘密信息已脱敏
- [ ] 提示模板为常见任务提供结构化起点
- [ ] 服务器在SIGINT/SIGTERM时处理优雅关闭
- [ ] 工具是可组合的(做好一件事),而不是单一的
- [ ] 客户端配置已记录,包括所需环境变量