В 2026 году закрытые кастомные плагины для языковых моделей уступили место открытому промышленному стандарту Model Context Protocol (MCP). Вместо написания уникальных интеграций под каждый AI-редактор, разработчик создает один MCP-сервер, который мгновенно подключается к Cursor IDE, Claude Desktop и автономным агентам. Ключевая инженерная задача — правильный выбор транспорта (stdio vs SSE) и контроль безопасности прав доступа.
rm -rf или отправить приватные токены в чужую сеть.┌─────────────────────────────────────────────────────────────┐
│ MCP Host Application (Cursor IDE / Claude Desktop) │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ LLM Engine (Claude 3.5 / 3.7 Sonnet / Gemini Flash)│ │
│ └──────────────────────────┬──────────────────────────┘ │
│ │ Инициирует Tool Call │
│ ▼ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ MCP Client Core (Диспетчер разрешений) │ │
│ │ - Human-in-the-loop: [Разрешить вызов инструмента?]│ │
│ └──────────────────────────┬──────────────────────────┘ │
└──────────────────────────────│──────────────────────────────┘
│
┌──────────────┴──────────────┐
│ │
▼ stdio (Local Process) ▼ SSE (Remote HTTP)
┌─────────────────────────────┐ ┌─────────────────────────────┐
│ Local MCP Server (Node.js) │ │ Remote Cloud MCP Server │
│ - stdin / stdout потоки │ │ - HTTP POST /events (SSE) │
│ - Доступ к локальному Git │ │ - Доступ к корпоративной CRM│
│ - Чтение локальной базы SQLite│ │ - Запросы к Supabase pgvector│
└─────────────────────────────┘ └─────────────────────────────┘Добавление секции mcpServers в файл конфигурации claude_desktop_config.json с указанием команды запуска node/npx.
Настройка вкладки Cursor Settings -> Features -> MCP с регистрацией серверов базы данных и терминала.
Использование @modelcontextprotocol/sdk/client для программного подключения к серверу через StdioClientTransport.
Запрос перечня доступных функций у сервера и динамическая передача их в промпт языковой модели.
Обязательный запрос подтверждения у пользователя перед выполнением мутирующих инструментов (запись файлов, SQL-запросы).
В каких случаях для взаимодействия хоста и сервера MCP следует выбрать транспорт stdio, а в каких — SSE (Server-Sent Events)?
Хост запускает сервер, выполняет обмен версиями протокола и считывает JSON-схемы всех зарегистрированных инструментов.
Модель сразу знает сигнатуру аргументов, типы данных и текстовые описания функций.
Модель решает, что для ответа пользователю необходимо выполнить поиск в БД, и генерирует вызов tools/call с аргументами.
Модель генерирует строгий JSON согласно объявленной схеме Zod.
Клиент отображает пользователю всплывающее окно с деталями команды: 'Сервер запрашивает чтение таблицы users. Разрешить?'.
Полный запрет автономного выполнения без явного согласия оператора.
Сервер выполняет команду и возвращает текстовые данные или структурированный результат в контекст диалога.
Модель формулирует финальный ответ пользователю на основе свежих фактических данных.
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-filesystem",
"/Users/developer/projects/wpskills"
]
},
"postgres": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-postgres",
"postgresql://postgres:password@localhost:5432/wpskills_dev"
]
},
"custom-dev-tools": {
"command": "node",
"args": ["/Users/developer/tools/mcp-server/dist/index.js"],
"env": {
"NODE_ENV": "development",
"API_SECRET_KEY": "dev_secret_mcp_123"
}
}
}
}import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
export class CustomMcpClient {
private client: Client;
private transport: StdioClientTransport;
constructor(serverScriptPath: string) {
this.client = new Client(
{
name: 'EnterpriseAgentClient',
version: '1.0.0',
},
{
capabilities: {
prompts: {},
resources: {},
tools: {},
},
}
);
// Запускаем сервер как дочерний процесс Node.js
this.transport = new StdioClientTransport({
command: 'node',
args: [serverScriptPath],
});
}
/**
* Инициализация соединения и рукопожатие
*/
public async connect(): Promise<void> {
await this.client.connect(this.transport);
console.info('[MCP Client] Connected to server successfully');
}
/**
* Получение списка всех доступных инструментов
*/
public async getAvailableTools() {
const { tools } = await this.client.listTools();
return tools;
}
/**
* Безопасный вызов инструмента с валидацией аргументов
*/
public async executeTool(toolName: string, args: Record<string, any>) {
console.info(`[MCP Client] Invoking tool "${toolName}" with arguments:`, args);
const result = await this.client.callTool({
name: toolName,
arguments: args,
});
return result;
}
public async disconnect(): Promise<void> {
await this.client.close();
}
}При использовании транспорта stdio любой вывод в console.log() попадает прямо в стандартный поток вывода stdout, который зарезервирован исключительно для сериализованных сообщений JSON-RPC 2.0. Посторонний текст логов ломает JSON-парсер хоста с ошибкой SyntaxError: Unexpected token in JSON. Отладочные сообщения обязаны направляться strictly в console.error() (поток stderr).
Если MCP-инструмент инициирует тяжелый запрос к недоступному удаленному API без AbortController, хост (Cursor или Claude) зависнет в состоянии ожидания ответа на неопределенное время. Всегда оборачивайте выполнение инструментов в таймауты (например, 15 000 мс).
В конфигурации файловых серверов никогда не указывайте корневую директорию операционной системы / или домашнюю папку пользователя ~. Ограничивайте рабочую директорию только конкретной изолированной папкой текущего проекта.
Разработчик пишет кастомный MCP-сервер на Node.js со stdio транспортом и вставляет строку console.log('Подключение к БД успешно!') в начало скрипта. Что произойдет при попытке подключения Claude Desktop?