MCP 服务器开发
本指南将详细介绍如何开发自己的 MCP (Model Context Protocol) 服务器,包括基础概念、开发流程和最佳实践。
开发概述
MCP 服务器是一个独立的程序,它通过标准化的协议与 MCP 客户端(如 Claude Desktop)进行通信。服务器可以提供:
- 🔧 工具 (Tools) - 可执行的功能
- 📚 资源 (Resources) - 可访问的数据
- 💬 提示 (Prompts) - 预定义的提示模板
技术架构
通信协议
MCP 基于 JSON-RPC 2.0 协议,支持多种传输方式:
┌─────────────────┐ JSON-RPC ┌─────────────────┐
│ MCP Client │ ←──────────→ │ MCP Server │
│ (Claude Desktop)│ │ (Your Server) │
└─────────────────┘ └─────────────────┘传输层选择
- stdio - 标准输入输出(推荐)
- SSE - Server-Sent Events
- WebSocket - 双向实时通信
快速开始
环境准备
bash
# Node.js 项目
mkdir my-mcp-server
cd my-mcp-server
npm init -y
# 安装 MCP SDK
npm install @modelcontextprotocol/sdk
# TypeScript 支持(推荐)
npm install -D typescript @types/node
npx tsc --init基础服务器结构
typescript
#!/usr/bin/env node
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
CallToolRequestSchema,
ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
// 创建服务器实例
const server = new Server(
{
name: "my-mcp-server",
version: "1.0.0",
},
{
capabilities: {
tools: {},
},
}
);
// 列出可用工具
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: "hello",
description: "Say hello to someone",
inputSchema: {
type: "object",
properties: {
name: {
type: "string",
description: "Name of the person to greet",
},
},
required: ["name"],
},
},
],
};
});
// 处理工具调用
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
if (name === "hello") {
const personName = args.name as string;
return {
content: [
{
type: "text",
text: `Hello, ${personName}! Nice to meet you.`,
},
],
};
}
throw new Error(`Unknown tool: ${name}`);
});
// 启动服务器
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("MCP server running on stdio");
}
main().catch((error) => {
console.error("Server error:", error);
process.exit(1);
});核心概念详解
1. 工具 (Tools)
工具是服务器提供的可执行功能:
typescript
// 工具定义
{
name: "read_file",
description: "Read contents of a file",
inputSchema: {
type: "object",
properties: {
path: {
type: "string",
description: "File path to read"
}
},
required: ["path"]
}
}
// 工具实现
server.setRequestHandler(CallToolRequestSchema, async (request) => {
if (request.params.name === "read_file") {
const path = request.params.arguments.path as string;
const content = await fs.readFile(path, 'utf-8');
return {
content: [
{
type: "text",
text: content
}
]
};
}
});2. 资源 (Resources)
资源提供对数据的访问:
typescript
import { ListResourcesRequestSchema, ReadResourceRequestSchema } from "@modelcontextprotocol/sdk/types.js";
// 列出资源
server.setRequestHandler(ListResourcesRequestSchema, async () => {
return {
resources: [
{
uri: "file://config.json",
name: "Configuration",
description: "Application configuration file",
mimeType: "application/json"
}
]
};
});
// 读取资源
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
const uri = request.params.uri;
if (uri === "file://config.json") {
const config = await loadConfig();
return {
contents: [
{
uri,
mimeType: "application/json",
text: JSON.stringify(config, null, 2)
}
]
};
}
throw new Error(`Resource not found: ${uri}`);
});3. 提示 (Prompts)
提示提供预定义的模板:
typescript
import { ListPromptsRequestSchema, GetPromptRequestSchema } from "@modelcontextprotocol/sdk/types.js";
// 列出提示
server.setRequestHandler(ListPromptsRequestSchema, async () => {
return {
prompts: [
{
name: "code_review",
description: "Review code for best practices",
arguments: [
{
name: "language",
description: "Programming language",
required: true
}
]
}
]
};
});
// 获取提示
server.setRequestHandler(GetPromptRequestSchema, async (request) => {
if (request.params.name === "code_review") {
const language = request.params.arguments?.language || "JavaScript";
return {
description: `Code review prompt for ${language}`,
messages: [
{
role: "user",
content: {
type: "text",
text: `Please review this ${language} code for best practices, security issues, and performance optimizations.`
}
}
]
};
}
throw new Error(`Prompt not found: ${request.params.name}`);
});高级功能
错误处理
typescript
import { McpError, ErrorCode } from "@modelcontextprotocol/sdk/types.js";
server.setRequestHandler(CallToolRequestSchema, async (request) => {
try {
// 工具逻辑
return result;
} catch (error) {
throw new McpError(
ErrorCode.InternalError,
`Tool execution failed: ${error.message}`
);
}
});