Будівництво серверів MCP: Частина 2 — Розширення ресурсів за допомогою шаблонів ресурсів

pic

Це зображення було створено за допомогою програми для створення зображень на основі штучного інтелекту.

Цю статтю було написано за допомогою кількох помічників на базі штучного інтелекту.

Це друга частина з чотирьох частин навчального посібника з побудови MCP серверів. В Частині 1 ми створили перший MCP сервер з базовим ресурсом. Тепер ми розширимо можливості нашого сервера за допомогою шаблонів ресурсів. Код у цьому пості передбачає, що ви продовжуєте з того місця, де ми зупинились.

Що таке шаблони ресурсів?

Шаблони ресурсів дозволяють визначати динамічні ресурси за допомогою шаблонів URI. На відміну від статичних ресурсів, що мають фіксовані URI, шаблони дозволяють створювати ресурси, URI та вміст яких можуть генеруватися на основі параметрів.

Можна уявити їх як шаблони URL у веб-фреймворку, де ресурс є більш динамічним і зазвичай базується на деякому тегу або ідентифікаторі — вони дозволяють обробляти і об'єднувати цілу групу ресурсів за допомогою одного визначення.

Чому використовувати шаблони ресурсів?

Шаблони ресурсів потужні, коли вам потрібно виконувати такі завдання, як обробка динамічних даних, генерування вмісту за запитом або створення ресурсів на основі параметрів.

Ось кілька прикладів:

Динамічні дані

"users://{userId}" -> Профілі користувачів  
"products://{sku}" -> Інформація про продукти

Користувач: "Можеш розповісти мені про користувача 12345?"
Помічник ШІ: "Шукаю користувача 12345... Він приєднався у 2023 році і зробив 50 покупок."

Генерація вмісту за запитом

"reports://{year}/{month}" -> Щомісячні звіти  
"analytics://{dateRange}" -> Індивідуальна аналітика

Користувач: "Покажи мені звіт за березень 2024 року"
Помічник ШІ: "Отримую звіт за березень 2024 року... Доходи зросли на 15% порівняно з лютим."

Ресурси на основі параметрів

"search://{query}" -> Результати пошуку  
"filter://{type}/{value}" -> Фільтровані дані

Користувач: "Знайди всі транзакції на суму понад $1000"
Помічник ШІ: "Використовую ресурс фільтра... Знайдено 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 => {  
 // Перелік доступних ресурсів, коли клієнти їх запитують  
 server.setRequestHandler(ListResourcesRequestSchema, async () => {  
 return {  
 resources: [  
 {  
 uri: "hello://world",  
 name: "Повідомлення Hello World",  
 description: "Простий привітальний текст",  
 mimeType: "text/plain",  
 },  
 ],  
 };  
 });  
 // Повернення вмісту ресурсу, коли клієнти його запитують  
 server.setRequestHandler(ReadResourceRequestSchema, async (request) => {  
 if (request.params.uri === "hello://world") {  
 return {  
 contents: [  
 {  
 uri: "hello://world",  
 text: "Привіт, Світ! Це моїй перший MCP ресурс.",  
 },  
 ],  
 };  
 }  
 throw new Error("Ресурс не знайдено");  
 });  
};

Оновимо наш основний файл 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);  

// Запуск сервера за допомогою транспорту stdio  
const transport = new StdioServerTransport();  
await server.connect(transport);  
console.info('{"jsonrpc": "2.0", "method": "log", "params": { "message": "Сервер працює..." }}');

Додавання нового ресурсу

Час додати наш новий шаблон ресурсу.

Спочатку додамо наш перелік, щоб помічник ШІ знав, що він існує. У файлі src/handlers.js додайте наступний код після переліку ресурсу hello://world (того, що з першим параметром ListResourcesRequestSchema):

export const setupHandlers = (server: Server): void => {  
 // Існуючий перелік ресурсу "hello://world" тут...  

 // Шаблони ресурсів  
 server.setRequestHandler(ListResourceTemplatesRequestSchema, async () => ({  
 resourceTemplates: [  
 {  
 greetings: {  
 uriTemplate: 'greetings://{name}',  
 name: 'Особисте привітання',  
 description: 'Персоналізоване привітальне повідомлення',  
 mimeType: 'text/plain',  
 },  
 },  
 ],  
 }));  

 // Існуючий вміст ресурсу "hello://world" тут...   
};

