MCP (Model Context Protocol)

в 7:52, , рубрики: MCP, model context protocol, искусственный интеллект

В последнее время аббревиатура MCP стала все более часто появляться в некоторых статьях и разделах комментариев на arXiv или Daily Papers Hugging Face, которые я просматриваю. Внезапно осознав, что мое представление об этом лишь приблизительное, я решил изучить его более подробно и поделиться с вами.

Single Agent

Давайте сначала рассмотрим архитектуру с одним агентом.

Figure
Figure
  1. Инструменты — это функции, которые определены и вызываются в текущей программе. Определение функции инструментов будет включено в системную подсказку, чтобы позволить LLM понять доступные в настоящее время инструменты.

  2. Память делится на две части: текущий поток данных сеанса, включая то, что выполняется на каждом шаге, и каков результат, сохраняется в памяти текущего сеанса и может быть полностью введен в LLM в любое время, чтобы позволить LLM определить, что делать дальше. Долгосрочные данные и база знаний пользователя, такие как данные о предпочтениях пользователя на платформе, контент домена, многораундовый контекст разговора и т. д., будут извлечены из векторной базы данных.

  3. Маршрутизатор централизует планирование программы всего процесса, передавая вводимые пользователем подсказки/системные подсказки/память в LLM, а LLM проводит углубленное мышление и выдает конкретные задачи по выполнению, а маршрутизатор вызывает соответствующую функцию действия (function calling).

Это простая и общая архитектура с одним агентом, которая реализует цикл Мысль – План – Действие – Размышление (Мысль) в Агенте, при этом за все отвечает одна модель.

MCP

В приведенной выше архитектуре модуль Tools (Инструменты) имеет некоторые незначительные проблемы: не очень хорошая поддерживаемость и масштабируемость функций инструмента. Сложно управлять, когда их слишком много. Чтобы добавить функции, нужно обновить основную программу. Кроме того, нужно самостоятельно определить спецификацию вызова функции. Некоторые внешние сервисы инструментов, которые будут использоваться, нужно инкапсулировать самостоятельно.

Для решения этих незначительных проблем данную архитектуру можно оптимизировать: модуль инструмента отделен от агента и управляется и реализуется единообразно с использованием протокола MCP.

Протокол контекста модели (MCP): новый стандарт интеграции в экосистеме ИИ

Протокол контекста модели (Model Context Protocol, MCP) — это открытый стандарт, разработанный и представленный компанией Anthropic 25 ноября 2024 года. Основная цель MCP — создание унифицированного протокола связи между большими языковыми моделями (LLM) и внешними источниками данных и инструментами. Как по мне, MCP появился как естественная эволюция подхода Function Calling, преодолевая его ограничения и расширяя возможности взаимодействия моделей ИИ с внешним миром. Если Function Calling можно рассматривать как точечное решение конкретных задач взаимодействия, то MCP представляет собой комплексный подход к проблеме интеграции, обеспечивая более гибкую, масштабируемую и стандартизированную экосистему.

Сущность MCP

MCP — это не фреймворк или инструмент, а именно протокол, аналогичный:

  • HTTP для интернета;

  • SMTP для обмена сообщениями;

  • LSP (Language Server Protocol) для поддержки языков программирования.

Anthropic точно характеризует MCP как "эквивалент порта USB-C для агентских систем" — универсальный интерфейс, позволяющий стандартизировать взаимодействие между различными компонентами экосистемы ИИ независимо от их производителя.

Как говорится, картинка стоит тысячи слов.

Figure_1

Figure_1

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

Figure_2

Figure_2

MCP Server работает независимо на любом сервере и может иметь собственную независимую базу данных информации/ресурсов. Он не привязан к серверу Agent и может использоваться повторно, а также его легко подключать и отключать.

Figure_3

Figure_3

Исходные вызовы функций инструмента инкапсулируются с помощью MCP Server, и архитектура становится такой:

Figure_4

Figure_4

Отличие от исходного чистого вызова функции заключается в том, что архитектура более гибкая, включая:

  1. Кластеризация : разрозненные функции можно объединить в одну службу для удобства управления.

  2. Развязка : вызов фактически происходит на соответствующей стороне сервера MCP, а не напрямую вызывается службой Agent. Инструмент расширения развертывания развязывается от проекта Agent.

  3. Сплоченность: сам сервер MCP может выполнять некоторые действия слаженно, включая независимое управление ресурсами, независимый контекст и т. д.

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

  5. Унификация: вызовы как клиентских, так и облачных инструментов могут быть реализованы с использованием унифицированного протокола MCP.

