Skip to main content
Glama
Kirill-FD

llm-analytics-mcp

by Kirill-FD

LLM-basiertes Analysesystem mit MCP-Integration

Ein MCP-Server, der der Sprachmodell eine Reihe von Werkzeugen zur Analyse tabellarischer Daten bereitstellt: Laden, Bereinigen, Erstellen von Diagrammen, Zusammenstellen eines Berichts. Eine eigene Chat-Oberfläche wird nicht entwickelt – verwendet wird die Weboberfläche der vorhandenen Plattform (Claude als Hauptclient, ChatGPT als Alternative).

Ein und derselbe Tool-Registry wird gleichzeitig über zwei Protokolle veröffentlicht:

Protokoll

Endpunkt

Client

MCP (Streamable HTTP)

/mcp

Claude – Web, Desktop, jeder MCP-Client

REST + OpenAPI

/tools/*, /openapi.json

ChatGPT Custom GPT Action


Was das System kann

12 Tools, 5 Skills. Die vollständige Liste erhalten Sie durch Aufruf von describe_system oder in ARCHITECTURE.md.

Tool

Skill

Zweck

list_datasets

—

Katalog der verfügbaren Daten

load_data

DataLoadingSkill

Laden von CSV/TSV/Excel/JSON/Parquet aus Katalog, Pfad oder URL

describe_data

DataLoadingSkill

Struktur, Typen, fehlende Werte, Duplikate

clean_data

DataCleaningSkill

Duplikate, fehlende Werte, Normalisierung, Ausreißer

suggest_analysis

InsightGenerationSkill

Automatische Auswahl eines Analyseplans passend zur Datensstruktur

plot_trend

VisualizationSkill

Verlauf einer Metrik über die Zeit

plot_distribution

VisualizationSkill

Histogramm oder Balkendiagramm (Typ wird automatisch gewählt)

correlation_analysis

VisualizationSkill

Korrelations-Heatmap

plot_breakdown

VisualizationSkill

Aufschlüsselung einer Metrik nach Kategorien

collect_evidence

InsightGenerationSkill

Überprüfbare Zahlen für den Berichtstext

build_report

ReportingSkill

Bericht in Markdown, HTML und PDF

describe_system

—

Introspektion: Zusammensetzung der Skills und Tools

Zusätzliche Funktionen:

  1. Automatische Analyseauswahl – suggest_analysis ermittelt, welche Spalte die Zeitachse ist, welche die Metriken und welche die Aufschlüsselungen sind, und liefert einen fertigen Aufrufplan mit Begründung für jeden Schritt.

  2. Multi-Format und Multi-Quelle – CSV, TSV, Excel, JSON, Parquet; Katalog, lokaler Pfad oder HTTP(S)-Link. Letzteres ist für das Webszenario entscheidend: Eine im Browser-Chat hochgeladene Datei ist für den Server nicht verfügbar.

  3. Berichterstellung mit einem Befehl – build_report ergänzt fehlende Diagramme selbst und liefert das Dokument in drei Formaten aus.


Related MCP server: Claude Data Buddy

Installation

Erforderlich ist Python 3.10 oder neuer.

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

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

pip install -r requirements.txt

Schritt 1. Testdaten

Die Daten im Repository wurden synthetisch generiert nach dem Superstore-Schema. Die Aufgabenstellung erlaubt dies ausdrücklich: „Sie können die Daten selbst generieren oder einen bekannten Datensatz verwenden.“

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

Die fertigen Dateien liegen bereits in data/ – der Befehl wird nur benötigt, wenn Sie sie neu erzeugen oder den Umfang ändern möchten.

Warum synthetische Daten statt Kaggle

Der Generator bietet Kontrolle darüber, was genau das System demonstriert:

  • Überprüfbare Muster sind eingebaut – ein Aufwärtstrend, eine jährliche Saisonalität mit Spitze am Jahresende und der Zusammenhang „Rabatt über 30 % → negativer Gewinn“. Dadurch sind die Analyseergebnisse aussagekräftig und nicht zufällig.

  • Fehler wurden absichtlich eingebaut. Der echte Superstore ist nahezu perfekt sauber: Ohne fehlende Werte und Duplikate würde DataCleaningSkill „0 Zeilen entfernt“ melden, und die Bereinigung ließe sich nicht demonstrieren.

  • Reproduzierbarkeit. Ein fester seed=42 – wer prüft, erhält exakt dieselben Daten und dieselben Zahlen im Bericht wie im Beispiel.

  • Das Repository ist eigenständig. Es ist kein Kaggle-Konto erforderlich, um das Projekt zu starten.

Das Laden des echten Superstore wird ebenfalls unterstützt – die Spaltenstruktur stimmt überein:

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

Was das Skript erzeugt

Datei

Zweck

data/superstore_clean.csv

Daten, auf die in der Aufgabenstellung festgelegten Spalten normiert

data/superstore_raw.csv

Dieselbe Tabelle mit eingebaunten Fehlern

Spalten: Date, Product, Region, Sales, Quantity, Profit (aus der Aufgabenstellung) plus Aufschlüsselungen Category, Sub-Category, Segment, Discount, Ship Mode. Zeitraum: 2021–2024, 48 Monate.

Die Zusammensetzung der Fehler wird beim Start ausgegeben und ist deterministisch:

Fehler

Umfang

Fehlende Werte in Sales / Profit / Quantity

~3.5% / 4.5% / 2%

Vollständige Zeilenduplikate

~0.8%

Uneinheitliche Schreibweise von Region (west, East, CENTRAL)

~6% der Zeilen

Extreme Ausreißer in Sales

12 Zeilen

Alternatives Datumsformat (15/03/2022)

~10% der Zeilen


Schritt 2. Prüfung ohne Server

Ein End-to-End-Durchlauf der gesamten Kette – vom Laden bis zum PDF-Bericht:

PYTHONPATH=src python -m analytics_mcp.selfcheck

Das Skript wiederholt, was das LLM im Dialog tut, aber deterministisch. Es eignet sich als Smoke-Test vor der Demo: Wenn es durchläuft, liegt das Problem fast sicher an der Integration, nicht an der Analyse.


Schritt 3. Start des Servers

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

Prüfung:

curl http://127.0.0.1:8000/health

Nützliche Adressen:

Adresse

Bedeutung

http://127.0.0.1:8000/health

Status und Anzahl der registrierten Komponenten

http://127.0.0.1:8000/docs

Swagger UI: Alle Tools können manuell aufgerufen werden

http://127.0.0.1:8000/openapi.json

Spezifikation für Custom GPT Action

http://127.0.0.1:8000/mcp

MCP-Endpunkt

Wenn der Port belegt ist. Ein zuvor gestarteter Prozess kann weiterhin mit altem Code antworten – das Symptom ist trügerisch: /health antwortet, aber Änderungen werden nicht übernommen. Vor dem Neustart: pkill -f uvicorn.


Schritt 4. Öffentliche Adresse über ngrok

Claude greift von außen auf den Server zu, daher wird eine HTTPS-Adresse benötigt.

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

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

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

Tragen Sie die Adresse anschließend in der Umgebung ein und starten Sie den Server neu:

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

Der häufigste Grund für „keine Verbindung“. Das MCP SDK aktiviert standardmäßig einen Schutz gegen DNS-Rebinding und akzeptiert nur einen Host-Header der Form localhost. Hinter dem Tunnel enthält Host die ngrok-Domäne, und die Anfrage wird beim Verbindungsaufbau des Konnektors abgelehnt, ohne klare Fehlermeldung in der Oberfläche. Die Variable MCP_ALLOWED_HOSTS löst genau dieses Problem.


Schritt 5. Verbindung zu Claude (Hauptszenario)

  1. Öffnen Sie Settings → Connectors → Add custom connector.

  2. Geben Sie die Adresse an: https://ваш-домен.ngrok-free.app/mcp (beachten Sie das Suffix /mcp).

  3. Speichern Sie und stellen Sie sicher, dass der Konnektor in den Zustand „verbunden“ übergegangen ist.

  4. Aktivieren Sie in einem neuen Dialog den Konnektor analytics_mcp über das Tool-Menü.

  5. Kopieren Sie den Inhalt von prompts/system_prompt.md in die Projektbeschreibung (Project instructions) – das legt die Reihenfolge der Aufrufe fest.

Testabfrage: „Welche Datensätze sind verfügbar?“ – Das Modell sollte list_datasets aufrufen und den Inhalt des Katalogs anzeigen.


Schritt 6. Verbindung zu ChatGPT (alternatives Szenario)

  1. Laden Sie die Spezifikation von der öffentlichen Adresse herunter:

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

  3. Create new action → Schema – fügen Sie den Inhalt von openapi.json ein.

  4. Authentication: None.

  5. Fügen Sie im Feld Instructions prompts/system_prompt.md ein.

Details und Besonderheiten der Diagrammdarstellung finden Sie in prompts/gpt_action_setup.md.


Demonstrationsszenario

Die Reihenfolge der Anfragen ist so gewählt, dass auf den Screenshots eine Kette von Aufrufen sichtbar ist, nicht nur eine einzelne Anfrage. Das Schlüsselbild ist Schritt 4: Man sieht, dass das Modell plant, und keinen Hardcode.

#

Benutzeranfrage

Erwartete Aufrufe

1

Welche Datensätze sind verfügbar?

list_datasets

2

Lade superstore_raw und beschreibe die Struktur

load_data, describe_data

3

Bereinige die Daten

clean_data

4

Was lohnt es sich hier zu analysieren?

suggest_analysis

5

Erstelle diese Diagramme

plot_trend, plot_breakdown, plot_distribution, correlation_analysis

6

Erstelle einen Bericht mit Erkenntnissen und Empfehlungen

collect_evidence, build_report

Ein Beispielergebnis finden Sie in docs/report_example.md, Diagramme in docs/plots/.


Screenshots der Arbeit

Die Demonstrationsmaterialien liegen in docs/screenshots/:

Datei

Inhalt

01-list-datasets.png

Claude ruft list_datasets auf und zeigt den Katalog des Servers

02-clean.png

Bericht clean_data: Normalisierung von Region, 30 Duplikate, 817 Ausreißer

02.2-clean.png

Vergleich der Datensatzversionen „mit Auffüllen fehlender Werte“ und „ohne“

03-suggest-analysis.png

Das Modell prüft Hypothesen aus dem Bericht mit neuen Tool-Aufrufen

03.2-suggest-analysis.png

Priorisierte Liste von Richtungen für die weitere Analyse

04-plots.png

Erstellung von Diagrammen; das Modell vermerkt ausdrücklich, was die Tools nicht können

Die Screenshots zeigen die zentrale Eigenschaft des Systems: Die Aufrufkette wird vom LLM gesteuert. Das Modell entscheidet selbst, welche Tools es aufruft, erkennt Einschränkungen des Tool-Sets (z. B. das Fehlen einer Zeilenfilterung) und berichtet darüber, anstatt das Ergebnis zurechtzubiegen.

Integrationsprüfung

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

Repository-Struktur

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             сквозная самопроверка

So fügen Sie ein eigenes Tool hinzu

Der Kern bleibt dabei unverändert. Erstellen Sie eine Datei 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()}

Starten Sie den Server neu. Das Tool erscheint sofort in beiden Protokollen: in tools/list bei MCP und in /openapi.json bei REST. Das Paket tools importiert seine Module automatisch, das JSON-Schema wird aus der Signatur abgeleitet, die Beschreibung aus dem Docstring.


Bekannte Einschränkungen

Sie sind bewusst genannt – das sind Grenzen des Prototyps, keine unfertigen Teile:

  • In-Memory-Speicherung der Datasets. Beim Neustart des Servers gehen die geladenen Daten verloren. Für einen Prototyp akzeptabel; in der Produktion — Redis oder Festplatte.

  • Keine Authentifizierung. Die Demo-Umgebung befindet sich hinter einem temporären Tunnel. Für die Produktion — API-Schlüssel im Header und Prüfung seitens FastAPI.

  • Keine Zeilenfilterung. Die Tools arbeiten mit dem gesamten Dataset: ein Ausschnitt „nur Region West für 2024“ lässt sich nicht erstellen. Das zeigt sich in der Demo — das Modell gibt ehrlich an, was es nicht berechnen kann, statt die Ausgabe anzupassen.

  • Fünf Skills, nicht mehr. Eine bewusste Entscheidung: besser fünf funktionierende als zehn formale.

  • Keine Unit-Tests — nur ein End-to-End-Selbsttest selfcheck.py und ein Integrationstest beider Transporte.

Related MCP Connectors

Related MCP Servers