引言
在前两篇文章中,我们已经详细介绍了MCP开发环境的搭建以及基础服务器开发。本文作为MCP TypeScript-SDK系列的第三篇,将聚焦于MCP资源开发基础,包括静态资源与动态资源的开发、资源模板设计与参数提取、资源列表与发现机制,以及常见资源类型与最佳实践。通过本文的学习,你将能够设计和实现高效、灵活的MCP资源,为AI应用提供丰富的上下文信息。
一、静态资源与动态资源开发
在MCP中,资源是一种为AI模型提供上下文信息的数据结构。MCP将资源分为静态资源和动态资源两种类型,它们在实现方式和使用场景上有明显区别。
1. 静态资源开发
静态资源是指内容固定不变的资源,通常用于提供参考文档、配置信息或者固定知识库等。
1.1 基本静态资源创建
import {
McpServer } from '@modelcontextprotocol/sdk';
const server = new McpServer({
name: 'resource-server',
description: '资源示例服务器',
version: '1.0.0',
});
// 注册静态资源
server.registerResource({
name: 'company-intro',
description: '公司简介文档',
content: '我们是一家专注于AI技术的创新公司,成立于2020年...',
});
1.2 从文件加载静态资源
import {
McpServer } from '@modelcontextprotocol/sdk';
import fs from 'fs';
import path from 'path';
const server = new McpServer({
name: 'resource-server',
description: '资源示例服务器',
version: '1.0.0',
});
// 从文件加载静态资源
const documentPath = path.join(__dirname, 'resources', 'product-manual.md');
const documentContent = fs.readFileSync(documentPath, 'utf-8');
server.registerResource({
name: 'product-manual',
description: '产品使用手册',
content: documentContent,
metadata: {
format: 'markdown',
lastUpdated: new Date().toISOString(),
version: '2.1.0',
}
});
1.3 静态资源分组与组织
// 通过命名空间组织静态资源
server.registerResource({
name: 'docs/api/authentication',
description: 'API认证文档',
content: '# API认证\n认证流程说明...',
});
server.registerResource({
name: 'docs/api/endpoints',
description: 'API端点文档',
content: '# API端点\n可用的API端点列表...',
});
// 使用tags标记资源
server.registerResource({
name: 'marketing-brand-guidelines',
description: '品牌营销指南',
content: '品牌标识使用规范...',
metadata: {
tags: ['marketing', 'brand', 'guidelines'],
department: 'marketing',
}
});
2. 动态资源开发
动态资源是指内容可以根据请求参数动态生成的资源,适用于需要实时数据或个性化内容的场景。
2.1 基本动态资源创建
import {
McpServer } from '@modelcontextprotocol/sdk';
import {
z } from 'zod';
const server = new McpServer({
name: 'dynamic-resource-server',
description: '动态资源示例服务器',
version: '1.0.0',
});
// 注册动态资源
server.registerResource({
name: 'weather-report',
description: '实时天气报告',
parameters: z.object({
city: z.string().describe('城市名称'),
unit: z.enum(['celsius', 'fahrenheit']).default('celsius').describe('温度单位'),
}),
resolve: async ({
city, unit }) => {
// 从天气API获取数据
const weatherData = await fetchWeatherData(city, unit);
return {
content: `${
city}天气报告:温度${
weatherData.temperature}${
unit === 'celsius' ? '°C' : '°F'},湿度${
weatherData.humidity}%,天气${
weatherData.condition}。`,
metadata: {
timestamp: new Date().toISOString(),
provider: 'WeatherAPI',
city: city,
}
};
}
});
// 模拟天气数据获取函数
async function fetchWeatherData(city: string, unit: string) {
// 实际应用中,这里会调用真实的天气API
return {
temperature: unit === 'celsius' ? 23 : 73.4,
humidity: 65,
condition: '晴天',
};
}
2.2 复杂参数的动态资源
// 带有复杂参数的动态资源
server.registerResource({
name: 'financial-report',
description: '财务报表生成器',
parameters: z.object({
companyId: z.string().describe('公司ID'),
period: z.object({
start: z.string().describe('开始日期 (YYYY-MM-DD)'),
end: z.string().describe('结束日期 (YYYY-MM-DD)'),
}).describe('报告周期'),
metrics: z.array(
z.enum(['revenue', 'expenses', 'profit', 'cash-flow'])
).default(['revenue', 'profit']).describe('要包含的指标'),
format: z.enum(['summary', 'detailed']).default('summary').describe('报告格式'),
}),
resolve: async ({
companyId, period, metrics, format }) => {
// 从数据库获取财务数据
const financialData = await fetchFinancialData(companyId, period, metrics);
// 根据format参数生成不同格式的报告
const report = format === 'summary'
? generateSummaryReport(financialData)
: generateDetailedReport(financialData);
return {
content: report,
metadata: {
companyId,
period,
metrics,
generatedAt: new Date().toISOString(),
}
};
}
});
2.3 分页和流式动态资源
// 支持分页的动态资源
server.registerResource({
name: 'user-list',
description: '用户列表',
parameters: z.object({
page: z.number().int().min(1).default(1).describe('页码'),
pageSize: z.number().int().min(1).max(100).default