Архитектура и принцип работы

MCP определяет:

  1. Способы взаимодействия клиентов с серверами;

  2. Методы обработки серверами инструментов (API, функции);

  3. Правила доступа к ресурсам (файлы, базы данных).

В этой архитектуре:

  • Модели ИИ выступают в роли клиентов;

  • Внешние сервисы и источники данных — периферийные устройства (инструменты);

  • MCP — стандартизированный интерфейс (порт) между ними.

Пример

Давайте рассмотрим пример реализации MCP-сервера и MCP-клиента, ниже я попробую ответить на два ключевых вопроса:

  1. Как LLM модель взаимодействует с MCP сервером?

  2. Как LLM модель вызывает инструменты на стороне MCP сервера?

Реализация собственного MCP-сервера

Создать базовый MCP-сервер достаточно просто. Вот пример сервера для работы с локальными Git репозиториями с использованием FastMCP: GitHub 🐙

Реализация клиента для работы с MCP-сервером

Пример минимального клиента, который может взаимодействовать с MCP-сервером: GitHub 🐙

Конфиг файл доя клиента

Пример реализации конфига: GitHub 🐙

Взаимодействие LLM моделей с MCP серверами

Техническая реализация взаимодействия LLM моделей с MCP серверами

В этом анализе я рассмотрю техническую реализацию взаимодействия языковых моделей (LLM) с серверами Model Context Protocol (MCP) на уровне библиотеки FastMCP, фокусируясь на конкретных механизмах и программном интерфейсе.

Как LLM модель взаимодействует с MCP сервером

Декларация и регистрация инструментов

На стороне сервера инструменты объявляются с использованием декоратора @mcp.tool(), который регистрирует функцию в менеджере инструментов:

@mcp.tool()
async def list_repositories() -> str:
    """
    Description:
    ---------------
        Возвращает список зарегистрированных локальных Git репозиториев.
    """
    # Реализация функции
    return result

Внутри FastMCP, декоратор tool() добавляет функцию в менеджер инструментов:

def tool(self, name: str | None = None, description: str | None = None) -> Callable:
    def decorator(fn: AnyFunction) -> AnyFunction:
        self.add_tool(fn, name=name, description=description)
        return fn
    return decorator

def add_tool(self, fn: AnyFunction, name: str | None = None, description: str | None = None) -> None:
    self._tool_manager.add_tool(fn, name=name, description=description)

При инициализации сервера MCP, он настраивает обработчики для основных запросов протокола:

def _setup_handlers(self) -> None:
    """Set up core MCP protocol handlers."""
    self._mcp_server.list_tools()(self.list_tools)
    self._mcp_server.call_tool()(self.call_tool)
    # ... другие обработчики ...

Установка соединения и обнаружение инструментов

Когда MCP-сервер запускается, он ожидает соединения:

def run(self, transport: Literal["stdio", "sse"] = "stdio") -> None:
    if transport == "stdio":
        anyio.run(self.run_stdio_async)
    else:  # transport == "sse"
        anyio.run(self.run_sse_async)

При подключении клиента (содержащего LLM) к серверу, первым шагом клиент запрашивает список доступных инструментов через метод list_tools:

async def list_tools(self) -> list[MCPTool]:
    """List all available tools."""
    tools = self._tool_manager.list_tools()
    return [
        MCPTool(
            name=info.name,
            description=info.description,
            inputSchema=info.parameters,
        )
        for info in tools
    ]

Этот метод преобразует все зарегистрированные инструменты в формат MCPTool, содержащий:

  • Имя инструмента;

  • Описание (получаемое из docstring);

  • Схему входных параметров (получаемую из аннотаций типов).

Протокол взаимодействия

Протокол MCP поддерживает два основных механизма связи: локальную связь на основе стандартного ввода и вывода и удаленную связь на основе SSE ( Server-Sent Events ).

Оба механизма используют формат JSON-RPC 2.0 для передачи сообщений, обеспечивая стандартизированную и масштабируемую связь.

  • Локальная связь : данные передаются через stdio, подходящий для связи между клиентами и серверами, работающими на одной машине.

  • Удаленная связь : SSE объединяется с HTTP для обеспечения передачи данных в реальном времени по сетям, что подходит для сценариев, требующих доступа к удаленным ресурсам или распределенного развертывания.