Далі ми можемо додати обробник вмісту. Для цього не потрібно додаткових обробників запитів. Ми просто додамо нову перевірку для запиту у такому форматі.

// Повернення вмісту ресурсу, коли клієнти його запитують  
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {  
 // ... Існуючий код обробника вмісту  

 // Код на основі шаблону ресурсу  
 const greetingExp = /^greetings:\/\/(.+)$/;  
 const greetingMatch = request.params.uri.match(greetingExp);  
 if (greetingMatch) {  
 const name = decodeURIComponent(greetingMatch[1]);  
 return {  
 contents: [  
 {  
 uri: request.params.uri,  
 text: `Привіт, ${name}! Ласкаво просимо до MCP.`,  
 },  
 ],  
 };  
 }  

 // ...
});

Розуміння коду

Організація обробників

  • Ми винесли обробники в окремий файл для кращої організації
  • Функція setupHandlers інкапсулює налаштування всіх обробників
  • Основний файл залишається чистим і зосередженим

Опис шаблонів

  • Обробник ListResourceTemplateRequestSchema надає доступні шаблони
  • Формат імені шаблону відповідає RFC 6570 (URL, що використовує {text} для вираження параметризації)
  • Шаблони включають метадані, такі як ім’я та опис

Обробка шаблонів

  • Обробник ReadResourceRequestSchema тепер перевіряє збіги шаблонів
  • Ми використовуємо формат регулярних виразів (regex), щоб витягти параметр імені з URI
  • Генеруємо динамічний вміст на основі параметрів

Тестування за допомогою Інспектора

У нашому останньому пості ми обговорювали використання MCP Інспектора. Запустіть інспектор зараз:

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

Тестуємо статичний ресурс, який ми створили минулого разу, щоб переконатися, що він все ще працює:

  • Перейдіть на вкладку "Resources"
  • Знайдіть і натисніть "Hello World Message"
  • Ви повинні побачити повідомлення: "Hello, World! This is my first MCP resource."

Тестуємо шаблон:

  • Перейдіть на вкладку "Resource Templates"
  • Знайдіть "Personal Greeting"
  • Введіть ім’я "Alice"
{  
 "contents": [  
 {  
 "uri": "greetings://Alice",  
 "text": "Hello, Alice! Welcome to MCP."  
 }  
 ]  
}

Тестування за допомогою Claude Desktop

Вам, ймовірно, не потрібно оновлювати нічого цього разу в Claude, але можливо, вам доведеться перезавантажити (також переконайтеся, що ви побудували сервіс за допомогою npx tsc).

Як і в моєму попередньому пості, Desktop-версія Claude для Mac, здається, не підтримує ресурси, але ви можете спробувати це в інших інструментах, які підтримують MCP, таких як Cline. Можливо, вам доведеться спеціально використовувати модель, яка розуміє MCP, як Sonnet 3.5 від Anthropic.

Спробуйте ці приклади (відповіді можуть відрізнятися):

Статичний ресурс:

User: "What’s in the greeting message?"  
Claude: "The greeting message says: 'Hello from MCP! This is your first resource.'"

Ресурс за шаблоном:

User: "Can you get a greeting for Alice?"  
Claude: "I’ll check the personalized greeting... It says: 'Hello, Alice! Welcome to MCP.'"

Перелік доступних ресурсів:

User: "What resources and templates are available?"  
Claude: "The server provides:  
1. A static 'Greeting Message' resource  
2. A 'Personal Greeting' template that can create customized greetings for any name"

Що далі?

У Частині 3 ми:

  • Покращимо організацію коду, розділивши ресурси та шаблони на окремі файли
  • Дізнаємося про MCP підказки (prompts) і чим вони відрізняються від ресурсів
  • Додамо можливості підказок до нашого сервера
  • Подивимося, як підказки можуть покращити функціональність наших привітань

Частина 4 завершить наш курс, додавши інструменти до нашого сервера.

Я планував це як щотижневе оновлення, але ШІ розвивається швидко. Я спробую надати наступні дві частини якнайшвидше.

Ресурси та додаткове читання:

Перекладено з: Building MCP Servers: Part 2 — Extending Resources with Resource Templates

Leave a Reply

Your email address will not be published. Required fields are marked *