Ты -- AI-агент, который выполняет этот файл от имени коллеги-человека. Документ написан во втором лице, повелительном наклонении и обращён именно к ТЕБЕ. Человек только отвечает на вопросы и подтверждает действия по ходу дела -- не пересказывай ему этот файл и не проси выполнить шаги вручную самостоятельно.
Если у тебя есть Bash/shell-инструмент: сам этот файл нужно было получить через
curl -fsSL <raw-url>, а не через инструмент, суммаризирующий веб-страницы -- ты сейчас будешь записывать его содержимое на диск дословно, а суммаризация могла бы его перефразировать или обрезать. Если у тебя есть только суммаризирующий web-fetch инструмент, попроси его воспроизвести содержимое документа дословно, а не описать его.Всё нужное уже встроено ниже в виде блоков кода. Тебе не понадобятся
git clone,git, Python илиuv. Единственное условие -- Docker, проверяется на шаге 1. Node.js может дополнительно понадобиться на шаге 7, но только если MCP-клиент человека -- Claude Desktop.
Выполни:
docker --version
docker compose versionЕсли хоть одна команда не сработала или не найдена: остановись здесь. Скажи человеку установить Docker Desktop (macOS/Windows) или Docker Engine
- плагин Compose (Linux) и дождись подтверждения, что всё установлено, прежде чем продолжать. Не действуй на основе предположений -- убедись, что обе команды реально отрабатывают успешно.
На Windows Docker Desktop может дополнительно потребовать включить виртуализацию в BIOS/UEFI и установить WSL2 при первом запуске -- Docker Desktop сам покажет, чего именно не хватает, и как правило может сам поставить недостающее (WSL2) после подтверждения. Дождись, пока Docker Desktop полностью запустится (иконка в трее перестанет показывать "Starting"), и только после этого повторяй команды выше.
Спроси у человека рабочую директорию, по умолчанию ~/sysblok-mcp-bundle/,
если предпочтений нет. Создай её, затем запиши в неё три файла ниже
дословно, используя блоки кода из этого документа как их точное
содержимое (не перефразируй, не переформатируй и не "улучшай" их -- эти
блоки поддерживаются байт-в-байт идентичными отслеживаемым файлам этого
репозитория через CI, так что всё ниже уже корректно и протестировано):
docker-compose.yml:
name: sysblok-mcp
services:
google-workspace-mcp:
image: ghcr.io/taylorwilsdon/google_workspace_mcp:${GOOGLE_WORKSPACE_MCP_VERSION:-latest}
container_name: sysblok-mcp-google
restart: unless-stopped
# Не переопределяем command: у образа ENTRYPOINT ["/bin/sh","-c"] и
# дефолтный CMD -- одна shell-строка вида
# `uv run main.py --transport streamable-http ${TOOL_TIER:+--tool-tier "$TOOL_TIER"} ...`,
# которая уже сама подставляет --transport и читает переменные TOOL_TIER
# и TOOLS. Переопределение command списком ломает это: /bin/sh -c
# получает наш список как command-string + позиционные параметры, а не
# как единственный аргумент -c (проверено: контейнер падал в краш-луп с
# `/bin/sh: 0: Illegal option --`).
environment:
- MCP_ENABLE_OAUTH21=true
- WORKSPACE_MCP_TRANSPORT=streamable-http
- WORKSPACE_MCP_HOST=0.0.0.0
- WORKSPACE_MCP_PORT=8000
- TOOL_TIER=${GOOGLE_WORKSPACE_TOOL_TIER:-core}
# --tool-tier сам по себе -- горизонтальный срез уровня "core" по ВСЕМ
# 12 сервисам образа (gmail, calendar, chat, contacts, forms, slides,
# tasks, search, appscript, ...), а не фильтр по конкретным сервисам.
# Без TOOLS ниже OAuth consent запросит доступ к Gmail/Calendar/etc.,
# хотя бандл заявлен как Docs+Sheets+Drive-only.
- TOOLS=${GOOGLE_WORKSPACE_TOOLS:-docs sheets drive}
- GOOGLE_OAUTH_CLIENT_ID=${GOOGLE_OAUTH_CLIENT_ID}
- GOOGLE_OAUTH_CLIENT_SECRET=${GOOGLE_OAUTH_CLIENT_SECRET}
- GOOGLE_OAUTH_REDIRECT_URI=http://localhost:8000/oauth2callback
- OAUTHLIB_INSECURE_TRANSPORT=1
# Образ работает под непривилегированным uid=1000(app), HOME=/home/app --
# /root закрыт для этого пользователя (0700 root:root), путь /root/...
# для этого образа непригоден (Permission denied).
- WORKSPACE_MCP_CREDENTIALS_DIR=/home/app/.google_workspace_mcp/credentials
ports:
# только localhost, и это обязательно: браузер стучится напрямую на
# localhost:8000 для OAuth-редиректа, поэтому порт должен быть
# опубликован на хосте, а не быть просто адресом во внутренней сети
# compose.
- "127.0.0.1:8000:8000"
volumes:
# bind mount, а не именованный volume, чтобы SETUP.md/человек могли
# проверить успешность авторизации простым `ls ./google-credentials`.
# Не кладём эту директорию под data/ -- если Docker успевает создать
# bind-mount директорию до первого успешного запуска, она достаётся
# root, и повторные попытки падают с Permission denied.
- ./google-credentials:/home/app/.google_workspace_mcp/credentials.env.example:
# ==============================================================================
# sysblok-mcp-bundle -- переменные окружения
# Скопируйте этот файл в .env и заполните пропуски. .env добавлен в
# .gitignore и никогда не должен коммититься -- см. раздел "Секреты" в README.md.
# ==============================================================================
# ---- Planka MCP (sysblok/planka-mcp) ----------------------------------------
# ПРИМЕЧАНИЕ: Planka MCP, как и WordPress MCP, НЕ управляется через
# docker-compose -- он работает только по stdio и запускается по требованию
# вашим MCP-клиентом (см. client-config.example.json). Эти значения всё
# равно хранятся в .env, чтобы SETUP.md мог прочитать их один раз и сразу
# прописать в конфиг клиента. Это форк omnicoreos/planka-mcp с правками под
# нашу доску (перенесённые из других трекеров данные, имена кастомных
# полей): https://github.com/sysblok/planka-mcp
# ОДНОКРАТНО, общая для всех константа: прод-инстанс Planka в sysblok.
PLANKA_BASE_URL=https://board.sysblok.team
# СВОЙ У КАЖДОГО, НО САМОСТОЯТЕЛЬНО НЕ СГЕНЕРИРОВАТЬ: у обычных
# пользователей Planka нет доступа к разделу API Keys в своих настройках --
# это может сделать только администратор через Administration -> Users ->
# (ваш аккаунт) -> Actions -> сгенерировать API Key. Попросите админа
# сгенерировать ключ для вашего аккаунта и прислать его вам -- ключ
# показывается только один раз в момент генерации, потом его не
# восстановить, только перевыпустить новый.
PLANKA_API_KEY=
# ОДНОКРАТНО, общая для всех константа: id доски «СБъ. Редакция». С ним
# boardId становится необязательным во всех инструментах, и агенту не
# нужно каждый раз искать доску через planka_get_structure. Другие доски
# остаются доступны -- это значение по умолчанию, а не ограничение.
PLANKA_DEFAULT_BOARD_ID=1773630445443876227
# ОДНОКРАТНО, общая для всех константа: ни один скилл в sysblok/sysblok-ai
# не пишет в Planka, поэтому 27 пишущих инструментов (создание, перенос,
# удаление карточек, комментарии, ...) скрыты от агента. Ключ при этом
# остаётся с правами вашего аккаунта -- это ограничение на стороне сервера,
# а не в самой Planka. Выключайте (false), только если появится скилл,
# которому нужна запись.
PLANKA_READ_ONLY=true
# Тег образа ghcr.io/sysblok/planka-mcp, который SETUP.md прописывает в
# запись "planka" конфига клиента. Закреплён на конкретном релизе, НЕ
# `latest`: при обновлении поменяйте его здесь и в client-config.example.json.
# Остальные необязательные переменные сервера (PLANKA_ALLOWED_BOARD_IDS,
# PLANKA_DISABLED_TOOLS, PLANKA_PROTECTED_LIST_IDS, ...) описаны в README
# форка, раздел "Scoping the server"; каждую нужно добавить и в `env`, и
# отдельным `-e ИМЯ` в `args` записи "planka".
PLANKA_MCP_VERSION=v0.3.0-sysblok.1
# ---- WordPress MCP (docdyhr/mcp-wordpress) ----------------------------------
# ПРИМЕЧАНИЕ: WordPress MCP НЕ управляется через docker-compose -- он работает
# только по stdio и запускается по требованию вашим MCP-клиентом (см.
# client-config.example.json). Эти значения всё равно хранятся в .env, чтобы
# SETUP.md мог прочитать их один раз и сразу прописать в конфиг клиента.
# ОДНОКРАТНО, общая для всех константа: адрес сайта WordPress sysblok.
WORDPRESS_SITE_URL=https://sysblok.ru
# СВОЙ У КАЖДОГО, генерируется самостоятельно: wp-admin -> ваш профиль ->
# Application Passwords -> "New Application Password Name" -> Add New.
# Нужна роль Editor или выше. Скопируйте сгенерированный пароль точно как
# показано, включая пробелы. ВАЖНО: пароль содержит пробелы (формат
# `xxxx xxxx xxxx xxxx xxxx xxxx`) -- обязательно берите значение в
# кавычки, иначе большинство инструментов (source, docker compose
# --env-file) обрежут его по первому пробелу или сломают команду.
WORDPRESS_USERNAME=
WORDPRESS_APP_PASSWORD=
# ---- Google Workspace MCP (taylorwilsdon/google_workspace_mcp) -------------
# ОДНОКРАТНО, ПРЕДОСТАВЛЯЕТСЯ АДМИНОМ: общий на всю организацию OAuth Client
# ID/Secret типа "Web application" (НЕ "Desktop app" -- у нас фиксированный
# redirect URI на постоянно работающем контейнере, а не динамический
# loopback-порт нативного приложения). Создаётся один раз в Google Cloud
# Console со scope'ами Docs+Sheets+Drive и зарегистрированным redirect URI
# http://localhost:8000/oauth2callback. ЭТО РЕАЛЬНЫЙ СЕКРЕТ: в отличие от
# Desktop-приложений, Google считает Client Secret Web-приложений
# конфиденциальным. Раздаётся админом отдельным каналом -- НЕ через этот
# репозиторий и НЕ в публичный канал, и никогда не должен попасть в git.
GOOGLE_OAUTH_CLIENT_ID=
GOOGLE_OAUTH_CLIENT_SECRET=
# Какой УРОВЕНЬ инструментов открывать -- но учтите: --tool-tier это
# горизонтальный срез "core"/"extended"/"complete" ПО ВСЕМ 12 сервисам
# образа (gmail, calendar, chat, contacts, forms, slides, tasks, search,
# appscript, docs, sheets, drive), а не переключатель "дай мне только
# Docs+Sheets+Drive". За выбор конкретных сервисов отвечает переменная
# GOOGLE_WORKSPACE_TOOLS ниже -- обе переменные работают вместе.
GOOGLE_WORKSPACE_TOOL_TIER=core
# Какие СЕРВИСЫ открывать -- вот это и есть Docs+Sheets+Drive-only,
# под что рассчитан бандл. Не меняйте, если не уверены, что нужны другие
# сервисы Google Workspace.
GOOGLE_WORKSPACE_TOOLS=docs sheets drive
# Опционально: закрепить конкретный тег образа google_workspace_mcp вместо
# `latest`.
GOOGLE_WORKSPACE_MCP_VERSION=latest
# ---- GitHub MCP (github/github-mcp-server) ----------------------------------
# ПРИМЕЧАНИЕ: GitHub MCP, как и WordPress MCP, НЕ управляется через
# docker-compose -- он работает только по stdio и запускается по требованию
# вашим MCP-клиентом (см. client-config.example.json).
#
# В ЭТОЙ СЕКЦИИ НЕТ НИ ОДНОГО ОБЯЗАТЕЛЬНОГО СЕКРЕТА. В отличие от Google
# Workspace, здесь нет выдаваемых админом client ID и client secret: в
# официальный образ ghcr.io/github/github-mcp-server уже зашито
# зарегистрированное OAuth-приложение GitHub, поэтому на github.com сервер
# стартует вообще без токена и без client ID. Авторизация проходит в
# браузере при первом обращении агента к инструменту -- см. SETUP.md, шаг 9.
# ОДНОКРАТНО, общая для всех константа: репозиторий скиллов, куда агент
# заводит issue. Автоматически её никто не читает -- у GitHub MCP нет
# привязки к репозиторию, реальную границу задаёт только выданный доступ.
# Она нужна, чтобы агент знал, куда писать, и чтобы на шаге 9 было что
# проверить.
GITHUB_ISSUES_REPO=sysblok/sysblok-ai
# СВОЙ У КАЖДОГО, генерируется самостоятельно -- НО ТОЛЬКО КАК ЗАПАСНОЙ
# ПУТЬ, поэтому строка ниже закомментирована. Штатный способ -- OAuth, для
# него здесь заполнять нечего. Токен нужен, только если организация
# запрещает доступ сторонним OAuth-приложениям и админ не готов одобрить
# приложение GitHub MCP Server. Заводится как fine-grained token: GitHub ->
# Settings -> Developer settings -> Personal access tokens -> Fine-grained
# tokens, владелец ресурса sysblok, доступ только к репозиторию sysblok-ai,
# права Issues: Read and write и Metadata: Read. Для репозитория
# организации такой токен может потребовать отдельного одобрения
# владельцем организации. Если переменная задана, она ПЕРЕБИВАЕТ OAuth --
# но её недостаточно прописать здесь, её нужно ещё прокинуть в конфиг
# клиента (см. SETUP.md, шаг 9).
# GITHUB_PERSONAL_ACCESS_TOKEN=client-config.example.json:
{
"mcpServers": {
"wordpress": {
"command": "docker",
"args": [
"run", "-i", "--rm",
"-e", "WORDPRESS_SITE_URL",
"-e", "WORDPRESS_USERNAME",
"-e", "WORDPRESS_APP_PASSWORD",
"docdyhr/mcp-wordpress:latest"
],
"env": {
"WORDPRESS_SITE_URL": "<будет заполнено SETUP.md из .env>",
"WORDPRESS_USERNAME": "<будет заполнено SETUP.md из .env>",
"WORDPRESS_APP_PASSWORD": "<будет заполнено SETUP.md из .env>"
}
},
"planka": {
"command": "docker",
"args": [
"run", "-i", "--rm",
"-e", "PLANKA_BASE_URL",
"-e", "PLANKA_API_KEY",
"-e", "PLANKA_DEFAULT_BOARD_ID",
"-e", "PLANKA_READ_ONLY",
"ghcr.io/sysblok/planka-mcp:v0.3.0-sysblok.1"
],
"env": {
"PLANKA_BASE_URL": "<будет заполнено SETUP.md из .env>",
"PLANKA_API_KEY": "<будет заполнено SETUP.md из .env>",
"PLANKA_DEFAULT_BOARD_ID": "<будет заполнено SETUP.md из .env>",
"PLANKA_READ_ONLY": "<будет заполнено SETUP.md из .env>"
}
},
"google-workspace": {
"type": "http",
"url": "http://localhost:8000/mcp"
},
"github": {
"command": "docker",
"args": [
"run", "-i", "--rm",
"-p", "127.0.0.1:8085:8085",
"-e", "GITHUB_OAUTH_CALLBACK_PORT",
"-e", "GITHUB_OAUTH_SCOPES",
"-e", "GITHUB_TOOLSETS",
"ghcr.io/github/github-mcp-server"
],
"env": {
"GITHUB_OAUTH_CALLBACK_PORT": "8085",
"GITHUB_OAUTH_SCOPES": "repo",
"GITHUB_TOOLSETS": "issues,context"
}
}
}
}Обрати внимание: google-workspace указывает на localhost, а не
127.0.0.1 -- это не опечатка. У Google-сервиса
GOOGLE_OAUTH_REDIRECT_URI зафиксирован на localhost, и для OAuth 2.1
resource-indicator matching URL клиента должен совпадать по origin с этим
redirect URI буквально (localhost и 127.0.0.1 считаются разными
origin, хотя технически один и тот же loopback-адрес).
У planka, wordpress и github URL нет вообще: это stdio-серверы,
клиент сам запускает их через docker run -i --rm на время сессии и
говорит с ними через stdin/stdout. planka и wordpress портов не
занимают; github публикует только порт 8085 для OAuth-редиректа (см.
шаг 9).
Скопируй только что записанный .env.example в .env в той же
директории. PLANKA_BASE_URL (https://board.sysblok.team),
PLANKA_DEFAULT_BOARD_ID (доска «СБъ. Редакция»), PLANKA_READ_ONLY,
PLANKA_MCP_VERSION и WORDPRESS_SITE_URL (https://sysblok.ru) уже
заполнены как фиксированные константы, общие для всей организации --
спрашивать у человека здесь нечего.
Проведи человека через шаги:
- Зайти на
$WORDPRESS_SITE_URL/wp-admin/. - Перейти в свой профиль (аватарка справа сверху, или
/wp-admin/profile.php). - Прокрутить до раздела "Application Passwords".
- Ввести имя (например, "sysblok-mcp-bundle"), нажать "Add New Application Password".
- Скопировать сгенерированный пароль точно как показано, включая пробелы.
Нужна роль Editor или выше. Запиши WORDPRESS_USERNAME и
WORDPRESS_APP_PASSWORD в .env. Пароль содержит пробелы (формат
xxxx xxxx xxxx xxxx xxxx xxxx) -- обязательно возьми значение в
кавычки: WORDPRESS_APP_PASSWORD="xxxx xxxx xxxx xxxx xxxx xxxx". Без
кавычек значение обрежется по первому пробелу или сломает команду при
чтении файла. Прежде чем идти дальше, проверь, что всё реально работает:
curl -u "$WORDPRESS_USERNAME:$WORDPRESS_APP_PASSWORD" \
"$WORDPRESS_SITE_URL/wp-json/wp/v2/users/me"Должен вернуться HTTP 200 с JSON ожидаемого пользователя, а не 401. Если
не сработало -- не гадай, в чём дело, покажи человеку реальную ошибку и
попроси перепроверить, что пароль скопирован верно и взят в кавычки.
Если ошибка стабильно incorrect_password даже после аккуратной
перегенерации пароля -- это может быть серверная проблема (nginx не
прокидывает заголовок Authorization в PHP-FPM), а не ошибка
пользователя; в этом случае скажи человеку обратиться к администратору
сайта, а не пытаться и дальше перегенерировать пароль.
В отличие от WordPress, здесь нет самостоятельной генерации: у обычных пользователей Planka нет раздела API Keys в своих настройках -- это может сделать только администратор, и только через панель Administration -> Users, выбрав нужного пользователя (даже свой собственный ключ администратор не может сгенерировать из своего же профиля -- ему тоже нужно зайти туда через список пользователей).
Спроси у человека, есть ли у него уже ключ, полученный от админа. Если нет -- скажи ему написать админу с просьбой сгенерировать API-ключ для его аккаунта в Planka и прислать его. Дождись, пока ключ не будет получен, прежде чем продолжать -- у тебя нет способа сгенерировать его самостоятельно.
Запиши PLANKA_API_KEY в .env. Проверь:
curl -H "X-Api-Key: $PLANKA_API_KEY" "$PLANKA_BASE_URL/api/users/me"Должен вернуться HTTP 200 с JSON ожидаемого пользователя.
Planka MCP запускается не через docker compose, а самим клиентом по
требованию (как WordPress и GitHub), поэтому скачай образ заранее --
тег возьми из PLANKA_MCP_VERSION в .env:
docker pull "ghcr.io/sysblok/planka-mcp:$PLANKA_MCP_VERSION"Иначе образ начнёт тянуться при первом же обращении клиента к серверу,
и вызов инструмента может отвалиться по таймауту. Если pull падает с
denied: denied -- см. ниже в шаге 6 про протухший docker login ghcr.io, причина та же.
Спроси у человека GOOGLE_OAUTH_CLIENT_ID и GOOGLE_OAUTH_CLIENT_SECRET
(предоставляются админом, это общие для всей организации значения --
никогда не придумывай и не угадывай их, спроси человека или скажи ему
спросить админа). Запиши их в .env.
Из рабочей директории выполни:
docker compose up -dЕсли docker compose up падает с denied: denied при попытке
скачать ghcr.io/taylorwilsdon/google_workspace_mcp, хотя образ
публичный: скорее всего на машине человека когда-то раньше был сделан
docker login ghcr.io с токеном, который с тех пор протух. Docker в
этом случае не откатывается на анонимный pull -- просто падает.
Почини: docker logout ghcr.io, затем повтори docker compose up -d.
Убедись, что сервис реально доступен -- не доверяй только статусу
docker compose ps, проверь порт напрямую:
curl -sf -o /dev/null -w "google-workspace-mcp: %{http_code}\n" http://127.0.0.1:8000/mcp || echo "google-workspace-mcp: недоступен"Любой ответ, кроме отказа в соединении (даже 4xx), означает, что сервис поднят и слушает порт. Не переходи к шагу 8, пока он не ответит -- шагу 7 (конфиг клиента) это не требуется, но шагу 8 (OAuth) требуется.
Если google-workspace-mcp падает с Permission denied на путь
.../google_workspace_mcp/credentials -- вероятно, директория
./google-credentials на хосте уже существует и принадлежит root
(Docker создаёт bind-mount директории от root, если их не было до
первого запуска, а первый запуск упал по другой причине раньше, чем
успел туда что-то записать). Почини: sudo rm -rf ./google-credentials
(или sudo chown -R $(whoami) ./google-credentials), затем mkdir ./google-credentials и повтори docker compose up -d.
Сделай этот шаг до OAuth-авторизации (шаг 8), а не после -- клиент не покажет кнопку "Authenticate" для сервера, о котором ещё не знает из своего конфига.
Спроси у человека, каким MCP-клиентом он пользуется (Claude Code, Claude Desktop или другим). Найди его реальный конфиг-файл для его ОС:
| Клиент | macOS | Windows | Linux |
|---|---|---|---|
| Claude Desktop | ~/Library/Application Support/Claude/claude_desktop_config.json |
%APPDATA%\Claude\claude_desktop_config.json |
~/.config/Claude/claude_desktop_config.json |
| Claude Code | .mcp.json в текущей директории проекта, либо claude mcp add |
так же | так же |
Прежде чем что-либо записывать: прочитай файл, если он уже существует.
Покажи человеку точное изменение, которое собираешься сделать -- слияние
четырёх записей mcpServers из client-config.example.json (с
подстановкой значений WordPress и Planka из .env в блоки env; тег
образа в args записи planka должен совпадать с PLANKA_MCP_VERSION)
в его существующий конфиг, не удаляя и не перезаписывая остальные записи,
которые там уже есть. Обязательно получи явное подтверждение перед
записью -- это реальное изменение файлов самого человека.
Для Claude Code предпочти claude mcp add-json (если CLI доступен)
ручному редактированию .mcp.json -- это избавляет от ручных ошибок
слияния JSON. Учти также: конфиг, добавленный с -s local, привязан к
той рабочей директории проекта, в которой была вызвана команда -- если
интерактивная сессия потом запускается из другой директории, /mcp не
увидит добавленный сервер без явной ошибки. Убедись, что команда
выполняется из той же директории, откуда человек обычно запускает
клиента. Также стоит свериться с claude mcp list на предмет других
локальных MCP-серверов, уже занимающих порты 8000/8085 -- конфликт
порта тоже проявляется не как явная ошибка, а как молчаливая
недоступность. С 8085 (его публикует контейнер github) отличие в
другом: этот порт занят всё время, пока живёт MCP-сессия, и при
конфликте контейнер вообще не стартует -- подробности на шаге 9.
Контейнеры planka и wordpress портов не занимают вообще.
Если клиент -- Claude Desktop, client-config.example.json в
исходном виде не сработает для google-workspace.
Локальный claude_desktop_config.json в Claude Desktop поддерживает
только stdio-серверы (command/args) -- записи с "type": "sse" или
"type": "http" он молча отбрасывает при загрузке, и в списке серверов
может оказаться пусто, хотя сам JSON-файл синтаксически корректен и
wordpress (stdio) в нём есть. У Claude Desktop подключить такой сервер
через файл конфига нельзя вообще -- удалённые серверы там добавляются
только через UI (Settings -> Connectors -> "Add custom connector"), а
это соединение устанавливает облако Anthropic, а не компьютер человека,
поэтому там требуется публично доступный HTTPS-адрес.
google-workspace-mcp нарочно опубликован только на 127.0.0.1 (см.
комментарий про порт в docker-compose.yml), и выставлять его в
публичный интернет через ngrok/Cloudflare Tunnel нельзя, так что путь
через "Add custom connector" для него не подходит принципиально, а не
из-за версии клиента.
Рабочий путь для google-workspace в Claude Desktop -- тот
же локальный мост mcp-remote, что и для по-настоящему старых клиентов:
он работает на компьютере человека, а не в облаке, и представляется
Claude Desktop обычным stdio-сервером, который файл конфига понимает.
Понадобится установленный Node.js (для npx). Замени в конфиге запись
google-workspace на:
"google-workspace": {
"command": "npx",
"args": ["-y", "mcp-remote", "http://localhost:8000/mcp"]
}wordpress, planka и github в конфиге не трогай -- они и так
stdio, mcp-remote им не нужен.
У Claude Desktop нет слэш-команды /mcp (это специфика Claude Code) --
статус серверов и переподключение для Claude Desktop смотри в Settings
-> Developer.
Авторизация проходит не через ссылку в логах контейнера, а через сам
MCP-клиент -- это единственный поддерживаемый в текущей версии образа
способ (старый механизм со статичной auth-ссылкой в логах в этой версии
отключён при OAuth 2.1). Конфиг из шага 7 уже должен быть записан и
клиент перезапущен/переподключён -- иначе сервер google-workspace
просто не появится в списке. Порядок действий зависит от клиента; для
Claude Code:
- Скажи человеку открыть
/mcpв Claude Code. - Выбрать в списке
google-workspace. - Выбрать пункт "Authenticate" (или аналогичный, инициирующий вход).
- Клиент откроет браузер с экраном согласия Google -- человек проходит его под своим личным аккаунтом.
Если клиент -- Claude Desktop и google-workspace настроен через
mcp-remote (см. шаг 7): явной кнопки "Authenticate" может не быть --
mcp-remote сам откроет браузер с экраном согласия Google при первой
попытке клиента вызвать инструмент этого сервера. Если браузер не
открылся сам, попроси человека задать агенту любой вопрос про Google
Docs/Sheets/Drive (или переподключить сервер через Settings ->
Developer) -- это и есть тот "первый вызов", который запускает OAuth.
Если клиент -- что-то ещё, скажи человеку поискать аналогичное действие
"Authenticate"/"Connect"/"Sign in" рядом с сервером google-workspace --
сам сервер инициативно ссылку не покажет, инициатива со стороны клиента.
Убедись в успехе, дожидаясь появления файла с креденшелами на хосте, а не спрашивая "получилось?":
ls ./google-credentials/Появление файла там -- конкретный, проверяемый признак того, что
авторизация прошла успешно. Если через минуту-две ничего не появилось,
проверь логи контейнера на ошибки (docker compose logs google-workspace-mcp) и убедись, что шаг с "Authenticate" (или первый
вызов инструмента, для mcp-remote) был пройден до конца, а не просто
начат.
Если ранее уже проходили эту авторизацию с более широким набором
разрешений (до того, как GOOGLE_WORKSPACE_TOOLS сузил доступ до
Docs+Sheets+Drive) -- сам грант на аккаунте Google останется широким,
пока его не отозвать вручную на
https://myaccount.google.com/permissions и не пройти consent заново.
Сервер github нужен, чтобы агент мог сам заводить issue в репозитории
скиллов (GITHUB_ISSUES_REPO, по умолчанию sysblok/sysblok-ai) -- на
это рассчитаны скиллы вроде report-skill-problem.
Сначала скачай образ заранее:
docker pull ghcr.io/github/github-mcp-serverЭто не формальность: иначе образ начнёт тянуться при первом же обращении клиента к серверу, и вызов инструмента может отвалиться по таймауту -- со стороны это выглядит как сломанный сервер, а не как идущая загрузка.
Здесь нет ни токена, ни client ID -- и это не упущение. В
официальный образ уже зашито зарегистрированное OAuth-приложение GitHub,
поэтому на github.com сервер стартует вообще без секретов. В .env для
GitHub заполнять нечего, у админа ничего просить не нужно.
Авторизация запускается лениво -- при первом обращении агента к
инструменту GitHub, а не при старте клиента. Отдельной кнопки
"Authenticate", как у google-workspace на шаге 8, здесь может не быть.
Тот самый первый вызов -- это и есть проверка ниже. Контейнер не может
открыть браузер на машине человека, поэтому ссылка на авторизацию придёт
либо отдельным запросом клиента, либо прямо в ответе инструмента --
человеку нужно её открыть и пройти согласие GitHub.
Токен живёт только в памяти контейнера и на диск не пишется. Значит, после перезапуска MCP-клиента авторизацию нужно будет пройти заново. Так и задумано -- не считай это поломкой и не чини конфиг. Повторный проход быстрый: грант на аккаунте уже выдан, и GitHub обычно сразу редиректит обратно, без второго экрана согласия.
Проверяй результат по реальным данным, а не вопросом "получилось?":
попроси агента показать открытые issue в $GITHUB_ISSUES_REPO и покажи
человеку реальные заголовки. Учти: curl-проверки, как на шагах 4 и 5,
здесь нет и быть не может -- проверять нечем, токена в .env нет.
Если авторизация прошла, но репозиторий не виден (пусто, 404 или "not
found") -- почти наверняка дело не в ошибке человека. Организация может
запрещать доступ сторонним OAuth-приложениям, и тогда приложение GitHub
MCP Server должен одобрить владелец организации
(https://github.com/organizations/sysblok/settings/oauth_application_policy).
Скажи человеку написать админу, а не проходи авторизацию по кругу.
Запасной путь, если одобрения не будет: fine-grained token вместо OAuth
(как его завести -- написано в комментарии к
GITHUB_PERSONAL_ACCESS_TOKEN в .env.example). Одного .env для него
недостаточно: в записи github в конфиге клиента нужно добавить
"-e", "GITHUB_PERSONAL_ACCESS_TOKEN" в args и сам токен в env.
Заданный токен перебивает OAuth, и -p с переменными GITHUB_OAUTH_* в
этом случае уже не нужны.
Отдельно распознавай ещё одну ситуацию: занятый порт 8085. Он нужен для
OAuth-редиректа и публикуется на всё время жизни контейнера, то есть на
всю MCP-сессию, а не только на момент авторизации. Если порт уже занят,
до сервера дело даже не доходит -- падает сам docker run, с кодом 125
и сообщением вида:
failed to bind host port for 127.0.0.1:8085: address already in use
В клиенте это выглядит как сервер github, который не смог
подключиться, а вовсе не как проблема с авторизацией. Самая частая
причина -- второй MCP-клиент (например, одновременно запущенные Claude
Code и Claude Desktop), у которого уже поднят свой контейнер github.
Лечится закрытием второго клиента, а не правкой конфига.
Выведи чек-лист того, что сделано и что ещё осталось:
- Docker установлен и работает
- Application Password для WordPress проверен
- API-ключ Planka проверен, образ
ghcr.io/sysblok/planka-mcpскачан -
google-workspace-mcpпослеdocker compose up -dдоступен - Конфиг MCP-клиента записан (подтверждено человеком)
- Google OAuth пройден через клиент, креденшелы появились в
./google-credentials/ - GitHub: авторизация пройдена, issue в
sysblok/sysblok-aiвидны
Напомни человеку про две команды, которые понадобятся позже:
docker compose up -d # снова запустить google-workspace-mcp
docker compose down # остановить егоСерверам WordPress, Planka и GitHub запуск/остановка не нужны -- они работают только на протяжении каждой MCP-сессии, запускаясь напрямую клиентом.
Этот раздел -- не часть первичной настройки. Выполняй его, только если у
человека бандл уже настроен по старой версии этого файла (в его
docker-compose.yml есть сервис planka-mcp, а в конфиге клиента запись
planka с "type": "sse" и http://127.0.0.1:3001/sse или с
mcp-remote на этот адрес).
Зачем: старый сервер отдавал доску «СБъ. Редакция» целиком (больше 4 млн символов) и падал, а список карточек молча обрезал на 50. Форк отвечает компактно, листает большие колонки и показывает кастомные поля карточки по именам («Автор», «Google Doc», ...).
-
Перезапиши в рабочей директории
docker-compose.ymlи.env.exampleблоками из шага 2. Из старого.envсохраниPLANKA_API_KEY-- ключ тот же, перевыпускать его не нужно. Добавь в.envновые переменныеPLANKA_DEFAULT_BOARD_ID,PLANKA_READ_ONLYи новое значениеPLANKA_MCP_VERSIONиз.env.example. -
Останови старый контейнер. Сервиса
planka-mcpв compose больше нет, поэтому обычныйdocker compose up -dего не уберёт:docker compose up -d --remove-orphans
(или точечно
docker rm -f sysblok-mcp-planka). Порт 3001 после этого должен освободиться. -
Скачай новый образ, как в шаге 5:
docker pull "ghcr.io/sysblok/planka-mcp:$PLANKA_MCP_VERSION". -
Замени в конфиге клиента запись
plankaцеликом на запись изclient-config.example.json(шаг 2) с подстановкой значений из.env-- с теми же правилами, что в шаге 7: показать изменение и получить подтверждение, остальные записи не трогать. В Claude Desktop мостmcp-remoteдляplankaбольше не нужен: запись теперь stdio. Для Claude Code:claude mcp remove planka, затемclaude mcp add-json planka '<запись>'из той же директории, что и раньше. -
Полностью перезапусти клиента -- MCP-серверы загружаются при старте сессии.
Названия инструментов поменялись: вместо boards, lists, cards и
т. п. теперь planka_get_structure, planka_board_summary,
planka_find_cards, planka_get_card и другие с префиксом planka_.
Если у человека в .claude/settings.json (или аналоге) есть правила
разрешений вида mcp__planka__cards, замени их на новые имена.
Проверь по реальным данным: попроси агента вызвать
planka_board_summary и покажи человеку колонки доски «СБъ. Редакция»
с числом карточек. Пишущих инструментов агент видеть не должен
(PLANKA_READ_ONLY=true).