stdio - общение через стандартный ввод/вывод:

async def run_stdio_async(self) -> None:
    """Run the server using stdio transport."""
    async with stdio_server() as (read_stream, write_stream):
        await self._mcp_server.run(
            read_stream,
            write_stream,
            self._mcp_server.create_initialization_options(),
        )

SSE (Server-Sent Events) - общение через HTTP:

async def run_sse_async(self) -> None:
    """Run the server using SSE transport."""
    # ... настройка HTTP сервера ...
    server = uvicorn.Server(config)
    await server.serve()

JSON-RPC 2.0 — это легкий протокол для удаленного вызова процедур (RPC), использующий JSON (JavaScript Object Notation) для кодирования данных. Он позволяет клиенту вызывать методы на сервере, передавая параметры в формате JSON, и получать ответы также в формате JSON.

Основные характеристики JSON-RPC 2.0:

  1. Простота: Протокол минималистичен и легко реализуем.

  2. Транспортная независимость: Может работать поверх различных транспортных протоколов, таких как HTTP, WebSocket и других.

  3. Уведомления: Поддерживает уведомления (notifications), которые не требуют ответа от сервера.

  4. Пакетные запросы: Позволяет отправлять несколько запросов в одном пакете.

  5. Обработка ошибок: Определяет стандартный формат для сообщений об ошибках.

Как LLM модель вызывает инструменты на стороне MCP сервера

Механизм вызова инструментов

Когда LLM решает вызвать инструмент, она формирует специальную структуру в ответе:

{
  "tool_calls": [
    {
      "id": "call_uniqueID",
      "type": "function",
      "function": {
        "name": "list_repositories",
        "arguments": "{}"
      }
    }
  ]
}

Этот вызов преобразуется клиентом в JSON-RPC запрос к серверу:

{
  "jsonrpc": "2.0",
  "method": "tool/call",
  "params": {
    "name": "list_repositories",
    "arguments": {}
  },
  "id": 1
}

На стороне сервера, этот запрос обрабатывается методом call_tool:

async def call_tool(
    self, name: str, arguments: dict[str, Any]
) -> Sequence[TextContent | ImageContent | EmbeddedResource]:
    """Call a tool by name with arguments."""
    context = self.get_context()
    result = await self._tool_manager.call_tool(name, arguments, context=context)
    converted_result = _convert_to_content(result)
    return converted_result

Процесс выполнения инструмента

Вот детальный процесс, происходящий на стороне сервера:

Получение контекста выполнения:

context = self.get_context()

Контекст содержит информацию о текущем запросе и сессии, что позволяет инструментам взаимодействовать с клиентом (например, отправлять промежуточные результаты).

Вызов инструмента через менеджер инструментов:

result = await self._tool_manager.call_tool(name, arguments, context=context)

Внутри ToolManager, происходит:

  • Поиск инструмента по имени;

  • Проверка аргументов на соответствие схеме;

  • Вызов функции инструмента с переданными аргументами;

  • Обработка исключений.

Преобразование результата в стандартный формат:

converted_result = _convert_to_content(result)

Функция convertto_content преобразует результат (который может быть строкой, объектом или другим типом данных) в стандартное представление:

def _convert_to_content(
    result: Any,
) -> Sequence[TextContent | ImageContent | EmbeddedResource]:
    """Convert a result to a sequence of content objects."""
    if result is None:
        return []

    if isinstance(result, (TextContent, ImageContent, EmbeddedResource)):
        return [result]

    # ... обработка других типов ...

    # Преобразование в текст, если это не строка
    if not isinstance(result, str):
        try:
            result = json.dumps(pydantic_core.to_jsonable_python(result))
        except Exception:
            result = str(result)

    return [TextContent(type="text", text=result)]

Пример полного потока выполнения

Рассмотрим полный поток выполнения для вызова инструмента list_repositories:

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

{
  "role": "assistant",
  "content": null,
  "tool_calls": [
    {
      "id": "call_unique123",
      "type": "function",
      "function": {
        "name": "list_repositories",
        "arguments": "{}"
      }
    }
  ]
}

Клиент преобразует вызов в JSON-RPC и отправляет на сервер:

2025-03-19 13:25:06,244 - mcp.server.lowlevel.server - INFO - Processing request of type CallToolRequest

Сервер обрабатывает запрос через метод call_tool:

