Перейти к основному контенту
Tech Path Finder
КурсыИнтервьюКод-ревьюБлог
Tech Path Finder

Персонализированный путеводитель в IT. Квизы, мок-интервью, код ревью и аналитика прогресса.

@potapov_me

Платформа

  • Курсы
  • Прогресс
  • Мок-интервью
  • Код ревью
  • Живое ревью с ИИ
  • Тренажёр переговоров
  • Закладки

Контент

  • Блог
  • Главная
  • Обратная связь

Компания

  • О проекте
  • Тарифы
  • Условия использования
  • Конфиденциальность
  • Согласие на обработку данных
  • Cookie
  • Реквизиты

Аккаунт

  • Войти
  • Зарегистрироваться
  • Профиль

© 2026 Tech Path Finder. Все права защищены.

·ИП Потапов К.С.·Политика конфиденциальности·
Сделано с ❤️ в России
  1. Инструменты и ресурсы
tools_and_resources

Инструменты и ресурсы

Создание tools с параметрами, валидацией через Pydantic, регистрация ресурсов и шаблонов ресурсов.

Инструменты и ресурсы

В этой теме мы углубимся в два главных объекта MCP: инструменты (tools) и ресурсы (resources). Туториал покажет, как создавать сложные инструменты с валидацией через Pydantic, регистрировать статические и динамические ресурсы, и использовать resource templates.

Инструменты — это действия (функции с аргументами), ресурсы — это данные (читаемые по URI).

#Инструменты с Pydantic-моделью

Простые аннотации типов подходят для базовых случаев. Но что если нужно ограничить диапазон чисел, задать минимальную длину строки или связать несколько параметров в логическую группу? Здесь помогает Pydantic.

from pydantic import BaseModel, Field from fastmcp import FastMCP mcp = FastMCP("SearchServer") class SearchParams(BaseModel): query: str = Field(..., min_length=1, max_length=200, description="Поисковый запрос") limit: int = Field(10, ge=1, le=100, description="Максимум результатов") category: str = Field("all", pattern=r"^(all|users|products|orders)$") @mcp.tool() def search(params: SearchParams) -> str: """Ищет данные по заданным критериям.""" return f"Поиск: '{params.query}', лимит: {params.limit}, категория: {params.category}"

Когда инструмент принимает Pydantic-модель как единственный параметр, FastMCP генерирует JSON Schema из полей модели. Каждый Field() задаёт ограничения:

  • min_length, max_length — ограничения на длину строки
  • ge, le, gt, lt — числовые границы (greater/equal, less/equal)
  • pattern — регулярное выражение для строки
  • description — описание поля, видимое AI-клиенту

Если клиент передаст query: "" (пустую строку), Pydantic выбросит ValidationError — FastMCP перехватит его и вернёт клиенту структурированную ошибку. Функция search даже не вызовется.

#Несколько Pydantic-моделей

Можно создавать несколько моделей для разных инструментов и переиспользовать их:

class Pagination(BaseModel): offset: int = Field(0, ge=0) limit: int = Field(20, ge=1, le=100) class UserFilter(BaseModel): name_contains: str | None = None min_age: int | None = Field(None, ge=0) is_active: bool | None = None @mcp.tool() def list_users(filter: UserFilter, pagination: Pagination) -> str: """Возвращает список пользователей с фильтрацией и пагинацией.""" return f"Фильтр: {filter.model_dump()}, Пагинация: {pagination.model_dump()}"

Каждый параметр — отдельная Pydantic-модель. FastMCP сгенерирует вложенную JSON Schema, и AI-клиент будет передавать аргументы как filter.name_contains, pagination.limit и т.д.

#Статические ресурсы

Ресурс — это данные, доступные для чтения по URI. Простейший ресурс не принимает аргументов:

import json APP_CONFIG = { "version": "2.1.0", "max_connections": 100, "features": ["search", "analytics", "alerts"] } @mcp.resource("config://app") def get_app_config() -> str: """Возвращает конфигурацию приложения.""" return json.dumps(APP_CONFIG, indent=2)

Клиент читает ресурс через resources/read с URI config://app. Функция возвращает строку — содержимое ресурса.

#Динамические ресурсы (Resource Templates)

Resource templates позволяют параметризовать URI. Переменные указываются в фигурных скобках и передаются в функцию как аргументы:

# База данных пользователей (имитация) USERS_DB = { "1": {"name": "Алиса", "role": "admin"}, "2": {"name": "Борис", "role": "user"}, "3": {"name": "Виктория", "role": "user"}, } @mcp.resource("user://{user_id}/profile") def get_user_profile(user_id: str) -> str: """Возвращает профиль пользователя по ID.""" user = USERS_DB.get(user_id) if user is None: return f"Пользователь {user_id} не найден" return json.dumps(user, indent=2, ensure_ascii=False)

Когда клиент запросит user://2/profile, FastMCP извлечёт user_id="2" из URI и передаёт в функцию. Один шаблон покрывает бесконечное число конкретных URI.

#Ресурсы с несколькими параметрами

Шаблон может содержать несколько переменных:

@mcp.resource("files://{workspace}/{path}/info") def get_file_info(workspace: str, path: str) -> str: """Возвращает информацию о файле в рабочем пространстве.""" full_path = f"/{workspace}/{path}" return f"File info for: {full_path}"

Клиент запрашивает files://project/src/main.py/info — workspace="project", path="src/main.py".

Важно: порядок переменных в URI определяется позициями в шаблоне, а не порядком параметров функции. FastMCP сопоставляет их по имени.

#MIME-типы ресурсов

По умолчанию FastMCP считает ресурс текстовым (text/plain). Для бинарных данных можно указать MIME-тип:

from fastmcp import FastMCP from fastmcp.server.context import Context mcp = FastMCP("ImageServer") @mcp.resource("images://{name}/thumbnail") def get_thumbnail(name: str) -> bytes: """Возвращает миниатюру изображения.""" # В реальности — чтение файла с диска return b"\x89PNG\r\n\x1a\n..." # бинарные данные PNG

Возврат bytes сигнализирует FastMCP, что ресурс бинарный. Клиент получит данные в base64-кодировке.

#Когда выбирать resource вместо tool

Правило простое: если операция — чтение данных по адресу, используйте ресурс. Если операция — действие с аргументами, используйте инструмент.

Resource (чтение по URI):

  • Конфигурация: config://app
  • Профиль пользователя: user://123/profile
  • Лог-файл: file:///var/log/app.log
  • Статус системы: status://health

Tool (действие с параметрами):

  • Поиск пользователей: search_users(query="Алиса", limit=10)
  • Создание записи: create_record(type="order", data={...})
  • Отправка уведомления: send_notification(user_id=123, message="Hello")

Разница аналогична GET vs POST/PUT в REST API: ресурс читает, инструмент действует.

Далее: Промпты и шаблоны