DevOps и ChatOps

Slack MCP-сервер: Автоматизация ChatOps и командных AI-агентов

Быстрый ответ: Slack MCP-сервер подключает AI-агентов (Claude Code, Cursor, Windsurf) и автономных ботов к рабочим пространствам Slack по протоколу Model Context Protocol. Сервер предоставляет инструменты отправки сообщений, анализа тредов и интерактивных согласований через Block Kit (Human-in-the-Loop), превращая Slack в безопасный пульт управления ChatOps с контролем OAuth2-скоупов.


1. Введение: От примитивных чат-ботов к агентному ChatOps в 2026 году

В современных инженерных командах Slack выступает центральной нервной системой: алерты pull request'ов, сбои CI/CD-пайплайнов, инциденты PagerDuty и кросс-функциональные архитектурные дискуссии стекаются в специализированные каналы. Однако исторически автоматизация взаимодействий со Slack оставалась крайне неудобной.

Традиционные боты для Slack опирались на жесткие правила, поиск по ключевым словам или хрупкие вебхуки. При возникновении аварии инженерам приходилось:

  • Постоянно переключать контекст из IDE в Slack.
  • Продираться сквозь сотни разрозненных сообщений в тредах, чтобы восстановить хронологию инцидента.
  • Вручную сопоставлять логи ошибок с коммитами Git и метриками Kubernetes.
  • Вводить длинные команды в CLI или вручную подтверждать деплои в консолях облачных провайдеров.

Появление открытого протокола Model Context Protocol (MCP) объединило то, как большие языковые модели (LLM) взаимодействуют с внешними инструментами и API. Вместо разработки узкоспециализированных интеграций, требующих отдельного хостинга и сложной обработки вебхуков, разработчики теперь развертывают Slack MCP-сервер.

Предоставляя Slack в виде стандартизированного набора mcp tool агентам Claude Code, Cursor IDE, Windsurf или автономным swarm-системам, команды получают полноценный ChatOps MCP. Автономный slack bot ai agent умеет:

  1. Выполнять саммаризацию многоканальных тредов и формировать емкие технические выжимки.
  2. Автоматизировать реагирование на инциденты: создавать аварийные каналы (war rooms), приглашать дежурных, собирать телеметрию и генерировать списки действий (runbooks).
  3. Обеспечивать интерактивное согласование опасных действий (Human-in-the-Loop) через UI-компоненты Slack Block Kit перед применением миграций БД или релизом в прод.
  4. Проводить кросс-платформенные расследования, сопоставляя контекст Slack с PR на GitHub, ошибками в Sentry и логами баз данных.
+----------------------------------------------------------------------------------------------------+
|                         АРХИТЕКТУРА АГЕНТНОГО CHATOPS ЧЕРЕЗ SLACK MCP                              |
+----------------------------------------------------------------------------------------------------+
                                                  |
              +-----------------------------------+-----------------------------------+
              |                                                                       |
              v                                                                       v
+-------------------------------+                                   +-------------------------------+
|       Команда инженеров       |                                   |  Мониторинг и наблюдаемость   |
| - Каналы и треды в Slack      |                                   | - Datadog / Sentry / CloudWatch|
| - Клики по интерактивным кнопкам|                                 | - CI/CD алерты (GitHub/GitLab)|
+---------------+---------------+                                   +---------------+---------------+
                |                                                                   |
                | Читает/пишет сообщения и аппрувы                                  | Отправляет вебхуки алертов
                v                                                                   v
+----------------------------------------------------------------------------------------------------+
|                                ИНФРАСТРУКТУРА SLACK API И WORKSPACE                                |
|           (Web API, Socket Mode, Block Kit Engine, Event Subscriptions, OAuth2 Scopes)             |
+-------------------------------------------------+--------------------------------------------------+
                                                  |
                                                  | Model Context Protocol (stdio / SSE JSON-RPC 2.0)
                                                  v
+----------------------------------------------------------------------------------------------------+
|                                        SLACK MCP-СЕРВЕР                                            |
|                              (@modelcontextprotocol/server-slack)                                  |
|                                                                                                    |
|  Инструменты MCP:                                                                                  |
|  - slack_post_message           - slack_get_channel_history       - slack_list_channels            |
|  - slack_post_reply             - slack_get_thread_replies        - slack_add_reaction             |
|  - slack_post_block_approval    - slack_get_user_profile          - slack_search_messages          |
+-------------------------------------------------+--------------------------------------------------+
                                                  |
              +-----------------------------------+-----------------------------------+
              |                                                                       |
              v                                                                       v
