Будівництво серверів MCP: Частина 3 — Додавання запитів

pic

Цю статтю написано за допомогою кількох асистентів ШІ.

Створення серверів MCP: Частина 3 — Додавання запитів

Це частина 3 з 4-х у нашому посібнику по створенню серверів MCP. В частині 1 ми створили перший сервер MCP з базовими ресурсами, а в частині 2 ми додали шаблони ресурсів та покращили організацію коду. Тепер ми ще більше рефакторимо наш код і додаємо запити.

Що таке запити MCP?

Запити в MCP — це структуровані шаблони, які сервери надають для стандартизації взаємодії з мовними моделями. На відміну від ресурсів, які надають дані, або інструментів, що виконують дії, запити визначають повторно використовувані послідовності повідомлень і робочі процеси, що допомагають направляти поведінку LLM (великих мовних моделей) у стабільний і передбачуваний спосіб. Вони можуть приймати аргументи для налаштування взаємодії, зберігаючи при цьому стандартизовану структуру. Якщо ви коли-небудь вивчали інженерію запитів, ви, ймовірно, маєте чітке уявлення про те, що таке запит. Створення таких запитів у сервері MCP дозволяє створити простір для найбільш корисних запитів, які можуть бути легко повторно використані і навіть поділені. Уявіть собі ресторан — запит схожий на пункт меню, який ви можете вибрати та надати офіціанту. Іноді ви можете налаштувати пункти меню, попросивши додати або видалити певні інгредієнти чи приготувати страву певним способом. Запити, надані таким чином, виконують подібну функцію.

Навіщо використовувати запити?

Запити допомагають створювати послідовні, багаторазові шаблони для взаємодії з LLM. Ось кілька практичних прикладів:

Запити на огляд коду

"name" -> code-review  
Please review the following {{language}} code focusing on {{focusAreas}} for the following block of code:  
```{{language}}  
{{codeBlock}}  

> Користувач: Please review the following Python code focusing on security and performance:  
> ```Python  
> … code  
> ```

## Запити на аналіз даних

"name" -> analyze-sales-data
Analyze {{timeframe}} sales data focusing on {{metrics}}
```

Користувач: Analyze Q1 sales data focusing on revenue and growth

Запити на створення контенту

"name" -> generate-email  
Generate a {{tone}} {{type}} email for {{context}}  

Користувач: Generate a formal support email for a refund request to Bob’s Barbecue LLC.

Організація коду

В частині 2 ми абстрагували наш код обробника з index.ts і перенесли його в файл handlers.ts. Цей файл може стати занадто великим.
Ми повинні організувати наш код обробників у зручні модулі:

// src/resources.ts  
export const resources = [  
 {  
 uri: "hello://world",  
 name: "Hello World Message",  
 description: "A simple greeting message",  
 mimeType: "text/plain",  
 },  
];  

export const resourceHandlers = {  
 "hello://world": () => ({  
 contents: [  
 {  
 uri: "hello://world",  
 text: "Hello, World! This is my first MCP resource.",  
 },  
 ],  
 }),  
};
// src/resource-templates.ts  
export const resourceTemplates = [  
 {  
 uriTemplate: "greetings://{name}",  
 name: "Personal Greeting",  
 description: "A personalized greeting message",  
 mimeType: "text/plain",  
 },  
];  

const greetingExp = /^greetings:\/\/(.+)$/;  
const greetingMatchHandler =  
 (uri: string, matchText: RegExpMatchArray) => () => {  
 const name = decodeURIComponent(matchText[1]);  
 return {  
 contents: [  
 {  
 uri,  
 text: `Hello, ${name}! Welcome to MCP.`,  
 },  
 ],  
 };  
 };  
export const getResourceTemplate = (uri: string) => {  
 const greetingMatch = uri.match(greetingExp);  
 if (greetingMatch) return greetingMatchHandler(uri, greetingMatch);  
};

Оновлюємо наш handlers:

// src/handlers.ts  
import {  
 ListResourcesRequestSchema,  
 ListResourceTemplatesRequestSchema,  
 ReadResourceRequestSchema,  
} from "@modelcontextprotocol/sdk/types.js";  
import { type Server } from "@modelcontextprotocol/sdk/server/index.js";  
import { resourceHandlers, resources } from "./resources.js";  
import {  
 getResourceTemplate,  
 resourceTemplates,  
} from "./resource-templates.js";  

export const setupHandlers = (server: Server): void => {  
 // List available resources when clients request them  
 server.setRequestHandler(  
 ListResourcesRequestSchema,  
 () => ({ resources }),  
 );  
 // Resource Templates  
 server.setRequestHandler(ListResourceTemplatesRequestSchema, () => ({  
 resourceTemplates,  
 }));  
 // Return resource content when clients request it  
 server.setRequestHandler(ReadResourceRequestSchema, (request) => {  
 const { uri } = request.params ?? {};  
 const resourceHandler =  
 resourceHandlers[uri as keyof typeof resourceHandlers];  
 if (resourceHandler) return resourceHandler();  
 const resourceTemplateHandler = getResourceTemplate(uri);  
 if (resourceTemplateHandler) return resourceTemplateHandler();  
 throw new Error("Resource not found");  
 });  
};

Додавання запитів

