Skip to content
This repository was archived by the owner on Nov 7, 2026. It is now read-only.

Latest commit

 

History

History
728 lines (607 loc) · 47.9 KB

SETUP.md

File metadata and controls

728 lines (607 loc) · 47.9 KB

SETUP.md -- скрипт настройки sysblok-mcp-bundle для агента

Ты -- AI-агент, который выполняет этот файл от имени коллеги-человека. Документ написан во втором лице, повелительном наклонении и обращён именно к ТЕБЕ. Человек только отвечает на вопросы и подтверждает действия по ходу дела -- не пересказывай ему этот файл и не проси выполнить шаги вручную самостоятельно.

Если у тебя есть Bash/shell-инструмент: сам этот файл нужно было получить через curl -fsSL <raw-url>, а не через инструмент, суммаризирующий веб-страницы -- ты сейчас будешь записывать его содержимое на диск дословно, а суммаризация могла бы его перефразировать или обрезать. Если у тебя есть только суммаризирующий web-fetch инструмент, попроси его воспроизвести содержимое документа дословно, а не описать его.

Всё нужное уже встроено ниже в виде блоков кода. Тебе не понадобятся git clone, git, Python или uv. Единственное условие -- Docker, проверяется на шаге 1. Node.js может дополнительно понадобиться на шаге 7, но только если MCP-клиент человека -- Claude Desktop.


Шаг 1 -- Проверка предварительных условий

Выполни:

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"), и только после этого повторяй команды выше.


Шаг 2 -- Выбор рабочей директории и создание файлов

Спроси у человека рабочую директорию, по умолчанию ~/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).


Шаг 3 -- Создание .env из .env.example

Скопируй только что записанный .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) уже заполнены как фиксированные константы, общие для всей организации -- спрашивать у человека здесь нечего.


Шаг 4 -- Application Password для WordPress

Проведи человека через шаги:

  1. Зайти на $WORDPRESS_SITE_URL/wp-admin/.
  2. Перейти в свой профиль (аватарка справа сверху, или /wp-admin/profile.php).
  3. Прокрутить до раздела "Application Passwords".
  4. Ввести имя (например, "sysblok-mcp-bundle"), нажать "Add New Application Password".
  5. Скопировать сгенерированный пароль точно как показано, включая пробелы.

Нужна роль 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), а не ошибка пользователя; в этом случае скажи человеку обратиться к администратору сайта, а не пытаться и дальше перегенерировать пароль.


Шаг 5 -- API-ключ Planka

В отличие от 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, причина та же.


Шаг 6 -- Запуск постоянного сервиса Google

Спроси у человека 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.


Шаг 7 -- Настройка конфига MCP-клиента

Сделай этот шаг до 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.


Шаг 8 -- OAuth-авторизация Google

Авторизация проходит не через ссылку в логах контейнера, а через сам MCP-клиент -- это единственный поддерживаемый в текущей версии образа способ (старый механизм со статичной auth-ссылкой в логах в этой версии отключён при OAuth 2.1). Конфиг из шага 7 уже должен быть записан и клиент перезапущен/переподключён -- иначе сервер google-workspace просто не появится в списке. Порядок действий зависит от клиента; для Claude Code:

  1. Скажи человеку открыть /mcp в Claude Code.
  2. Выбрать в списке google-workspace.
  3. Выбрать пункт "Authenticate" (или аналогичный, инициирующий вход).
  4. Клиент откроет браузер с экраном согласия 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 заново.


Шаг 9 -- GitHub: авторизация и проверка

Сервер 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. Лечится закрытием второго клиента, а не правкой конфига.


Шаг 10 -- Итог

Выведи чек-лист того, что сделано и что ещё осталось:

  • 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-сессии, запускаясь напрямую клиентом.


Обновление: переход с chmald/planka-mcp на sysblok/planka-mcp

Этот раздел -- не часть первичной настройки. Выполняй его, только если у человека бандл уже настроен по старой версии этого файла (в его docker-compose.yml есть сервис planka-mcp, а в конфиге клиента запись planka с "type": "sse" и http://127.0.0.1:3001/sse или с mcp-remote на этот адрес).

Зачем: старый сервер отдавал доску «СБъ. Редакция» целиком (больше 4 млн символов) и падал, а список карточек молча обрезал на 50. Форк отвечает компактно, листает большие колонки и показывает кастомные поля карточки по именам («Автор», «Google Doc», ...).

  1. Перезапиши в рабочей директории docker-compose.yml и .env.example блоками из шага 2. Из старого .env сохрани PLANKA_API_KEY -- ключ тот же, перевыпускать его не нужно. Добавь в .env новые переменные PLANKA_DEFAULT_BOARD_ID, PLANKA_READ_ONLY и новое значение PLANKA_MCP_VERSION из .env.example.

  2. Останови старый контейнер. Сервиса planka-mcp в compose больше нет, поэтому обычный docker compose up -d его не уберёт:

    docker compose up -d --remove-orphans

    (или точечно docker rm -f sysblok-mcp-planka). Порт 3001 после этого должен освободиться.

  3. Скачай новый образ, как в шаге 5: docker pull "ghcr.io/sysblok/planka-mcp:$PLANKA_MCP_VERSION".

  4. Замени в конфиге клиента запись 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 '<запись>' из той же директории, что и раньше.

  5. Полностью перезапусти клиента -- 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).