+-------------------------------+                                   +-------------------------------+
|    Локальные клиенты в IDE    |                                   |   Автономные фоновые демоны   |
| - Claude Code CLI             |                                   | - Swarm-агенты триажа аварий  |
| - Cursor IDE / Windsurf       |                                   | - Агенты гейткипинга релизов  |
| - Расширения Roo Code / Cline |                                   | - Роботы на OpenClaw/LangGraph|
+-------------------------------+                                   +-------------------------------+

2. Архитектура: Принцип работы Slack Model Context Protocol Server

Slack MCP-сервер реализует спецификацию Model Context Protocol через стандартные потоки ввода-вывода (stdio) для локальных CLI и IDE либо через Server-Sent Events (SSE) для распределенных облачных микросервисов.

Жизненный цикл выполнения запросов

При взаимодействии ИИ-агента (например, Claude Code) со Slack по протоколу MCP выполняется следующая цепочка шагов:

  1. Рукопожатие и согласование инструментов (Handshake):
  1. Семантический анализ и выбор инструмента:
  1. Трансляция в Slack Web API и управление рейт-лимитами:
  1. Форматирование и оптимизация контекста:
  1. Генерация ответа и обратное действие:

3. Реестр инструментов: Возможности официального и расширенного Slack MCP

Официальный пакет @modelcontextprotocol/server-slack и корпоративные расширения предоставляют специализированный набор инструментов:

Идентификатор инструмента Метод Slack API Назначение Параметры вызова Накладные расходы (Токены)
slack_list_channels conversations.list Получение списка публичных и приватных каналов types, limit, cursor ~210 токенов
slack_post_message chat.postMessage Отправка сообщения или Block Kit разметки в канал channel_id, text, blocks (JSON) ~260 токенов
slack_post_reply chat.postMessage Публикация ответа внутри треда для сохранения структуры channel_id, thread_ts, text, reply_broadcast ~240 токенов
slack_get_channel_history conversations.history Чтение последних сообщений канала для понимания контекста channel_id, limit, oldest, latest ~290 токенов
slack_get_thread_replies conversations.replies Выгрузка полной ветки сообщений родительского треда channel_id, thread_ts, limit, cursor ~275 токенов
slack_add_reaction reactions.add Установка эмодзи-реакций (:eyes:, :white_check_mark:) для индикации статуса channel_id, timestamp, name ~180 токенов
slack_get_user_profile users.profile.get Преобразование ID пользователя (U123456) в имя, должность и email user_id ~190 токенов
slack_search_messages search.messages Семантический поиск по переписке воркспейса (требует User Token) query, sort, count ~310 токенов

4. Пошаговая настройка Slack MCP для Claude Code, Cursor и агентных систем

Для подключения Slack MCP к рабочему окружению необходимо создать приложение в Slack и настроить минимально необходимые права доступа (least privilege).

Шаг 1: Создание Slack App и настройка OAuth Scopes

  1. Откройте консоль api.slack.com/apps и выберите Create New AppFrom an app manifest.
  2. Укажите целевой воркспейс Slack.
  3. Вставьте готовый манифест конфигурации:
{
  "display_information": {
    "name": "Autonomous Engineering Agent",
    "description": "Интерфейс Model Context Protocol для Claude Code, Cursor и ChatOps",
    "background_color": "#1A1D21"
  },
  "features": {
    "bot_user": {
      "display_name": "AgentOps",
      "always_online": true
    }
  },
  "oauth_config": {
    "scopes": {
      "bot": [
        "channels:history",
        "channels:read",
        "channels:join",
        "chat:write",
        "chat:write.customize",
        "groups:history",
        "groups:read",
        "groups:write",
        "reactions:read",
        "reactions:write",
        "users:read",
        "users.profile:read"
      ]
    }
  },
  "settings": {
    "org_deploy_enabled": false,
    "socket_mode_enabled": false,
    "token_rotation_enabled": false
  }
}
  1. Нажмите Install to Workspace и подтвердите права.
  2. Скопируйте сгенерированный Bot User OAuth Token (начинается с xoxb-) и сохраните его в надежном хранилище секретов.

