# 第七阶段 · 模块七 · 第四节:MCP 服务器开发
如何开发一个 MCP 服务器?MCP 服务器需要实现哪些端点?如何注册和发布 MCP 服务器?
Claude Code 全局架构
┌─────────────────────────────────────────────────────────────────────┐
│ MCP 系统 │
│ │
│ MCP 服务器开发 ← 本节 │
│ ├── 创建服务器 ──> Server 实现 │
│ ├── 实现端点 ──> tools/list、tools/call │
│ └── 注册发布 ──> Claude Code 配置 │
└─────────────────────────────────────────────────────────────────────┘
// 使用 @modelcontextprotocol/sdk 创建服务器
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
const server = new Server(
{
name: 'my-mcp-server',
version: '1.0.0',
},
{
capabilities: {
tools: {}, // 工具能力
resources: {}, // 资源能力
},
}
);
// 1. STDIO(本地进程)
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
const transport = new StdioServerTransport();
await server.connect(transport);
// 2. SSE(远程服务器)
import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js';
const transport = new SSEServerTransport('/sse');
await server.connect(transport);
// 实现 tools/list 端点
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: 'get_weather',
description: 'Get weather for a location',
inputSchema: {
type: 'object',
properties: {
location: {
type: 'string',
description: 'City name',
},
},
required: ['location'],
},
},
{
name: 'send_email',
description: 'Send an email',
inputSchema: {
type: 'object',
properties: {
to: { type: 'string' },
subject: { type: 'string' },
body: { type: 'string' },
},
required: ['to', 'subject', 'body'],
},
},
],
};
});
// 实现 tools/call 端点
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
try {
switch (name) {
case 'get_weather':
return await getWeather(args.location);
case 'send_email':
return await sendEmail(args.to, args.subject, args.body);
default:
throw new Error(`Unknown tool: ${name}`);
}
} catch (error) {
return {
content: [
{
type: 'text',
text: `Error: ${error.message}`,
},
],
isError: true,
};
}
});
async function getWeather(location: string) {
const weather = await fetchWeather(location);
return {
content: [
{
type: 'text',
text: `Weather in ${location}: ${weather.description}, ${weather.temperature}°C`,
},
],
};
}
// 实现 resources/list 端点
server.setRequestHandler(ListResourcesRequestSchema, async () => {
return {
resources: [
{
uri: 'weather://cities',
name: 'Available Cities',
description: 'List of available cities for weather queries',
mimeType: 'application/json',
},
],
};
});
// 实现 resources/read 端点
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
const { uri } = request.params;
switch (uri) {
case 'weather://cities':
return {
contents: [
{
uri,
mimeType: 'application/json',
text: JSON.stringify(['Beijing', 'Shanghai', 'Guangzhou']),
},
],
};
default:
throw new Error(`Unknown resource: ${uri}`);
}
});
// weather-server.ts
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: 'weather-server', version: '1.0.0' },
{ capabilities: { tools: {} } }
);
// 工具列表
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: 'get_weather',
description: 'Get weather for a location',
inputSchema: {
type: 'object',
properties: {
location: { type: 'string' },
},
required: ['location'],
},
},
],
};
});
// 工具调用
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
if (name === 'get_weather') {
const weather = await fetch(`https://api.weather.com?q=${args.location}`)
.then(r => r.json());
return {
content: [
{
type: 'text',
text: `${args.location}: ${weather.temp}°C, ${weather.description}`,
},
],
};
}
throw new Error(`Unknown tool: ${name}`);
});
// 启动
const transport = new StdioServerTransport();
server.connect(transport);
{
"name": "mcp-weather-server",
"version": "1.0.0",
"type": "module",
"main": "weather-server.ts",
"scripts": {
"start": "tsx weather-server.ts"
},
"dependencies": {
"@modelcontextprotocol/sdk": "^0.5.0"
}
}
{
"mcpServers": {
"weather": {
"type": "stdio",
"command": "npx",
"args": ["mcp-weather-server"]
}
}
}
# 1. 登录 NPM
npm login
# 2. 发布
npm publish
# 3. 用户安装
npm install -g mcp-weather-server
# 4. 配置使用
claude mcp add weather npx mcp-weather-server
# 1. 运行服务器
npx mcp-weather-server
# 2. 测试工具调用
echo '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"get_weather","arguments":{"location":"Beijing"}}}' | npx mcp-weather-server
// 添加日志
server.setRequestHandler(CallToolRequestSchema, async (request) => {
console.error('[DEBUG] Tool call:', request.params);
try {
const result = await handleTool(request.params);
console.error('[DEBUG] Result:', result);
return result;
} catch (error) {
console.error('[ERROR]', error);
throw error;
}
});
答案:
// 可以,但需要实现自定义传输
// 或使用 MCP 的 OAuth 支持
// 简单场景:不需要认证
// 内部工具、无敏感数据
// 复杂场景:需要认证
// 外部 API、用户数据
答案:
// MCP 服务器支持并发
// 每个请求独立处理
// 但如果共享资源(如数据库连接),需要加锁
const db = await getDatabase();
server.setRequestHandler(CallToolRequestSchema, async (request) => {
// 数据库操作已经处理了并发
return await db.query(request.params);
});
答案:
// 错误时返回 isError: true
return {
content: [
{
type: 'text',
text: `Error: ${error.message}`,
},
],
isError: true,
};
| 资源 | 说明 |
| MCP SDK | @modelcontextprotocol/sdk |
| MCP 协议规范 | https://modelcontextprotocol.io |
| MCP 服务器示例 | https://github.com/modelcontextprotocol/servers |
第八章:调试与日志:
- 日志系统架构
- 调试模式
- 常见问题排查
*- 第一轮:□ 事实准确性*
*- 第二轮:□ 深度与洞见*
*- 第三轮:□ 可读性与价值*