-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmcp_server.py
More file actions
292 lines (230 loc) · 11.1 KB
/
Copy pathmcp_server.py
File metadata and controls
292 lines (230 loc) · 11.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
"""
DataPrepAgent MCP Server
========================
Exposes the full data-preparation + feature-engineering pipeline as Model
Context Protocol (MCP) tools so any MCP client — GitHub Copilot Agent Mode,
Claude Desktop, VS Code Copilot Chat — can profile, plan, clean, validate,
and ML-prepare datasets without a UI.
Usage
-----
Run the server (stdio transport, compatible with all MCP clients):
python src/mcp_server.py
Add to your MCP client config (e.g. Claude Desktop ~/claude_desktop_config.json):
{
"mcpServers": {
"dataprepagent": {
"command": "python",
"args": ["<absolute-path-to-repo>/src/mcp_server.py"],
"env": {
"AZURE_AI_PROJECT_ENDPOINT": "...",
"AZURE_AI_PROJECT_KEY": "...",
"AZURE_AI_MODEL_DEPLOYMENT_NAME": "gpt-4o"
}
}
}
}
Tools exposed
-------------
Cleaning pipeline:
1. profile_data(file_path) → ProfileReport JSON
2. suggest_cleaning_plan(file_path, profile_json) → CleaningPlan JSON
3. clean_data(file_path, plan_json) → cleaned CSV path + TransformationLog JSON
4. validate_cleaning(original, cleaned, profile, log) → ValidationReport JSON
5. list_supported_formats() → list of supported file extensions
Feature engineering pipeline:
6. recommend_feature_engineering(cleaned_path, target_column?) → FeatureEngineeringPlan JSON
7. apply_feature_engineering(cleaned_path, fe_plan_json) → ML-ready CSV path + FeatureEngineeringLog JSON
"""
import sys
import os
import asyncio
import json
import tempfile
# Ensure src/ is importable when run directly
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
from mcp.server.fastmcp import FastMCP
mcp = FastMCP(
"DataPrepAgent",
instructions=(
"DataPrepAgent automates data preparation and ML feature engineering using "
"a multi-agent AI pipeline. "
"Cleaning flow: profile_data → suggest_cleaning_plan → clean_data → validate_cleaning. "
"Feature engineering flow (optional): recommend_feature_engineering → apply_feature_engineering. "
"Each tool accepts and returns JSON strings."
),
)
# ── Tool 1: profile_data ──────────────────────────────────────────────────────
@mcp.tool()
async def profile_data(file_path: str) -> str:
"""
Ingest a CSV, Excel, JSON, or XML file and return a full data-quality
profile as a JSON string (ProfileReport schema).
Args:
file_path: Absolute or relative path to the data file.
Returns:
JSON string containing the ProfileReport, including column types,
missing-value counts, outlier flags, duplicate rows, quality score,
key issues, and an AI-generated summary.
"""
from src.agents.ingestion_agent import ingest
from src.agents.profiler_agent import profile_dataframe
df, metadata = await ingest(file_path)
report = await profile_dataframe(df, metadata)
return report.model_dump_json(indent=2)
# ── Tool 2: suggest_cleaning_plan ────────────────────────────────────────────
@mcp.tool()
async def suggest_cleaning_plan(file_path: str, profile_json: str) -> str:
"""
Given a data file and its ProfileReport JSON (from profile_data), return
an AI-generated cleaning plan as a JSON string (CleaningPlan schema).
Args:
file_path: Path to the original data file (needed for sample values).
profile_json: JSON string returned by profile_data.
Returns:
JSON string containing the CleaningPlan — an ordered list of
CleaningActions with priorities, parameters, and reasoning.
All actions start with approved=true; callers may set approved=false
to skip specific actions before passing to clean_data.
"""
from src.agents.ingestion_agent import ingest
from src.agents.strategy_agent import generate_cleaning_plan
from src.models.schemas import ProfileReport
profile = ProfileReport.model_validate_json(profile_json)
df, _ = await ingest(file_path)
plan = await generate_cleaning_plan(profile, df)
return plan.model_dump_json(indent=2)
# ── Tool 3: clean_data ───────────────────────────────────────────────────────
@mcp.tool()
async def clean_data(file_path: str, plan_json: str) -> str:
"""
Execute a cleaning plan (from suggest_cleaning_plan) on a data file.
Only actions with approved=true are executed.
Args:
file_path: Path to the original data file.
plan_json: JSON string (CleaningPlan) from suggest_cleaning_plan.
You may set any action's "approved" field to false to skip it.
Returns:
JSON string with two keys:
"cleaned_file": path to the cleaned CSV (written next to the original)
"transformation_log": TransformationLog JSON with per-action results
"""
from src.agents.ingestion_agent import ingest
from src.agents.cleaner_agent import execute_cleaning_plan
from src.models.schemas import CleaningPlan
df, _ = await ingest(file_path)
plan = CleaningPlan.model_validate_json(plan_json)
cleaned_df, tlog = await execute_cleaning_plan(df, plan)
# Write cleaned file alongside the original
base, ext = os.path.splitext(file_path)
cleaned_path = base + "_cleaned.csv"
cleaned_df.to_csv(cleaned_path, index=False)
return json.dumps({
"cleaned_file": cleaned_path,
"transformation_log": json.loads(tlog.model_dump_json()),
}, indent=2)
# ── Tool 4: validate_cleaning ────────────────────────────────────────────────
@mcp.tool()
async def validate_cleaning(
original_path: str,
cleaned_path: str,
profile_json: str,
transformation_log_json: str,
) -> str:
"""
Compare the original and cleaned files and return a ValidationReport.
Args:
original_path: Path to the original (uncleaned) file.
cleaned_path: Path to the cleaned CSV (from clean_data).
profile_json: ProfileReport JSON from profile_data.
transformation_log_json: TransformationLog JSON from clean_data.
Returns:
JSON string (ValidationReport) with 6 quality checks, before/after
quality scores, improvement percentage, and an AI-generated certificate.
"""
from src.agents.ingestion_agent import ingest
from src.agents.validator_agent import validate
from src.models.schemas import ProfileReport, TransformationLog
import pandas as pd
original_df, _ = await ingest(original_path)
cleaned_df = pd.read_csv(cleaned_path, dtype=str)
profile = ProfileReport.model_validate_json(profile_json)
tlog = TransformationLog.model_validate_json(transformation_log_json)
report = await validate(original_df, cleaned_df, profile, tlog)
return report.model_dump_json(indent=2)
# ── Tool 5: list_supported_formats ───────────────────────────────────────────
@mcp.tool()
def list_supported_formats() -> str:
"""
Return the list of file formats DataPrepAgent can ingest.
Returns:
JSON array of supported file extensions.
"""
return json.dumps([".csv", ".tsv", ".xlsx", ".xls", ".json", ".xml", ".pdf"])
# ── Tool 6: recommend_feature_engineering ────────────────────────────────────
@mcp.tool()
async def recommend_feature_engineering(
cleaned_path: str,
target_column: str = "",
) -> str:
"""
Analyze a cleaned dataset and return an AI-generated feature engineering plan.
Performs two-phase analysis:
1. Statistical: skewness, cardinality, correlation, variance analysis
2. LLM reasoning: recommends encoding, scaling, distribution transforms,
feature creation, and feature selection actions
Args:
cleaned_path: Path to a cleaned CSV file (output of clean_data).
target_column: Optional name of the prediction target column.
Enables target-aware encoding (e.g. target_encode).
Pass empty string for general-purpose ML preparation.
Returns:
JSON string (FeatureEngineeringPlan) with a list of FeatureEngineeringAction
objects. Each action has: id, action_type, column_name, description, reason,
impact, priority, parameters, approved=true, and an optional warning.
Callers may set any action's "approved" field to false before passing to
apply_feature_engineering to skip it.
"""
import pandas as pd
from src.agents.feature_engineering_agent import recommend_feature_engineering as _rfe
df = pd.read_csv(cleaned_path)
target = target_column.strip() or None
plan = await _rfe(df, target_column=target)
return plan.model_dump_json(indent=2)
# ── Tool 7: apply_feature_engineering ────────────────────────────────────────
@mcp.tool()
async def apply_feature_engineering(
cleaned_path: str,
fe_plan_json: str,
) -> str:
"""
Execute an approved feature engineering plan on a cleaned dataset.
Only actions with approved=true are executed. Each action is fault-tolerant:
failures are logged but do not abort the pipeline.
Args:
cleaned_path: Path to the cleaned CSV (from clean_data).
fe_plan_json: JSON string (FeatureEngineeringPlan) from
recommend_feature_engineering. You may set any action's
"approved" field to false to skip it.
Returns:
JSON string with two keys:
"ml_ready_file": path to the ML-ready CSV (written next to the input)
"feature_engineering_log": FeatureEngineeringLog JSON with per-action
results, columns added/removed totals, and success counts.
"""
import pandas as pd
from src.agents.feature_transformer_agent import execute_feature_engineering
from src.models.schemas import FeatureEngineeringPlan
df = pd.read_csv(cleaned_path)
plan = FeatureEngineeringPlan.model_validate_json(fe_plan_json)
ml_df, fe_log = await execute_feature_engineering(df, plan)
# Write ML-ready file alongside the cleaned file
base, _ = os.path.splitext(cleaned_path)
ml_path = base + "_ml_ready.csv"
ml_df.to_csv(ml_path, index=False)
return json.dumps({
"ml_ready_file": ml_path,
"feature_engineering_log": json.loads(fe_log.model_dump_json()),
}, indent=2)
# ── Entry point ───────────────────────────────────────────────────────────────
if __name__ == "__main__":
mcp.run(transport="stdio")