async def call_tool(self, name: str, arguments: dict[str, Any]) -> Sequence[...]:
    context = self.get_context()
    result = await self._tool_manager.call_tool(name, arguments, context=context)
    converted_result = _convert_to_content(result)
    return converted_result
  

ToolManager находит функцию и вызывает её:

# Внутри ToolManager
tool_info = self._find_tool(name)
result = await self._invoke_tool(tool_info, arguments, context)

Выполняется функция, декорированная @mcp.tool():

@mcp.tool()
async def list_repositories() -> str:
    logger.info("Запрос списка репозиториев")
    repos = repo_manager.list_repositories()
    # ... формирование результата ...
    return result

Результат преобразуется в стандартный формат и возвращается клиенту:

2025-03-19 13:25:35,227 - __main__ - INFO - Репозиторий зарегистрирован: /path/to/repo

Клиент преобразует ответ и передаёт LLM:

messages.append({
    "role": "tool",
    "tool_call_id": tool_call_id,
    "content": tool_result
})

LLM формирует итоговый ответ пользователю:

⭐ Итерация 2/5 ⭐
2025-03-19 13:29:39,274 - httpx - INFO - HTTP Request: POST https://api.openai.com/v1/chat/completions "HTTP/1.1 200 OK"
✅ Получен ответ от модели: {'role': 'assistant', 'content': '...интерпретация результатов...'}

Контекст выполнения и дополнительные возможности

FastMCP предоставляет инструментам контекст выполнения через класс Context, который позволяет:

@server.tool()
def tool_with_context(x: int, ctx: Context) -> str:
    # Логирование
    ctx.info(f"Processing {x}")
    
    # Отчёт о прогрессе
    ctx.report_progress(50, 100)
    
    # Доступ к ресурсам
    data = ctx.read_resource("resource://data")
    
    # Получение информации о запросе
    request_id = ctx.request_id
    
    return str(x)

Это расширяет возможности инструментов, позволяя им взаимодействовать с клиентом во время выполнения.

Заключение

Библиотека FastMCP предоставляет элегантный интерфейс для создания серверов MCP, абстрагируя сложности протокола и обеспечивая простой путь для регистрации инструментов через декораторы.

LLM взаимодействует с MCP-сервером через стандартизированный протокол JSON-RPC, используя специальную структуру в своих ответах для вызова инструментов. Сервер преобразует эти вызовы в выполнение соответствующих функций и возвращает результаты в формате, который LLM может интерпретировать.

Ключевые компоненты этого взаимодействия:

  1. Декораторы @mcp.tool() для регистрации инструментов

  2. Механизм обнаружения инструментов через list_tools

  3. Вызов инструментов через метод call_tool

  4. Преобразование результатов в стандартный формат контента

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

Решаемые проблемы

MCP решает ключевую проблему современных моделей ИИ — ограничения их потенциала из-за изоляции данных. До появления MCP:

  • Передача данных осуществлялась через ручное копирование/вставку или загрузку/скачивание

  • Каждый новый источник данных требовал индивидуальной настройки и реализации

  • Формировались "информационные острова", ограничивающие возможности даже самых мощных моделей

Возможности и перспективы

MCP позволяет построить прямой "мост" между ИИ и различными источниками данных и инструментами, включая:

  • Локальные файловые системы

  • Интернет-ресурсы

  • Инструменты разработки

  • Средства автоматизации веб-сайтов и браузеров

  • Системы для повышения производительности и коммуникации

При широком внедрении стандарта MCP создается возможность для реализации концепции "Интернета всего" в сфере искусственного интеллекта, обеспечивая мощные возможности для совместной работы различных систем и компонентов.

MCP призван стать промежуточным уровнем протокола, который упростит и стандартизирует разработку и интеграцию приложений ИИ, делая экосистему более открытой, гибкой и функциональной.


🔥Не пропустите важные обновления и углубленные материалы!🔥  

Хотите быть в курсе самых свежих обзоров и исследований в мире ML и AI? Переходите по ссылкам ниже, чтобы получить доступ к эксклюзивному контенту:  

📌 Все обзоры также доступны в нашем Telegram канале TheWeeklyBrief📢

📌 Более подробный обзор с математической формализацией и программным кодом ждет вас в нашем репозитории Weekly-arXiv-ML-AI-Research-Review 👩‍💻📂✨  

Не упустите шанс глубже погрузиться в мир технологий! 🚀

Автор: Verbasik

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js