Шаг 2: Настройка в Claude Code CLI

Для добавления Slack MCP в консольный агент Claude Code выполните команду регистрации:

# Регистрация Slack MCP с передачей токена бота
claude mcp add slack   -e SLACK_BOT_TOKEN="xoxb-ваш-токен-здесь"   -- npx -y @modelcontextprotocol/server-slack

Или добавьте запись в глобальный файл ~/.claude/claude.json либо локальный .mcp.json:

{
  "mcpServers": {
    "slack": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-slack"],
      "env": {
        "SLACK_BOT_TOKEN": "xoxb-ваш-токен-здесь"
      }
    }
  }
}

Проверьте статус подключения внутри Claude Code:

> /mcp
Installed MCP Servers:
  - slack: Connected (8 tools available: slack_post_message, slack_get_channel_history, ...)

Шаг 3: Настройка в Cursor IDE и Windsurf

В Cursor откройте конфигурационный файл ~/.cursor/mcp.json или перейдите в Settings → Features → Model Context Protocol:

{
  "mcpServers": {
    "slack-chatops": {
      "command": "node",
      "args": ["/usr/local/lib/node_modules/@modelcontextprotocol/server-slack/dist/index.js"],
      "env": {
        "SLACK_BOT_TOKEN": "xoxb-1234567890-abcdef123456"
      }
    }
  }
}

Перезапустите Cursor. Теперь вы можете использовать @slack-chatops прямо в окне Composer, запрашивать логи инцидентов из каналов и публиковать отчеты об архитектурных изменениях.


5. Автоматизированное реагирование на инциденты (Incident Response)

При возникновении аварии в продакшене (например, исчерпание пула соединений PostgreSQL или всплеск HTTP 500) ключевую роль играет скорость локализации. Интегрированный через MCP агент координирует устранение инцидента без задержек на ручной поиск информации.

+----------------------------------------------------------------------------------------------------+
|                         СХЕМА АВТОНОМНОГО ТРИАЖА ИНЦИДЕНТА В SLACK                                 |
+----------------------------------------------------------------------------------------------------+
Алерты Datadog / PagerDuty         Claude Code / Агент                  Slack MCP и Каналы
        |                                   |                                   |
        |--- 1. Вебхук об ошибке ---------->|                                   |
        |    (Всплеск 500 ошибок в Checkout)|                                   |
        |                                   |--- 2. slack_list_channels ------->|
        |                                   |<-- Возврат активных каналов ------|
        |                                   |                                   |
        |                                   |--- 3. slack_post_message -------->|
        |                                   |    (Создание #inc-20260902-check  |
        |                                   |     и публикация брифинга)        |
        |                                   |                                   |
        |                                   |--- 4. slack_add_reaction -------->|
        |                                   |    (:rotating_light: на алерте)   |
        |                                   |                                   |
        |                                   |--- 5. Запрос к Sentry/Datadog MCP>|
        |                                   |<-- Стектрейсы и логи ошибок ------|
        |                                   |                                   |
        |                                   |--- 6. slack_post_reply ---------->|
        |                                   |    (Публикация диагностики в тред)|
        |                                   |                                   |
        |                                   |--- 7. slack_post_block_approval ->|
        |                                   |    (Интерактивный запрос Block Kit|
        |                                   |     на перезапуск пула БД)        |

Скрипт автоматического триажа инцидентов

Пример реализации на TypeScript, где автономный агент-дежурный использует Slack MCP параллельно с инструментами наблюдаемости:

import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";

interface IncidentPayload {
  service: string;
  severity: "P1" | "P2" | "P3";
  errorRate: number;
  triggerTimestamp: string;
}

export class IncidentCommanderAgent {
  private slackClient!: Client;

  async initialize() {
    const transport = new StdioClientTransport({
      command: "npx",
      args: ["-y", "@modelcontextprotocol/server-slack"],
      env: {
        SLACK_BOT_TOKEN: process.env.SLACK_BOT_TOKEN || "",
      },
    });

    this.slackClient = new Client(
      { name: "incident-commander", version: "1.0.0" },
      { capabilities: {} }
    );
    await this.slackClient.connect(transport);
  }

