Как подключить MCP-сервер к Claude Code
На живом примере: находим сервер, проверяем ключ, прячем его от git и убеждаемся, что он действительно поднялся.
MCP — способ дать агенту доступ к внешнему сервису: базе, API, инструменту. Подключается за одну команду, но между «команда прошла» и «оно работает» есть зазор, в который попадают почти все.
Разберём на живом примере — сервис генерации презентаций с платным API.
Шаг 1. Найти сервер и проверить, что он настоящий
Половина MCP-серверов на GitHub — заброшенные однодневки. Прежде чем ставить, стоит посмотреть на пакет в npm:
npm view 2slides-mcp version description time.modifiedДата последнего изменения важнее числа звёзд. Сервер, не обновлявшийся год, скорее всего сломается на первом же изменении API.
Шаг 2. Спрятать ключ до того, как он утечёт
Ключи от личных кабинетов выгружают обычным .txt, и он не попадает ни под одно типовое правило .gitignore — там есть *.key и .env, но не 2slides-api-key.txt.
Один git add -A, и ключ навсегда в истории репозитория. Сначала правило, потом всё остальное:
cat >> .gitignore <<'EOF'
*api-key*
*api_key*
*-secret*
.mcp.json
EOF
git check-ignore -q kluch.txt && echo "игнорируется" || echo "ПОПАДЁТ В КОММИТ"
chmod 600 kluch.txtШаг 3. Подключить
claude mcp add --env API_KEY=ВАШ_КЛЮЧ --transport stdio 2slides -- npx 2slides-mcpЕсли claude не на PATH, запись делается прямо в .mcp.json проекта:
{
"mcpServers": {
"2slides": {
"command": "npx",
"args": ["-y", "2slides-mcp"],
"env": { "API_KEY": "..." }
}
}
}Два транспорта делают одно и то же. stdio запускает сервер локально и передаёт ключ через переменную окружения. Streamable HTTP ходит на удалённый адрес, и ключ там нередко идёт прямо в URL — а значит, попадает в логи. При прочих равных берите stdio.
Шаг 4. Убедиться, что сервер поднялся
Запись в конфиге ничего не доказывает. Проверить можно, поговорив с сервером напрямую по JSON-RPC:
import { spawn } from "node:child_process";
const p = spawn("npx", ["-y", "2slides-mcp"], { stdio: ["pipe", "pipe", "ignore"] });
let buf = "";
p.stdout.on("data", d => buf += d.toString());
const send = o => p.stdin.write(JSON.stringify(o) + "\n");
send({ jsonrpc: "2.0", id: 1, method: "initialize",
params: { protocolVersion: "2024-11-05", capabilities: {},
clientInfo: { name: "proba", version: "1" } } });
setTimeout(() => send({ jsonrpc: "2.0", id: 2, method: "tools/list", params: {} }), 3000);
setTimeout(() => {
buf.split("\n").filter(Boolean).forEach(s => {
try {
const m = JSON.parse(s);
if (m.id === 1) console.log("сервер:", m.result?.serverInfo?.name);
if (m.id === 2) console.log("инструменты:",
(m.result?.tools || []).map(t => t.name).join(", "));
} catch {}
});
p.kill();
}, 12000);Три подводных камня в этом коде, и все три встречаются на практике.
Первый запуск долгий. npx качает пакет, и это занимает больше времени, чем кажется. Проба с таймаутом в шесть секунд убьёт процесс на середине загрузки, и вы получите npm error signal SIGTERM вместо ответа. Прогрейте кэш заранее: npm exec --yes 2slides-mcp -- --help.
Ключ проверяется только вызовом. Список инструментов приходит и с неверным ключом: сервер поднялся, а до API ещё не ходил. Вызовите любой бесплатный инструмент и посмотрите на ответ.
stderr нужно отделять. Предупреждения npm летят в stderr и ломают разбор, если смешать потоки.
Шаг 5. Посмотреть на цену до первого запуска
Отдельный совет для платных серверов. В документации 2slides сказано: один кредит за страницу. На практике генерация девяти слайдов списала 90 кредитов из 500 — вдесятеро больше заявленного.
Ответ на запуск задания содержит и остаток, и стоимость:
{"credits": {"current": 500, "required": 90}}Прочитайте это поле до того, как запланируете бюджет. Разница между документацией и фактом здесь не редкость.
Что запомнить
Проверьте дату последнего обновления пакета, а не звёзды. Закройте ключ в .gitignore до подключения, а не после. Поговорите с сервером напрямую — запись в конфиге не доказывает, что он работает. И вызовите хотя бы один инструмент: список приходит и с неверным ключом.