构建 MCP 服务器:第 2 部分 — 使用资源模板扩展资源

news2025/6/8 8:22:52

该图像是使用 AI 图像创建程序创建的。

这个故事是在多位人工智能助手的帮助下写成的。

这是构建MCP 服务器教程(共四部分)的第二部分。在第一部分中,我们使用基本资源创建了第一个 MCP 服务器。现在,我们将使用资源模板扩展服务器的功能。本文中的代码假设您从上次中断的地方继续学习。

什么是资源模板?

资源模板允许您使用 URI 模式定义动态资源。与具有固定 URI 的静态资源不同,模板允许您创建可根据参数生成 URI 和内容的资源。

可以将它们想象成 Web 框架中的 URL 模式,其中资源更具动态性,通常基于某些标签或 ID - 它们允许您使用单个定义匹配和处理整个资源系列。

为什么要使用资源模板?

当您需要处理动态数据、按需生成内容或创建基于参数的资源等时,资源模板非常强大。

以下是一些示例:

动态数据

“users://{userId}”  ->用户资料
“products://{sku}”  ->产品信息

用户:“你能告诉我关于用户 12345 的情况吗?”
AI 助手:“正在查找用户 12345......他于 2023 年加入,已进行 50 次购买。”

按需生成内容

“reports://{year}/{month}”  ->月度报告
“analytics://{dateRange}”  ->自定义分析

用户:“给我看看2024年3月的报告”
AI助手:“正在访问2024年3月的报告……与2月份相比,收入增长了15%。”

基于参数的资源

"search://{query}"  ->搜索结果
"filter://{type}/{value}"  ->过滤数据

用户:“查找所有超过 1000 美元的交易”
AI 助手:“使用过滤资源...找到 23 笔符合您条件的交易。”

组织我们的代码

我们再来改进一下上篇文章中构建的代码结构,分离一些关注点。首先,把处理程序拆分成一个新文件 (handlers.ts),这样就不会太杂乱了:

// src/handlers.ts
import {
  ListResourcesRequestSchema,
  ReadResourceRequestSchema,
  ListResourceTemplatesRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
import { type Server } from "@modelcontextprotocol/sdk/server/index.js";

export const setupHandlers = (server: Server): void => {
  // List available resources when clients request them
  server.setRequestHandler(ListResourcesRequestSchema, async () => {
    return {
      resources: [
        {
          uri: "hello://world",
          name: "Hello World Message",
          description: "A simple greeting message",
          mimeType: "text/plain",
        },
      ],
    };
  });
  // Return resource content when clients request it
  server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
    if (request.params.uri === "hello://world") {
      return {
        contents: [
          {
            uri: "hello://world",
            text: "Hello, World! This is my first MCP resource.",
          },
        ],
      };
    }
    throw new Error("Resource not found");
  });
};

更新我们的主要文件src/index.ts

// src/index.ts
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { setupHandlers } from './handlers.js';

const server = new Server(
  {
    name: "hello-mcp",
    version: "1.0.0",
  },
  {
    capabilities: {
      resources: {},
    },
  }
);

setupHandlers(server);

// Start server using stdio transport
const transport = new StdioServerTransport();
await server.connect(transport);
console.info('{"jsonrpc": "2.0", "method": "log", "params": { "message": "Server running..." }}');

添加新资源

现在是时候添加我们的新资源模板了。

首先,让我们添加清单,以便 AI 助手知道它在那里。在资源清单(第一个参数为 的那个)src/handlers.js之后添加以下代码。hello://worldListResourcesRequestSchema

export const setupHandlers = (server: Server): void => {
  // Existing "hello://world" resource listing here ...

  // Resource Templates
  server.setRequestHandler(ListResourceTemplatesRequestSchema, async () => ({
    resourceTemplates: [
      {
        greetings: {
          uriTemplate: 'greetings://{name}',
          name: 'Personal Greeting',
          description: 'A personalized greeting message',
          mimeType: 'text/plain',
        },
      },
    ],
  }));

  // Existing "hello://world" resource content here ... 
};

接下来我们可以添加内容处理程序。这不需要额外的请求处理程序。我们只需为这种格式的请求添加一个新的检查即可。

// Return resource content when clients request it
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
  // ... Existing content handler code

  // Template-based resource code
  const greetingExp = /^greetings:\/\/(.+)$/;
  const greetingMatch = request.params.uri.match(greetingExp);
  if (greetingMatch) {
    const name = decodeURIComponent(greetingMatch[1]);
    return {
        contents: [
        {
            uri: request.params.uri,
            text: `Hello, ${name}! Welcome to MCP.`,
        },
      ],
    };
  }

  // ...
});

理解代码

处理程序组织

  • 我们已将处理程序移至单独的文件以便更好地组织
  • setupHandlers 函数封装了所有处理程序的设置
  • 主文件保持干净且专注

