Почему это важно именно вам
На протяжении Фазы 6 мы подключали Claude к реальным системам — Notion, GitHub, Slack, базам данных. И в каждом случае рано или поздно возникал один и тот же вопрос: а куда класть токен? API-ключ от Google Sheets, токен от Notion, OAuth от GitHub — все они нужны MCP-серверу, чтобы работать от вашего имени. И если положить их не туда — вы либо потеряете доступ к собственным системам через Claude, либо откроете дыру, через которую утечёт что-то важное.
Для директора, который работает с корпоративными данными, это не паранойя, а базовая гигиена. Один токен от корпоративного Google Workspace в руках не того человека — это доступ ко всей переписке, документам, встречам. Токен от GitHub с правами на запись — это возможность изменить код или документацию. Токен от CRM с полными правами — это данные всех клиентов. Настройка MCP — это не только «как подключить», но и «как не устроить утечку».
Этот урок закрывает именно этот пробел. Мы разберём: как Claude получает OAuth-доступ к внешним сервисам, где хранить токены чтобы они работали но не утекали, как ограничить права до минимально необходимых, и что делать когда токен нужно заменить — не ломая при этом всё что работало.
Что это такое
Представьте стандартную ситуацию: вы нанимаете временного помощника для работы с почтой. Вы не отдаёте ему свой пароль от Gmail — вы создаёте ему отдельный доступ с правом читать и отвечать на письма, но без права удалять аккаунт или менять пароль. Именно этот принцип лежит в основе OAuth.
OAuth — это протокол делегированного доступа. Вместо того чтобы передать сервису ваш логин и пароль, вы говорите сервису: «я разрешаю вот этому приложению делать вот это от моего имени». Сервис выдаёт токен — специальный ключ с ограниченными правами и сроком действия. Это не ваш пароль, это временное разрешение на конкретные действия.
В контексте MCP это работает так: MCP-сервер для GitHub или Notion должен обращаться к их API от вашего имени. Для этого ему нужен токен. Токен можно получить двумя способами: либо вы создаёте его вручную в настройках сервиса (это называется «Personal Access Token» или просто API-ключ), либо используете OAuth flow — интерактивный процесс, где вы нажимаете «разрешить» в браузере и токен создаётся автоматически.
Токен и пароль — принципиально разные вещи
Пароль даёт полный доступ ко всему аккаунту навсегда. Токен — ограниченный доступ к конкретным функциям на определённое время. Если токен утечёт — вы его отзываете, не меняя пароль. Поэтому всегда используйте токены, а не пароли, при интеграциях.
Scopes — это список конкретных разрешений, которые вы даёте токену. Например, GitHub-токен может иметь scope repo:read (читать репозитории), или repo (полный доступ включая запись), или delete_repo (удалять репозитории). Разница огромная, а выбор делаете вы при создании токена.
Как работает на практике
Получить OAuth-токен через claude mcp add
Claude Code поддерживает OAuth напрямую, но это два отдельных шага: сначала добавляете сервер, потом проходите вход. Флага --oauth у команды добавления нет:
claude mcp add --transport http --callback-port 8080 github https://api.githubcopilot.com/mcp/
claude mcp login github
Что происходит пошагово:
- Claude Code запускает локальный HTTP-сервер на порту 8080 — именно туда сервис вернёт токен после авторизации.
- В браузере открывается страница авторизации GitHub (или другого сервиса).
- Вы видите запрашиваемые разрешения и нажимаете «Authorize».
- GitHub перенаправляет браузер на
http://localhost:8080/callbackс кодом авторизации. - Claude Code обменивает этот код на токен доступа.
- Токен сохраняется в защищённое хранилище Claude Code (не в файлы проекта).
Параметр --callback-port 8080 указывает, какой порт использовать для callback. Порт должен быть свободен в момент авторизации. Если 8080 занят — можно указать любой другой, например --callback-port 9090.
Порт должен совпадать с тем, что ожидает сервис
Многие OAuth-сервисы заранее регистрируют список разрешённых callback URL. Если вы указываете --callback-port 8080, но сервис ожидает localhost:3000 — авторизация упадёт с ошибкой. Уточняйте допустимые порты в документации конкретного MCP-сервера.
Где хранить токены — правильный способ
Когда OAuth недоступен и токен приходится передавать вручную (Personal Access Token, API Key), есть один правильный способ и несколько неправильных.
Правильный способ: переменные окружения.
Устанавливаете переменную в вашей системе:
# В ~/.zshenv или ~/.bashrc
export NOTION_API_KEY="secret_abc123..."
export GITHUB_TOKEN="ghp_xyz789..."
export GOOGLE_SHEETS_KEY="AIzaSy..."
В файле .mcp.json ссылаетесь на переменную через синтаксис ${VAR}:
{
"mcpServers": {
"notion": {
"command": "npx",
"args": ["-y", "@notionhq/notion-mcp-server"],
"env": {
"NOTION_API_KEY": "${NOTION_API_KEY}"
}
}
}
}
Что происходит: когда Claude Code запускает MCP-сервер, он подставляет реальное значение переменной в это место. В самом файле .mcp.json токена нет — там только ссылка на него. Файл можно безопасно показать коллеге или даже положить в систему контроля версий.
Никогда не кладите токены в CLAUDE.md
CLAUDE.md — это файл, который попадает в контекст каждой сессии Claude. Он может синхронизироваться с облаком, копироваться в репозитории, передаваться другим людям. Токен, написанный в CLAUDE.md — это публичный токен, даже если вам так не кажется.
Неправильные способы:
Напрямую в .mcp.json:
"env": {
"NOTION_API_KEY": "secret_abc123..."
}
Этот файл может уйти в Git, Dropbox, Яндекс.Диск — и токен окажется там вместе с ним.
В CLAUDE.md с пометкой «для служебного пользования». Пометка ничего не защищает.
В комментарии в скрипте. Комментарии читаются всеми.
Проверить, что переменная действительно доступна
Прежде чем настраивать MCP, убедитесь что переменная установлена корректно:
# Проверить что переменная есть
echo $NOTION_API_KEY
# Если пустой вывод — переменная не установлена
# Установить в текущей сессии (временно, для теста):
export NOTION_API_KEY="secret_abc123"
# Чтобы работало постоянно — добавить в ~/.zshenv
После добавления в ~/.zshenv нужно либо открыть новый терминал, либо выполнить:
source ~/.zshenv
Минимальные права — принцип least privilege
При создании токена (Personal Access Token) всегда выбирайте минимально необходимые scopes. Конкретные примеры:
GitHub. Если MCP-сервер нужен только для чтения кода и задач — выбирайте repo:read и issues:read. Не repo (полный доступ), не admin:org. Зайдите в Settings → Developer settings → Personal access tokens → создайте новый, отметив только нужные галочки.
Notion. При интеграции Notion выдаёт доступ только к тем страницам, которые вы явно добавите интеграции. Не создавайте интеграцию с «Полным доступом к рабочему пространству» — добавляйте только те базы данных и страницы, которые нужны Claude.
Google Workspace. OAuth scope https://www.googleapis.com/auth/spreadsheets.readonly даёт чтение таблиц. Scope https://www.googleapis.com/auth/spreadsheets даёт запись. Если вам нужен только анализ — используйте readonly.
Принцип минимальных прав работает в обе стороны
Ограниченный токен не только безопаснее — он ещё и понятнее. Когда через полгода вы откроете список интеграций и увидите токен с правами «read-only: sheets, calendar» — вы сразу поймёте зачем он создавался. Токен с правами «полный доступ ко всему» создаёт вопросы.
Ротация токенов: когда и как менять
Токены нужно менять в нескольких случаях:
- Токен мог утечь (видели его в логах, показали экран постороннему, залили в Git случайно)
- Истёк срок действия (если при создании установили expiry)
- Человек, через чей аккаунт был создан токен, уволился
- Периодически по регламенту — раз в 6-12 месяцев как минимум
Процедура ротации без остановки работы:
- Создайте новый токен с теми же правами в настройках сервиса.
- Обновите значение переменной в
~/.zshenv(замените старое значение). - Выполните
source ~/.zshenvили откройте новый терминал. - Запустите
claude mcp listи убедитесь что сервер отображается. - Сделайте тестовый запрос через Claude, убедитесь что работает.
- Только после этого отзовите старый токен в настройках сервиса.
Порядок важен: сначала убедитесь что новый токен работает, потом отзывайте старый. Иначе получите период когда всё сломано.
Хранение в keychain как альтернатива
На macOS можно хранить секреты в Keychain и читать их в скрипте: security find-generic-password -s "notion-mcp" -w. Это надёжнее чем plaintext в .zshenv, но сложнее в настройке. Для большинства рабочих задач достаточно файла ~/.zshenv с правильными правами (chmod 600 ~/.zshenv).
Частые ошибки
Ошибка 1: Токен в .mcp.json напрямую, а файл в Яндекс.Диске.
Очень распространённая ситуация: .mcp.json лежит в рабочей папке, которая синхронизируется с облаком. Токен уходит в облако, где его теоретически может увидеть кто угодно — или увидит, если облако взломают. Исправление очевидно: токен → в переменную окружения, в .mcp.json → только ${VAR}.
Ошибка 2: Один токен для всего.
Создали один GitHub Personal Access Token со всеми правами и используете его и для работы через Claude, и для CI/CD пайплайна, и для скриптов. Когда нужно будет отозвать токен (утечка, смена места работы, плановая ротация) — упадёт всё сразу. Решение: отдельный токен для каждого инструмента или сервиса с минимально необходимыми правами.
Ошибка 3: OAuth flow на занятом порту.
Порт фиксируется при добавлении сервера (claude mcp add --callback-port 8080 …), а claude mcp login <имя> использует записанное значение. Если порт занят, но в фоне уже работает локальный сервис на 8080. Claude Code не может запустить callback-сервер, OAuth flow падает. Проверьте свободность порта заранее: lsof -i :8080. Если занят — укажите другой порт, например --callback-port 9091.
Ошибка 4: Переменная установлена, но не в том файле.
Добавили переменную в ~/.bashrc, но используете zsh. Или добавили в ~/.zshrc, но Claude Code запускается через launchd который читает только ~/.zshenv. Симптом: Claude Code не видит переменную, хотя echo $TOKEN в терминале работает. Правило: секреты для интеграций — в ~/.zshenv, он читается и интерактивными сессиями, и скриптами, и launchd.
Когда нужно / когда нет
Нужно разобраться с OAuth flow, если:
- Подключаете MCP-сервер для корпоративного сервиса (Google Workspace, Microsoft 365) — там OAuth обязателен, личных API-ключей нет
- MCP-сервер в своей документации требует OAuth
- Хотите чтобы токен автоматически обновлялся (OAuth refresh tokens делают это без вашего участия)
Достаточно Personal Access Token, если:
- Сервис предоставляет статические API-ключи (Notion, большинство SaaS)
- Это личный, не корпоративный аккаунт
- Вам не нужен автоматический refresh — готовы раз в несколько месяцев обновить вручную
Не нужно усложнять, если:
- Вы единственный пользователь на машине, машина не общая, данные не критичные
- MCP-сервер работает с публично доступными данными без аутентификации
Обязательно нужно пересмотреть подход, если:
- Токен когда-либо случайно попал в файл который синхронизируется в облако
- На машине работают несколько человек
- MCP-сервер имеет доступ к персональным данным клиентов или финансовой информации
Связь с другими уроками
День 53 (Scopes MCP) — мы разбирали три уровня: local, project, user. Это напрямую связано с безопасностью токенов: токены с широкими правами логичнее хранить на уровне user scope (файл ~/.claude.json), чтобы они не оказывались в папках конкретных проектов.
День 51 (Что такое MCP) — базовая концепция. Если не до конца ясно зачем вообще MCP-серверу нужен токен — вернитесь к дню 51, там объясняется что именно MCP-сервер делает от вашего имени.
День 41–42 (события hooks, включая PreToolUse) — с помощью хуков можно добавить дополнительный контроль: логировать какие MCP-инструменты вызываются, и при необходимости блокировать нежелательные вызовы. Это второй уровень защиты помимо ограничений на уровне токена.
Задание на сегодня
Откройте .mcp.json в корне проекта (или ~/.claude.json, если добавляли серверы для себя) и проверьте: есть ли в нём токены напрямую в виде "KEY": "значение_токена" — не через ${VAR}.
Если есть — выполните ротацию: перенесите значение в ~/.zshenv как переменную (export MY_SERVICE_KEY="значение"), в .mcp.json замените значение на "${MY_SERVICE_KEY}", выполните source ~/.zshenv, убедитесь что Claude Code видит сервер через claude mcp list.
Критерий «выполнено»: в .mcp.json нет ни одного токена в открытом виде — только ссылки на переменные окружения.
Если токенов в файле не оказалось — вы всё делали правильно. В этом случае задание: убедитесь что ~/.zshenv существует и имеет правильные права: ls -la ~/.zshenv должен показать -rw------- (только вы можете читать и писать). Если права другие — исправьте: chmod 600 ~/.zshenv.
Резюме
- Токены хранятся в переменных окружения (
~/.zshenv), в.mcp.json— только ссылки через${VAR}. Никогда не в CLAUDE.md, не в файлах проекта напрямую. - OAuth проходится командой
claude mcp login <имя>; порт callback, если сервис требует конкретный, задаётся заранее флагом--callback-portуclaude mcp add; порт должен быть свободен и совпадать с ожиданиями сервиса. Отозвать вход —claude mcp logout <имя>. - Scopes — минимальные. Read-only если достаточно чтения; только нужные ресурсы, не «полный доступ к рабочему пространству».
- Ротация токенов: сначала создать новый, убедиться что работает, только потом отзывать старый.
- Один токен — одна задача. Разные интеграции — разные токены. Так при отзыве упадёт одно, а не всё.