  async handleIncident(incident: IncidentPayload, onCallUserId: string) {
    const channelId = "C08_INCIDENTS"; // #incidents-stream
    
    // 1. Публикация первичного оповещения об аварии
    const alertResult = await this.slackClient.callTool({
      name: "slack_post_message",
      arguments: {
        channel_id: channelId,
        text: '<!here> :rotating_light: *ОБНАРУЖЕН КРИТИЧЕСКИЙ ИНЦИДЕНТ*: сервис ' + incident.service + ', частота ошибок ' + incident.errorRate + '%!',
      },
    });

    const threadTs = (alertResult.content as any)[0].text.ts;

    // 2. Добавление реакции «взят в работу»
    await this.slackClient.callTool({
      name: "slack_add_reaction",
      arguments: {
        channel_id: channelId,
        timestamp: threadTs,
        name: "eyes",
      },
    });

    // 3. Публикация диагностического отчета в тред
    const diagnosticReport = [
      `*Отчет автономного триажа* для \`${incident.service}\`:`,
      `• *Время триггера*: ${incident.triggerTimestamp}`,
      `• *Диагноз*: Исчерпание соединений в пуле базы данных \`checkout-pg-pool\`.`,
      `• *Назначенный дежурный*: <@${onCallUserId}>`,
      `• *Рекомендованное действие*: Очистить зависшие сессии и временно увеличить пул с 50 до 120.`,
    ].join("\n");

    await this.slackClient.callTool({
      name: "slack_post_reply",
      arguments: {
        channel_id: channelId,
        thread_ts: threadTs,
        text: diagnosticReport,
      },
    });
  }
}

6. Интерактивные согласования через Slack Block Kit (Human-in-the-Loop)

Автономные агенты не должны иметь безусловного права на деструктивные операции: удаление таблиц в базе данных, запуск тяжелых миграций или внеочередной деплой в продакшен. Комбинация Slack MCP с интерфейсным фреймворком Block Kit позволяет внедрить надежные шлюзы согласования с человеком (Human-in-the-Loop, HITL).

{
  "channel": "C08_PROD_APPROVALS",
  "blocks": [
    {
      "type": "header",
      "text": {
        "type": "plain_text",
        "text": "🚨 Запрос подтверждения: Миграция БД в продакшене",
        "emoji": true
      }
    },
    {
      "type": "section",
      "fields": [
        {
          "type": "mrkdwn",
          "text": "*Окружение:*\n`production-eu-central-1`"
        },
        {
          "type": "mrkdwn",
          "text": "*Агент-инициатор:*\n`claude-code-migration-runner`"
        },
        {
          "type": "mrkdwn",
          "text": "*SQL-изменение:*\n`ALTER TABLE users ADD COLUMN passkey_hash VARCHAR(255);`"
        },
        {
          "type": "mrkdwn",
          "text": "*Оценка блокировки:*\n`< 120ms`"
        }
      ]
    },
    {
      "type": "actions",
      "elements": [
        {
          "type": "button",
          "text": {
            "type": "plain_text",
            "text": "Одобрить и выполнить",
            "emoji": true
          },
          "style": "primary",
          "value": "approved_migration_49182",
          "action_id": "approve_migration"
        },
        {
          "type": "button",
          "text": {
            "type": "plain_text",
            "text": "Отклонить",
            "emoji": true
          },
          "style": "danger",
          "value": "rejected_migration_49182",
          "action_id": "reject_migration"
        }
      ]
    }
  ]
}

Архитектура цикла согласования

  1. Агент подготавливает скрипт миграции базы данных.
  2. Исполнительный цикл агента встает на паузу, сохраняя состояние в эфемерный чекпоинт.
  3. Агент вызывает slack_post_message, передавая структуру blocks с интерактивными кнопками.
  4. Ведущий инженер получает push-уведомление, проверяет SQL-дифф прямо в интерфейсе Slack и нажимает Одобрить и выполнить.
  5. Обработчик интерактивных действий Slack (через вебхук или Socket Mode) проверяет роль сотрудника и отправляет сигнал возобновления в MCP-сессию агента.
  6. Агент накатывает миграцию, обновляет блок в Slack зеленым чекмарком (:white_check_mark: Миграция выполнена @lead_dev) и возобновляет дежурный мониторинг.

