
Протокол Model Context Protocol (MCP), представленный разработчиками Anthropic в конце 2024 года и получивший активное развитие в течение 2025–2026 годов, стал стандартом де-факто для подключения внешних инструментов, баз данных и контекстных хранилищ к LLM-агентам. Вместо того чтобы жестко прописывать специфичные для каждого вендора вызовы API в системных промптах или коде приложения, разработчики теперь могут использовать стандартизированный клиент-серверный интерфейс. Однако перенос логики работы с данными на уровень MCP-серверов порождает новые архитектурные вызовы: от изоляции процессов ОС до детерминированного контроля контекста, передаваемого языковой модели.
В этом материале мы разберем устройство транспортных уровней MCP, сценарии разделения прав доступа, схемы управления памятью агентов и реальные ограничения при интеграции сторонних модулей в продакшн-контуры.
Архитектура Model Context Protocol: клиенты, хосты и изолированные серверы
В основе MCP лежит разделение на три компонента: хост (например, Claude Desktop или собственная среда выполнения агента), клиент (модуль внутри хоста, управляющий соединением) и сам сервер (легковесный процесс, предоставляющий ресурсы, промпты или инструменты).
Главное архитектурное преимущество такого подхода — слабая связанность. Агент не знает, как именно устроена база данных PostgreSQL или файловая система хоста: он обращается к абстрактным эндпоинтам, которые сервер объявляет через JSON-RPC схему.
+——————————————————-+
| AI Host |
| +——————-+ +———————+ |
| | LLM Agent | <----> | MCP Client | |
| +——————-+ +———+———-+ |
+——————————————|————-+
| JSON-RPC (stdio / SSE)
+——————————————v————-+
| MCP Server |
| +——————-+ +———————+ |
| | Tools / Resources | | Local Sandbox | |
| +——————-+ +———————+ |
+——————————————————-+
При проектировании продакшн-систем инженеры часто допускают ошибку, запуская все MCP-серверы в том же пространстве пользователя и с теми же привилегиями, что и основной процесс агента. Спецификация протокола поддерживает два основных транспорта: `stdio` (стандартный ввод-вывод через порожденные процессы) и Server-Sent Events (SSE) поверх HTTP. Для локальных сред `stdio` является наиболее безопасным по умолчанию, так как жизненный цикл сервера жестко привязан к жизненному циклу клиентского процесса, но он требует жесткой изоляции на уровне операционной системы, если сервер выполняет небезопасный код.
Транспортные уровни: stdio против SSE в распределенных контурах
Выбор транспортного уровня определяет не только скорость обмена сообщениями, но и модель угроз (threat model) всего агентского приложения.
- stdio (Standard I/O): Клиент запускает MCP-сервер как дочерний процесс (например, через Node.js или Python-скрипт) и общается с ним через стандартные потоки `stdin` и `stdout`. Это идеальный выбор для локальных утилит (файловый поиск, локальный Git, отладчики). Плюс: отсутствие открытых сетевых портов. Минус: масштабируемость ограничена одной машиной.
- SSE (Server-Sent Events): Используется для удаленных или микросервисных архитектур. Клиент отправляет HTTP POST-запросы на сервер, а сервер транслирует события обратно через постоянное SSE-соединение. Плюс: возможность вынести тяжелые инструменты на выделенные GPU/CPU-узлы. Минус: необходимость реализации полноценной аутентификации (обычно Bearer-токены или mTLS) и защиты от MitM-атак, так как JSON-RPC трафик идет по сети.
На практике гибридные агентские системы используют `stdio` для работы с локальной файловой системой и секретами разработчика, а SSE — для обращения к корпоративным базам данных, защищенным шлюзами API.
Управление контекстом и ограничения пропускной способности
Один из главных мифов вокруг MCP заключается в том, что он «автоматически решает проблему контекста». Напротив, некорректно написанный MCP-сервер может забить контекстное окно LLM мусорными данными за несколько итераций.
Спецификация выделяет три примитива, которые сервер может передавать клиенту:
1. Resources (Ресурсы): Статические или динамические данные (файлы, лог-хи, схемы БД), которые агент читает по URI (например, `postgres://db/users/schema`).
2. Prompts (Промпты): Шаблоны и заготовки, которые пользователь или агент может вызывать для стандартизации задач.
3. Tools (Инструменты): Исполняемые функции, принимающие аргументы и возвращающие результат (например, запуск SQL-запроса или отправка письма).
Проблема возникает при возврате крупных ресурсов. Если MCP-сервер возвращает содержимое файла размером в 2 мегабайта в теле ответа инструмента, модель получает перегруженный контекст, что ведет к деградации внимания (attention degradation) и росту стоимости токенов.
Решение на уровне архитектуры: Серверы должны возвращать не сырые данные, а их краткие срезы, хендлы или указатели на пагинацию. Если агенту требуется изучить большой лог, он должен сначала запросить оглавление или выполнить поисковый запрос (`grep`), а не считывать весь файл целиком через инструмент чтения.
Безопасность и изоляция: песочницы для MCP-серверов
Поскольку экосистема MCP активно пополняется сторонними серверами из репозиториев GitHub и npm, риск выполнения вредоносного кода (Supply Chain Attack) через скомпрометированный инструмент крайне высок. Если агент получает доступ к инструменту `execute_shell_command` без ограничений, злоумышленник может внедрить подсказку (prompt injection), которая заставит агента вызвать этот инструмент с деструктивными аргументами.
Для защиты контура применяются следующие инженерные практики:
- Изоляция в контейнерах (Docker): Даже при использовании локального транспорта серверы критической важности следует запускать внутри минималистичных контейнеров с отключенным доступом в сеть ( `—network none`) и жестко ограниченными точками монтирования (`—read-only`).
- Принцип наименьших привилегий для учетных записей: Если MCP-сервер подключается к базе данных, он должен использовать отдельную роль в БД с правами только на чтение (`SELECT`), если обратное явно не требуется бизнес-логикой.
- Валидация аргументов на стороне сервера: Нельзя полагаться на то, что языковая модель всегда передаст корректные типы данных или безопасные пути. Каждый MCP-сервер обязан валидировать входящие параметры через схемы (например, Pydantic в Python или Zod в TypeScript) до выполнения операций.
Практический пример: минимизация рисков при написании кастомного сервера
Ниже приведена базовая структура безопасного локального MCP-сервера на Python (`mcp` SDK), который предоставляет агенту доступ только к строго определенной директории с логами, исключая обход путей (Path Traversal).
python
from mcp.server import Server
import mcp.types as types
import os
from pathlib import Path
app = Server(«secure-log-reader»)
ALLOWED_DIR = Path(«/var/log/app»).resolve()
@app.list_tools()
async def handle_list_tools() -> list[types.Tool]:
return [
types.Tool(
name=»read_app_log»,
description=»Безопасное чтение строк из разрешенного лог-файла»,
inputSchema={
«type»: «object»,
«properties»: {
«filename»: {«type»: «string», «description»: «Имя файла в директории логов»},
«lines»: {«type»: «integer», «description»: «Количество строк с конца», «default»: 50}
},
«required»: [«filename»]
}
)
]
@app.call_tool()
async def handle_call_tool(name: str, arguments: dict | None) -> list[types.TextContent]:
if name != «read_app_log»:
raise ValueError(f»Неизвестный инструмент: {name}»)
filename = arguments.get(«filename»)
lines_count = arguments.get(«lines», 50)
# Защита от Path Traversal
target_path = (ALLOWED_DIR / filename).resolve()
if not target_path.is_relative_to(ALLOWED_DIR) or not target_path.is_file():
raise ValueError(«Доступ запрещен или файл не найден»)
with open(target_path, «r», encoding=»utf-8″) as f:
content = f.readlines()
result = «».join(content[-lines_count:])
return [types.TextContent(type=»text», text=result)]
В данном примере жесткая проверка `is_relative_to(ALLOWED_DIR)` предотвращает попытки агента прочитать системные файлы вроде `/etc/passwd` через инъекцию вида `../../etc/passwd`.
Чек-лист проверки готовности MCP-контура к продакшну
Перед выводом агентской системы с поддержкой MCP в промышленную эксплуатацию рекомендуется проверить следующие параметры:
Транспортный уровень: Локальные утилиты используют изолированный `stdio`, удаленные сервисы используют зашифрованные каналы с взаимной аутентификацией.
2. Ограничение контекста: Инструменты не возвращают неструктурированные массивы данных объемом более 100 КБ за один вызов; внедрена пагинация.
3. Песочница: Сторонние серверы запущены в контейнерах с минимальными привилегиями ОС.
4. Валидация схем: Все входящие от агента аргументы проверяются через строгие схемы типов до выполнения бизнес-логики.
5. Аудит вызовов: Ведется детальный лог всех вызовов инструментов с фиксацией аргументов и кодов возврата для последующего разбора инцидентов безопасности.
