mdl-train-mcp
by JoshuaSP
README.md
# mdl-train-mcp
An MCP server for monitoring and managing training jobs on [Modal](https://modal.com). Built for LLMs that need to check on long-running GPU training without drowning in log output.
## Why?
Training logs on Modal can be tens of thousands of lines — weight loading bars, Omniverse init spam, 8 ranks of identical output. Dumping all of that into an LLM context is wasteful and often hits resource limits.
This server gives you **browsable logs**: start with a summary, then drill into what matters.
| Tool | What it does |
|---|---|
| `list_apps` | List running, deployed, and recent apps with filtering |
| `get_logs` | Browse logs with summary/window/grep modes |
| `stop_app` | Stop a running app |
## The `get_logs` workflow
Instead of returning a giant blob, `get_logs` has three modes:
**1. Summary (default)** — returns line count, first/last 10 lines, and any errors with line numbers. Small response, always works.
```
get_logs(app_id="ap-xxx")
→ {total_lines: 30000, errors: [{line: 847, text: "CUDA error: ..."}], head: [...], tail: [...]}
```
**2. Window** — read a specific range. Like scrolling through a file.
```
get_logs(app_id="ap-xxx", window_start=840, window_size=30)
→ 30 lines around the error
```
**3. Grep** — search with regex and context lines. Like `grep -C`.
```
get_logs(app_id="ap-xxx", grep="Error|Traceback", grep_context=15)
→ all errors with 15 lines of surrounding context
```
**Landmarks** — pass `landmark_patterns` in summary mode to get a table of contents:
```
get_logs(app_id="ap-xxx", landmark_patterns=["Iteration \\d+", "success_rate", "checkpoint"])
→ landmarks: [{line: 200, text: "Iteration 1/3000"}, {line: 5000, text: "success_rate: 0.95"}, ...]
```
Landmark sampling is fair across patterns — one pattern won't dominate.
## Features
- **Progress bar collapsing** — tqdm bars, HF weight loading, and downloads are collapsed to their latest update (50 progress lines → 1 showing current state)
- **Auto-retry on resource limits** — if Modal's API rejects a large `tail`, automatically retries with smaller values and tells you what happened
- **Error deduplication** — 10,000 identical `[Error]` lines become a handful of unique entries
- **Case-sensitive error detection** — won't false-positive on metric names like `rot_align_error`
## Setup
### 1. Install
```bash
# Using uv (recommended)
uv pip install mdl-train-mcp
# Or from source
git clone https://github.com/JoshuaSP/mdl-train-mcp
cd mdl-train-mcp
uv venv && uv pip install -e .
```
### 2. Configure Modal
Make sure you have the [Modal CLI](https://modal.com/docs/guide/cli) installed and authenticated:
```bash
pip install modal
modal setup
```
### 3. Add to Claude Code
Add to your `.mcp.json`:
```json
{
"mcpServers": {
"mdl": {
"command": "mdl-train-mcp",
"env": {
"MODAL_PROFILE": "your-profile"
}
}
}
}
```
Or from source:
```json
{
"mcpServers": {
"mdl": {
"command": "uv",
"args": ["--directory", "/path/to/mdl-train-mcp", "run", "mdl-train-mcp"],
"env": {
"MODAL_BIN": "/path/to/modal",
"MODAL_PROFILE": "your-profile"
}
}
}
}
```
### Environment variables
| Variable | Description | Default |
|---|---|---|
| `MODAL_BIN` | Path to modal CLI binary | `modal` |
| `MODAL_PROFILE` | Modal profile to use | (default profile) |
## Tools reference
### list_apps
```
list_apps(state?: string, name_contains?: string)
```
Filter by state (`"running"`, `"deployed"`, `"stopped"`, `"ephemeral"`) or name substring.
### get_logs
```
get_logs(
app_id: string,
tail?: number, # log entries to fetch (default 500, max 5000)
since?: string, # "1h", "30m", "2d", or ISO datetime
until?: string,
source?: string, # "stdout", "stderr", "system"
window_start?: number, # line number for window mode
window_size?: number, # lines to return (default 50, max 200)
grep?: string, # regex search (case-insensitive)
grep_context?: number, # context lines around matches (max 30)
landmark_patterns?: string[] # regex patterns for summary landmarks
)
```
### stop_app
```
stop_app(app_id: string)
```
Irreversible — terminates the app and all its containers.
## License
MIT
This server cannot be deployed
Maintenance
ActivityInactive
ResponsivenessNo issues