mcp-dwh
Provides introspection of the ClickHouse warehouse schema, querying of allowed data layers (core and mart), and profiling of tables and columns for building dashboards and reports.
Publishes and renders live dashboards by pushing declarative dashboard specifications to a Grafana instance.
Stores and manages the semantic layer and dashboard specifications, including metrics, join graphs, value hints, versioned dashboard specs, and migration status.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@mcp-dwhbuild a Grafana dashboard for daily sales trends"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
mcp-dwh
MCP-сервер, который даёт агентам строить дашборды и отчёты по хранилищу на ClickHouse — и переживает изменения его структуры без правок кода.
Схема не вкладывается в промпт: агент добывает её вызовами интроспекции, поэтому добавление таблиц, переименование колонок и даже замена предметной области целиком не требуют ни правок сервера, ни обновления инструкций.
Документация архитектуры: Живая схема · Спек дашборда — откройте файлы в браузере.
Что это делает
Интроспекция | Агент ищет таблицы, читает типы, комментарии, ключ сортировки, профилирует колонки |
Семантический слой | Метрики, join-граф, подсказки по значениям — в Postgres, отдельно от физической схемы |
Дашборды | Декларативные спеки с версиями, уровнями поддержки и валидацией против актуальной схемы |
Рендер | Push в Grafana (живой дашборд) или самодостаточный HTML-отчёт (срез на момент времени) |
Реакция на миграции | Снимки схемы, дифф, автоматический перевод устаревшего в |
30 инструментов, 53 теста, четыре сервиса в compose.
Related MCP server: SLayer
Быстрый старт на Linux
Нужен Docker с плагином compose. Всё остальное скрипт сделает сам: сгенерирует секреты, поднимет ClickHouse, Postgres, Grafana и MCP, создаст слои хранилища и наполнит их тестовыми данными.
git clone <репозиторий> mcp-dwh && cd mcp-dwh
./scripts/setup.shПолный прогон с чистого листа — около двух минут. По окончании скрипт напечатает адреса и подскажет, где взять токен.
./scripts/setup.sh --no-seed # только структура, без тестовых данных
./scripts/setup.sh --recreate # снести тома и начать с нуля
./scripts/setup.sh --domain sales # другой набор SQL (по умолчанию tutoring)Скрипт идемпотентен: повторный запуск пересоздаёт слои, но не трогает уже созданные секреты.
Что поднимется
Сервис | Порт | Назначение |
| 8765 | MCP по HTTP, требует Bearer-токен |
| 8123, 9000 | Хранилище |
| 5433 | Семантический слой и дашборды |
| 3000 | Рендер живых дашбордов |
Все порты публикуются только на петлевой интерфейс. Перед выставлением наружу поставьте обратный прокси с TLS: Bearer-токен без шифрования канала бессмысленен.
Установка Docker, если его нет
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker "$USER" && newgrp dockerПроверка: docker compose version должна вывести v2 или выше.
Быстрый старт на Windows
Docker Desktop, PowerShell 5.1 и уже установленный PostgreSQL.
powershell -ExecutionPolicy Bypass -File scripts\bootstrap.ps1
powershell -ExecutionPolicy Bypass -File scripts\init_postgres.ps1Альтернатива — запустить scripts/setup.sh из Git Bash: он работает и там,
поднимая Postgres в контейнере вместо установленного на хосте.
Если Docker не поднимается
На машине разработки встретились две независимые проблемы.
1. Служба WSL отключена (Wsl/0x80070422). Разово от администратора:
Set-Service -Name WSLService -StartupType Manual
Start-Service -Name WSLService
Start-Service -Name com.docker.service2. Осиротевшие Unix-сокеты. Бэкенд падает с
initializing Inference manager: ... The file cannot be accessed by the system.
Здесь <HOME> в логе — маскировка домашнего каталога, а не незаполненный
шаблон. Файл сокета остался от аварийного завершения, стал битым reparse point
и не удаляется ничем — ни Remove-Item, ни fsutil reparsepoint delete.
Лечится переименованием каталога, Docker создаёт его заново:
Move-Item "$env:LOCALAPPDATA\Docker\run" "$env:LOCALAPPDATA\Docker\run.broken"
Move-Item "$env:LOCALAPPDATA\docker-secrets-engine" "$env:LOCALAPPDATA\docker-secrets-engine.broken"Каждая неудачная попытка старта плодит новый такой сокет, поэтому чистить надо непосредственно перед запуском.
Подключение клиента
Локально, режим stdio
Клиент сам запускает процесс, строки подключения не существует. Готовый конфиг — .cursor/mcp.json:
{
"mcpServers": {
"mcp-dwh": {
"command": "/путь/к/.venv/bin/mcp-dwh",
"args": []
}
}
}Удалённо, режим HTTP
Шаблон — deploy/client-remote.json:
{
"mcpServers": {
"mcp-dwh": {
"url": "https://mcp.example.com/mcp",
"headers": { "Authorization": "Bearer ВАШ_ТОКЕН" }
}
}
}Путь именно /mcp. Обращение к /mcp/ даёт редирект 307, а часть клиентов
теряет на нём заголовок Authorization.
Настройка
Только переменные окружения. Локально подхватываются из .env рядом с
pyproject.toml, в контейнере передаются compose-ом.
ClickHouse
Переменная | По умолчанию | Назначение |
|
| Адрес сервера |
|
| Порт HTTP-интерфейса |
|
| Пользователь только для чтения |
|
| TLS. Обязателен, когда база на другом сервере |
|
| Проверять сертификат |
|
| Слои, видимые агенту |
|
| Обрезка выдачи |
|
| Размер пула клиентов |
CH_ALLOWED_DATABASES — не про безопасность, её обеспечивают гранты на стороне
ClickHouse. Список нужен, чтобы интроспекция не показывала агенту лишнего, и
настраивается, потому что у заказчика слои могут называться иначе.
Postgres, Grafana, сервер
Переменная | По умолчанию | Назначение |
| — | Обязательна |
|
| Размер пула |
|
| Нужна только для |
|
|
|
|
| Порт HTTP-режима |
| корень проекта или | Куда складывать отчёты |
Секреты
Пароли и токены не передаются через переменные окружения: содержимое env
видно в docker inspect и попадает в логи оркестратора. Вместо этого — файлы
в каталоге secrets/ (в git не попадает).
secrets/
ch_admin_password пароль default в ClickHouse
ch_dashboard_password пароль пользователя дашбордов
gf_admin_password админ Grafana
mcp_auth_token Bearer-токен MCP-сервера
pg_dsn строка Postgres для контейнера
pg_dsn_local то же для запуска с хоста
pg_password пароль PostgresКомпонент | Механизм |
ClickHouse |
|
Grafana (админ) |
|
Grafana (источник данных) |
|
MCP-сервер |
|
.env содержит только несекретные настройки и указатели вида
CH_DASHBOARD_PASSWORD_FILE=secrets/ch_dashboard_password.
Проверка: docker inspect --format '{{json .Config.Env}}' mcp-server — в выводе
должны быть только пути *_FILE, ни одного значения.
Для Swarm или Kubernetes определения secrets: в compose меняются с file: на
внешние. Код сервера при этом не трогается: он читает всё те же /run/secrets/*.
Изменили секрет — пересоздайте контейнер. Compose не отслеживает содержимое
файлов: docker compose up -d --force-recreate mcp.
Диагностика
Инструмент mcp_diagnostics показывает, к каким адресам сервер обращается
на самом деле, и проверяет связь со всеми тремя системами. Пароли скрыты.
Вызывайте первым при ошибках подключения.
Слои хранилища
Слой | Назначение | Доступ пользователя |
| Сырые выгрузки: всё строками, с дублями и разнобоем значений | нет |
| Типизация, дедупликация, нормализация | нет |
| Очищенные факты и измерения, минимум бизнес-логики | SELECT |
| OBT и агрегаты под дашборды | SELECT |
Гранты кодируют слоистость: агент физически не может построить дашборд на
сыром или промежуточном слое — они не видны даже в system.tables. Это
надёжнее, чем просить его об этом в промпте.
Тестовые данные
Оба домена вымышлены. Это синтетические стенды, а не выгрузка чьей-либо системы: структура придумана так, чтобы быть правдоподобной и содержать типовые сложности реального хранилища. Никаких настоящих данных, схем или бизнес-правил конкретной компании здесь нет.
По умолчанию разворачивается домен репетиторства: занятия с репетитором, домашние работы, экзамены. Около 219 тысяч занятий, 126 тысяч домашних работ, 3 тысячи учеников, 120 репетиторов за 2024-01-01 … 2025-08-31.
Данные не случайны: в них есть тренд роста, летняя просадка и связь между числом занятий и сдачей экзамена — от 0% при менее чем 20 занятиях до 100% при сотне. Это позволяет проверять, что дашборды показывают осмысленное.
Второй домен, продажи, остался в sql/ и разворачивается через
--domain sales. Он существует не для полноты, а как инструмент проверки:
переключение между двумя непохожими доменами показывает, что сервер
действительно не знает предметной области.
Ловушки, заложенные намеренно
Тестовая база содержит те грабли, которые семантический слой обязан документировать:
статус приходит в разном регистре:
ACTIVE,active,PAUSED,churned;поле
revenueуже обнулено для несостоявшихся занятий, аprice— нет: суммировать нужно первое;тестовые аккаунты отсекаются только на слое
core— правило бизнесовое, из схемы не выводится;у части учеников нет класса (взрослые), у части событий — идентификатора;
в
rawесть дубли по ключу: брать нужно последнюю запись по_ingested_at.
Безопасность
readonly = 2с потолками, а неreadonly = 1. Значение 1 запрещает любойSET, и на этом падает плагин ClickHouse для Grafana: он выставляетmax_execution_timeна каждый запрос. Гарантия возвращена секциейconstraints— настройку можно менять только в пределах потолка, а самиreadonlyиallow_ddlобъявлены неизменяемыми.Квоты: время выполнения, число прочитанных и возвращённых строк, память, часовая квота на пользователя.
Принудительный
LIMITна уровне MCP — только чтобы не топить контекст агента; защиту базы обеспечивает сервер.HTTP-режим не стартует без
MCP_AUTH_TOKEN.
Проверено семь запретов: поднять таймаут выше потолка (код 452), снять
readonly (164), разрешить DDL (392), поднять лимит строк (452), запись,
создание таблиц и чтение слоя raw (497).
Про монтирование конфигов
В compose монтируются отдельные файлы, а не каталоги config.d и users.d.
Bind-mount каталога скрывает то, что кладёт в него образ:
в
config.dобраз ClickHouse кладётdocker_related_config.xmlсlisten_host = 0.0.0.0; если его затенить, сервер слушает только localhost внутри контейнера, и проброс портов перестаёт работать — при этомdocker exec clickhouse-clientпродолжает отвечать, потому что выполняется внутри. Симптом обманчивый: порт на хосте слушается, но ответ пустой;в
users.dentrypoint дописываетdefault-user.xml; каталог, смонтированный как:ro, отправляет контейнер в цикл перезапуска.
Разработка
uv venv --python 3.10
uv pip install -e .
.venv/bin/python -m pytest tests -qТесты не знают предметной области: имена таблиц, колонок и метрик
добываются интроспекцией через фикстуры в tests/conftest.py. Это не
аккуратность ради аккуратности — при смене домена с продаж на репетиторство
продуктовый код не потребовал правок, а 9 тестов упали именно потому, что
ссылались на конкретные имена.
Интеграционные тесты пропускаются, если сервисы не подняты.
Структура
docs/ архитектура и спек дашборда (HTML)
src/mcp_dwh/
config.py настройки, секреты из файлов
clickhouse.py доступ к ClickHouse через пул
pool.py, db.py пулы соединений
introspect.py интроспекция схемы
semantic.py семантический слой
dashboards.py хранение дашбордов, уровни поддержки
validation.py валидация виджетов
grafana.py адаптер рендера
reports.py HTML-отчёты
schema_watch.py снимки схемы, дифф, реакция
http_server.py HTTP-транспорт, Bearer-аутентификация
server.py регистрация инструментов MCP
sql/ домен продаж + общие файлы
sql/tutoring/ домен репетиторства
sql/pg/ схема семантического слоя (доменно-нейтральна)
scripts/setup.sh развёртывание на Linux
scripts/bootstrap.ps1 развёртывание на WindowsЭто MVP: как встраивается в реальный стек
Проект собран самодостаточным, чтобы его можно было запустить и потрогать. В боевой инфраструктуре часть деталей заменяется, а ядро остаётся.
Компонент | Здесь (MVP) | В боевом стеке |
Загрузка в | SQL-генератор данных | dlt со своими |
Преобразования слоёв |
| dbt — мои скрипты не нужны целиком |
Описания, линиж, допустимые значения | Руками в | Из |
Расписание | Вручную | Prefect — нужен CLI или HTTP-эндпоинты, по MCP оркестратор не ходит |
Рендер дашбордов | Адаптер Grafana | Datalens — заменяется один модуль, ради этого адаптер и делался сменным |
HTML-отчёты | — | Без изменений: BI здесь не участвует |
Ядро не зависит от краёв. Интроспекция, спеки дашбордов и валидатор
обращаются к system.tables и system.columns, а не к тому, чем эти таблицы
наполнены. Заменяются только края — источник описаний, планировщик и таргет
рендера.
Главное следствие: семантический слой не должен дублировать dbt. Описания
моделей и колонок команда уже поддерживает в schema.yml под ревью в PR;
держать их ещё и в Postgres значит гарантированно получить расхождение.
За MCP остаётся то, чего в dbt нет: профилирование фактических значений
(accepted_values описывает намерение, профиль — что в таблице лежит на самом
деле) и записи, дописанные агентом по ходу работы.
Подробнее, с диаграммой и разбором по компонентам — в Живой схеме, раздел «Интеграция с инфраструктурой заказчика». Там же перечислено, что нужно выяснить: используется ли dbt Semantic Layer, насколько полон API Datalens, есть ли доступ к манифесту.
Что сделано и что дальше
Полный статус с обоснованиями — в Живой схеме, разделы «Что реализовано» и «Возможности развития».
Работает: интроспекция, семантический слой, спеки дашбордов с уровнями поддержки, валидатор с четырьмя статусами виджета, адаптер Grafana, HTML-отчёты, снимки схемы и реакция на миграции, HTTP-транспорт с аутентификацией, пулы соединений, файловые секреты.
Направления развития, по убыванию отношения пользы к трудозатратам:
Читатель
manifest.json. Убирает дублирование описаний с dbt — наибольшая польза и снятие риска расхождения.Адаптер Datalens. Grafana здесь MVP-таргет; сначала разведка API.
CLI для Prefect. Логика снимков и валидации готова, не хватает вызова извне MCP.
Автообогащение черновиков. С dbt сильно упрощается: описания приходят из манифеста, агенту остаётся профилирование значений.
Агент-починщик.
dash_list_brokenуже отдаёт ошибку и актуальную схему — не хватает цикла, который скармливает это агенту; естественное место для него — flow в Prefect.Разделение прав. Любой обладатель токена может заархивировать чужой дашборд. Молчаливое затирание уже закрыто проверкой занятого uid.
Приоритет очереди ревью по частоте использования таблиц из
system.query_log.Кросс-фильтрация и drill-down — только на собственном рендерере, между таргетами не портируется.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Safe, read-only Postgres and MySQL access for AI agents. Audit log + column-level controls.
AI marketing agent for Google Ads, Meta, GA4, TikTok, LinkedIn, Shopify, HubSpot and more.
The grounded data layer for any LLM: governed SQL, metrics, lineage and catalog over your data.
Ask data questions in natural language. Get SQL, insights, and charts from your databases.
Related MCP Servers
FlicenseNot gradedqualityAmaintenanceProduction-ready MCP server designed to empower AI agents and LLMs to interact seamlessly with ClickHouse. It exposes your ClickHouse database as a set of standardized tools and resources that adhere to the MCP protocol, making it easy for agents built on OpenAI, Claude, or other platforms to query, explore, and analyse your data.37- AlicenseNot gradedqualityAmaintenanceAgent-native semantic layer, letting AI agents query databases through specifying intent instead of writing SQL, then compiling structured queries into correct, dialect-aware SQL. Dynamic and expressive, supporting multi-stage queries, time-shifts, and complex join schemas.166MIT
- AlicenseAqualityDmaintenanceEnables AI assistants to query and manage ClickHouse databases, supporting SELECT queries, DDL/DML statements, and metadata listing.515MIT
- AlicenseNot gradedqualityCmaintenanceEnables AI agents to securely interact with multiple databases (MySQL, PostgreSQL) via natural language queries, with cross-database querying and enterprise-grade security.21MIT
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/ivanmandat/clickhouse-mcp-server'
If you have feedback or need assistance with the MCP directory API, please join our Discord server