Примеры создания пользовательских инструментов
Теперь, когда мы разобрались с тем, как описывать и интегрировать функции-инструменты в MCP-сервер, настало время перейти к самому интересному — созданию реальных, полезных инструментов, которые позволят вашему ИИ-агенту не просто рассуждать, а действовать.
Мы уже знаем: LLM может вызывать функции только тогда, когда они чётко описаны в спецификации MCP и доступны через /capabilities. Но описание — это только начало. Настоящая сила агента раскрывается, когда он может взаимодействовать с внешними системами, обрабатывать данные и генерировать контент. Именно это мы и будем реализовывать.
Практические примеры пользовательских инструментов
Давайте рассмотрим два типовых, но мощных сценария: получение данных из API и создание PDF-отчётов. Оба примера написаны на TypeScript, используют асинхронные функции и включают валидацию и обработку ошибок — ключевые элементы надёжного агента.
Инструмент API-запроса: получение данных с GigaChat
Один из самых распространённых сценариев — интеграция с внешними сервисами. В России особенно актуальна работа с локальными LLM, такими как GigaChat от Сбербанка. Давайте создадим инструмент, который будет получать краткое резюме текста через её API.
Сначала опишем инструмент в формате, понятном LLM:
{
"name": "summarizeTextWithGigaChat",
"description": "Анализирует текст и возвращает краткое резюме с помощью GigaChat API-сервиса",
"parameters": {
"type": "object",
"properties": {
"text": {
"type": "string",
"description": "Текст для анализа и резюмирования"
}
},
"required": ["text"]
}
}
Теперь реализуем функцию:
import axios from 'axios';
const GIGACHAT_URL = 'https://gigachat.api.cloud.sber.ru/v1/chat/completions';
const API_KEY = process.env.GIGACHAT_API_KEY;
interface GigaChatResponse {
choices: { message: { content: string } }[];
}
async function summarizeTextWithGigaChat(text: string): Promise<string> {
// Валидация входных данных
if (!text || text.length < 10) {
throw new Error('Текст слишком короткий для резюмирования');
}
try {
const response = await axios.post<GigaChat游戏副本>(
GIGACHAT_URL,
{
model: 'GigaChat',
messages: [
{
role: 'system',
content: 'Ты — помощник, который создаёт краткие, ёмкие резюме текстов.'
},
{ role: 'user', content: `Сделай резюме: ${text}` }
]
},
{
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json'
}
}
);
return response.data.choices[0].message.content.trim();
} catch (error: any) {
console.error('Ошибка при вызове GigaChat:', error.message);
throw new Error('Не удалось получить резюме. Проверьте API-ключ и подключение.');
}
}
Важно!
Обратите внимание на использованиеasync/await, валидацию входных данных и обработку ошибок. Без этого инструмент может "падать" при первом же некорректном запросе, что сделает агента ненадёжным.
Теперь LLM сможет вызывать эту функцию, передавая текст, а MCP-сервер — выполнять запрос и возвращать результат. Это и есть инструмент API-запроса — функция, которая взаимодействует с внешним сервисом и возвращает структурированный ответ.
Инструмент генерации PDF: создание отчётов
Ещё один полезный инструмент — генерация файлов. Представим, что наш агент должен создавать PDF-отчёты по запросу пользователя. Мы используем библиотеку pdf-lib, которая отлично работает в Node.js.
Описание инструмента:
{
"name": "generateUserReportPDF",
"description": "Создаёт PDF-отчёт с информацией о пользователе: имя, email, статус подписки",
"parameters": {
"type": "object",
"properties": {
"name": { "type": "string" },
"email": { "type": "string", "format": "email" },
"subscription": { "type": "string", "enum": ["free", "pro", "enterprise"] }
},
"required": ["name", "email", "subscription"]
}
}
Реализация:
import { PDFDocument, StandardFonts } from 'pdf-lib';
async function generateUserReportPDF(
name: string,
email: string,
subscription: string
): Promise<Uint8Array> {
// Валидация
if (!name || !email || !subscription) {
throw new Error('Все поля обязательны для заполнения');
}
if (!email.includes('@')) {
throw new Error('Некорректный email');
}
try {
const pdfDoc = await PDFDocument.create();
const page = pdfDoc.addPage([400, 200]);
const font = await pdfDoc.embedFont(StandardFonts.Helvetica);
const fontSize = 12;
page.drawText(`Отчёт о пользователе`, { x: 50, y: 170, size: fontSize, font });
page.drawText(`Имя: ${name}`, { x: 50, y: 140, size: fontSize, font });
page.drawText(`Email: ${email}`, { x: 50, y: 120, size: fontSize, font });
page.drawText(`Подписка: ${subscription}`, { x: 50, y: 100, size: fontSize, font });
return await pdfDoc.save(); // Возвращает бинарные данные PDF
} catch (error) {
console.error('Ошибка при генерации PDF:', error);
throw new Error('Не удалось создать PDF-отчёт');
}
}
Теперь ваш агент может не просто говорить о пользователе, а создавать официальный документ — настоящий шаг к автоматизации бизнес-процессов.
Совет: безопасность
Всегда проверяйте входные данные в инструментах. Особенно если они используются для генерации файлов или запросов к API. Это защитит ваш сервер от инъекций и перегрузок.
Практическое упражнение: инструмент для работы с данными
Теперь пришло время применить знания на практике. Создайте простой инструмент для чтения данных из JSON-файла — например, списка задач.
Задача:
Реализуйте инструмент getTasksFromJSON, который:
- Читает файл
tasks.json - Возвращает массив задач (с полями
id,title,status) - Обрабатывает ошибки (файл не найден, повреждён и т.д.)
import fs from 'fs/promises';
async function getTasksFromJSON(): Promise<any[]> {
try {
const data = await fs.readFile('tasks.json', 'utf-8');
const tasks = JSON.parse(data);
if (!Array.isArray(tasks)) {
throw new Error('Формат данных неверен: ожидается массив');
}
return tasks;
} catch (error: any) {
if (error.code === 'ENOENT') {
throw new Error('Файл tasks.json не найден');
}
throw new Error(`Ошибка чтения данных: ${error.message}`);
}
}
Проверьте себя:
- Есть ли описание инструмента для LLM?
- Используется ли асинхронность?
- Обрабатываются ли ошибки?
- Проверяется ли структура данных?
Если да — вы создали полноценный пользовательский инструмент.
Подводим итоги
Мы создали три типа инструментов:
- Инструмент API-запроса — для взаимодействия с внешними сервисами (GigaChat)
- Инструмент генерации PDF — для создания контента
- Инструмент для работы с файлами — для доступа к локальным данным
Каждый из них расширяет возможности агента, превращая его из "говорящего" в действующего агента.
Помните:
Без описания в/capabilitiesLLM не увидит ваш инструмент. Он должен быть явно объявлен — как мы это делали в предыдущей теме.
Теперь ваш агент может:
- Получать информацию извне
- Генерировать документы
- Работать с данными
Это уже не просто чат-бот. Это автономный помощник, способный выполнять реальные задачи.
Что дальше?
Теперь, когда у нас есть набор полезных инструментов, пришло время объединить их в полноценный сервер. В следующей теме мы начнём создавать MCP-сервер на TypeScript с использованием Express.js — одного из самых популярных фреймворков для Node.js.
Там мы:
- Определим эндпоинты
/capabilities,/prompt,/tool - Подключим наши инструменты
- Сделаем сервер готовым к интеграции с LLM
Вы уже почти у цели: через несколько шагов вы сможете запустить своего первого рабочего ИИ-агента.
Готовы превратить инструменты в реальный сервер? Тогда — вперёд! 🚀