运行时依赖
版本
- 将技能重命名为“mcp-server-builder”,并将 slug 更新为“skylv-mcp-server-builder”。 - 版本号升至 1.0.2。 - 扩充了从零构建 MCP(Model Context Protocol)服务器的文档,新增概述、项目结构及详细实现示例。 - 新增代码示例,涵盖工具与资源定义、服务器初始化,以及文件操作和数据库查询等示例工具。 - 补充测试说明与部署指南,支持 Claude Desktop、Cursor 和 VS Code。 - 列出错误处理、类型安全、日志、性能与安全的最佳实践。
安装命令
点击复制技能文档
功能说明
构建 Model Context Protocol 服务器,扩展 AI 能力边界。MCP 协议概述
MCP 是 Anthropic 推出的 AI 模型上下文协议,让 AI 能调用外部工具和数据源。项目结构
``
mcp-server/
├── package.json
├── tsconfig.json
├── src/
│ ├── index.ts # 主入口
│ ├── tools/ # 工具定义
│ └── resources/ # 资源定义
└── tsconfig.json
` 完整实现
1. 初始化项目
`bash
npm init -y
npm install @modelcontextprotocol/sdk zod
npm install -D typescript @types/node ts-node
` `json
// package.json
{
"name": "my-mcp-server",
"version": "1.0.0",
"type": "module",
"scripts": {
"build": "tsc",
"start": "node dist/index.js",
"dev": "ts-node src/index.ts"
},
"dependencies": {
"@modelcontextprotocol/sdk": "^0.5.0",
"zod": "^3.22.0"
}
}
`
`json
// tsconfig.json
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true
},
"include": ["src/*/"]
}
`
2. 定义工具
`typescript
// src/tools/search.ts
import { z } from 'zod'; export const searchTool = {
name: 'web_search',
description: '搜索互联网获取最新信息',
inputSchema: z.object({
query: z.string().describe('搜索关键词'),
limit: z.number().optional().default(5).describe('返回结果数量')
}),
async handler(args: { query: string; limit?: number }) {
const results = await performSearch(args.query, args.limit || 5);
return {
content: results.map(r => ({
type: 'text' as const,
text: 标题: ${r.title}\n链接: ${r.url}\n摘要: ${r.snippet}
}))
};
}
};
`
3. 定义资源
`typescript
// src/resources/knowledge.ts
export const knowledgeResources = {
uriPrefix: 'knowledge://',
list: async () => [
{
uri: 'knowledge://docs/latest',
name: '最新文档',
description: '系统最新文档版本',
mimeType: 'text/markdown'
}
],
read: async (uri: string) => {
if (uri === 'knowledge://docs/latest') {
return {
contents: [{
uri,
mimeType: 'text/markdown',
text: '# 最新文档\n\n...'
}]
};
}
throw new Error('Resource not found');
}
};
` 4. 主入口
`typescript
// src/index.ts
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema } from '@modelcontextprotocol/sdk/types.js';
import { searchTool } from './tools/search.js';
import { knowledgeResources } from './resources/knowledge.js'; class MyMCPServer {
private server: Server;
constructor() {
this.server = new Server(
{ name: 'my-mcp-server', version: '1.0.0' },
{ capabilities: { tools: {}, resources: {} } }
);
this.setupToolHandlers();
this.setupResourceHandlers();
}
private setupToolHandlers() {
this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: [{
name: searchTool.name,
description: searchTool.description,
inputSchema: searchTool.inputSchema
}]
}));
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
if (name === 'web_search') {
return await searchTool.handler(args as any);
}
throw new Error(Unknown tool: ${name});
});
}
private setupResourceHandlers() {
this.server.setRequestHandler(ListResourcesRequestSchema, async () => ({
resources: await knowledgeResources.list()
}));
this.server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
return await knowledgeResources.read(request.params.uri);
});
}
async start() {
const transport = new StdioServerTransport();
await this.server.connect(transport);
console.error('MCP Server started on stdio');
}
}
new MyMCPServer().start().catch(console.error);
`
5. 更多工具示例
`typescript
// 文件操作工具
export const fileTools = {
name: 'file_operations',
description: '读取、写入、列出文件',
inputSchema: z.object({
operation: z.enum(['read', 'write', 'list', 'delete']),
path: z.string(),
content: z.string().optional()
}),
async handler(args: any) {
const fs = await import('fs/promises');
switch (args.operation) {
case 'read': {
const content = await fs.readFile(args.path, 'utf-8');
return { content: [{ type: 'text', text: content }] };
}
// 其余 case 省略
}
}
};
``