ml-inspector-mcp 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ml_inspector_mcp-0.1.0/.github/workflows/publish.yml +30 -0
- ml_inspector_mcp-0.1.0/.github/workflows/test.yml +31 -0
- ml_inspector_mcp-0.1.0/.gitignore +41 -0
- ml_inspector_mcp-0.1.0/PKG-INFO +170 -0
- ml_inspector_mcp-0.1.0/README.md +105 -0
- ml_inspector_mcp-0.1.0/examples/demo_model.onnx +0 -0
- ml_inspector_mcp-0.1.0/examples/demo_model.pkl +0 -0
- ml_inspector_mcp-0.1.0/examples/demo_test.csv +46 -0
- ml_inspector_mcp-0.1.0/examples/demo_train.csv +106 -0
- ml_inspector_mcp-0.1.0/examples/train_demo_model.py +49 -0
- ml_inspector_mcp-0.1.0/pyproject.toml +98 -0
- ml_inspector_mcp-0.1.0/src/ml_inspector/__init__.py +0 -0
- ml_inspector_mcp-0.1.0/src/ml_inspector/adapters/__init__.py +0 -0
- ml_inspector_mcp-0.1.0/src/ml_inspector/adapters/auto_detect.py +77 -0
- ml_inspector_mcp-0.1.0/src/ml_inspector/adapters/base.py +87 -0
- ml_inspector_mcp-0.1.0/src/ml_inspector/adapters/onnx.py +79 -0
- ml_inspector_mcp-0.1.0/src/ml_inspector/adapters/pytorch.py +144 -0
- ml_inspector_mcp-0.1.0/src/ml_inspector/adapters/sklearn.py +142 -0
- ml_inspector_mcp-0.1.0/src/ml_inspector/adapters/tensorflow.py +108 -0
- ml_inspector_mcp-0.1.0/src/ml_inspector/adapters/version_utils.py +84 -0
- ml_inspector_mcp-0.1.0/src/ml_inspector/server.py +351 -0
- ml_inspector_mcp-0.1.0/src/ml_inspector/session.py +46 -0
- ml_inspector_mcp-0.1.0/src/ml_inspector/tools/__init__.py +0 -0
- ml_inspector_mcp-0.1.0/src/ml_inspector/tools/drift_tools.py +145 -0
- ml_inspector_mcp-0.1.0/src/ml_inspector/tools/eval_tools.py +289 -0
- ml_inspector_mcp-0.1.0/src/ml_inspector/tools/explain_tools.py +197 -0
- ml_inspector_mcp-0.1.0/src/ml_inspector/tools/model_tools.py +110 -0
- ml_inspector_mcp-0.1.0/src/ml_inspector/tools/report_tools.py +306 -0
- ml_inspector_mcp-0.1.0/src/ml_inspector/utils/__init__.py +1 -0
- ml_inspector_mcp-0.1.0/src/ml_inspector/utils/types.py +23 -0
- ml_inspector_mcp-0.1.0/tests/conftest.py +1 -0
- ml_inspector_mcp-0.1.0/tests/test_core.py +56 -0
- ml_inspector_mcp-0.1.0/tests/test_inspectors/__init__.py +0 -0
- ml_inspector_mcp-0.1.0/tests/test_tools/__init__.py +0 -0
- ml_inspector_mcp-0.1.0/uv.lock +5546 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
publish:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
environment: pypi
|
|
12
|
+
permissions:
|
|
13
|
+
contents: read
|
|
14
|
+
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
|
|
18
|
+
- name: Set up Python
|
|
19
|
+
uses: actions/setup-python@v5
|
|
20
|
+
with:
|
|
21
|
+
python-version: "3.11"
|
|
22
|
+
|
|
23
|
+
- name: Install uv
|
|
24
|
+
uses: astral-sh/setup-uv@v4
|
|
25
|
+
|
|
26
|
+
- name: Build package
|
|
27
|
+
run: uv build
|
|
28
|
+
|
|
29
|
+
- name: Publish to PyPI
|
|
30
|
+
run: uv publish --token ${{ secrets.PYPI_API_TOKEN }}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
name: Tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v4
|
|
15
|
+
|
|
16
|
+
- name: Set up Python 3.11
|
|
17
|
+
uses: actions/setup-python@v5
|
|
18
|
+
with:
|
|
19
|
+
python-version: "3.11"
|
|
20
|
+
|
|
21
|
+
- name: Install uv
|
|
22
|
+
uses: astral-sh/setup-uv@v4
|
|
23
|
+
|
|
24
|
+
- name: Install dependencies
|
|
25
|
+
run: uv sync --extra sklearn-onnx --extra explain
|
|
26
|
+
|
|
27
|
+
- name: Generate demo model files
|
|
28
|
+
run: uv run python examples/train_demo_model.py
|
|
29
|
+
|
|
30
|
+
- name: Run tests
|
|
31
|
+
run: uv run python -m pytest tests/ -v
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.pyo
|
|
5
|
+
*.pyd
|
|
6
|
+
*.egg
|
|
7
|
+
*.egg-info/
|
|
8
|
+
dist/
|
|
9
|
+
build/
|
|
10
|
+
.eggs/
|
|
11
|
+
*.whl
|
|
12
|
+
|
|
13
|
+
# uv / virtual envs
|
|
14
|
+
.venv/
|
|
15
|
+
venv/
|
|
16
|
+
.python-version
|
|
17
|
+
|
|
18
|
+
# Testing & coverage
|
|
19
|
+
.pytest_cache/
|
|
20
|
+
.coverage
|
|
21
|
+
coverage.xml
|
|
22
|
+
htmlcov/
|
|
23
|
+
|
|
24
|
+
# Mypy
|
|
25
|
+
.mypy_cache/
|
|
26
|
+
|
|
27
|
+
# Ruff
|
|
28
|
+
.ruff_cache/
|
|
29
|
+
|
|
30
|
+
# IDEs
|
|
31
|
+
.vscode/
|
|
32
|
+
.idea/
|
|
33
|
+
*.swp
|
|
34
|
+
*.swo
|
|
35
|
+
|
|
36
|
+
# OS
|
|
37
|
+
.DS_Store
|
|
38
|
+
Thumbs.db
|
|
39
|
+
|
|
40
|
+
# Distribution
|
|
41
|
+
MANIFEST
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: ml-inspector-mcp
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Framework-agnostic ML model analysis MCP server — evaluate, explain, and report on any trained model via Claude
|
|
5
|
+
Project-URL: Homepage, https://github.com/YOUR_USERNAME/ml-inspector-mcp
|
|
6
|
+
Project-URL: Repository, https://github.com/YOUR_USERNAME/ml-inspector-mcp
|
|
7
|
+
License: MIT
|
|
8
|
+
Keywords: claude,explainability,machine-learning,mcp,mlops,model-evaluation,shap
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
12
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
13
|
+
Requires-Python: >=3.11
|
|
14
|
+
Requires-Dist: anyio
|
|
15
|
+
Requires-Dist: fastapi
|
|
16
|
+
Requires-Dist: httpx
|
|
17
|
+
Requires-Dist: jinja2
|
|
18
|
+
Requires-Dist: joblib
|
|
19
|
+
Requires-Dist: matplotlib
|
|
20
|
+
Requires-Dist: mcp<2.0.0,>=1.0.0
|
|
21
|
+
Requires-Dist: numpy
|
|
22
|
+
Requires-Dist: onnx>=1.14.0
|
|
23
|
+
Requires-Dist: onnxruntime>=1.16.0
|
|
24
|
+
Requires-Dist: packaging
|
|
25
|
+
Requires-Dist: pandas
|
|
26
|
+
Requires-Dist: pillow
|
|
27
|
+
Requires-Dist: pydantic>=2.0
|
|
28
|
+
Requires-Dist: scikit-learn
|
|
29
|
+
Requires-Dist: scipy
|
|
30
|
+
Requires-Dist: seaborn
|
|
31
|
+
Requires-Dist: uvicorn
|
|
32
|
+
Provides-Extra: dev
|
|
33
|
+
Requires-Dist: mypy>=1.10.0; extra == 'dev'
|
|
34
|
+
Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
|
|
35
|
+
Requires-Dist: pytest-cov>=5.0.0; extra == 'dev'
|
|
36
|
+
Requires-Dist: pytest>=8.0.0; extra == 'dev'
|
|
37
|
+
Requires-Dist: ruff>=0.4.0; extra == 'dev'
|
|
38
|
+
Provides-Extra: drift
|
|
39
|
+
Requires-Dist: evidently; extra == 'drift'
|
|
40
|
+
Provides-Extra: explain
|
|
41
|
+
Requires-Dist: shap; extra == 'explain'
|
|
42
|
+
Provides-Extra: full
|
|
43
|
+
Requires-Dist: anthropic; extra == 'full'
|
|
44
|
+
Requires-Dist: evidently; extra == 'full'
|
|
45
|
+
Requires-Dist: plotly; extra == 'full'
|
|
46
|
+
Requires-Dist: shap; extra == 'full'
|
|
47
|
+
Requires-Dist: skl2onnx; extra == 'full'
|
|
48
|
+
Requires-Dist: tensorflow>=2.13; extra == 'full'
|
|
49
|
+
Requires-Dist: tf2onnx>=1.15; extra == 'full'
|
|
50
|
+
Requires-Dist: torch; extra == 'full'
|
|
51
|
+
Requires-Dist: torchvision; extra == 'full'
|
|
52
|
+
Requires-Dist: weasyprint; extra == 'full'
|
|
53
|
+
Provides-Extra: pytorch
|
|
54
|
+
Requires-Dist: torch; extra == 'pytorch'
|
|
55
|
+
Requires-Dist: torchvision; extra == 'pytorch'
|
|
56
|
+
Provides-Extra: reports
|
|
57
|
+
Requires-Dist: anthropic; extra == 'reports'
|
|
58
|
+
Requires-Dist: weasyprint; extra == 'reports'
|
|
59
|
+
Provides-Extra: sklearn-onnx
|
|
60
|
+
Requires-Dist: skl2onnx; extra == 'sklearn-onnx'
|
|
61
|
+
Provides-Extra: tensorflow
|
|
62
|
+
Requires-Dist: tensorflow>=2.13; extra == 'tensorflow'
|
|
63
|
+
Requires-Dist: tf2onnx>=1.15; extra == 'tensorflow'
|
|
64
|
+
Description-Content-Type: text/markdown
|
|
65
|
+
|
|
66
|
+
# ml-inspector-mcp
|
|
67
|
+
|
|
68
|
+
[](https://pypi.org/project/ml-inspector-mcp/)
|
|
69
|
+
[](https://www.python.org/)
|
|
70
|
+
[](LICENSE)
|
|
71
|
+
|
|
72
|
+
Framework-agnostic ML model analysis MCP server. Drop in any trained model
|
|
73
|
+
and test data — Claude evaluates it, explains predictions, detects drift,
|
|
74
|
+
and generates PDF reports via natural language.
|
|
75
|
+
|
|
76
|
+
## Installation
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
pip install ml-inspector-mcp # minimal
|
|
80
|
+
pip install "ml-inspector-mcp[full]" # everything
|
|
81
|
+
pip install "ml-inspector-mcp[sklearn-onnx,explain,reports]" # common combo
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Claude Desktop setup
|
|
85
|
+
|
|
86
|
+
Add to `~/Library/Application Support/Claude/claude_desktop_config.json` (Mac):
|
|
87
|
+
|
|
88
|
+
```json
|
|
89
|
+
{
|
|
90
|
+
"mcpServers": {
|
|
91
|
+
"ml-inspector": {
|
|
92
|
+
"command": "ml-inspector",
|
|
93
|
+
"env": {
|
|
94
|
+
"ANTHROPIC_API_KEY": "your-key-here",
|
|
95
|
+
"MLFLOW_TRACKING_URI": "http://localhost:5000"
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Quick start
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
python examples/train_demo_model.py
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Then in Claude Desktop:
|
|
109
|
+
> "Load the demo model from examples/demo_model.onnx"
|
|
110
|
+
> "Load test data from examples/demo_test.csv"
|
|
111
|
+
> "Evaluate the model and tell me how it's performing"
|
|
112
|
+
> "Explain what drove the prediction for sample 5"
|
|
113
|
+
> "Generate a PDF evaluation report"
|
|
114
|
+
|
|
115
|
+
## Model compatibility
|
|
116
|
+
|
|
117
|
+
| Format | Framework | Install |
|
|
118
|
+
|--------|-----------|---------|
|
|
119
|
+
| `.onnx` | Any | Always works — recommended |
|
|
120
|
+
| `.pkl` / `.joblib` | scikit-learn | `pip install "ml-inspector-mcp[sklearn-onnx]"` |
|
|
121
|
+
| `.h5` / `.keras` | TensorFlow/Keras | `pip install "ml-inspector-mcp[tensorflow]"` |
|
|
122
|
+
| `.pt` / `.pth` | PyTorch (full model only) | `pip install "ml-inspector-mcp[pytorch]"` |
|
|
123
|
+
|
|
124
|
+
### Version mismatch fix
|
|
125
|
+
|
|
126
|
+
If you get version errors loading a `.pkl` or `.pt` file, export to ONNX first:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
# scikit-learn — use the convert_to_onnx tool after loading, or:
|
|
130
|
+
python -c "
|
|
131
|
+
import joblib
|
|
132
|
+
from skl2onnx import convert_sklearn
|
|
133
|
+
from skl2onnx.common.data_types import FloatTensorType
|
|
134
|
+
model = joblib.load('model.pkl')
|
|
135
|
+
onnx_model = convert_sklearn(model, initial_types=[('input', FloatTensorType([None, N_FEATURES]))])
|
|
136
|
+
open('model.onnx', 'wb').write(onnx_model.SerializeToString())
|
|
137
|
+
"
|
|
138
|
+
|
|
139
|
+
# PyTorch
|
|
140
|
+
torch.onnx.export(model, dummy_input, "model.onnx", opset_version=17)
|
|
141
|
+
|
|
142
|
+
# TensorFlow / Keras
|
|
143
|
+
python -m tf2onnx.convert --keras model.h5 --output model.onnx
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## All tools
|
|
147
|
+
|
|
148
|
+
| Tool | Description |
|
|
149
|
+
|------|-------------|
|
|
150
|
+
| `load_model` | Load any model file (`.pkl`, `.h5`, `.pt`, `.onnx`) — auto-detects framework |
|
|
151
|
+
| `get_model_info` | Info about the currently loaded model |
|
|
152
|
+
| `convert_to_onnx` | Convert loaded model to ONNX format |
|
|
153
|
+
| `list_supported_formats` | Show all supported formats and install instructions |
|
|
154
|
+
| `load_test_data` | Load a CSV as test dataset |
|
|
155
|
+
| `evaluate_model` | Full evaluation — accuracy, F1, AUC, confusion matrix, per-class metrics |
|
|
156
|
+
| `find_worst_predictions` | Find samples the model struggled most with |
|
|
157
|
+
| `evaluate_by_slice` | Evaluate on a data subset (e.g. by group or label) |
|
|
158
|
+
| `threshold_analysis` | Sweep decision threshold — precision/recall/F1/FPR trade-offs |
|
|
159
|
+
| `explain_prediction` | SHAP explanation for a single sample |
|
|
160
|
+
| `global_feature_importance` | Mean absolute SHAP values across all samples |
|
|
161
|
+
| `plot_shap_summary` | SHAP beeswarm summary plot saved as PNG |
|
|
162
|
+
| `data_quality_report` | Null counts, class imbalance, outliers, data type warnings |
|
|
163
|
+
| `detect_drift` | Statistical drift detection between two datasets (Evidently) |
|
|
164
|
+
| `plot_confusion_matrix` | Confusion matrix heatmap (raw + normalized) saved as PNG |
|
|
165
|
+
| `plot_roc_curve` | ROC curve with per-class AUC scores saved as PNG |
|
|
166
|
+
| `generate_report` | Full PDF / HTML / Markdown report with metrics, charts, and optional AI narrative |
|
|
167
|
+
|
|
168
|
+
## License
|
|
169
|
+
|
|
170
|
+
MIT
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# ml-inspector-mcp
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/ml-inspector-mcp/)
|
|
4
|
+
[](https://www.python.org/)
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
|
|
7
|
+
Framework-agnostic ML model analysis MCP server. Drop in any trained model
|
|
8
|
+
and test data — Claude evaluates it, explains predictions, detects drift,
|
|
9
|
+
and generates PDF reports via natural language.
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pip install ml-inspector-mcp # minimal
|
|
15
|
+
pip install "ml-inspector-mcp[full]" # everything
|
|
16
|
+
pip install "ml-inspector-mcp[sklearn-onnx,explain,reports]" # common combo
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Claude Desktop setup
|
|
20
|
+
|
|
21
|
+
Add to `~/Library/Application Support/Claude/claude_desktop_config.json` (Mac):
|
|
22
|
+
|
|
23
|
+
```json
|
|
24
|
+
{
|
|
25
|
+
"mcpServers": {
|
|
26
|
+
"ml-inspector": {
|
|
27
|
+
"command": "ml-inspector",
|
|
28
|
+
"env": {
|
|
29
|
+
"ANTHROPIC_API_KEY": "your-key-here",
|
|
30
|
+
"MLFLOW_TRACKING_URI": "http://localhost:5000"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Quick start
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
python examples/train_demo_model.py
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Then in Claude Desktop:
|
|
44
|
+
> "Load the demo model from examples/demo_model.onnx"
|
|
45
|
+
> "Load test data from examples/demo_test.csv"
|
|
46
|
+
> "Evaluate the model and tell me how it's performing"
|
|
47
|
+
> "Explain what drove the prediction for sample 5"
|
|
48
|
+
> "Generate a PDF evaluation report"
|
|
49
|
+
|
|
50
|
+
## Model compatibility
|
|
51
|
+
|
|
52
|
+
| Format | Framework | Install |
|
|
53
|
+
|--------|-----------|---------|
|
|
54
|
+
| `.onnx` | Any | Always works — recommended |
|
|
55
|
+
| `.pkl` / `.joblib` | scikit-learn | `pip install "ml-inspector-mcp[sklearn-onnx]"` |
|
|
56
|
+
| `.h5` / `.keras` | TensorFlow/Keras | `pip install "ml-inspector-mcp[tensorflow]"` |
|
|
57
|
+
| `.pt` / `.pth` | PyTorch (full model only) | `pip install "ml-inspector-mcp[pytorch]"` |
|
|
58
|
+
|
|
59
|
+
### Version mismatch fix
|
|
60
|
+
|
|
61
|
+
If you get version errors loading a `.pkl` or `.pt` file, export to ONNX first:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
# scikit-learn — use the convert_to_onnx tool after loading, or:
|
|
65
|
+
python -c "
|
|
66
|
+
import joblib
|
|
67
|
+
from skl2onnx import convert_sklearn
|
|
68
|
+
from skl2onnx.common.data_types import FloatTensorType
|
|
69
|
+
model = joblib.load('model.pkl')
|
|
70
|
+
onnx_model = convert_sklearn(model, initial_types=[('input', FloatTensorType([None, N_FEATURES]))])
|
|
71
|
+
open('model.onnx', 'wb').write(onnx_model.SerializeToString())
|
|
72
|
+
"
|
|
73
|
+
|
|
74
|
+
# PyTorch
|
|
75
|
+
torch.onnx.export(model, dummy_input, "model.onnx", opset_version=17)
|
|
76
|
+
|
|
77
|
+
# TensorFlow / Keras
|
|
78
|
+
python -m tf2onnx.convert --keras model.h5 --output model.onnx
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## All tools
|
|
82
|
+
|
|
83
|
+
| Tool | Description |
|
|
84
|
+
|------|-------------|
|
|
85
|
+
| `load_model` | Load any model file (`.pkl`, `.h5`, `.pt`, `.onnx`) — auto-detects framework |
|
|
86
|
+
| `get_model_info` | Info about the currently loaded model |
|
|
87
|
+
| `convert_to_onnx` | Convert loaded model to ONNX format |
|
|
88
|
+
| `list_supported_formats` | Show all supported formats and install instructions |
|
|
89
|
+
| `load_test_data` | Load a CSV as test dataset |
|
|
90
|
+
| `evaluate_model` | Full evaluation — accuracy, F1, AUC, confusion matrix, per-class metrics |
|
|
91
|
+
| `find_worst_predictions` | Find samples the model struggled most with |
|
|
92
|
+
| `evaluate_by_slice` | Evaluate on a data subset (e.g. by group or label) |
|
|
93
|
+
| `threshold_analysis` | Sweep decision threshold — precision/recall/F1/FPR trade-offs |
|
|
94
|
+
| `explain_prediction` | SHAP explanation for a single sample |
|
|
95
|
+
| `global_feature_importance` | Mean absolute SHAP values across all samples |
|
|
96
|
+
| `plot_shap_summary` | SHAP beeswarm summary plot saved as PNG |
|
|
97
|
+
| `data_quality_report` | Null counts, class imbalance, outliers, data type warnings |
|
|
98
|
+
| `detect_drift` | Statistical drift detection between two datasets (Evidently) |
|
|
99
|
+
| `plot_confusion_matrix` | Confusion matrix heatmap (raw + normalized) saved as PNG |
|
|
100
|
+
| `plot_roc_curve` | ROC curve with per-class AUC scores saved as PNG |
|
|
101
|
+
| `generate_report` | Full PDF / HTML / Markdown report with metrics, charts, and optional AI narrative |
|
|
102
|
+
|
|
103
|
+
## License
|
|
104
|
+
|
|
105
|
+
MIT
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
sepal_length,sepal_width,petal_length,petal_width,label
|
|
2
|
+
6.1,2.8,4.7,1.2,versicolor
|
|
3
|
+
5.7,3.8,1.7,0.3,setosa
|
|
4
|
+
7.7,2.6,6.9,2.3,virginica
|
|
5
|
+
6.0,2.9,4.5,1.5,versicolor
|
|
6
|
+
6.8,2.8,4.8,1.4,versicolor
|
|
7
|
+
5.4,3.4,1.5,0.4,setosa
|
|
8
|
+
5.6,2.9,3.6,1.3,versicolor
|
|
9
|
+
6.9,3.1,5.1,2.3,virginica
|
|
10
|
+
6.2,2.2,4.5,1.5,versicolor
|
|
11
|
+
5.8,2.7,3.9,1.2,versicolor
|
|
12
|
+
6.5,3.2,5.1,2.0,virginica
|
|
13
|
+
4.8,3.0,1.4,0.1,setosa
|
|
14
|
+
5.5,3.5,1.3,0.2,setosa
|
|
15
|
+
4.9,3.1,1.5,0.1,setosa
|
|
16
|
+
5.1,3.8,1.5,0.3,setosa
|
|
17
|
+
6.3,3.3,4.7,1.6,versicolor
|
|
18
|
+
6.5,3.0,5.8,2.2,virginica
|
|
19
|
+
5.6,2.5,3.9,1.1,versicolor
|
|
20
|
+
5.7,2.8,4.5,1.3,versicolor
|
|
21
|
+
6.4,2.8,5.6,2.2,virginica
|
|
22
|
+
4.7,3.2,1.6,0.2,setosa
|
|
23
|
+
6.1,3.0,4.9,1.8,virginica
|
|
24
|
+
5.0,3.4,1.6,0.4,setosa
|
|
25
|
+
6.4,2.8,5.6,2.1,virginica
|
|
26
|
+
7.9,3.8,6.4,2.0,virginica
|
|
27
|
+
6.7,3.0,5.2,2.3,virginica
|
|
28
|
+
6.7,2.5,5.8,1.8,virginica
|
|
29
|
+
6.8,3.2,5.9,2.3,virginica
|
|
30
|
+
4.8,3.0,1.4,0.3,setosa
|
|
31
|
+
4.8,3.1,1.6,0.2,setosa
|
|
32
|
+
4.6,3.6,1.0,0.2,setosa
|
|
33
|
+
5.7,4.4,1.5,0.4,setosa
|
|
34
|
+
6.7,3.1,4.4,1.4,versicolor
|
|
35
|
+
4.8,3.4,1.6,0.2,setosa
|
|
36
|
+
4.4,3.2,1.3,0.2,setosa
|
|
37
|
+
6.3,2.5,5.0,1.9,virginica
|
|
38
|
+
6.4,3.2,4.5,1.5,versicolor
|
|
39
|
+
5.2,3.5,1.5,0.2,setosa
|
|
40
|
+
5.0,3.6,1.4,0.2,setosa
|
|
41
|
+
5.2,4.1,1.5,0.1,setosa
|
|
42
|
+
5.8,2.7,5.1,1.9,virginica
|
|
43
|
+
6.0,3.4,4.5,1.6,versicolor
|
|
44
|
+
6.7,3.1,4.7,1.5,versicolor
|
|
45
|
+
5.4,3.9,1.3,0.4,setosa
|
|
46
|
+
5.4,3.7,1.5,0.2,setosa
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
sepal_length,sepal_width,petal_length,petal_width,label
|
|
2
|
+
5.5,2.4,3.7,1.0,versicolor
|
|
3
|
+
6.3,2.8,5.1,1.5,virginica
|
|
4
|
+
6.4,3.1,5.5,1.8,virginica
|
|
5
|
+
6.6,3.0,4.4,1.4,versicolor
|
|
6
|
+
7.2,3.6,6.1,2.5,virginica
|
|
7
|
+
5.7,2.9,4.2,1.3,versicolor
|
|
8
|
+
7.6,3.0,6.6,2.1,virginica
|
|
9
|
+
5.6,3.0,4.5,1.5,versicolor
|
|
10
|
+
5.1,3.5,1.4,0.2,setosa
|
|
11
|
+
7.7,2.8,6.7,2.0,virginica
|
|
12
|
+
5.8,2.7,4.1,1.0,versicolor
|
|
13
|
+
5.2,3.4,1.4,0.2,setosa
|
|
14
|
+
5.0,3.5,1.3,0.3,setosa
|
|
15
|
+
5.1,3.8,1.9,0.4,setosa
|
|
16
|
+
5.0,2.0,3.5,1.0,versicolor
|
|
17
|
+
6.3,2.7,4.9,1.8,virginica
|
|
18
|
+
4.8,3.4,1.9,0.2,setosa
|
|
19
|
+
5.0,3.0,1.6,0.2,setosa
|
|
20
|
+
5.1,3.3,1.7,0.5,setosa
|
|
21
|
+
5.6,2.7,4.2,1.3,versicolor
|
|
22
|
+
5.1,3.4,1.5,0.2,setosa
|
|
23
|
+
5.7,3.0,4.2,1.2,versicolor
|
|
24
|
+
7.7,3.8,6.7,2.2,virginica
|
|
25
|
+
4.6,3.2,1.4,0.2,setosa
|
|
26
|
+
6.2,2.9,4.3,1.3,versicolor
|
|
27
|
+
5.7,2.5,5.0,2.0,virginica
|
|
28
|
+
5.5,4.2,1.4,0.2,setosa
|
|
29
|
+
6.0,3.0,4.8,1.8,virginica
|
|
30
|
+
5.8,2.7,5.1,1.9,virginica
|
|
31
|
+
6.0,2.2,4.0,1.0,versicolor
|
|
32
|
+
5.4,3.0,4.5,1.5,versicolor
|
|
33
|
+
6.2,3.4,5.4,2.3,virginica
|
|
34
|
+
5.5,2.3,4.0,1.3,versicolor
|
|
35
|
+
5.4,3.9,1.7,0.4,setosa
|
|
36
|
+
5.0,2.3,3.3,1.0,versicolor
|
|
37
|
+
6.4,2.7,5.3,1.9,virginica
|
|
38
|
+
5.0,3.3,1.4,0.2,setosa
|
|
39
|
+
5.0,3.2,1.2,0.2,setosa
|
|
40
|
+
5.5,2.4,3.8,1.1,versicolor
|
|
41
|
+
6.7,3.0,5.0,1.7,versicolor
|
|
42
|
+
4.9,3.1,1.5,0.2,setosa
|
|
43
|
+
5.8,2.8,5.1,2.4,virginica
|
|
44
|
+
5.0,3.4,1.5,0.2,setosa
|
|
45
|
+
5.0,3.5,1.6,0.6,setosa
|
|
46
|
+
5.9,3.2,4.8,1.8,versicolor
|
|
47
|
+
5.1,2.5,3.0,1.1,versicolor
|
|
48
|
+
6.9,3.2,5.7,2.3,virginica
|
|
49
|
+
6.0,2.7,5.1,1.6,versicolor
|
|
50
|
+
6.1,2.6,5.6,1.4,virginica
|
|
51
|
+
7.7,3.0,6.1,2.3,virginica
|
|
52
|
+
5.5,2.5,4.0,1.3,versicolor
|
|
53
|
+
4.4,2.9,1.4,0.2,setosa
|
|
54
|
+
4.3,3.0,1.1,0.1,setosa
|
|
55
|
+
6.0,2.2,5.0,1.5,virginica
|
|
56
|
+
7.2,3.2,6.0,1.8,virginica
|
|
57
|
+
4.6,3.1,1.5,0.2,setosa
|
|
58
|
+
5.1,3.5,1.4,0.3,setosa
|
|
59
|
+
4.4,3.0,1.3,0.2,setosa
|
|
60
|
+
6.3,2.5,4.9,1.5,versicolor
|
|
61
|
+
6.3,3.4,5.6,2.4,virginica
|
|
62
|
+
4.6,3.4,1.4,0.3,setosa
|
|
63
|
+
6.8,3.0,5.5,2.1,virginica
|
|
64
|
+
6.3,3.3,6.0,2.5,virginica
|
|
65
|
+
4.7,3.2,1.3,0.2,setosa
|
|
66
|
+
6.1,2.9,4.7,1.4,versicolor
|
|
67
|
+
6.5,2.8,4.6,1.5,versicolor
|
|
68
|
+
6.2,2.8,4.8,1.8,virginica
|
|
69
|
+
7.0,3.2,4.7,1.4,versicolor
|
|
70
|
+
6.4,3.2,5.3,2.3,virginica
|
|
71
|
+
5.1,3.8,1.6,0.2,setosa
|
|
72
|
+
6.9,3.1,5.4,2.1,virginica
|
|
73
|
+
5.9,3.0,4.2,1.5,versicolor
|
|
74
|
+
6.5,3.0,5.2,2.0,virginica
|
|
75
|
+
5.7,2.6,3.5,1.0,versicolor
|
|
76
|
+
5.2,2.7,3.9,1.4,versicolor
|
|
77
|
+
6.1,3.0,4.6,1.4,versicolor
|
|
78
|
+
4.5,2.3,1.3,0.3,setosa
|
|
79
|
+
6.6,2.9,4.6,1.3,versicolor
|
|
80
|
+
5.5,2.6,4.4,1.2,versicolor
|
|
81
|
+
5.3,3.7,1.5,0.2,setosa
|
|
82
|
+
5.6,3.0,4.1,1.3,versicolor
|
|
83
|
+
7.3,2.9,6.3,1.8,virginica
|
|
84
|
+
6.7,3.3,5.7,2.1,virginica
|
|
85
|
+
5.1,3.7,1.5,0.4,setosa
|
|
86
|
+
4.9,2.4,3.3,1.0,versicolor
|
|
87
|
+
6.7,3.3,5.7,2.5,virginica
|
|
88
|
+
7.2,3.0,5.8,1.6,virginica
|
|
89
|
+
4.9,3.6,1.4,0.1,setosa
|
|
90
|
+
6.7,3.1,5.6,2.4,virginica
|
|
91
|
+
4.9,3.0,1.4,0.2,setosa
|
|
92
|
+
6.9,3.1,4.9,1.5,versicolor
|
|
93
|
+
7.4,2.8,6.1,1.9,virginica
|
|
94
|
+
6.3,2.9,5.6,1.8,virginica
|
|
95
|
+
5.7,2.8,4.1,1.3,versicolor
|
|
96
|
+
6.5,3.0,5.5,1.8,virginica
|
|
97
|
+
6.3,2.3,4.4,1.3,versicolor
|
|
98
|
+
6.4,2.9,4.3,1.3,versicolor
|
|
99
|
+
5.6,2.8,4.9,2.0,virginica
|
|
100
|
+
5.9,3.0,5.1,1.8,virginica
|
|
101
|
+
5.4,3.4,1.7,0.2,setosa
|
|
102
|
+
6.1,2.8,4.0,1.3,versicolor
|
|
103
|
+
4.9,2.5,4.5,1.7,virginica
|
|
104
|
+
5.8,4.0,1.2,0.2,setosa
|
|
105
|
+
5.8,2.6,4.0,1.2,versicolor
|
|
106
|
+
7.1,3.0,5.9,2.1,virginica
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"""Run this once to generate demo model files for testing ml-inspector-mcp."""
|
|
2
|
+
import pandas as pd
|
|
3
|
+
import numpy as np
|
|
4
|
+
from sklearn.datasets import load_iris
|
|
5
|
+
from sklearn.ensemble import RandomForestClassifier
|
|
6
|
+
from sklearn.model_selection import train_test_split
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
import joblib
|
|
9
|
+
|
|
10
|
+
Path("examples").mkdir(exist_ok=True)
|
|
11
|
+
|
|
12
|
+
iris = load_iris()
|
|
13
|
+
X, y = iris.data, iris.target
|
|
14
|
+
class_names = list(iris.target_names) # ['setosa', 'versicolor', 'virginica']
|
|
15
|
+
|
|
16
|
+
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
|
|
17
|
+
|
|
18
|
+
model = RandomForestClassifier(n_estimators=100, random_state=42)
|
|
19
|
+
model.fit(X_train, y_train)
|
|
20
|
+
|
|
21
|
+
# Save as sklearn pkl
|
|
22
|
+
joblib.dump(model, "examples/demo_model.pkl")
|
|
23
|
+
print("Saved examples/demo_model.pkl")
|
|
24
|
+
|
|
25
|
+
# Save as ONNX (recommended)
|
|
26
|
+
try:
|
|
27
|
+
from skl2onnx import convert_sklearn
|
|
28
|
+
from skl2onnx.common.data_types import FloatTensorType
|
|
29
|
+
onnx_model = convert_sklearn(model, initial_types=[("input", FloatTensorType([None, 4]))])
|
|
30
|
+
with open("examples/demo_model.onnx", "wb") as f:
|
|
31
|
+
f.write(onnx_model.SerializeToString())
|
|
32
|
+
print("Saved examples/demo_model.onnx (recommended)")
|
|
33
|
+
except ImportError:
|
|
34
|
+
print("skl2onnx not installed, skipping ONNX export. pip install skl2onnx")
|
|
35
|
+
|
|
36
|
+
# Save train/test CSVs
|
|
37
|
+
feature_cols = ["sepal_length", "sepal_width", "petal_length", "petal_width"]
|
|
38
|
+
train_df = pd.DataFrame(X_train, columns=feature_cols)
|
|
39
|
+
train_df["label"] = [class_names[i] for i in y_train]
|
|
40
|
+
train_df.to_csv("examples/demo_train.csv", index=False)
|
|
41
|
+
|
|
42
|
+
test_df = pd.DataFrame(X_test, columns=feature_cols)
|
|
43
|
+
test_df["label"] = [class_names[i] for i in y_test]
|
|
44
|
+
test_df.to_csv("examples/demo_test.csv", index=False)
|
|
45
|
+
|
|
46
|
+
print("Saved examples/demo_train.csv and examples/demo_test.csv")
|
|
47
|
+
print("\nDemo files ready. Load in Claude Desktop:")
|
|
48
|
+
print(" load_model('examples/demo_model.onnx', 'classification')")
|
|
49
|
+
print(" load_test_data('examples/demo_test.csv', 'label')")
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "ml-inspector-mcp"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Framework-agnostic ML model analysis MCP server — evaluate, explain, and report on any trained model via Claude"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.11"
|
|
11
|
+
license = {text = "MIT"}
|
|
12
|
+
keywords = ["mcp", "machine-learning", "model-evaluation", "explainability", "mlops", "shap", "claude"]
|
|
13
|
+
classifiers = [
|
|
14
|
+
"Development Status :: 4 - Beta",
|
|
15
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
16
|
+
"Programming Language :: Python :: 3.11",
|
|
17
|
+
"Programming Language :: Python :: 3.12",
|
|
18
|
+
]
|
|
19
|
+
dependencies = [
|
|
20
|
+
"mcp>=1.0.0,<2.0.0",
|
|
21
|
+
"fastapi",
|
|
22
|
+
"uvicorn",
|
|
23
|
+
"pydantic>=2.0",
|
|
24
|
+
"numpy",
|
|
25
|
+
"pandas",
|
|
26
|
+
"scikit-learn",
|
|
27
|
+
"onnx>=1.14.0",
|
|
28
|
+
"onnxruntime>=1.16.0",
|
|
29
|
+
"joblib",
|
|
30
|
+
"matplotlib",
|
|
31
|
+
"seaborn",
|
|
32
|
+
"pillow",
|
|
33
|
+
"scipy",
|
|
34
|
+
"jinja2",
|
|
35
|
+
"packaging",
|
|
36
|
+
"anyio",
|
|
37
|
+
"httpx",
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
[project.urls]
|
|
41
|
+
Homepage = "https://github.com/YOUR_USERNAME/ml-inspector-mcp"
|
|
42
|
+
Repository = "https://github.com/YOUR_USERNAME/ml-inspector-mcp"
|
|
43
|
+
|
|
44
|
+
[project.scripts]
|
|
45
|
+
ml-inspector = "ml_inspector.server:main"
|
|
46
|
+
|
|
47
|
+
[project.optional-dependencies]
|
|
48
|
+
tensorflow = ["tensorflow>=2.13", "tf2onnx>=1.15"]
|
|
49
|
+
pytorch = ["torch", "torchvision"]
|
|
50
|
+
sklearn-onnx = ["skl2onnx"]
|
|
51
|
+
explain = ["shap"]
|
|
52
|
+
drift = ["evidently"]
|
|
53
|
+
reports = ["weasyprint", "anthropic"]
|
|
54
|
+
full = [
|
|
55
|
+
"tensorflow>=2.13", "tf2onnx>=1.15",
|
|
56
|
+
"torch", "torchvision",
|
|
57
|
+
"skl2onnx", "shap",
|
|
58
|
+
"evidently", "weasyprint", "anthropic", "plotly",
|
|
59
|
+
]
|
|
60
|
+
|
|
61
|
+
# Development & CI
|
|
62
|
+
dev = [
|
|
63
|
+
"pytest>=8.0.0",
|
|
64
|
+
"pytest-asyncio>=0.23.0",
|
|
65
|
+
"pytest-cov>=5.0.0",
|
|
66
|
+
"ruff>=0.4.0",
|
|
67
|
+
"mypy>=1.10.0",
|
|
68
|
+
]
|
|
69
|
+
|
|
70
|
+
[tool.hatch.build.targets.wheel]
|
|
71
|
+
packages = ["src/ml_inspector"]
|
|
72
|
+
|
|
73
|
+
# ── Ruff (linter + formatter) ──────────────────────────────────────────────
|
|
74
|
+
[tool.ruff]
|
|
75
|
+
target-version = "py311"
|
|
76
|
+
line-length = 88
|
|
77
|
+
|
|
78
|
+
[tool.ruff.lint]
|
|
79
|
+
select = ["E", "F", "I", "UP", "B", "SIM"]
|
|
80
|
+
ignore = ["E501"]
|
|
81
|
+
|
|
82
|
+
[tool.ruff.lint.isort]
|
|
83
|
+
known-first-party = ["ml_inspector"]
|
|
84
|
+
|
|
85
|
+
# ── Mypy ──────────────────────────────────────────────────────────────────
|
|
86
|
+
[tool.mypy]
|
|
87
|
+
python_version = "3.11"
|
|
88
|
+
strict = true
|
|
89
|
+
ignore_missing_imports = true
|
|
90
|
+
|
|
91
|
+
# ── Pytest ────────────────────────────────────────────────────────────────
|
|
92
|
+
[tool.pytest.ini_options]
|
|
93
|
+
testpaths = ["tests"]
|
|
94
|
+
asyncio_mode = "auto"
|
|
95
|
+
|
|
96
|
+
[tool.coverage.run]
|
|
97
|
+
source = ["src/ml_inspector"]
|
|
98
|
+
omit = ["tests/*"]
|
|
File without changes
|
|
File without changes
|