Тепер додаємо нашу нову функціональність запитів:

// src/prompts.ts  
export const prompts = {  
 "create-greeting": {  
 name: "create-greeting",  
 description: "Generate a customized greeting message",  
 arguments: [  
 {   
 name: "name",  
 description: "Name of the person to greet",  
 required: true,  
 },  
 {  
 name: "style",  
 description: "The style of greeting, such a formal, excited, or casual. If not specified casual will be used"  
 }  
 ],  
 },  
};  

export const promptHandlers = {  
 "create-greeting": ({ name, style = "casual" }: { name: string, style?: string }) => {  
 return {  
 messages: [  
 {  
 role: "user",  
 content: {  
 type: "text",  
 text: `Please generate a greeting in ${style} style to ${name}.`,  
 },  
 },  
 ],  
 };  
 },  
};

Додаємо нові обробники запитів до файлу обробників:

// src/handlers.ts  
import {  
 GetPromptRequestSchema,  
 ListPromptsRequestSchema,  
 // ... інші імпорти  
} from "@modelcontextprotocol/sdk/types.js";  
// ... інші імпорти  
import { promptHandlers, prompts } from "./prompts.js";  

export const setupHandlers = (server: Server): void => {  

 // ...

Інші обробники ресурсів тут  

 // Запити  
 server.setRequestHandler(ListPromptsRequestSchema, () => ({  
 prompts: Object.values(prompts),  
 }));  
 server.setRequestHandler(GetPromptRequestSchema, (request) => {  
 const { name, arguments: args } = request.params;  
 const promptHandler = promptHandlers[name as keyof typeof promptHandlers];  
 if (promptHandler) return promptHandler(args as { name: string, style?: string });  
 throw new Error("Prompt not found");  
 });  
};

Нарешті, нам потрібно оновити ініціалізацію сервера:

// 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: {  
 prompts: {}, // <-- Додати запити  
 resources: {},  
 },  
 },  
);  

setupHandlers(server);  

// ... решта коду

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

Організація модулів

  • Ресурси та шаблони були розміщені в окремих модулях
  • Запити чітко відокремлені
  • Обробники тепер виконують функцію маршрутизації

Структура запиту

  • Кожен запит має ім’я, опис та аргументи, якщо потрібно
  • Аргументи описують очікувані введення для запиту
  • Обробники генерують структуровані повідомлення для запитів до цільового ШІ

Послідовність повідомлень

  • Запити повертають масиви повідомлень
  • Повідомлення мають ролі (‘user’ або ‘assistant’)
  • Зміст може включати як початковий запит, так і подальші відповіді для багатокрокових робочих процесів (зверніть увагу, що багатокрокові робочі процеси мають обмежену підтримку на даний момент)

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

Запустіть інспектор:

npx @modelcontextprotocol/inspector node build/index.js

Тестування запитів:

  • Перейдіть на вкладку “Prompts”
  • Знайдіть “create-greeting”
  • Спробуйте різні комбінації аргументів:
name: "Alice", style: "excited"
{  
 "messages": [  
 {  
 "role": "user",  
 "content": {  
 "type": "text",  
 "text": "Please generate a greeting in excited style to Alice."  
 }  
 }  
 ]  
}

Тестування з Claude Desktop

Спробуйте ці приклади:

Базовий запит:

1: Відкрийте Claude Desktop
Припущення:

2: Так само, як ми додавали ресурси, натисніть на “Attach from MCP”

pic

3: У вікні модального діалогу натисніть “Choose and integration” і виберіть “create-greeting” з меню під “hello-mcp”

pic

4: На цей момент спробуйте просто ввести ім’я. Введіть, наприклад, “John” у поле для імені та натисніть “Submit”

pic

5: Ви побачите вкладку “create-greeting”. Натисніть на неї, щоб побачити вміст.

pic

6: Ви побачите, що для Claude створено запит, що виглядає як “Please generate a casual greeting to John.”

pic

7: Без введення додаткових запитів просто натисніть на стрілку для відправлення в правому верхньому куті чат-боксу

pic

8: Ви побачите відповідь, схожу на “Hi John! How are you doing today?”

pic

Стильований запит:

1: Тепер спробуйте привітання з іншим, конкретним стилем. Відкрийте діалог “Attach from MCP” і знову виберіть запит “create-greeting”.

Цього разу ми можемо додати ім’я "Alice" та стиль "formal", після чого відправимо чат, знову натиснувши на стрілку або, можливо, просто натискання клавіші Enter також спрацює, я ще не пробував.

pic

2: Цього разу ви, ймовірно, побачите повідомлення, яке виглядатиме ось так:

Dear Alice,

I hope this message finds you well. I am writing to extend my warmest greetings.

Best regards,
Claude

pic

Що далі?

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

  • Абстрагуємо наші типи в окремий файл types.ts
  • Дізнаємось про інструменти MCP і як вони відрізняються від запитів
  • Додамо можливості інструментів до нашого сервера
  • Побачимо, як інструменти можуть надати динамічний функціонал
  • Завершимо наш сервер привітань з усіма основними можливостями MCP

Джерела та додаткові матеріали для читання:

Перекладено з: “Building MCP Servers: Part 3 — Adding Prompts

Leave a Reply

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