Skip to main content
Glama
Kirill-FD

llm-analytics-mcp

by Kirill-FD

Аналитическая система на базе LLM с интеграцией MCP

MCP-сервер, который даёт языковой модели набор инструментов для анализа табличных данных: загрузка, очистка, построение графиков, сборка отчёта. Собственный чат-интерфейс не разрабатывается — используется веб-интерфейс готовой платформы (Claude как основной клиент, ChatGPT как альтернативный).

Один и тот же реестр инструментов публикуется по двум протоколам сразу:

Протокол

Эндпоинт

Клиент

MCP (Streamable HTTP)

/mcp

Claude — веб, десктоп, любой MCP-клиент

REST + OpenAPI

/tools/*, /openapi.json

ChatGPT Custom GPT Action


Что умеет система

12 инструментов, 5 скиллов. Полный список — вызовом describe_system или в ARCHITECTURE.md.

Инструмент

Скилл

Назначение

list_datasets

—

Каталог доступных данных

load_data

DataLoadingSkill

Загрузка CSV/TSV/Excel/JSON/Parquet из каталога, пути или URL

describe_data

DataLoadingSkill

Структура, типы, пропуски, дубликаты

clean_data

DataCleaningSkill

Дубликаты, пропуски, нормализация, выбросы

suggest_analysis

InsightGenerationSkill

Автоподбор плана анализа под структуру данных

plot_trend

VisualizationSkill

Динамика метрики во времени

plot_distribution

VisualizationSkill

Гистограмма или бар-чарт (тип выбирается сам)

correlation_analysis

VisualizationSkill

Тепловая карта корреляций

plot_breakdown

VisualizationSkill

Разрез метрики по категориям

collect_evidence

InsightGenerationSkill

Проверяемые числа для текста отчёта

build_report

ReportingSkill

Отчёт в Markdown, HTML и PDF

describe_system

—

Интроспекция: состав скиллов и инструментов

Дополнительные возможности:

  1. Автоподбор анализа — suggest_analysis определяет, какая колонка является временной осью, какие метриками, какие разрезами, и возвращает готовый план вызовов с обоснованием каждого шага.

  2. Мульти-формат и мульти-источник — CSV, TSV, Excel, JSON, Parquet; каталог, локальный путь или HTTP(S)-ссылка. Последнее принципиально для веб-сценария: файл, загруженный в браузерный чат, серверу недоступен.

  3. Сборка отчёта одной командой — build_report сам достраивает недостающие графики и выдаёт документ в трёх форматах.


Related MCP server: Claude Data Buddy

Установка

Требуется Python 3.10 и новее.

git clone <адрес-репозитория>
cd llm-analytics-mcp

python -m venv .venv
source .venv/bin/activate          # Windows: .venv\Scripts\activate

pip install -r requirements.txt

Шаг 1. Тестовые данные

Данные в репозитории сгенерированы синтетически по схеме Superstore. ТЗ прямо это допускает: «вы можете сгенерировать данные самостоятельно или взять известный датасет».

python scripts/prepare_dataset.py --synthetic --rows 4000

Готовые файлы уже лежат в data/ — команда нужна, только если вы хотите пересоздать их или изменить объём.

Почему синтетика, а не Kaggle

Генератор даёт контроль над тем, что именно демонстрирует система:

  • Заложены проверяемые закономерности — восходящий тренд, годовая сезонность с пиком в конце года и связь «скидка выше 30% → отрицательная прибыль». Благодаря этому выводы анализа содержательны, а не случайны.

  • Дефекты внесены намеренно. Реальный Superstore практически идеально чист: без пропусков и дубликатов DataCleaningSkill отчитался бы «удалено 0 строк», и продемонстрировать очистку было бы нечем.

  • Воспроизводимость. Фиксированный seed=42 — проверяющий получает ровно те же данные и те же числа в отчёте, что и в примере.

  • Репозиторий самодостаточен. Не нужен аккаунт Kaggle, чтобы запустить проект.

Загрузка реального Superstore тоже поддерживается — структура колонок совпадает:

python scripts/prepare_dataset.py --input ~/Downloads/Sample-Superstore.csv

Что создаёт скрипт

Файл

Назначение

data/superstore_clean.csv

Данные, приведённые к колонкам из ТЗ

data/superstore_raw.csv

Та же таблица с внесёнными дефектами

Колонки: Date, Product, Region, Sales, Quantity, Profit (из ТЗ) плюс разрезы Category, Sub-Category, Segment, Discount, Ship Mode. Период — 2021–2024, 48 месяцев.

Состав дефектов печатается при запуске и детерминирован:

Дефект

Объём

Пропуски в Sales / Profit / Quantity

~3.5% / 4.5% / 2%

Полные дубликаты строк

~0.8%

Разнобой в написании Region (west, East, CENTRAL)

~6% строк

Экстремальные выбросы в Sales

12 строк

Альтернативный формат даты (15/03/2022)

~10% строк


Шаг 2. Проверка без сервера

Сквозной прогон всей цепочки — от загрузки до PDF-отчёта:

PYTHONPATH=src python -m analytics_mcp.selfcheck

Скрипт повторяет то, что делает LLM в диалоге, но детерминированно. Полезен как smoke-тест перед демонстрацией: если он проходит, проблема почти наверняка в интеграции, а не в аналитике.


Шаг 3. Запуск сервера

PYTHONPATH=src uvicorn analytics_mcp.app:app --host 127.0.0.1 --port 8000

Проверка:

curl http://127.0.0.1:8000/health

Полезные адреса:

Адрес

Что это

http://127.0.0.1:8000/health

Статус и число зарегистрированных компонентов

http://127.0.0.1:8000/docs

Swagger UI: все инструменты можно вызвать руками

http://127.0.0.1:8000/openapi.json

Спецификация для Custom GPT Action

http://127.0.0.1:8000/mcp

MCP-эндпоинт

Если порт занят. Стартовавший ранее процесс может продолжать отвечать старым кодом — симптом обманчивый: /health отвечает, а изменения не применяются. Перед перезапуском: pkill -f uvicorn.


Шаг 4. Публичный адрес через ngrok

Claude обращается к серверу снаружи, поэтому нужен HTTPS-адрес.

# 1. Установка и регистрация: https://ngrok.com/download
ngrok config add-authtoken <ваш-токен>

# 2. В личном кабинете ngrok зарезервируйте бесплатный статический домен
#    (Domains -> Create Domain). Без него адрес меняется при каждом
#    перезапуске, и настройку коннектора придётся повторять.

# 3. Запуск туннеля
ngrok http 8000 --domain=ваш-домен.ngrok-free.app

Затем пропишите адрес в окружении и перезапустите сервер:

cp .env.example .env
# в .env укажите:
#   PUBLIC_BASE_URL=https://ваш-домен.ngrok-free.app

export PUBLIC_BASE_URL=https://ваш-домен.ngrok-free.app
export MCP_ALLOWED_HOSTS='127.0.0.1:*,localhost:*,*.ngrok-free.app'
PYTHONPATH=src uvicorn analytics_mcp.app:app --host 127.0.0.1 --port 8000

Самая частая причина «не подключается». MCP SDK по умолчанию включает защиту от DNS rebinding и принимает только заголовок Host вида localhost. За туннелем Host содержит домен ngrok, и запрос отклоняется на этапе подключения коннектора, без внятной ошибки в интерфейсе. Переменная MCP_ALLOWED_HOSTS решает ровно эту проблему.


Шаг 5. Подключение к Claude (основной сценарий)

  1. Откройте Settings → Connectors → Add custom connector.

  2. Укажите адрес: https://ваш-домен.ngrok-free.app/mcp (обратите внимание на суффикс /mcp).

  3. Сохраните и убедитесь, что коннектор перешёл в состояние подключённого.

  4. В новом диалоге включите коннектор analytics_mcp через меню инструментов.

  5. Скопируйте содержимое prompts/system_prompt.md в описание проекта (Project instructions) — это задаёт порядок вызовов.

Проверочный запрос: «Какие датасеты доступны?» — модель должна вызвать list_datasets и показать содержимое каталога.


Шаг 6. Подключение к ChatGPT (альтернативный сценарий)

  1. Выгрузите спецификацию с публичным адресом:

    PUBLIC_BASE_URL=https://ваш-домен.ngrok-free.app \
      PYTHONPATH=src python scripts/export_openapi.py
  2. Создайте Custom GPT: Explore GPTs → Create → Configure.

  3. Create new action → Schema — вставьте содержимое openapi.json.

  4. Authentication: None.

  5. В поле Instructions вставьте prompts/system_prompt.md.

Подробности и особенности отображения графиков — в prompts/gpt_action_setup.md.


Демонстрационный сценарий

Порядок запросов подобран так, чтобы на скриншотах была видна цепочка вызовов, а не один запрос. Ключевой кадр — шаг 4: видно, что планирует модель, а не хардкод.

#

Запрос пользователю

Ожидаемые вызовы

1

Какие датасеты доступны?

list_datasets

2

Загрузи superstore_raw и опиши структуру

load_data, describe_data

3

Почисти данные

clean_data

4

Что здесь стоит проанализировать?

suggest_analysis

5

Построй эти графики

plot_trend, plot_breakdown, plot_distribution, correlation_analysis

6

Сделай отчёт с выводами и рекомендациями

collect_evidence, build_report

Пример результата — docs/report_example.md, графики — в docs/plots/.


Скриншоты работы

Материалы демонстрации лежат в docs/screenshots/:

Файл

Что показано

01-list-datasets.png

Claude вызывает list_datasets и показывает каталог сервера

02-clean.png

Отчёт clean_data: нормализация Region, 30 дубликатов, 817 выбросов

02.2-clean.png

Сравнение версий датасета «с заполнением пропусков» и «без»

03-suggest-analysis.png

Модель проверяет гипотезы из отчёта новыми вызовами инструментов

03.2-suggest-analysis.png

Приоритизированный список направлений дальнейшего анализа

04-plots.png

Построение графиков; модель явно отмечает, чего инструменты не умеют

Скриншоты показывают ключевое свойство системы: цепочкой вызовов управляет LLM. Модель сама решает, какие инструменты вызвать, находит ограничения набора (например, отсутствие фильтрации строк) и сообщает о них вместо того, чтобы подгонять вывод.

Проверка интеграции

# Полный цикл по обоим транспортам: initialize, tools/list, tools/call,
# возврат изображения, обработка ошибочных аргументов
python scripts/integration_test.py

Структура репозитория

llm-analytics-mcp/
├── README.md                    инструкция (этот файл)
├── ARCHITECTURE.md              архитектура и роль MCP/скиллов
├── openapi.json                 спецификация для Custom GPT Action
├── requirements.txt
├── .env.example
├── data/                        тестовые данные
├── docs/
│   ├── report_example.md/html/pdf   пример сгенерированного отчёта
│   ├── plots/                       примеры графиков
│   └── screenshots/                 скриншоты диалога
├── prompts/
│   ├── system_prompt.md         инструкция для LLM
│   └── gpt_action_setup.md      настройка Custom GPT Action
├── scripts/
│   ├── prepare_dataset.py       подготовка данных
│   ├── export_openapi.py        выгрузка спецификации
│   └── integration_test.py      проверка обоих транспортов
└── src/analytics_mcp/
    ├── core/                    реестр инструментов, хранилище, модели
    ├── skills/                  бизнес-логика этапов анализа
    ├── tools/                   инструменты, публикуемые наружу
    ├── transports/              адаптеры MCP и REST
    ├── rendering/               оформление графиков, артефакты
    ├── app.py                   сборка ASGI-приложения
    └── selfcheck.py             сквозная самопроверка

Как добавить свой инструмент

Ядро при этом не меняется. Создайте файл src/analytics_mcp/tools/my_tools.py:

from __future__ import annotations

from analytics_mcp.core.datasets import store
from analytics_mcp.core.registry import tool


@tool(tags=("stats",), skill="DataLoadingSkill", title="Топ значений")
def top_values(column: str, dataset_id: str | None = None, limit: int = 10) -> dict:
    """Возвращает самые частые значения колонки.

    Args:
        column: Имя колонки.
        dataset_id: Датасет. По умолчанию — последний использованный.
        limit: Сколько значений вернуть.
    """
    record = store.get(dataset_id)
    record.require_column(column)
    counts = record.df[column].value_counts().head(limit)
    return {str(k): int(v) for k, v in counts.items()}

Перезапустите сервер. Инструмент появится сразу в обоих протоколах: в tools/list у MCP и в /openapi.json у REST. Пакет tools импортирует свои модули автоматически, JSON-схема выводится из сигнатуры, описание — из докстринга.


Известные ограничения

Названы сознательно — это границы прототипа, а не недоделки:

  • Хранилище датасетов в памяти. При перезапуске сервера загруженные данные теряются. Для прототипа приемлемо; в продакшене — Redis или диск.

  • Нет авторизации. Демонстрационный стенд за временным туннелем. Для продакшена — API-ключ в заголовке и проверка на стороне FastAPI.

  • Нет фильтрации строк. Инструменты работают с датасетом целиком: срез «только регион West за 2024 год» построить нельзя. Это заметно в демонстрации — модель честно сообщает, чего не может посчитать, вместо подгонки вывода.

  • Пять скиллов, а не больше. Сознательный выбор: лучше пять работающих, чем десять формальных.

  • Юнит-тестов нет — только сквозная самопроверка selfcheck.py и интеграционный тест обоих транспортов.

Related MCP Connectors

Related MCP Servers