Агенту нужен контракт: как разработчику спроектировать свой MCP-сервер

В центре агентной инженерии — разработчик, который проектирует и оркестрирует систему ИИ-агентов. Но без инфраструктуры агент остаётся генератором текста. Чтобы он стал рабочим инструментом, ему нужен доступ к коду, CI, логам, конфигурациям и другим элементам. С их помощью оркестр наконец «заиграет» и возьмёт на себя рутинные задачи, уступая инженеру место за пультом.

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

Как устроен MCP в инженерной архитектуре

MCP добавляет в агентную систему отдельный инфраструктурный слой для формализованного доступа к инструментам. Архитектурно в нём три роли:

  • MCP-сервер — реализует конкретные инструменты и экспонирует контракт: что агенту разрешено делать, с какими параметрами и в каких границах.
  • MCP-клиент — агент или среда (IDE, CLI, Dev Tools), которая вызывает инструменты.
  • Транспорт — механизм обмена сообщениями между ними.

MCP задаёт формат взаимодействия между клиентом и сервером. В рамках этого протокола сервер определяет доступные действия, параметры инструментов, возможные ошибки и ограничения доступа. Система формализует рабочую операцию и делает её доступной агенту в безопасной и воспроизводимой форме. Такой подход позволяет создавать в том числе полезные для Dev-to-Dev сервера, которые, например: 

  • анализируют CI-лог и выделяют вероятную причину падения;
  • собирают release notes из git-истории;
  • проверяют Dockerfile на анти-паттерны;
  • ищут техдолг в репозитории.

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

Сущности MCP-сервера, которые важно спроектировать

Tools — действия, доступные агенту. Хороший инструмент выполняет одну понятную операцию, имеет чёткую схему входных данных, возвращает предсказуемый формат результата и не имеет скрытых побочных эффектов.

Resources — данные, к которым агент получает доступ. Инженер должен определить разрешённые источники, допустимые пути и ограничения по объёму и типу данных.

Prompts — шаблоны или инструкции, встроенные в сервер. В контексте Dev-to-Dev они полезны для стандартизации операций: например, анализа логов или генерации отчётов.

Пример: автоматизация повседневной рутины 

Представим типичную ситуацию: CI-пайплайн упал. Лог содержит тысячи строк, и нужно быстро понять, где именно произошёл сбой и что стало причиной. Эту задачу можно поручить агенту. Но прежде чем он сможет помочь, инженер должен формализовать операцию — вынести её в MCP-сервер. Именно отсюда начинаются архитектурные решения.

При проектировании такого сервера нужно учесть 5 основных моментов. 

Границы ответственности

Сервер должен выполнять одну чётко определённую операцию. Инженеру нужно решить:
что именно делает инструмент? Плохой вариант — создать сервер с размытым назначением: «Найди причину ошибки в проекте». Чем более размыта формулировка, тем менее предсказуемым становится поведение агента. Он не ограничен конкретным артефактом, может обращаться к произвольным данным и возвращает непредсказуемый текстовый ответ.

Хороший подход начинается с декомпозиции задачи:

  1. Определить конкретный вход — например, файл CI-лога.
  2. Зафиксировать операцию — извлечение структурированных сведений о сбое.
  3. Ограничить область анализа — только содержимое переданного лога, без обхода всего репозитория.

В этом случае сервер не заменяет модель, а подготавливает для неё данные.

Формат результата

Агент работает лучше, когда получает не свободный текст, а формализованный ответ. Допустим, сервер проанализировал лог. Если сервер возвращает что-то в духе «похоже, ошибка связана с зависимостями», агенту сложно принимать дальнейшие решения. Это субъективная интерпретация. 

Инженер должен задать структуру результата. Для этого потребуется определить, какие поля реально нужны агенту, зафиксировать их формат, обеспечить стабильность структуры ответа. После этого агент сможет сопоставить ошибку с последним коммитом, проверить, менялись ли зависимости и сформировать объяснение.

