Skip to content

Commit d81eba4

Browse files
authored
MCP and WebUI (#218)
1 parent b21142b commit d81eba4

40 files changed

+4048
-344
lines changed

.gitignore

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
maab/datasets/
33
runs/
44
maab/runs/
5+
/maab/
56

67
# OS specific
78
*.DS_Store
@@ -21,6 +22,18 @@ cdk.out/
2122
output_*.csv
2223
runs/
2324

25+
# MCP specific
26+
.flask.pid
27+
.mcp.pid
28+
mcp_output/
29+
mcp/__pycache__/
30+
mcp/examples/credentials_template.txt
31+
mcp/examples/example_config.yaml
32+
mcp/*.pyc
33+
34+
# IDE specific
35+
.vscode/
36+
2437
# Byte-compiled / optimized / DLL files
2538
__pycache__/
2639
*.py[cod]
@@ -190,10 +203,21 @@ aga-output-*.csv
190203
# ignore the MLAgent output folder
191204
output/
192205

193-
# MLZero Specific
194-
maab/datasets/
195-
runs/
196-
maab/runs/
197-
198206
# OS specific
199207
*.DS_Store
208+
209+
src/autogluon/mcp/server/.flask.pid
210+
src/autogluon/mcp/server/.mcp.pid
211+
src/autogluon/mcp/server/test_output/
212+
src/autogluon/mcp/server/test_data/
213+
src/autogluon/mcp/server/nohup.out
214+
src/autogluon/mcp/**/uploads/
215+
src/autogluon/mcp/**/mlzero-*/
216+
217+
# Credentials
218+
*.credentials
219+
*.creds
220+
credentials.txt
221+
aws_credentials.txt
222+
223+
.claude

README.md

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ uv pip install git+https://github.com/autogluon/autogluon-assistant.git
3434

3535
For detailed usage instructions, Anthropic/Azure/OpenAI setup, and advanced configuration options, see our [Getting Started Tutorial](docs/tutorials/getting_started.md).
3636

37-
## API Setup
37+
### 1. API Setup
3838
MLZero uses AWS Bedrock by default. Configure your AWS credentials:
3939

4040
```bash
@@ -45,17 +45,15 @@ export AWS_SECRET_ACCESS_KEY="<your-secret-key>"
4545

4646
We also support Anthropic, Azure, and OpenAI. Support for more LLM providers (e.g. DeepSeek, etc.) will be added soon.
4747

48-
## Basic Usage
49-
50-
### CLI UI
48+
### 2.1 CLI
5149

5250
![Demo](https://github.com/autogluon/autogluon-assistant/blob/main/docs/assets/cli_demo.gif)
5351

5452
```bash
55-
mlzero -i <input_data_folder> [-u <optional_user_instructions>]
53+
mlzero -i <input_data_folder> [-t <optional_user_instructions>]
5654
```
5755

58-
## WEB UI
56+
### 2.2 Web UI
5957

6058
![Demo](https://github.com/autogluon/autogluon-assistant/blob/main/docs/assets/web_demo.gif)
6159

@@ -67,6 +65,33 @@ mlzero-frontend # command to start frontend on 8509(default)
6765
1. **Configure**: Set your model provider and credentials in settings
6866
2. **Upload & Describe**: Drag your data folder into the chat input box, then type what you want to accomplish and press Enter
6967

68+
### 2.3 MCP (Model Context Protocol)
69+
70+
Note: The system can run on a single machine or distributed across multiple machines (e.g., server on EC2, client on local).
71+
1. **Start the server**
72+
```bash
73+
cd autogluon-assistant
74+
mlzero-backend # command to start backend
75+
mlzero-mcp-server # This will start the service—run it in a new terminal.
76+
```
77+
2. **Start the client**
78+
```bash
79+
cd autogluon-assistant
80+
mlzero-mcp-client
81+
```
82+
Note: You may need to set up port tunneling to expose your local MCP Client Server (port 8005) if you want to use it with remote LLM services (e.g., Claude API, OpenAI API).
83+
84+
### 2.4 Python API
85+
86+
```python
87+
from autogluon.assistant.coding_agent import run_agent
88+
run_agent(
89+
input_data_folder=<your-input-folder>,
90+
output_folder=<your-output-folder>,
91+
# more args ...
92+
)
93+
```
94+
7095
## Citation
7196
If you use Autogluon Assistant (MLZero) in your research, please cite our paper:
7297

docs/tutorials/getting_started.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ You can select the LLM provider, model, and credentials to use. If using Bedrock
7070
### CLI
7171

7272
```bash
73-
mlzero -i INPUT_DATA_FOLDER [-o OUTPUT_DIR] [-c CONFIG_PATH] [-n MAX_ITERATIONS] [--need-user-input] [-u INITIAL_USER_INPUT] [-e EXTRACT_TO] [-v VERBOSITY_LEVEL]
73+
mlzero -i INPUT_DATA_FOLDER [-o OUTPUT_DIR] [-c CONFIG_PATH] [-n MAX_ITERATIONS] [--ENABLE-PER-ITERATION-INSTRUCTION] [-t --INITIAL-INSTRUCTION] [-e EXTRACT_TO] [-v VERBOSITY_LEVEL]
7474
```
7575

7676
#### Required Arguments
@@ -89,10 +89,10 @@ mlzero -i INPUT_DATA_FOLDER [-o OUTPUT_DIR] [-c CONFIG_PATH] [-n MAX_ITERATIONS]
8989
- `-n, --max-iterations`:
9090
Maximum number of iterations. Default is `5`.
9191

92-
- `--need-user-input`:
93-
Whether to prompt user input at each iteration. Defaults to `False`.
92+
- `--enable-per-iteration-instruction`:
93+
If enabled, provide an instruction at the start of each iteration (except the first, which uses the initial instruction). The process suspends until you provide it.
9494

95-
- `-u, --user-input`:
95+
- `-t, --initial-instruction`:
9696
Initial user input to use in the first iteration. Optional.
9797

9898
- `-e, --extract-to`:

maab/agents/mlzero_default/mlzero_default.sh

100644100755
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ mlzero \
5959
-o "$OUTPUT_DIR" \
6060
-n 10 \
6161
-v 1 \
62-
-u "complete the task in 10 minutes"
62+
--initial-instruction "complete the task in 10 minutes"
6363

6464
# Check if the process was successful
6565
if [ $? -ne 0 ]; then

pyproject.toml

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,20 +42,27 @@ dependencies = [
4242
"streamlit-extras>=0.4",
4343
"psutil>=5.9.8",
4444
"peft>=0.15.2",
45+
"fastmcp>=2.0.0",
46+
"aiohttp>=3.8.0",
47+
"requests>=2.28.0",
48+
"boto3>=1.28.0",
49+
"mcp>=0.1.0",
4550
]
4651

4752
[project.scripts]
4853
aga = "autogluon.assistant.cli.app:app"
4954
mlzero = "autogluon.assistant.cli.app:app"
50-
mlzero-webui = "autogluon.assistant.webui.Home:main"
5155
mlzero-backend = "autogluon.assistant.webui.backend.app:main"
5256
mlzero-frontend = "autogluon.assistant.webui.runner:run_frontend"
57+
mlzero-mcp-server = "autogluon.mcp.server.runner:main"
58+
mlzero-mcp-client = "autogluon.mcp.client.server:main"
5359

5460
[project.optional-dependencies]
5561
dev = [
5662
"black>=24",
5763
"GitRepo>=1",
5864
"pytest>=7",
65+
"pytest-asyncio>=0.21.0",
5966
"isort",
6067
"ruff==0.4",
6168
]
@@ -65,7 +72,7 @@ Homepage = "https://github.com/autogluon/autogluon-assistant"
6572

6673
[tool.setuptools.packages.find]
6774
where = ["src"]
68-
include = ["autogluon.assistant*"]
75+
include = ["autogluon.assistant*", "autogluon.mcp*"]
6976
namespaces = true
7077

7178
[tool.setuptools.package-data]

src/autogluon/assistant/cli/app.py

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,23 @@
11
#!/usr/bin/env python3
22
from __future__ import annotations
33

4+
import multiprocessing.resource_tracker
45
from pathlib import Path
56

67
import typer
78

89
from autogluon.assistant.coding_agent import run_agent
910

10-
from .. import __file__ as assistant_file
1111

12-
PACKAGE_ROOT = Path(assistant_file).parent
12+
def _noop(*args, **kwargs):
13+
pass
14+
15+
16+
multiprocessing.resource_tracker.register = _noop
17+
multiprocessing.resource_tracker.unregister = _noop
18+
multiprocessing.resource_tracker.ensure_running = _noop
19+
20+
PACKAGE_ROOT = Path(__file__).parent.parent
1321
DEFAULT_CONFIG_PATH = PACKAGE_ROOT / "configs" / "default.yaml"
1422

1523
app = typer.Typer(add_completion=False)
@@ -31,14 +39,39 @@ def main(
3139
"--config",
3240
help=f"YAML config file (default: {DEFAULT_CONFIG_PATH})",
3341
),
34-
max_iterations: int = typer.Option(5, "-n", "--max-iterations", help="Max iteration count"),
35-
need_user_input: bool = typer.Option(False, "--need-user-input", help="Whether to prompt user each iteration"),
36-
initial_user_input: str | None = typer.Option(None, "-u", "--user-input", help="Initial user input"),
42+
max_iterations: int = typer.Option(
43+
5,
44+
"-n",
45+
"--max-iterations",
46+
help="Max iteration count. If the task hasn’t succeeded after this many iterations, it will terminate.",
47+
),
48+
need_user_input: bool = typer.Option(
49+
False,
50+
"--enable-per-iteration-instruction",
51+
help="If enabled, provide an instruction at the start of each iteration (except the first, which uses the initial instruction). The process suspends until you provide it.",
52+
),
53+
initial_user_input: str | None = typer.Option(
54+
None, "-t", "--initial-instruction", help="You can provide the initial instruction here."
55+
),
3756
extract_archives_to: str | None = typer.Option(
38-
None, "-e", "--extract-to", help="Directory in which to unpack any archives"
57+
None,
58+
"-e",
59+
"--extract-to",
60+
help="Copy input data to specified directory and automatically extract all .zip archives. ",
3961
),
4062
# === Logging parameters ===
41-
verbosity: int = typer.Option(1, "-v", "--verbosity", help="Verbosity level (0–4)"),
63+
verbosity: int = typer.Option(
64+
1,
65+
"-v",
66+
"--verbosity",
67+
help=(
68+
"-v 0: Only includes error messages\n"
69+
"-v 1: Contains key essential information\n"
70+
"-v 2: Includes brief information plus detailed information such as file save locations\n"
71+
"-v 3: Includes info-level information plus all model training related information\n"
72+
"-v 4: Includes full debug information"
73+
),
74+
),
4275
):
4376
"""
4477
mlzero: a CLI for running the AutoMLAgent pipeline.

src/autogluon/assistant/coding_agent.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77
from omegaconf import OmegaConf
88

9-
from .managers import Manager
109
from .rich_logging import configure_logging
1110
from .utils import extract_archives
1211

@@ -45,6 +44,7 @@ def run_agent(
4544
output_dir.mkdir(parents=False, exist_ok=True)
4645

4746
configure_logging(verbosity=verbosity, output_dir=output_dir)
47+
from .managers import Manager
4848

4949
if extract_archives_to is not None:
5050
if extract_archives_to and extract_archives_to != input_data_folder:

src/autogluon/assistant/rich_logging.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ def _configure_logging(console_level: int, output_dir: Path = None) -> None:
4747
console = Console(file=sys.stderr)
4848
console_handler = RichHandler(console=console, markup=True, rich_tracebacks=True)
4949
console_handler.setLevel(console_level)
50+
console_handler.name = CONSOLE_HANDLER
5051
handlers = [console_handler]
5152
else:
5253
stdout_handler = logging.StreamHandler(sys.stdout)

src/autogluon/assistant/tools_registry/indexing.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
import contextlib
2+
import io
13
import logging
4+
import os
25
import pickle
36
from pathlib import Path
47
from typing import Dict, List, Optional, Tuple
@@ -11,6 +14,8 @@
1114

1215
logger = logging.getLogger(__name__)
1316

17+
os.environ["TRANSFORMERS_NO_ADVISORY_WARNINGS"] = "true"
18+
1419

1520
class TutorialIndexer:
1621
"""
@@ -32,6 +37,10 @@ def __del__(self):
3237
"""Cleanup method to properly close the embedding model."""
3338
self.cleanup()
3439

40+
def __silent_encode(self, input):
41+
with contextlib.redirect_stderr(io.StringIO()):
42+
return self.model.encode(input)
43+
3544
def cleanup(self):
3645
"""Cleanup the embedding model to avoid multiprocessing issues."""
3746
if self.model is not None:
@@ -41,6 +50,8 @@ def cleanup(self):
4150
self.model.close()
4251
elif hasattr(self.model, "stop_multi_process_pool"):
4352
self.model.stop_multi_process_pool()
53+
else:
54+
del self.model
4455
except Exception as e:
4556
logger.debug(f"Error during model cleanup: {e}")
4657
finally:
@@ -141,7 +152,7 @@ def _build_tool_index(self, tool_name: str, tutorial_type: str) -> Tuple[faiss.I
141152

142153
for i in range(0, len(summaries), batch_size):
143154
batch_summaries = summaries[i : i + batch_size]
144-
batch_embeddings = self.model.encode(batch_summaries)
155+
batch_embeddings = self.__silent_encode(batch_summaries)
145156

146157
# Ensure proper format
147158
if not isinstance(batch_embeddings, np.ndarray):
@@ -316,7 +327,7 @@ def search(self, query: str, tool_name: str, condensed: bool = False, top_k: int
316327
return []
317328

318329
# Generate query embedding
319-
query_embedding = self.model.encode([query])
330+
query_embedding = self.__silent_encode([query])
320331

321332
# Ensure proper data type and memory layout
322333
if not isinstance(query_embedding, np.ndarray):

src/autogluon/assistant/webui/Home.py

Lines changed: 0 additions & 56 deletions
This file was deleted.

0 commit comments

Comments
 (0)