GitHub_Trending/ty/typescript-sdk资源模板:动态内容生成与参数绑定
GitHub_Trending/ty/typescript-sdk资源模板:动态内容生成与参数绑定
核心功能概览
GitHub_Trending/ty/typescript-sdk是Model Context Protocol(MCP)的官方TypeScript SDK,提供了服务器和客户端实现的完整工具链。该SDK的核心价值在于其资源模板系统,能够实现动态内容生成与参数绑定,帮助开发者快速构建具备上下文感知能力的AI应用。
主要模块架构
该项目采用分层架构设计,主要包含以下核心模块:
- 客户端模块:提供了多种传输协议实现,包括HTTP流、SSE(Server-Sent Events)和WebSocket,位于src/client/目录下
- 服务器模块:实现了MCP服务器核心功能,包括资源管理、工具注册和认证授权,位于src/server/目录下
- 资源模板系统:允许定义动态资源,支持URI参数绑定和内容生成,核心实现位于src/server/mcp.ts
资源模板基础
资源模板定义
资源模板是SDK中最强大的功能之一,它允许开发者定义动态资源,这些资源的内容可以根据请求参数或上下文动态生成。在src/server/mcp.ts中,ResourceTemplate类是这一功能的核心:
// 资源模板定义示例
const userProfileTemplate = new ResourceTemplate({
uriTemplate: new UriTemplate("/users/{userId}"),
completeCallback: async (paramName, value, context) => {
// 参数自动补全逻辑
if (paramName === "userId") {
return await userService.findUserIdsStartingWith(value);
}
return [];
}
});
URI模板与参数绑定
SDK使用URI模板(src/shared/uriTemplate.ts)实现参数化资源路径。通过UriTemplate类,可以轻松定义包含动态参数的资源路径:
// URI模板使用示例
const template = new UriTemplate("/api/resources/{category}/{id}");
const uri = template.expand({ category: "documents", id: "123" });
// 结果: "/api/resources/documents/123"
// 参数提取示例
const variables = template.match("/api/resources/images/456");
// 结果: { category: "images", id: "456" }
动态内容生成实践
服务器端实现
下面我们通过src/examples/server/simpleStreamableHttp.ts中的示例,了解如何创建支持动态内容生成的MCP服务器:
// 创建MCP服务器实例
const server = new McpServer({
name: 'simple-streamable-http-server',
version: '1.0.0',
websiteUrl: 'https://github.com/modelcontextprotocol/typescript-sdk',
});
// 注册动态资源模板
server.resource(
"userProfileTemplate",
new ResourceTemplate({
uriTemplate: new UriTemplate("/users/{userId}"),
completeCallback: async (paramName, value) => {
if (paramName === "userId") {
return await userService.searchUsers(value);
}
return [];
},
listCallback: async (extra) => {
const users = await userService.listUsers();
return {
resources: users.map(user => ({
uri: `/users/${user.id}`,
name: user.name,
mimeType: "application/json"
}))
};
}
}),
async (uri, variables, extra) => {
// 动态内容生成逻辑
const user = await userService.getUserById(variables.userId);
return {
contents: [{
uri,
text: JSON.stringify(user),
mimeType: "application/json"
}]
};
}
);
客户端使用方式
客户端可以通过多种传输协议访问这些动态资源。以Streamable HTTP传输为例:
// 创建Streamable HTTP客户端
const transport = new StreamableHTTPClientTransport({
serverUrl: "http://localhost:3000/mcp"
});
const client = new Client(transport);
// 读取动态资源
const result = await client.readResource("/users/123");
console.log(result.contents[0].text); // 用户123的资料JSON
高级特性
参数自动补全
SDK提供了强大的参数自动补全功能,当用户输入资源URI时,可以根据上下文提供参数建议。这一功能在src/server/mcp.ts的handleResourceCompletion方法中实现:
private async handleResourceCompletion(
request: CompleteRequest,
ref: ResourceTemplateReference,
): Promise<CompleteResult> {
const template = Object.values(this._registeredResourceTemplates).find(
(t) => t.resourceTemplate.uriTemplate.toString() === ref.uri,
);
if (!template) {
throw new McpError(
ErrorCode.InvalidParams,
`Resource template ${request.params.ref.uri} not found`,
);
}
const completer = template.resourceTemplate.completeCallback(
request.params.argument.name,
);
if (!completer) {
return EMPTY_COMPLETION_RESULT;
}
const suggestions = await completer(request.params.argument.value, request.params.context);
return createCompletionResult(suggestions);
}
资源链接与内容嵌入
SDK支持资源链接(ResourceLink)功能,允许在返回结果中包含对其他资源的引用,而不是直接嵌入内容:
// 资源链接示例
server.registerTool(
"list-files",
{
title: "List Files with ResourceLinks",
description: "Returns a list of files as ResourceLinks",
inputSchema: {}
},
async (): Promise<CallToolResult> => {
return {
content: [
{
type: "text",
text: "Available files:"
},
{
type: "resource_link",
uri: "https://example.com/greetings/default",
name: "Default Greeting",
mimeType: "text/plain"
},
{
type: "resource_link",
uri: "file:///example/report.pdf",
name: "Monthly Report",
mimeType: "application/pdf"
}
]
};
}
);
实践案例
用户信息管理系统
以下是一个完整的用户信息管理系统示例,展示了如何结合资源模板、参数绑定和动态内容生成:
// 1. 定义用户资源模板
const userTemplate = new ResourceTemplate({
uriTemplate: new UriTemplate("/users/{userId}"),
completeCallback: async (paramName, value) => {
if (paramName === "userId") {
const users = await userService.searchUsers(value);
return users.map(user => ({
value: user.id,
label: `${user.name} (${user.id})`
}));
}
return [];
},
listCallback: async () => {
const users = await userService.getAllUsers();
return {
resources: users.map(user => ({
uri: `/users/${user.id}`,
name: user.name,
mimeType: "application/json"
}))
};
}
});
// 2. 注册资源模板
server.resource(
"userProfile",
userTemplate,
async (uri, variables) => {
const user = await userService.getUserById(variables.userId);
return {
contents: [{
uri,
text: JSON.stringify({
id: user.id,
name: user.name,
email: user.email,
createdAt: user.createdAt
}),
mimeType: "application/json"
}]
};
}
);
// 3. 注册操作工具
server.tool(
"update-user",
"Updates user information",
{
userId: z.string().describe("User ID"),
name: z.string().optional().describe("New name"),
email: z.string().optional().describe("New email")
},
async ({ userId, name, email }) => {
await userService.updateUser(userId, { name, email });
return {
content: [{
type: "text",
text: `User ${userId} updated successfully`
}]
};
}
);
最佳实践与性能优化
缓存策略
对于频繁访问的动态资源,建议实现缓存机制:
// 带缓存的资源实现示例
const cache = new Map();
const CACHE_TTL = 5 * 60 * 1000; // 5分钟缓存
server.resource(
"product-info",
new ResourceTemplate({
uriTemplate: new UriTemplate("/products/{productId}")
}),
async (uri, variables) => {
const cacheKey = variables.productId;
// 检查缓存
const cached = cache.get(cacheKey);
if (cached && Date.now() - cached.timestamp < CACHE_TTL) {
return cached.data;
}
// 获取新数据
const product = await productService.getProduct(variables.productId);
const result = {
contents: [{
uri,
text: JSON.stringify(product),
mimeType: "application/json"
}]
};
// 更新缓存
cache.set(cacheKey, {
timestamp: Date.now(),
data: result
});
return result;
}
);
错误处理
完善的错误处理对于动态资源至关重要:
// 资源错误处理示例
server.resource(
"sensitive-data",
new ResourceTemplate({
uriTemplate: new UriTemplate("/secrets/{secretId}")
}),
async (uri, variables, extra) => {
try {
// 权限检查
if (!await authService.hasAccess(extra.user, variables.secretId)) {
throw new UnauthorizedError("Access denied to this resource");
}
const secret = await secretService.getSecret(variables.secretId);
return {
contents: [{
uri,
text: JSON.stringify(secret),
mimeType: "application/json"
}]
};
} catch (error) {
// 错误日志记录
logger.error(`Error accessing resource ${uri}:`, error);
// 返回适当的错误响应
if (error instanceof UnauthorizedError) {
throw new McpError(ErrorCode.Unauthorized, error.message);
}
throw new McpError(ErrorCode.InternalError, "Failed to retrieve resource");
}
}
);
总结与后续学习
GitHub_Trending/ty/typescript-sdk的资源模板系统为动态内容生成和参数绑定提供了强大支持,主要优势包括:
- 灵活性:通过URI模板和动态生成逻辑,可以轻松应对各种复杂的内容需求
- 可扩展性:多种传输协议支持,易于集成到现有系统
- 开发者友好:类型安全的API设计,完善的错误处理机制
要深入学习该SDK,建议进一步研究以下资源:
- 示例代码:src/examples/目录包含各种使用场景的完整示例
- 测试用例:src/integration-tests/提供了更多高级用法
- API文档:查看各模块的JSDoc注释了解详细用法
通过掌握资源模板的使用,您可以构建出高度动态且上下文感知的AI应用,为用户提供更加智能和个性化的体验。
更多推荐
所有评论(0)