Пример удачной структуры ответа, который поможет правильно интерпретировать результат: 

  • этап пайплайна;
  • команда, завершившаяся с ошибкой;
  • код возврата;
  • фрагмент сообщения об ошибке;
  • предполагаемая категория (если она выводится по формальным правилам).

Проектируя MCP-сервер, важно думать о том, как с его результатом будет работать другой агент, а не человек. 

Детерминированность

В примере с логом есть соблазн добавить «умную» эвристику или модель прямо внутрь сервера. Но решение на базе MCP должно быть максимально предсказуемым. Если один и тот же входной артефакт даёт разные ответы, агентная система становится нестабильной. Это особенно критично, когда инструменты участвуют в цепочке автоматических решений.

Проектируя сервер, инженер должен:

  1. Использовать формальные правила анализа.
  2. Исключить случайность.
  3. Зафиксировать версии библиотек.
  4. Ограничить объём входного файла.
  5. Учитывать лимиты контейнера (CPU, RAM).

Это особенно важно в Dev-to-Dev, где сервер тестируют другие участники. Такой подход поможет избегать скрытой случайности, ограничивать объём входных данных и учитывать лимиты по CPU и памяти.

Ограничения доступа

CI-лог — лишь один файл. Но сервер может быть запущен внутри контейнера проекта. Инженер должен решить:

  • может ли инструмент читать любые файлы?
  • может ли он выполнять системные команды?
  • допустим ли доступ к сети?

Одна из частых ошибок — давать серверу слишком широкие права, например, доступ ко всей файловой системе, выполнение произвольных команд или обращение к внешним сервисам без контроля.

Грамотный подход:

  1. Ограничить директорию, в которой сервер может работать.
  2. Запретить произвольное выполнение shell-команд.
  3. Ввести ограничения по размеру входных данных.
  4. Установить таймаут выполнения.

Такой сервер будет безопасен, воспроизводим и понятен для ревью.

Тестируемость без модели

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

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

  • Берём конкретный файл CI-лога с известной ошибкой.
  • Передаём его серверу.
  • Проверяем, что сервер возвращает корректно определённый этап, правильный код, фрагмент ошибки и ожидаемую классификацию, если она предусмотрена.

Таким образом мы проверим, что инструмент корректно анализирует лог, правильно выделяет ошибку и стабильно формирует структуру ответа.

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

Мини-чеклист: как спроектировать MCP-сервер за вечер

  1. Сформулировать одну операцию в формате «глагол + объект», например: «извлечь причину падения из CI-лога».
  2. Зафиксировать входной артефакт: файл, путь или ресурс.
  3. Описать схему ответа и минимально необходимые поля.
  4. Установить границы доступа: директория, сеть, команды.
  5. Добавить лимиты: размер входа, таймаут, CPU/RAM.
  6. Сделать детерминированную обработку без LLM внутри инструмента.
  7. Подготовить 2–3 эталонных лога для тестов.
  8. Добавить smoke-проверку: один запуск → ожидаемая структура ответа.
  9. Документировать контракт: что делает инструмент, что не делает, какие ошибки возвращает.

Когда MCP-сервер начинает ломать систему

Ошибки в проектировании MCP-сервера редко заметны сразу. На первых тестах всё может выглядеть корректно. Проблемы проявляются позже, когда инструмент включается в цепочку агентов и начинает участвовать в автоматических решениях.

Агент компенсирует архитектуру. Если сервер возвращает неструктурированный результат или работает слишком широко, агент вынужден компенсировать архитектурные пробелы. Он повторно интерпретирует текст, угадывает структуру и усложняет промпты. Система начинает зависеть от поведения конкретной модели: небольшое изменение контекста или версии может нарушить логику всей цепочки.

Что делать:

  • Сузить ответственность инструмента до одной операции.
  • Возвращать структурированные данные вместо текста.
  • Явно фиксировать схему входа и выхода.
  • Убрать из сервера логику, которую должна выполнять модель.

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