模板定义

  • 处理程序公开可用的模板 ListResourceTemplateRequestSchema
  • 模板名称格式遵循RFC 6570{text} (用于表达参数化的URL )
  • 模板包括名称和描述等元数据

模板处理

  • 处理程序现在检查模板匹配 ReadResourceRequestSchema
  • 我们使用正则表达式格式从 URI 中提取名称参数
  • 我们根据参数生成动态内容

使用检查器进行测试

在上一篇文章中,我们讨论了如何使用MCP 检查器。现在启动检查器:

npx tsc
npx @modelcontextprotocol/inspector node build/index.js

测试我们上次创建的静态资源,以确保它仍然有效:

  • 点击“资源”选项卡
  • 找到并点击“Hello World Message”
  • 您应该会看到“Hello, World! 这是我的第一个 MCP 资源。”的消息。

测试模板:

  • 点击“资源模板”选项卡
  • 找到“个人问候语”
  • 输入名字“Alice”
{
  "contents": [
    {
      "uri": "greetings://Alice",
      "text": "Hello, Alice! Welcome to MCP."
    }
  ]
}

使用 Claude Desktop 进行测试

这次您不需要在 Claude 中更新任何内容,但您可能需要重新加载(同时,确保您已经使用构建了服务npx tsc)。

正如我上一篇文章所述,我为 Mac 使用的 Claude Desktop 似乎还不支持资源,但您可以在其他支持 MCP 的工具中尝试此操作,例如 Cline,您可能必须专门使用支持 MCP 的模型,例如 Anthropic 的 Sonnet 3.5。

尝试以下示例(响应可能有所不同):

静态资源:

用户: “问候语里有什么?” 
Claude: “问候语是:‘来自 MCP 的问候!这是您的第一个资源。’”

模板资源:

用户: “你能给爱丽丝找个问候语吗?”
克劳德: “我去看看个性化问候语……上面写着:‘你好,爱丽丝!欢迎来到 MCP。’”

列出可用资源:

用户:“有哪些资源和模板可用?” 
Claude:“服务器提供:
1. 静态‘问候语’资源
2. 可以为任何姓名创建自定义问候语的‘个人问候语’模板”

下一步是什么?

在第 3 部分中,我们将:

  • 通过将资源和模板分离到各自的文件中,进一步改善代码组织
  • 了解 MCP 提示以及它们与资源的区别
  • 为我们的服务器添加提示功能
  • 看看提示如何增强我们的问候功能

第 4 部分将通过向我们的服务器添加工具来完成我们的课程。

资源和其他阅读材料:

  • Introduction - Model Context Protocol
  • Cline - Visual Studio Marketplace
  • RFC 6570: URI Template
  • App unavailable \ Anthropic

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2403917.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【算法设计与分析】实验——汽车加油问题, 删数问题(算法实现:代码,测试用例,结果分析,算法思路分析,总结)

说明:博主是大学生,有一门课是算法设计与分析,这是博主记录课程实验报告的内容,题目是老师给的,其他内容和代码均为原创,可以参考学习,转载和搬运需评论吱声并注明出处哦。 4-1算法实现题 汽车…

【C++进阶篇】C++11新特性(下篇)

C函数式编程黑魔法:Lambda与包装器实战全解析 一. lambda表达式1.1 仿函数使用1.2 lambda表达式的语法1.3 lambda表达式使用1.3.1 传值和传引用捕捉1.3.2 隐式捕捉1.3.3 混合捕捉 1.4 lambda表达式原理1.5 lambda优点及建议 二. 包装器2.1 function2.2 bind绑定 三.…

全生命周期的智慧城市管理

前言 全生命周期的智慧城市管理。未来,城市将在 实现从基础设施建设、日常运营到数据管理的 全生命周期统筹。这将避免过去智慧城市建设 中出现的“碎片化”问题,实现资源的高效配 置和项目的协调发展。城市管理者将运用先进 的信息技术,如物…

echarts柱状图实现动态展示时报错

echarts柱状图实现动态展示时报错 1、问题: 在使用Echarts柱状图时,当数据量过多,x轴展示不下的时候,可以使用dataZoom实现动态展示。如下图所示: 但是当鼠标放在图上面滚动滚轮时或拖动滚动条时会报错,…

408第一季 - 数据结构 - 线性表

只能用C/C! 顺序表 闲聊 线性表的逻辑顺序和物理顺序相同 都是1234 顺序表的优点: 随机访问,随机访问的意思是访问的时间 和位置没有关系,访问下标1和100一样的,更深层就是直接计算 a100 * 数组大小,随便…

第23讲、Odoo18 邮件系统整体架构

目录 Odoo 邮件系统整体架构邮件发送方式邮件模板配置SMTP 邮件服务器配置邮件发送过程开发中常见邮件发送需求常见问题排查提示与最佳实践完整示例:审批通过自动发邮件门户表单自动邮件通知案例邮件队列与异步发送邮件添加附件邮件日志与调试多语言邮件模板邮件安…

