Model Context Protocol (MCP) — это открытый спецификационный стандарт, регламентирующий двунаправленное взаимодействие между LLM-агентами (Clients) и изолированными средами исполнения инструментов и источников данных (Servers). До появления MCP каждая IDE или агентская среда реализовывала проприетарные адаптеры к локальным файловым системам, базам данных и корпоративным API, что приводило к фрагментации экосистемы и дублированию кода интеграций.
MCP формализует протокольный обмен через три ключевые абстракции:
В качестве транспортных уровней спецификация MCP определяет:
Взаимодействие строится по модели клиент-серверной архитектуры с передачей типизированных кадров JSON-RPC 2.0.
Автономный процесс, регистрирующий примитивы Tools, Resources и Prompts и предоставляющий к ним типизированный доступ через JSON-RPC 2.0. Межпроцессное взаимодействие (IPC) через стандартные потоки stdin/stdout операционной системы, обеспечивающее нулевой сетевой оверхед и привязку жизненного цикла сервера к клиенту. Фаза рукопожатия (Initialize Handshake), в ходе которой клиент и сервер обмениваются поддерживаемыми спецификациями и протоколами расширений.[ AI Agent / IDE Host ] <--- (JSON-RPC 2.0 over STDIO) ---> [ MCP Server (Node.js) ]
(MCP Client) |
| +-------+-------+
- Capability Handshake | |
- CallTool(name, args) [ PostgreSQL ] [ File System ]
- ReadResource(uri)Клиент порождает дочерний процесс сервера и обменивается Capabilities через методы initialize и notifications/initialized.
Клиент запрашивает перечень доступных функций; сервер возвращает имена, описания и Zod/JSON-схемы валидации аргументов.
LLM генерирует tool_call с аргументами; клиент транслирует его в JSON-RPC запрос CallToolRequestSchema на stdin сервера.
Сервер валидирует входные параметры, исполняет логику и сериализует результат в массив content-блоков в stdout.
Почему в локальной среде разработки для взаимодействия клиента MCP (IDE / агент) и сервера инструментов выбран транспорт STDIO поверх JSON-RPC 2.0 вместо локального HTTP REST-сервера?
list_tables, describe_schema и run_readonly_query. Агент автономно анализирует схему БД и генерирует оптимизированные SQL-запросы для разработчика.Ниже представлен пример реализации отказоустойчивого MCP-сервера на TypeScript с использованием официального @modelcontextprotocol/sdk.
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
import { z } from "zod";
const server = new Server(
{ name: "Enterprise-DevOps-MCP", version: "1.0.0" },
{ capabilities: { tools: {}, resources: {} } }
);
// Схема валидации входных параметров инструмента через Zod
const GetWeatherInputSchema = z.object({
city: z.string().min(1, "Название города обязательно для заполнения"),
units: z.enum(["celsius", "fahrenheit"]).default("celsius"),
});
// 1. Декларация доступных инструментов
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: "get_weather_telemetry",
description: "Получить актуальную метеорологическую телеметрию для указанного города",
inputSchema: {
type: "object",
properties: {
city: { type: "string", description: "Название города" },
units: { type: "string", enum: ["celsius", "fahrenheit"], description: "Единицы измерения" }
},
required: ["city"]
}
}
]
};
});
// 2. Обработка вызовов инструментов с валидацией схемы
server.setRequestHandler(CallToolRequestSchema, async (request) => {
if (request.params.name === "get_weather_telemetry") {
const parseResult = GetWeatherInputSchema.safeParse(request.params.arguments);
if (!parseResult.success) {
return {
content: [{ type: "text", text: `Ошибка валидации: ${parseResult.error.message}` }],
isError: true,
};
}
const { city, units } = parseResult.data;
const temperature = units === "celsius" ? "21°C" : "70°F";
const telemetry = `Погода в ${city}: ${temperature}, переменная облачность, влажность 45%.`;
return {
content: [{ type: "text", text: telemetry }],
isError: false
};
}
throw new Error(`Запрошенный инструмент не найден: ${request.params.name}`);
});
// 3. Запуск STDIO транспорта
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
// ВАЖНО: Все логи пишутся строго в stderr, чтобы не коррумпировать stdout JSON-RPC поток!
console.error("MCP Server successfully started on STDIO transport");
}
main().catch((err) => {
console.error("Fatal MCP Server Error:", err);
process.exit(1);
});Разработчик MCP-сервера вызвал `console.log('Fetching database rows...')` для отладки внутри обработчика CallToolRequestSchema. К какому сбою это приведет в клиенте MCP?
Использование console.log() в коде MCP-сервера или зависимых библиотеках ломает JSON-RPC протокол, так как дескриптор stdout зарезервирован для протокольных фреймов.
Решение: Направлять диагностические логи исключительно в console.error() (stderr) либо переопределять глобальный метод console.log = (...args) => console.error(...args).
Слепое доверие параметрам, переданным моделью (request.params.arguments). Агент может галлюцинировать и прислать неожиданные типы, строки вместо чисел или инъекции.
Решение: Обязательная валидация входящих данных через Zod-схемы (safeParse()) с возвратом структурированного объекта ошибки при несовпадении типов.
Предоставление MCP-серверу инструментов прямого исполнения команд (execute_bash) с неограниченными правами root на хостовой машине.
Решение: Изоляция среды исполнения в контейнерах (Docker/Podman), строгий whitelist разрешенных бинарных файлов и запуск процесса от имени непривилегированного пользователя.