Model Context Protocol (MCP) - это просто API, разработанный для LLM. Конечно, LLM могут использовать традиционные API, но это как просить повара готовить в кладовке из-за:

  • Сложных промптов для обучения LLM схемам API

  • Подверженного ошибкам парсинга JSON

  • Обработки аутентификации/лимитов запросов без истерик

  • Управления состоянием между множественными вызовами (иными словами запоминания того что было 3 вызова апи назад)

Стандартные API созданы для языков программирования, а не для естественного языка. MCP решает это, используя упрощенные, дружественные для LLM интерфейсы, описанные на естественном языке.

Секретный ингредиент MCP - управление состоянием

Секретный ингредиент MCP - это управление состоянием, что отражено в термине "контекст" в Model Context Protocol. В отличие от традиционных API (которые забывают вас быстрее золотой рыбки), MCP помнит контекст между вызовами. Это обычное дело для веб-сайтов (хранение пользовательской сессии, например), но редко встречается в API из-за масштабирования и других причин.

Традиционный API:

// [Запрос] → [Ответ] (Без состояния)

POST /flights/search
{"from": "NYC", "to": "Paris", "date": "2024-03-15"}
// Возвращает результаты

POST /flights/book
{"flight_id": "AF123", "passenger": ???} // Подождите, кто бронировал?

MCP:

// [Запрос + Предыдущий контекст] → [Ответ + Обновленный контекст]

SEARCH_FLIGHTS to=Paris date=next_week
// Система помнит, что вы в NYC из контекста

BOOK_FLIGHT flight=AF123
// Система знает, что это вы, помнит контекст поиска

Эта осведомленность о контексте делает MCP уникально подходящим для рабочих процессов LLM. Название напрямую отражает его цель - протокол, который дает моделям контекстную осведомленность во время взаимодействий с API.

Таким образом, MCP фокусируется на намерении, а не на технической реализации, и действует как слой интерпретатора между LLM и backend-системами.

MCP заменяет API-специфичный синтаксис последовательной структурой команд:

[ДЕЙСТВИЕ] [ИМЯ_ИНСТРУМЕНТА] [ПАРАМЕТРЫ]

Пример вызова инструмента:

BOOK_FLIGHT to=Paris date=2023–12–01

*При создании этой команды ни одна фигурная скобка не пострадала.

MCP заменяет традиционный паттерн запрос-ответ более разговорным вариантом. Инструменты определяются в стандартизированном формате манифеста:

tools:
  - name: search_flights
    description: "Найти доступные рейсы"
    params:
      - name: destination
        type: string
      - name: date
        type: date
        
  - name: book_flight
    description: "Забронировать конкретный рейс"
    params:
      - name: flight_id
        type: string

Заметили, чего не хватает? Нет заголовков аутентификации. Нет сложных вложенных объектов. Нет 47-страничной документации API. Только инструменты с ясными целями и простыми параметрами.

Ключевые различия: Традиционный API vs. MCP

В качестве примера MCP давайте создадим простой MCP для поиска билетов из манифеста выше.

Его можно вызвать так:

BOOK_FLIGHT to=Paris date=2023–12–01

Как видите, есть некоторые преимущества по сравнению с использованием API:

  • Нет управления токенами: MCP обрабатывает аутентификацию

  • Авто-контекст: помнит репозиторий, пользователя, предыдущие issues

  • Упрощенные команды: естественный язык вместо JSON-нагрузок

  • Обработка ошибок: стандартизированные сообщения об ошибках, которые LLM может понять

Вот код для этого MCP-сервера:

class FlightMCP:
    def __init__(self, api_key: str):
        self.api_key = api_key
        self.context = {
            "user_location": None,
            "recent_searches": [],
            "preferences": {}
        }
    
    def get_tools(self):
        return [
            {
                "name": "search_flights",
                "description": "Поиск рейсов в пункт назначения",
                "params": [
                    {"name": "to", "type": "string"},
                    {"name": "date", "type": "string"},
                    {"name": "class", "type": "string", "optional": True}
                ]
            },
            {
                "name": "book_flight",
                "description": "Забронировать конкретный рейс",
                "params": [
                    {"name": "flight_id", "type": "string"},
                    {"name": "passengers", "type": "integer", "default": 1}
                ]
            }
        ]
    
    def execute_tool(self, tool_name: str, params: dict):
        # Выполнение с учетом контекста
        if tool_name == "search_flights":
            # Используем контекст для заполнения недостающей информации
            from_location = params.get("from") or self.context.get("user_location")
            
            results = self._search_flights(
                from_loc=from_location,
                to_loc=params["to"],
                date=self._parse_natural_date(params["date"])
            )
            
            # Обновляем контекст для будущих вызовов
            self.context["recent_searches"].append({
                "destination": params["to"],
                "results": len(results)
            })
            
            return {
                "success": True,
                "flights": results,
                "next_actions": ["BOOK_FLIGHT", "SEARCH_HOTELS"]
            }

Тут вещи становится интересными - у MCP есть двунаправленная коммуникация, сервер может отправлять обновления назад в LLM:

class FlightMCP:
    def __init__(self):
        self.notification_handler = None
        self.monitored_flights = {}
    
    def book_flight(self, flight_id: str):
        # Бронируем рейс
        booking = self._process_booking(flight_id)
        
        # Начинаем мониторинг изменений
        self._monitor_flight(booking["confirmation_number"])
        
        return {
            "success": True,
            "confirmation": booking["confirmation_number"],
            "monitoring": True
        }
    
    def _monitor_flight(self, confirmation: str):
        def check_status():
            while confirmation in self.monitored_flights:
                status = self._get_flight_status(confirmation)
                
                if status["changed"]:
                    self._send_notification({
                        "type": "flight_update",
                        "message": f"Ваш рейс теперь {status['new_status']}",
                        "data": status
                    })
                
                time.sleep(300)  # Проверяем каждые 5 минут
        
        threading.Thread(target=check_status, daemon=True).start()

Claude Desktop MCP интеграция

Claude Desktop имеет встроенную поддержку MCP, которая позволяет подключать внешние инструменты и источники данных напрямую к вашим разговорам с изолированным выполнением и контролем разрешений.

Он поставляется с несколькими предустановленными MCP:

  • Filesystem: Чтение/запись локальных файлов

  • SQLite: Запросы к базам данных

  • Web Search: Поиск в интернете

  • Git: Операции с репозиториями

Обнаружение инструментов

Когда вы запускаете Claude Desktop, он автоматически запускает настроенный MCP-сервер, обнаруживает доступные инструменты, делает их доступными в чате.

Он использует файл конфигурации (claude_desktop_config.json) для определения доступных MCP:

{
  "mcpServers": {
    "flights": {
      "command": "python",
      "args": ["flight_mcp_server.py"],
      "env": {
        "API_KEY": "your_flight_api_key"
      }
    },
    "calendar": {
      "command": "node",
      "args": ["calendar_mcp.js"],
      "env": {
        "GOOGLE_CALENDAR_TOKEN": "your_token"
      }
    }
  }
}

В чате:

**Пользователь**: Забронируй мне рейс в Токио на следующий вторник
**Claude**: Я найду рейсы в Токио на следующий вторник.
           [Автоматически использует инструмент SEARCH_FLIGHTS]
           Найдено 3 рейса. Лучший вариант - JAL 061 в 14:00 за $1,200.
           [Использует инструмент BOOK_FLIGHT]
           Забронировано! Подтверждение #ABC123. 
           Я буду отслеживать этот рейс и уведомлю вас о любых изменениях.

Продвинутые концепции MCP

MCP могут предоставлять не только инструменты, но и ресурсы (источники данных):