HarmonyOS:Counter计数器组件

一、概述 计数器组件,提供相应的增加或者减少的计数操作。 说明 该组件从API Version 7开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。 二、属性 除支持通用属性外,还支持以下属性。 enableInc enableInc(value: b…

sqlsugar WhereIF条件的大于等于和等于查出来的坑

一、如下图所示,当我用 .WhereIF(input.Plancontroltype > 0, u > u.Plancontroltype (DnjqPlancontroltype)input.Plancontroltype) 这里面用等于的时候,返回结果一条数据都没有。 上图中生成的SQL如下: SELECT id AS Id ,code AS …

Pandas 技术解析:从数据结构到应用场景的深度探索

序 我最早用Python做大数据项目时,接触最早的就是Pandas了。觉得对于IT技术人员而言,它是可以属于多场景的存在,因为它的本身就是数据驱动的技术生态中,对于软件工程师而言,它是快速构建数据处理管道的基石&#xff1…

数据库系统概论(十七)超详细讲解数据库规范化与五大范式(从函数依赖到多值依赖,再到五大范式,附带例题,表格,知识图谱对比带你一步步掌握)

数据库系统概论(十七)超详细讲解数据库规范化与五大范式(从函数依赖到多值依赖,再到五大范式,附带例题,表格,知识图谱对比带你一步步掌握) 前言一、为什么需要规范化1. 我们先想一个…

并发编程实战(生产者消费者模型)

在并发编程中使用生产者和消费者模式能够解决绝大多数的并发问题。该模式通过平衡生产线程和消费线程的工作能力来提高程序整体处理数据的速度。 生产者和消费者模式: 在线程的世界中生产者就是产生数据的线程,而消费者则是消费数据的线程。在多线程开…

git小乌龟不显示图标状态解决方案

第一步 在开始菜单的搜索处,输入regedit命令,打开注册表。 第二步 在注册表编辑器中,找到HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers 这一项。 第三步 让Tortoise相关的项目排在前…

获取 OpenAI API Key

你可以按照以下步骤来获取 openai.api_key,用于调用 OpenAI 的 GPT-4、DALLE、Whisper 等 API 服务: 🧭 获取 OpenAI API Key 的步骤: ✅ 1. 注册或登录 OpenAI 账号 打开 https://platform.openai.com/ 使用你的邮箱或 Google/…

【Android基础回顾】五:AMS(Activity Manager Service)

Android 的 AMS(Activity Manager Service)是 Android 系统中的核心服务之一,负责管理整个应用生命周期、任务栈、进程和四大组件(Activity、Service、BroadcastReceiver、ContentProvider)的运行。它运行在系统进程 s…

pycharm中提示C++ compiler not found -- please install a compiler

1.最近用pycharm编译一个开源库,编译的依赖c compiler 2.单单使用pycharm编译,编译器报错C compiler not found – please install a compiler 3.需要在配置环境中引入对应库 4.从新编译后没有提示:C compiler not found – please install a compiler错误。

一站式直播工具:助力内容创作者高效开启直播新时代

近年来,随着互联网技术的不断进步和短视频、直播行业的爆发式增长,越来越多的企业和个人投入到直播电商、互动娱乐、在线教育等场景。直播运营过程中,涉及到数据统计、弹幕互动、流程自动化、内容同步等诸多环节。如何提升运营效率、减少人工…

以智能管理为基础,楼宇自控打造建筑碳中和新路径

在全球气候变化的严峻形势下,“碳中和”已成为各国发展的重要战略目标。建筑行业作为能源消耗与碳排放的“大户”,其运行阶段的能耗占全社会总能耗近40%,碳排放占比与之相当,实现建筑碳中和迫在眉睫。传统建筑管理模式下&#xff…

day029-Shell自动化编程-计算与while循环

文章目录 1. read 交互式初始化变量1.1 案例-安装不同的软件1.2 案例-比较大小 2. 计算2.1 bc2.2 awk2.3 expr2.4 let2.5 案例-计算内存的空闲率2.6 案例-检查域名过期时间和https整数过期时间 3. 循环3.1 循环控制语句3.2 for循环-c语言格式3.3 while循环3.3.1 案例-猜数字3.3…

Linux命令基础(2)

su和exit命令 可以通过su命令切换到root账户 语法:su [-] 用户名 -符号是可选的,表示是否在切换用户后加载环境变量,建议带上 参数:用户名,表示要切换的用户,用户名可以省略,省略表示切换到ro…

vue3 + vite实现动态路由,并进行vuex持久化设计

在后台管理系统中,如何根据后端返回的接口,来动态的设计路由呢,今天一片文章带你们解 1、在vuex中设置一个方法 拿到完整的路由数据 const state {routerList: []}; const mutations { dynameicMenu(state, payload) {// 第一步 通过glob…