stats-compass-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.
- stats_compass_mcp-0.1.0/LICENSE +21 -0
- stats_compass_mcp-0.1.0/PKG-INFO +187 -0
- stats_compass_mcp-0.1.0/README.md +163 -0
- stats_compass_mcp-0.1.0/pyproject.toml +53 -0
- stats_compass_mcp-0.1.0/stats_compass_mcp/__init__.py +7 -0
- stats_compass_mcp-0.1.0/stats_compass_mcp/cli.py +57 -0
- stats_compass_mcp-0.1.0/stats_compass_mcp/server.py +129 -0
- stats_compass_mcp-0.1.0/stats_compass_mcp/tools.py +65 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Olatunji Ogunbiyi
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: stats-compass-mcp
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: MCP server exposing stats-compass-core tools to LLMs like ChatGPT, Claude, and Gemini
|
|
5
|
+
License: MIT
|
|
6
|
+
Keywords: mcp,llm,data-science,pandas,ai-agents,chatgpt,claude
|
|
7
|
+
Author: Olatunji Ogunbiyi
|
|
8
|
+
Author-email: oogunbiyi21@users.noreply.github.com
|
|
9
|
+
Requires-Python: >=3.11,<4.0
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Intended Audience :: Science/Research
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Topic :: Scientific/Engineering
|
|
19
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
20
|
+
Requires-Dist: mcp (>=1.0.0,<2.0.0)
|
|
21
|
+
Requires-Dist: stats-compass-core[all] (>=0.1.3,<0.2.0)
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
|
|
24
|
+
# stats-compass-mcp
|
|
25
|
+
|
|
26
|
+
MCP server that exposes [stats-compass-core](https://pypi.org/project/stats-compass-core/) tools to LLMs like ChatGPT, Claude, and Gemini.
|
|
27
|
+
|
|
28
|
+
## What is this?
|
|
29
|
+
|
|
30
|
+
This package turns the `stats-compass-core` toolkit into an MCP (Model Context Protocol) server. Once running, any MCP-compatible client (ChatGPT, Claude, Cursor, VS Code, etc.) can use your data analysis tools directly.
|
|
31
|
+
|
|
32
|
+
## Installation
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pip install stats-compass-mcp
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Quick Start
|
|
39
|
+
|
|
40
|
+
### Start the server
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
stats-compass-mcp serve
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Configure your MCP client
|
|
47
|
+
|
|
48
|
+
#### For Claude Desktop (Recommended)
|
|
49
|
+
|
|
50
|
+
The easiest way to run this server is using `uvx` (part of the [uv](https://github.com/astral-sh/uv) toolkit), which downloads and runs the server in an isolated environment without installation.
|
|
51
|
+
|
|
52
|
+
Add this to your `claude_desktop_config.json`:
|
|
53
|
+
|
|
54
|
+
```json
|
|
55
|
+
{
|
|
56
|
+
"mcpServers": {
|
|
57
|
+
"stats-compass": {
|
|
58
|
+
"command": "uvx",
|
|
59
|
+
"args": ["stats-compass-mcp", "serve"]
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
#### Manual Installation
|
|
66
|
+
|
|
67
|
+
If you prefer to install it globally:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
pip install stats-compass-mcp
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Then configure your client:
|
|
74
|
+
|
|
75
|
+
```json
|
|
76
|
+
{
|
|
77
|
+
"mcpServers": {
|
|
78
|
+
"stats-compass": {
|
|
79
|
+
"command": "stats-compass-mcp",
|
|
80
|
+
"args": ["serve"]
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Available Tools
|
|
87
|
+
|
|
88
|
+
Once connected, the following tools are available to LLMs:
|
|
89
|
+
|
|
90
|
+
### Data Loading & Management
|
|
91
|
+
- `load_csv` - Load CSV files into state
|
|
92
|
+
- `load_dataset` - Load built-in sample datasets
|
|
93
|
+
- `list_dataframes` - List all DataFrames in state
|
|
94
|
+
- `get_schema` - Get column types and info
|
|
95
|
+
- `get_sample` - Preview rows from a DataFrame
|
|
96
|
+
|
|
97
|
+
### Data Cleaning
|
|
98
|
+
- `dropna` - Remove missing values
|
|
99
|
+
- `apply_imputation` - Fill missing values
|
|
100
|
+
- `dedupe` - Remove duplicate rows
|
|
101
|
+
- `handle_outliers` - Detect and handle outliers
|
|
102
|
+
|
|
103
|
+
### Transforms
|
|
104
|
+
- `filter_dataframe` - Filter rows by condition
|
|
105
|
+
- `groupby_aggregate` - Group and aggregate data
|
|
106
|
+
- `pivot` - Pivot tables
|
|
107
|
+
- `add_column` - Add calculated columns
|
|
108
|
+
- `rename_columns` - Rename columns
|
|
109
|
+
- `drop_columns` - Remove columns
|
|
110
|
+
|
|
111
|
+
### EDA & Statistics
|
|
112
|
+
- `describe` - Summary statistics
|
|
113
|
+
- `correlations` - Correlation matrix
|
|
114
|
+
- `hypothesis_tests` - T-tests, chi-square, etc.
|
|
115
|
+
- `data_quality` - Data quality report
|
|
116
|
+
|
|
117
|
+
### Visualization
|
|
118
|
+
- `histogram` - Distribution plots
|
|
119
|
+
- `scatter_plot` - Scatter plots
|
|
120
|
+
- `bar_chart` - Bar charts
|
|
121
|
+
- `lineplot` - Line plots
|
|
122
|
+
|
|
123
|
+
### Machine Learning
|
|
124
|
+
- `train_linear_regression` - Linear regression
|
|
125
|
+
- `train_logistic_regression` - Logistic regression
|
|
126
|
+
- `train_random_forest_classifier` - Random forest classification
|
|
127
|
+
- `train_random_forest_regressor` - Random forest regression
|
|
128
|
+
- `evaluate_model` - Model evaluation metrics
|
|
129
|
+
|
|
130
|
+
### Time Series (ARIMA)
|
|
131
|
+
- `check_stationarity` - ADF/KPSS tests
|
|
132
|
+
- `fit_arima` - Fit ARIMA models
|
|
133
|
+
- `forecast_arima` - Generate forecasts
|
|
134
|
+
- `find_optimal_arima` - Auto parameter search
|
|
135
|
+
|
|
136
|
+
## How It Works
|
|
137
|
+
|
|
138
|
+
```
|
|
139
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
140
|
+
│ MCP Client │
|
|
141
|
+
│ (ChatGPT, Claude, Cursor, VS Code) │
|
|
142
|
+
└─────────────────────────┬───────────────────────────────────┘
|
|
143
|
+
│ MCP Protocol
|
|
144
|
+
▼
|
|
145
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
146
|
+
│ stats-compass-mcp │
|
|
147
|
+
│ ┌─────────────────────────────────────────────────────┐ │
|
|
148
|
+
│ │ MCP Server (this package) │ │
|
|
149
|
+
│ │ • Registers tools from stats-compass-core │ │
|
|
150
|
+
│ │ • Manages DataFrameState per session │ │
|
|
151
|
+
│ │ • Converts tool results to MCP responses │ │
|
|
152
|
+
│ └─────────────────────────────────────────────────────┘ │
|
|
153
|
+
│ │ │
|
|
154
|
+
│ ▼ │
|
|
155
|
+
│ ┌─────────────────────────────────────────────────────┐ │
|
|
156
|
+
│ │ stats-compass-core (PyPI) │ │
|
|
157
|
+
│ │ • DataFrameState (server-side state) │ │
|
|
158
|
+
│ │ • 40+ deterministic tools │ │
|
|
159
|
+
│ │ • Pydantic schemas for all inputs/outputs │ │
|
|
160
|
+
│ └─────────────────────────────────────────────────────┘ │
|
|
161
|
+
└─────────────────────────────────────────────────────────────┘
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## Development
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
# Clone and install
|
|
168
|
+
git clone https://github.com/oogunbiyi21/stats-compass-mcp.git
|
|
169
|
+
cd stats-compass-mcp
|
|
170
|
+
poetry install
|
|
171
|
+
|
|
172
|
+
# Run tests
|
|
173
|
+
poetry run pytest
|
|
174
|
+
|
|
175
|
+
# Run the server locally
|
|
176
|
+
poetry run stats-compass-mcp serve
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## Related Projects
|
|
180
|
+
|
|
181
|
+
- [stats-compass-core](https://github.com/oogunbiyi21/stats-compass-core) - The underlying toolkit
|
|
182
|
+
- [stats-compass](https://github.com/oogunbiyi21/stats-compass) - Streamlit chat UI for data analysis
|
|
183
|
+
|
|
184
|
+
## License
|
|
185
|
+
|
|
186
|
+
MIT
|
|
187
|
+
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# stats-compass-mcp
|
|
2
|
+
|
|
3
|
+
MCP server that exposes [stats-compass-core](https://pypi.org/project/stats-compass-core/) tools to LLMs like ChatGPT, Claude, and Gemini.
|
|
4
|
+
|
|
5
|
+
## What is this?
|
|
6
|
+
|
|
7
|
+
This package turns the `stats-compass-core` toolkit into an MCP (Model Context Protocol) server. Once running, any MCP-compatible client (ChatGPT, Claude, Cursor, VS Code, etc.) can use your data analysis tools directly.
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pip install stats-compass-mcp
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Quick Start
|
|
16
|
+
|
|
17
|
+
### Start the server
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
stats-compass-mcp serve
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### Configure your MCP client
|
|
24
|
+
|
|
25
|
+
#### For Claude Desktop (Recommended)
|
|
26
|
+
|
|
27
|
+
The easiest way to run this server is using `uvx` (part of the [uv](https://github.com/astral-sh/uv) toolkit), which downloads and runs the server in an isolated environment without installation.
|
|
28
|
+
|
|
29
|
+
Add this to your `claude_desktop_config.json`:
|
|
30
|
+
|
|
31
|
+
```json
|
|
32
|
+
{
|
|
33
|
+
"mcpServers": {
|
|
34
|
+
"stats-compass": {
|
|
35
|
+
"command": "uvx",
|
|
36
|
+
"args": ["stats-compass-mcp", "serve"]
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
#### Manual Installation
|
|
43
|
+
|
|
44
|
+
If you prefer to install it globally:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
pip install stats-compass-mcp
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Then configure your client:
|
|
51
|
+
|
|
52
|
+
```json
|
|
53
|
+
{
|
|
54
|
+
"mcpServers": {
|
|
55
|
+
"stats-compass": {
|
|
56
|
+
"command": "stats-compass-mcp",
|
|
57
|
+
"args": ["serve"]
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Available Tools
|
|
64
|
+
|
|
65
|
+
Once connected, the following tools are available to LLMs:
|
|
66
|
+
|
|
67
|
+
### Data Loading & Management
|
|
68
|
+
- `load_csv` - Load CSV files into state
|
|
69
|
+
- `load_dataset` - Load built-in sample datasets
|
|
70
|
+
- `list_dataframes` - List all DataFrames in state
|
|
71
|
+
- `get_schema` - Get column types and info
|
|
72
|
+
- `get_sample` - Preview rows from a DataFrame
|
|
73
|
+
|
|
74
|
+
### Data Cleaning
|
|
75
|
+
- `dropna` - Remove missing values
|
|
76
|
+
- `apply_imputation` - Fill missing values
|
|
77
|
+
- `dedupe` - Remove duplicate rows
|
|
78
|
+
- `handle_outliers` - Detect and handle outliers
|
|
79
|
+
|
|
80
|
+
### Transforms
|
|
81
|
+
- `filter_dataframe` - Filter rows by condition
|
|
82
|
+
- `groupby_aggregate` - Group and aggregate data
|
|
83
|
+
- `pivot` - Pivot tables
|
|
84
|
+
- `add_column` - Add calculated columns
|
|
85
|
+
- `rename_columns` - Rename columns
|
|
86
|
+
- `drop_columns` - Remove columns
|
|
87
|
+
|
|
88
|
+
### EDA & Statistics
|
|
89
|
+
- `describe` - Summary statistics
|
|
90
|
+
- `correlations` - Correlation matrix
|
|
91
|
+
- `hypothesis_tests` - T-tests, chi-square, etc.
|
|
92
|
+
- `data_quality` - Data quality report
|
|
93
|
+
|
|
94
|
+
### Visualization
|
|
95
|
+
- `histogram` - Distribution plots
|
|
96
|
+
- `scatter_plot` - Scatter plots
|
|
97
|
+
- `bar_chart` - Bar charts
|
|
98
|
+
- `lineplot` - Line plots
|
|
99
|
+
|
|
100
|
+
### Machine Learning
|
|
101
|
+
- `train_linear_regression` - Linear regression
|
|
102
|
+
- `train_logistic_regression` - Logistic regression
|
|
103
|
+
- `train_random_forest_classifier` - Random forest classification
|
|
104
|
+
- `train_random_forest_regressor` - Random forest regression
|
|
105
|
+
- `evaluate_model` - Model evaluation metrics
|
|
106
|
+
|
|
107
|
+
### Time Series (ARIMA)
|
|
108
|
+
- `check_stationarity` - ADF/KPSS tests
|
|
109
|
+
- `fit_arima` - Fit ARIMA models
|
|
110
|
+
- `forecast_arima` - Generate forecasts
|
|
111
|
+
- `find_optimal_arima` - Auto parameter search
|
|
112
|
+
|
|
113
|
+
## How It Works
|
|
114
|
+
|
|
115
|
+
```
|
|
116
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
117
|
+
│ MCP Client │
|
|
118
|
+
│ (ChatGPT, Claude, Cursor, VS Code) │
|
|
119
|
+
└─────────────────────────┬───────────────────────────────────┘
|
|
120
|
+
│ MCP Protocol
|
|
121
|
+
▼
|
|
122
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
123
|
+
│ stats-compass-mcp │
|
|
124
|
+
│ ┌─────────────────────────────────────────────────────┐ │
|
|
125
|
+
│ │ MCP Server (this package) │ │
|
|
126
|
+
│ │ • Registers tools from stats-compass-core │ │
|
|
127
|
+
│ │ • Manages DataFrameState per session │ │
|
|
128
|
+
│ │ • Converts tool results to MCP responses │ │
|
|
129
|
+
│ └─────────────────────────────────────────────────────┘ │
|
|
130
|
+
│ │ │
|
|
131
|
+
│ ▼ │
|
|
132
|
+
│ ┌─────────────────────────────────────────────────────┐ │
|
|
133
|
+
│ │ stats-compass-core (PyPI) │ │
|
|
134
|
+
│ │ • DataFrameState (server-side state) │ │
|
|
135
|
+
│ │ • 40+ deterministic tools │ │
|
|
136
|
+
│ │ • Pydantic schemas for all inputs/outputs │ │
|
|
137
|
+
│ └─────────────────────────────────────────────────────┘ │
|
|
138
|
+
└─────────────────────────────────────────────────────────────┘
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Development
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
# Clone and install
|
|
145
|
+
git clone https://github.com/oogunbiyi21/stats-compass-mcp.git
|
|
146
|
+
cd stats-compass-mcp
|
|
147
|
+
poetry install
|
|
148
|
+
|
|
149
|
+
# Run tests
|
|
150
|
+
poetry run pytest
|
|
151
|
+
|
|
152
|
+
# Run the server locally
|
|
153
|
+
poetry run stats-compass-mcp serve
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Related Projects
|
|
157
|
+
|
|
158
|
+
- [stats-compass-core](https://github.com/oogunbiyi21/stats-compass-core) - The underlying toolkit
|
|
159
|
+
- [stats-compass](https://github.com/oogunbiyi21/stats-compass) - Streamlit chat UI for data analysis
|
|
160
|
+
|
|
161
|
+
## License
|
|
162
|
+
|
|
163
|
+
MIT
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
[tool.poetry]
|
|
2
|
+
name = "stats-compass-mcp"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "MCP server exposing stats-compass-core tools to LLMs like ChatGPT, Claude, and Gemini"
|
|
5
|
+
authors = ["Olatunji Ogunbiyi <oogunbiyi21@users.noreply.github.com>"]
|
|
6
|
+
license = "MIT"
|
|
7
|
+
readme = "README.md"
|
|
8
|
+
packages = [{include = "stats_compass_mcp"}]
|
|
9
|
+
keywords = ["mcp", "llm", "data-science", "pandas", "ai-agents", "chatgpt", "claude"]
|
|
10
|
+
classifiers = [
|
|
11
|
+
"Development Status :: 3 - Alpha",
|
|
12
|
+
"Intended Audience :: Developers",
|
|
13
|
+
"Intended Audience :: Science/Research",
|
|
14
|
+
"License :: OSI Approved :: MIT License",
|
|
15
|
+
"Programming Language :: Python :: 3",
|
|
16
|
+
"Programming Language :: Python :: 3.11",
|
|
17
|
+
"Programming Language :: Python :: 3.12",
|
|
18
|
+
"Topic :: Scientific/Engineering",
|
|
19
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
[tool.poetry.dependencies]
|
|
23
|
+
python = "^3.11"
|
|
24
|
+
stats-compass-core = {extras = ["all"], version = "^0.1.3"}
|
|
25
|
+
mcp = "^1.0.0"
|
|
26
|
+
|
|
27
|
+
[tool.poetry.group.dev.dependencies]
|
|
28
|
+
pytest = "^8.2.0"
|
|
29
|
+
pytest-asyncio = "^0.24.0"
|
|
30
|
+
ruff = "^0.8.0"
|
|
31
|
+
mypy = "^1.0.0"
|
|
32
|
+
|
|
33
|
+
[tool.poetry.scripts]
|
|
34
|
+
stats-compass-mcp = "stats_compass_mcp.cli:main"
|
|
35
|
+
|
|
36
|
+
[build-system]
|
|
37
|
+
requires = ["poetry-core>=2.0.0,<3.0.0"]
|
|
38
|
+
build-backend = "poetry.core.masonry.api"
|
|
39
|
+
|
|
40
|
+
[tool.pytest.ini_options]
|
|
41
|
+
testpaths = ["tests"]
|
|
42
|
+
asyncio_mode = "auto"
|
|
43
|
+
|
|
44
|
+
[tool.ruff]
|
|
45
|
+
line-length = 88
|
|
46
|
+
target-version = "py311"
|
|
47
|
+
|
|
48
|
+
[tool.ruff.lint]
|
|
49
|
+
select = ["E", "F", "I", "W"]
|
|
50
|
+
|
|
51
|
+
[tool.mypy]
|
|
52
|
+
python_version = "3.11"
|
|
53
|
+
strict = true
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"""
|
|
2
|
+
CLI entrypoint for stats-compass-mcp.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import sys
|
|
7
|
+
import logging
|
|
8
|
+
|
|
9
|
+
# Setup debug logging to file
|
|
10
|
+
logging.basicConfig(
|
|
11
|
+
filename='/tmp/stats_compass_mcp_debug.log',
|
|
12
|
+
level=logging.DEBUG,
|
|
13
|
+
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
def main() -> None:
|
|
17
|
+
"""Main CLI entrypoint."""
|
|
18
|
+
parser = argparse.ArgumentParser(
|
|
19
|
+
prog="stats-compass-mcp",
|
|
20
|
+
description="MCP server for stats-compass-core data analysis tools",
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
subparsers = parser.add_subparsers(dest="command", help="Available commands")
|
|
24
|
+
|
|
25
|
+
# serve command
|
|
26
|
+
serve_parser = subparsers.add_parser("serve", help="Start the MCP server")
|
|
27
|
+
serve_parser.add_argument(
|
|
28
|
+
"--transport",
|
|
29
|
+
choices=["stdio", "sse"],
|
|
30
|
+
default="stdio",
|
|
31
|
+
help="Transport protocol (default: stdio)",
|
|
32
|
+
)
|
|
33
|
+
serve_parser.add_argument(
|
|
34
|
+
"--port",
|
|
35
|
+
type=int,
|
|
36
|
+
default=8000,
|
|
37
|
+
help="Port for SSE transport (default: 8000)",
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
# list-tools command
|
|
41
|
+
subparsers.add_parser("list-tools", help="List all available tools")
|
|
42
|
+
|
|
43
|
+
args = parser.parse_args()
|
|
44
|
+
|
|
45
|
+
if args.command == "serve":
|
|
46
|
+
from .server import run_server
|
|
47
|
+
run_server(transport=args.transport, port=args.port)
|
|
48
|
+
elif args.command == "list-tools":
|
|
49
|
+
from .tools import list_tools
|
|
50
|
+
list_tools()
|
|
51
|
+
else:
|
|
52
|
+
parser.print_help()
|
|
53
|
+
sys.exit(1)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
if __name__ == "__main__":
|
|
57
|
+
main()
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
"""
|
|
2
|
+
MCP Server for stats-compass-core.
|
|
3
|
+
|
|
4
|
+
Exposes all tools via the Model Context Protocol.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import json
|
|
8
|
+
import logging
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
from mcp.server import Server
|
|
12
|
+
from mcp.server.stdio import stdio_server
|
|
13
|
+
from mcp.types import (
|
|
14
|
+
Tool,
|
|
15
|
+
TextContent,
|
|
16
|
+
)
|
|
17
|
+
from pydantic import BaseModel
|
|
18
|
+
|
|
19
|
+
from stats_compass_core.state import DataFrameState
|
|
20
|
+
from stats_compass_core.registry import registry
|
|
21
|
+
|
|
22
|
+
from .tools import get_all_tools
|
|
23
|
+
|
|
24
|
+
# Configure logging
|
|
25
|
+
logging.basicConfig(level=logging.INFO)
|
|
26
|
+
logger = logging.getLogger(__name__)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def create_server() -> Server:
|
|
30
|
+
"""Create and configure the MCP server."""
|
|
31
|
+
server = Server("stats-compass")
|
|
32
|
+
|
|
33
|
+
# Server-side state - one DataFrameState per session
|
|
34
|
+
state = DataFrameState()
|
|
35
|
+
|
|
36
|
+
# Load all tools from stats-compass-core
|
|
37
|
+
registry.auto_discover()
|
|
38
|
+
tools = get_all_tools()
|
|
39
|
+
|
|
40
|
+
@server.list_tools()
|
|
41
|
+
async def list_tools() -> list[Tool]:
|
|
42
|
+
"""List all available tools."""
|
|
43
|
+
mcp_tools = []
|
|
44
|
+
for tool in tools:
|
|
45
|
+
mcp_tool = Tool(
|
|
46
|
+
name=tool["name"],
|
|
47
|
+
description=tool["description"] or f"{tool['category']} tool: {tool['original_name']}",
|
|
48
|
+
inputSchema=tool.get("input_schema", {"type": "object", "properties": {}}),
|
|
49
|
+
)
|
|
50
|
+
mcp_tools.append(mcp_tool)
|
|
51
|
+
return mcp_tools
|
|
52
|
+
|
|
53
|
+
@server.call_tool()
|
|
54
|
+
async def call_tool(name: str, arguments: dict[str, Any]) -> list[TextContent]:
|
|
55
|
+
"""Execute a tool and return results."""
|
|
56
|
+
logger.info(f"Tool called: {name} with args: {arguments}")
|
|
57
|
+
|
|
58
|
+
# Find the tool
|
|
59
|
+
tool_info = None
|
|
60
|
+
for t in tools:
|
|
61
|
+
if t["name"] == name:
|
|
62
|
+
tool_info = t
|
|
63
|
+
break
|
|
64
|
+
|
|
65
|
+
if not tool_info:
|
|
66
|
+
return [TextContent(
|
|
67
|
+
type="text",
|
|
68
|
+
text=json.dumps({"error": f"Tool '{name}' not found"}),
|
|
69
|
+
)]
|
|
70
|
+
|
|
71
|
+
try:
|
|
72
|
+
# Validate and parse input if schema exists
|
|
73
|
+
if "input_model" in tool_info:
|
|
74
|
+
params = tool_info["input_model"](**arguments)
|
|
75
|
+
else:
|
|
76
|
+
params = arguments
|
|
77
|
+
|
|
78
|
+
# Call the tool with state injected
|
|
79
|
+
result = tool_info["function"](state, params)
|
|
80
|
+
|
|
81
|
+
# Convert result to JSON-serializable format
|
|
82
|
+
if isinstance(result, BaseModel):
|
|
83
|
+
result_data = result.model_dump()
|
|
84
|
+
elif hasattr(result, "to_dict"):
|
|
85
|
+
result_data = result.to_dict()
|
|
86
|
+
else:
|
|
87
|
+
result_data = result
|
|
88
|
+
|
|
89
|
+
return [TextContent(
|
|
90
|
+
type="text",
|
|
91
|
+
text=json.dumps(result_data, default=str, indent=2),
|
|
92
|
+
)]
|
|
93
|
+
|
|
94
|
+
except Exception as e:
|
|
95
|
+
logger.error(f"Tool error: {e}")
|
|
96
|
+
return [TextContent(
|
|
97
|
+
type="text",
|
|
98
|
+
text=json.dumps({
|
|
99
|
+
"error": str(e),
|
|
100
|
+
"error_type": type(e).__name__,
|
|
101
|
+
}),
|
|
102
|
+
)]
|
|
103
|
+
|
|
104
|
+
return server
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def run_server(transport: str = "stdio", port: int = 8000) -> None:
|
|
108
|
+
"""Run the MCP server."""
|
|
109
|
+
import asyncio
|
|
110
|
+
|
|
111
|
+
server = create_server()
|
|
112
|
+
|
|
113
|
+
if transport == "stdio":
|
|
114
|
+
logger.info("Starting Stats Compass MCP server (stdio transport)...")
|
|
115
|
+
asyncio.run(run_stdio(server))
|
|
116
|
+
elif transport == "sse":
|
|
117
|
+
logger.info(f"Starting Stats Compass MCP server (SSE on port {port})...")
|
|
118
|
+
# SSE transport would go here - for now just stdio
|
|
119
|
+
raise NotImplementedError("SSE transport not yet implemented")
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
async def run_stdio(server: Server) -> None:
|
|
123
|
+
"""Run the server with stdio transport."""
|
|
124
|
+
async with stdio_server() as (read_stream, write_stream):
|
|
125
|
+
await server.run(
|
|
126
|
+
read_stream,
|
|
127
|
+
write_stream,
|
|
128
|
+
server.create_initialization_options(),
|
|
129
|
+
)
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Tool loader and registry bridge for MCP.
|
|
3
|
+
|
|
4
|
+
Loads all tools from stats-compass-core and prepares them for MCP registration.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
from stats_compass_core.registry import registry
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def get_all_tools() -> list[dict[str, Any]]:
|
|
13
|
+
"""
|
|
14
|
+
Get all registered tools from stats-compass-core.
|
|
15
|
+
|
|
16
|
+
Returns:
|
|
17
|
+
List of tool metadata dicts with name, category, description, and schema.
|
|
18
|
+
"""
|
|
19
|
+
# Ensure tools are discovered
|
|
20
|
+
registry.auto_discover()
|
|
21
|
+
|
|
22
|
+
tools = []
|
|
23
|
+
for metadata in registry.list_tools():
|
|
24
|
+
tool_info: dict[str, Any] = {
|
|
25
|
+
"name": f"{metadata.category}_{metadata.name}",
|
|
26
|
+
"category": metadata.category,
|
|
27
|
+
"original_name": metadata.name,
|
|
28
|
+
"description": metadata.description,
|
|
29
|
+
"function": metadata.function,
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
# Add JSON schema if available
|
|
33
|
+
if metadata.input_schema:
|
|
34
|
+
tool_info["input_schema"] = metadata.input_schema.model_json_schema()
|
|
35
|
+
tool_info["input_model"] = metadata.input_schema
|
|
36
|
+
|
|
37
|
+
tools.append(tool_info)
|
|
38
|
+
|
|
39
|
+
return tools
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def list_tools() -> None:
|
|
43
|
+
"""Print all available tools to stdout."""
|
|
44
|
+
tools = get_all_tools()
|
|
45
|
+
|
|
46
|
+
print(f"\n📊 Stats Compass MCP Tools ({len(tools)} available)\n")
|
|
47
|
+
print("=" * 60)
|
|
48
|
+
|
|
49
|
+
# Group by category
|
|
50
|
+
by_category: dict[str, list[dict[str, Any]]] = {}
|
|
51
|
+
for tool in tools:
|
|
52
|
+
cat = tool["category"]
|
|
53
|
+
if cat not in by_category:
|
|
54
|
+
by_category[cat] = []
|
|
55
|
+
by_category[cat].append(tool)
|
|
56
|
+
|
|
57
|
+
for category, cat_tools in sorted(by_category.items()):
|
|
58
|
+
print(f"\n🔧 {category.upper()} ({len(cat_tools)} tools)")
|
|
59
|
+
print("-" * 40)
|
|
60
|
+
for tool in cat_tools:
|
|
61
|
+
desc = tool["description"][:50] + "..." if len(tool["description"]) > 50 else tool["description"]
|
|
62
|
+
print(f" • {tool['original_name']}: {desc}")
|
|
63
|
+
|
|
64
|
+
print("\n" + "=" * 60)
|
|
65
|
+
print("Run 'stats-compass-mcp serve' to start the MCP server.\n")
|