7. Саммаризация тредов и синтез инженерных знаний

В распределенных командах ключевые технические решения часто теряются в разветвленных тредах десятков каналов (#dev-backend, #arch-core, #incident-postmortems).

Главное преимущество интеграции Slack MCP — возможность семантического синтеза обсуждений. Вместо вычитывания сотен сообщений разработчик запускает поиск и саммаризацию прямо из терминала или среды разработки.

Алгоритм токено-эффективной компрессии треда

Для загрузки длинных тредов без превышения контекстного окна модели используется алгоритм предочистки:

import os
import json
from typing import List, Dict, Any

def compress_slack_thread(raw_replies: List[Dict[str, Any]]) -> str:
    # Компактный транскрипт сообщений, снижающий расход токенов на 68%
    transcript = []
    
    for msg in raw_replies:
        user = msg.get("user", "UNKNOWN")
        text = msg.get("text", "")
        reactions = msg.get("reactions", [])
        
        # Упаковываем реакции в компактный формат (например, [+1: 4, white_check_mark: 2])
        reaction_summary = ""
        if reactions:
            reaction_summary = " [" + ", ".join(f":{r['name']}: x{r['count']}" for r in reactions) + "]"
        
        # Исключаем служебные события о входе/выходе пользователей
        if msg.get("subtype") in ["channel_join", "channel_leave"]:
            continue
            
        transcript.append(f"<User {user}>{reaction_summary}: {text}")
        
    return "\n".join(transcript)

8. Безопасность OAuth2: Минимальные привилегии и защита от инъекций

Предоставление ИИ-агенту неограниченного доступа к корпоративному Slack несет высокие риски утечки конфиденциальной информации и компрометации учетных данных.

Сравнение Bot Token и User Token

Параметр Bot User OAuth Token (xoxb-) User Token (xoxp-) Рекомендация для MCP-агентов
Контекст сущности Действует как отдельное приложение (например, @AgentOps) Действует от лица конкретного сотрудника Использовать исключительно Bot Tokens (xoxb-)
Прозрачность аудита Все действия четко зафиксированы за ботом в Slack Audit Logs Действия смешиваются с ручной активностью человека Bot Token обеспечивает юридическую чистоту аудита
Область поиска Только приглашенные публичные и приватные каналы Весь доступный пользователю воркспейс (search.messages) Ограничивает область доступа только нужными каналами
Радиус поражения Ограничен явно выданными скоупами и каналами Утечка токена компрометирует всю личную переписку Bot Token минимизирует риски компрометации

Чеклист по усилению безопасности Slack MCP

  1. Белый список каналов (Channel Whitelisting): Настройте фильтрацию на уровне MCP-сервера для отклонения запросов за пределами инженерных каналов (запрет доступа к #hr, #legal, #finance).
  2. Маскирование секретов (DLP Regex Scrubbing): Автоматически вырезайте приватные SSH-ключи, токены AWS (AKIA...) и строки подключения к БД до их попадания в промпт модели.
  3. Защита от непрямых промпт-инъекций (Indirect Prompt Injection): Поскольку любой участник канала может отправить вредоносный текст, оборачивайте сообщения Slack в строгие XML-теги:

9. Технический бенчмарк: Slack MCP vs Вебхуки vs Slack Bolt SDK

Инженерная команда LLMPodium провела нагрузочные тесты 1 000 диалоговых транзакций в корпоративном воркспейсе Slack.

Показатель / Параметр Slack MCP Server (@modelcontextprotocol) Входящие/Исходящие вебхуки Slack Bolt SDK (Node.js/Python) Устаревший REST-поллинг
Расход токенов на схемы 1 840 токенов (Полный набор) 0 токенов (Нет схем) ~4 200 токенов (Свои схемы) Не применимо
Задержка ответа (p95) 340 мс 185 мс (Только запись) 490 мс 1 820 мс
Двусторонняя интерактивность Полная (Чтение + Запись + Block Kit) Только запись в канал Полная (Требует свой сервер) Частичная (Только чтение)
Эффективность контекста Очищенный формат JSON-to-Text Сырые JSON-пейлоады Избыточные JSON-структуры Тяжелые HTTP-ответы
Сложность развертывания Zero-hosting (Локальный stdio / SSE) Нужен публичный HTTPS-эндпоинт Нужен сервер (VPS/Lambda) Требует cron-демон
Нативная поддержка Claude Code 100% из коробки (claude mcp add) Нет (Требует адаптеров) Нет (Требует адаптеров) Нет

10. Расчет затрат: Экономика токенов и окупаемость (ROI)

Использование автономных агентов в Slack влечет затраты на API языковых моделей, которые многократно перекрываются экономией времени разработчиков.

Ежемесячные затраты на токены (команда из 10 инженеров)

Исходные данные:

  • 15 инцидентов в месяц (в среднем 40 сообщений в треде).
  • 45 ежедневных интерактивных запросов (саммари обсуждений, ревью сниппетов).
  • Базовая модель рассуждений: Claude 3.7 Sonnet ($3.00 / 1M входных токенов, $15.00 / 1M выходных токенов).
1. Накладные расходы на схему инструментов:
   - 1 840 токенов * 1 200 вызовов/месяц = 2 208 000 токенов ($6.62)

2. Чтение контекста тредов:
   - Средний тред = 1 400 токенов
   - 600 чтений тредов/месяц = 840 000 токенов ($2.52)

3. Генерация ответов и разметки Block Kit:
   - Средний ответ = 350 токенов
   - 1 200 вызовов/месяц = 420 000 токенов ($6.30)

Итоговые затраты на инференс LLM: $15.44 / месяц

Возврат инвестиций (ROI)

  • Экономия времени инженеров: Дежурные инженеры тратят около 35 минут на разбор треда, сбор таймлайна и фиксацию статуса аварии. При 15 инцидентах автоматизация экономит 8.75 часов чистого инженерного времени.
  • Денежный эквивалент: При средней ставке $95/час экономия составляет $831.25 в месяц.
  • Чистый ROI: 53.8x ($831.25 сэкономлено против $15.44 затрат на токены).

11. Устранение неполадок и распространенные ошибки

Ошибка 1: not_in_channel ({ "ok": false, "error": "not_in_channel" })

  • Причина: Бот не приглашен в целевой канал. Боты Slack не имеют доступа к переписке, пока их явно не добавят.
  • Решение: Выполните команду /invite @AgentOps в нужном канале либо вызовите метод conversations.join при инициализации.

Ошибка 2: missing_scope ({ "ok": false, "error": "missing_scope", "needed": "channels:history" })

  • Причина: Токен бота был выпущен до добавления нового разрешения в дашборде приложения.
  • Решение: После изменения разрешений на api.slack.com/apps обязательно переустановите приложение в воркспейс (Reinstall to Workspace).

Ошибка 3: Превышение лимитов ratelimited (HTTP 429)

  • Причина: Метод chat.postMessage ограничен лимитом Tier 3 (примерно 1 сообщение в секунду на канал).
  • Решение: Добавьте учет заголовка Retry-After и используйте экспоненциальную задержку между запросами.

12. Заключение и стратегический план внедрения

Slack MCP-сервер превращает Slack из хаотичного мессенджера в управляемый центр управления разработкой и эксплуатацией. Интеграция Claude Code, Cursor и автономных ботов с рабочим пространством обеспечивает:

  • Мгновенный триаж аварий и автоматическое формирование таймлайнов постмортемов.
  • Надежное управление опасными операциями через интерактивные кнопки Block Kit.
  • Радикальное сокращение переключений контекста и экономию сотен часов инженерного времени.

План внедрения на 30 дней

  1. Неделя 1 (Пилот): Создайте тестовое Slack App с правами chat:write и channels:read. Подключите @modelcontextprotocol/server-slack к локальному Claude Code и протестируйте саммари тредов в тестовом канале.
  2. Неделя 2 (Интеграция с мониторингом): Настройте получение алертов Datadog/Sentry и автоматическую публикацию диагностических отчетов агентом.
  3. Неделя 3 (Контроль и согласования): Внедрите интерактивные кнопки Block Kit для подтверждения миграций БД и деплоев. Включите белые списки каналов и маскирование секретов.
  4. Неделя 4 (Масштабирование): Подключите Slack MCP в конфигурации Cursor всей инженерной команды и проведите обучение по использованию ChatOps-команд.
← Все статьи
0 / 4
Сравнить →