Что делать:

  • Ограничить область доступа к данным.
  • Исключить скрытые побочные действия.
  • Логировать входные параметры и ключевые этапы обработки.
  • Документировать контракт инструмента.

Система теряет воспроизводимость. Если сервер работает только в окружении автора, он остаётся прототипом. Различия в версиях зависимостей или состоянии среды начинают влиять на результат. Поведение становится нестабильным, а повторный запуск не гарантирует тот же вывод.

Что делать:

  • Зафиксировать версии зависимостей.
  • Ограничить влияние внешней среды.
  • Проверять инструмент на одинаковых входных данных.
  • Добавить отдельный сценарий smoke-проверки.

Модель становится «клеем». Когда архитектура сервера продумана слабо, модель начинает компенсировать её недостатки: нормализует данные, исправляет формат, сглаживает ошибки, пытаясь удержать систему. Но поскольку модель — вероятностный компонент, устойчивость всей конструкции снижается.

Что делать:

  • Чётко разделить зоны ответственности сервера и агента.
  • Убрать из сервера вероятностную логику.
  • Делать формат ответа строгим и предсказуемым.
  • Проектировать инструменты так, чтобы модель использовала их, а не исправляла.

Ограничения MCP-сервера: что ему не стоит поручать

MCP-сервер — инфраструктурный компонент. Он необходим, чтобы формализовать операции и обеспечить предсказуемый доступ к инструментам. Главный принцип:

  • MCP-сервер отвечает за операции.
  • Агент отвечает за интерпретацию.
  • Оркестрация отвечает за стратегию.

Если эти роли смешиваются, система становится сложнее, а не умнее. Есть классы задач, которые лучше оставить на уровне агента или оркестрации:

  1. Стратегические решения. Сервер не должен принимать решения о том, что делать дальше. Например, инструмент может вернуть сведения о сбое в CI, но решение — откатить релиз, создать задачу или инициировать повторную сборку — принимает агент или человек.
  2. Вероятностный анализ и интерпретация. MCP-серверу не следует поручать задачи, требующие гибкой интерпретации контекста. Инструмент может подготовить данные, но не должен подменять собой LLM.
  3. Комплексная оркестрация. Сервер не управляет цепочками инструментов и не координирует работу нескольких агентов. Если инструмент вызывает другие инструменты и запускает последовательности действий, он превращается в скрытый оркестратор.

Как настроить MCP-сервер: шпаргалка по SDK

Независимо от языка, сервер состоит из трёх частей:

  1. Инициализация сервера.
  2. Объявление инструментов.
  3. Запуск транспортного слоя.

На примере Python это выглядит предельно просто:

from mcp.server.fastmcp import FastMCP

mcp = FastMCP("demo")


@mcp.tool()
def my_tool(input: str) -> dict:
    """Описание инструмента"""
    # логика обработки
    return {"result": "..."}


if __name__ == "__main__":
    mcp.run(transport="stdio")

Вся архитектура сводится к одной идее: каждая функция, помеченная декоратором @mcp.tool, становится доступной агенту как инструмент. SDK упрощает регистрацию инструментов, но не решает архитектурные задачи. При создании сервера нужно учитывать несколько принципов:

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

SDK позволяет быстро объявить инструмент. Но предсказуемость, границы и воспроизводимость определяет разработчик.

MCP-сервера на хакатоне

Dev-to-Dev: Agentic Engineering Challenge — это хакатон про инженерную инфраструктуру для агентов. Участникам предстоит спроектировать и реализовать собственный MCP-сервер, который решает рутинную задачу разработчика. Решение оценят другие участники и эксперты Codenrock. 

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


    Оставьте заявку, мы подберем для вас лучшие решения для работы с ИТ-сообществом

    Будьте в курсе лучших кейсов хакатонов, ML-турниров, CTF и соревнований по спортивному программированию на Codenrock
    Добавить комментарий