ML MCP Server
by pktcopilot2
README.md
# ML MCP Server
MCP server untuk melatih dan memakai model *machine learning* plug-and-play
atas dataset CSV lokal — diporting dari prototipe `mcp-chatbot-multi`
(`model_factory.py` + `sensor_ml.py` + `code_executor.py`), disusun ulang
mengikuti pola `grk-mcp`/`idms_mcp`/`irim-mcp`/`docs-mcp` (satu server per
domain, `tools.py` dipakai bersama `server.py` stdio dan `http_api.py`
bridge HTTP) supaya bisa dipakai lewat Claude Code maupun aplikasi Laravel
`chatbot-ai`.
Fitur inti dari prototipe tetap dipertahankan (list katalog algoritma, latih
model, prediksi pakai model tersimpan, jalankan kode Python ad hoc), hanya
digeneralisasi supaya bekerja atas dataset & kolom apa pun — bukan hanya
skema `sensor_A..D` yang dihardcode di prototipe.
## Setup
```bash
cd ml-mcp
python -m venv .venv
./.venv/Scripts/pip install -r requirements.txt
cp .env.example .env
./.venv/Scripts/python.exe generate_sample_dataset.py # opsional: dataset contoh datasets/sensors.csv
```
Taruh file `.csv` apa pun di folder `datasets/` — nama file (tanpa `.csv`)
menjadi nilai parameter `dataset` di semua tool. Kolom bernama
`timestamp`/`date`/`datetime`/`time` (case-insensitive) otomatis di-parse
sebagai waktu dan dipakai untuk mengurutkan baris.
## Sumber data dari MCP lain (bukan hanya CSV lokal)
Selain dataset yang ditaruh manual, dataset ML juga bisa berasal dari MCP
server LAIN yang datanya ditarik AI di tengah percakapan — ini yang
membuat `chatbot-ai` bisa menjawab pertanyaan seperti "latih model prediksi
dari data vibrasi pompa X" tanpa data itu pernah ada sebagai file CSV.
Alur yang dijalankan AI (semua lewat tool-calling, satu percakapan):
1. Panggil tool MCP lain untuk menarik data, mis.
`idms__get_predictive_parameter_trend(...)`,
`pkt-grk__get_emission_detail(...)`, atau `irim__list_issues(...)` —
semuanya mengembalikan baris data berbentuk list of dict (`rows`/`trend`/
list hasil tool itu).
2. Lempar baris data itu ke `ml__ingest_dataset(name, records)` — `name`
bebas (mis. `"vibrasi_pompa_101"`), `records` persis baris yang didapat
dari langkah 1. Tool ini menyimpannya sebagai dataset bernama, dan
mengembalikan kolom-kolom yang berhasil terbaca (termasuk mana yang
numerik) supaya AI tahu nilai apa yang valid untuk `target_column`/
`feature_columns`.
3. Lanjut seperti dataset biasa: `ml__get_dataset_summary(name)` (opsional,
untuk cek kolom), `ml__train_model(dataset=name, task=..., ...)`, lalu
`ml__predict_with_model(model_key)`.
4. Kalau dataset itu memang cuma dipakai sekali untuk pertanyaan ini,
`ml__delete_dataset(name)` membersihkannya (model yang sudah dilatih atas
dataset itu tetap bisa dipakai `predict_with_model` selama `input_data`
diisi lengkap — lihat catatan di tabel tools).
`ingest_dataset` dibatasi ketat karena isi `name`/`records` datang dari LLM,
bukan dari file yang sudah dikurasi manusia: nama dataset hanya boleh
huruf/angka/`-`/`_` (mencegah path traversal), dan `records` maksimum
50.000 baris per panggilan.
## Menjalankan
Stdio (dipakai Claude Code lewat `.mcp.json`, atau manual untuk debug):
```bash
./.venv/Scripts/python.exe server.py
```
HTTP bridge (dipakai aplikasi `chatbot-ai`):
```bash
./.venv/Scripts/uvicorn http_api:app --host 127.0.0.1 --port 8769
```
Daftarkan sebagai MCP server baru di `chatbot-ai` (menu **MCP Servers**,
atau lewat `McpServerSeeder`), mengikuti pola `pkt-grk`/`irim`/`docs`:
| Kolom | Nilai |
|---|---|
| `slug` | `ml` (jadi prefix nama tool: `ml__train_model`, dst.) |
| `base_url` | `http://127.0.0.1:8769` |
| `token` | isi sama dengan `ML_API_TOKEN` di `.env` server ini |
Port `8765`/`8766`/`8767`/`8768` sudah dipakai `grk-mcp`/`irim-mcp`/
`idms_mcp`/`docs-mcp`, jadi server ini memakai `8769`.
## Keamanan
- Server ini tidak menyentuh database aplikasi lain — "database"-nya hanya
registry SQLite lokal (`ml_registry.sqlite3`) yang mencatat metadata model
terlatih, dan file `.pkl` di `models/`. Tidak ada risiko SQL injection ke
data produksi karena tidak ada tool query SQL ad hoc di sini.
- `execute_python` (jalankan kode Python bebas atas sebuah dataset, disandbox
dasar: whitelist import, blokir pola berbahaya, timeout 15 detik — lihat
`code_executor.py`) **hanya didaftarkan di `server.py` (stdio, dipakai
Claude Code secara lokal)** dan **sengaja tidak diekspos** lewat
`http_api.py`, karena mengizinkan LLM yang menghadap pengguna akhir
menjalankan kode bebas adalah permukaan risiko yang jauh lebih besar
daripada tool terkurasi lainnya — sama seperti `run_readonly_query` yang
dikecualikan dari bridge HTTP `grk-mcp`/`irim-mcp`.
- `.env` berisi token asli dan sengaja di-*gitignore* — jangan pernah
di-commit.
## Tools yang tersedia
| Tool | Transport | Kegunaan |
|---|---|---|
| `list_datasets()` | stdio + HTTP | Daftar dataset yang tersedia (CSV lokal maupun hasil `ingest_dataset`), jumlah baris/kolom, kolom numerik. |
| `get_dataset_summary(dataset)` | stdio + HTTP | Statistik kolom (describe, nilai hilang, contoh baris) — dipakai sebelum `train_model`. |
| `ingest_dataset(name, records, overwrite)` | stdio + HTTP | Simpan data yang ditarik dari MCP server LAIN (list of dict) sebagai dataset bernama — lihat bagian "Sumber data dari MCP lain". |
| `delete_dataset(name)` | stdio + HTTP | Hapus dataset (mis. hasil `ingest_dataset` yang sudah tidak dipakai). |
| `list_ml_catalog()` | stdio + HTTP | Daftar task (`forecast`/`regression`/`classification`/`anomaly`) & algoritma yang tersedia. |
| `train_model(dataset, task, target_column, feature_columns, algorithm, horizon, threshold)` | stdio + HTTP | Latih model, simpan ke registry + disk, kembalikan metrik evaluasi dan `model_key`. |
| `predict_with_model(model_key, input_data)` | stdio + HTTP | Prediksi pakai model tersimpan — `input_data` opsional, default pakai baris/window terbaru dataset asal model. |
| `list_trained_models()` | stdio + HTTP | Daftar semua model terlatih beserta metriknya. |
| `delete_model(model_key)` | stdio + HTTP | Hapus model terlatih (file + entri registry). |
| `execute_python(code, dataset)` | **stdio saja** | Jalankan kode Python ad hoc atas sebuah dataset (analisis/ML custom di luar `train_model`). |
## Task ML yang didukung
- **forecast** — prediksi nilai `target_column` (kolom numerik) N langkah ke
depan, berbasis pola historis kolom itu sendiri (lag features), analog
`forecast_sensor` di prototipe.
- **regression** — prediksi nilai numerik `target_column` dari
`feature_columns` (kolom lain).
- **classification** — prediksi kelas/kategori `target_column` dari
`feature_columns`. Kalau `target_column` berupa angka (bukan kategori),
wajib isi `threshold` (kelas 1 jika nilai ≥ threshold) — analog task
`outage`/`predict_failure` di prototipe.
- **anomaly** — deteksi baris tidak normal pada `feature_columns` (default
semua kolom numerik) pakai `IsolationForest`, tanpa target — sama seperti
`detect_anomalies` di prototipe.
Algoritma yang tersedia: `linear_regression`/`random_forest` untuk
regression/forecast, `logistic_regression`/`random_forest` untuk
classification. `anomaly` selalu memakai `IsolationForest` otomatis.
## Yang sengaja tidak diporting dari prototipe
Tool analisis khusus data sensor di `mcp-chatbot-multi` (`analyze_sensors`,
`get_correlation`, `get_downtime`, `make_chart`, `forecast_chart`) tidak
diporting karena spesifik ke skema sensor & menghasilkan file gambar (PNG) —
di luar cakupan "model ML plug-and-play" dan tidak konsisten dengan pola
MCP server lain di proyek ini (semuanya mengembalikan JSON, bukan file).
`get_dataset_summary` (statistik `describe()`) dan `execute_python` sudah
cukup untuk eksplorasi data serupa tanpa dependensi `matplotlib`.