resources:
  - name: "project_files"
    description: "Доступ к исходному коду проекта"
    uri: "file:///project/src/"
  - name: "database_schema"
    description: "Текущая структура базы данных"
    uri: "sqlite:///app.db"

MCP композиция

Несколько MCP работают вместе:

{
  "mcpServers": {
    "flights": {...},
    "hotels": {...},
    "calendar": {...},
    "expense_tracker": {...}
  }
}

LLM оркестрирует все из них: "Забронируй мою обычную поездку в Сан-Франциско" запускает:

  • Calendar MCP проверяет доступность

  • Flight MCP бронирует на основе предпочтений

  • Hotel MCP резервирует обычное место

  • Expense tracker регистрирует все расходы

Соображения безопасности

Сохранение контекста MCP это интересная, но опасная техника:

  • Изоляция данных между пользователями критична

  • Контекст не должен утекать между сессиями

  • Разрешения нуждаются в тщательном продумывании

class SecureMCP:
    def __init__(self):
        self.contexts = {}  # Изолированные контексты пользователей
    
    def get_context(self, user_id: str):
        if user_id not in self.contexts:
            self.contexts[user_id] = self._create_isolated_context()
        return self.contexts[user_id]

Когда не использовать MCP?

Хотя MCP отлично подходит для интеграции LLM, это не волшебная палочка, которая решает все проблемы API. Вот случаи, когда имеет смысл придерживаться традиционных подходов:

  1. Не-LLM потребители: Если ваш API в основном потребляется традиционным программным обеспечением (мобильные приложения, веб-фронтенды и т.д.), стандартные REST или GraphQL API более подходящие. Фокус MCP на естественном языке не добавляет здесь ценности.

  2. Критичные к производительности системы: Статичная природа MCP и упрощенная обработка ошибок вводят накладные расходы. Для высокочастотных систем реального времени (например, торговля акциями) каждая миллисекунда на счету.

  3. Простые операции без состояния: Если ваш случай использования включает одноразовые запросы без контекста (например, получение данных о погоде), управление состоянием MCP становится ненужной сложностью.

  4. Существующие экосистемы API: Если у вас есть хорошо установленные API-шлюзы, клиентские библиотеки и документация, передалека этого в MCP может не оправдать усилий.

  5. Ограничения безопасности: Автоматическая передача контекста MCP может нарушать строгие требования изоляции данных (например, мультитенантные системы). Традиционные API предлагают более тонкий контроль.

  6. Масштабирование: есть хорошая причина, почему API не имеют контекста - так их гораздо легче масштабировать. Если вам действительно нужно масштабируемое решение - MCP может быть не лучшим способом делать вещи.

Что дальше?

Поскольку размер контекстныъ окон LLM постоянно растет (ждем 10 миллионов токенов Gemini), MCP может стать менее критичным для некоторых случаев использования. Зачем поддерживать состояние, когда можно просто послать все в контексте?

Но реальная ценность MCP не только в управлении состоянием - это стандартизация. Так же как REST дал нам общий язык для API, MCP дает нам общий язык для интеграций LLM.

Резюме: MCP - это просто еще один способ предоставления API, на этот раз для LLM.


Я из Рафт. Мой телеграм-канал.

Пишете ваши вопросы в комментариях.

Комментарии (2)


  1. titulusdesiderio
    14.07.2025 08:09

    Stateful и Stateless не имеют никакого отношения к MCP. Вы сами это выдумали и зачем-то через это определяете технологию.

    Как MCP, так и API могут быть и Stateful и Stateless.

    Статья вводит читателей в заблуждение.


  1. ARazum
    14.07.2025 08:09

    Кажется, требует особого внимания и отдельной статьи тема сохранения контекста и обеспечения его безопасности. Тут это затронуто вскольз.
    Где он физически хранится во время работы? В оперативной памяти? или в какой-то бд? Или нужен чуть ли не отдельный контейнер, под каждого пользователя.

    Может есть уже какие-то бестпрактис на этотсчёт?