Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 88 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ TMLL provides users with pre-built, automated solutions integrating general Trac
## Table of Contents
- [Installation](#installation)
- [Quick Start](#quick-start)
- [MCP Server](#mcp-server)
- [CLI Usage](#cli-usage)
- [Features and Modules](#features-and-modules)
- [Prerequisites](#prerequisites)
- [Documentation](#documentation)
Expand Down Expand Up @@ -99,6 +101,92 @@ anomalies = ad.find_anomalies(method='iforest')
ad.plot_anomalies(anomalies)
```

## MCP Server

TMLL provides an MCP (Model Context Protocol) server that exposes trace analysis capabilities to AI assistants and other MCP clients.

### Setup

1. Install TMLL (see [Installation](#installation))

2. Start your Trace Server:
```bash
./tracecompass-server -vmargs -Dtraceserver.port=8080
```

3. Configure in your MCP client (e.g., `~/.config/kiro-cli/mcp.json`). Point `command` at the Python interpreter of the environment where TMLL is installed, and set `PYTHONPATH` so the `tmll` package is importable:
```json
{
"mcpServers": {
"tmll": {
"type": "stdio",
"command": "/path/to/tmll/venv/bin/python",
"args": ["-m", "tmll.mcp.server"],
"env": {
"PYTHONPATH": "/path/to/tmll"
}
}
}
}
```

### Available Tools

- `ensure_server`: Check if the Trace Compass server is running; downloads, installs, and starts it automatically if not found
- `create_experiment`: Create trace experiments from files
- `list_outputs`: List available outputs for an experiment
- `fetch_data`: Fetch data from experiment outputs
- `detect_anomalies`: Run anomaly detection analysis
- `detect_memory_leak`: Detect memory leaks
- `detect_changepoints`: Detect performance trend changes
- `analyze_correlation`: Perform root cause correlation analysis
- `detect_idle_resources`: Identify underutilized resources
- `plan_capacity`: Run capacity planning predictions

## CLI Usage

TMLL includes a command-line interface for running analyses without writing code.

### Basic Commands

```bash
# Create an experiment
tmll_cli.py create --traces /path/to/trace1 /path/to/trace2 --name "My Experiment"

# List outputs for an experiment
tmll_cli.py list-outputs --experiment <UUID>

# Fetch data from outputs
tmll_cli.py fetch-data --experiment <UUID> --keywords "cpu usage"

# Run anomaly detection
tmll_cli.py detect-anomalies --experiment <UUID> --keywords "cpu usage" --method iforest

# Detect memory leaks
tmll_cli.py detect-memory-leak --experiment <UUID>

# Detect change points
tmll_cli.py detect-changepoints --experiment <UUID> --method pelt

# Analyze correlations
tmll_cli.py analyze-correlation --experiment <UUID> --method pearson

# Detect idle resources
tmll_cli.py detect-idle --experiment <UUID> --threshold 5

# Run capacity planning
tmll_cli.py plan-capacity --experiment <UUID> --horizon 30

# Perform clustering
tmll_cli.py cluster --experiment <UUID> --method kmeans --n-clusters 3
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See the other comment.

```

### Options

- `--host`: Trace Server host (default: localhost)
- `--port`: Trace Server port (default: 8080)
- `--verbose`: Enable verbose output

## Prerequisites

- Python 3.8 or higher
Expand Down
48 changes: 33 additions & 15 deletions tmll/mcp/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,22 +68,22 @@ def fetch_data_cmd(args):
data = client.fetch_data(experiment, outputs_with_tree)

if args.output:
for key, value in data.items():
if isinstance(value, pd.DataFrame):
value.to_csv(f"{args.output}_{key}.csv", index=False)
elif isinstance(value, dict):
for sub_key, df in value.items():
if isinstance(df, pd.DataFrame):
df.to_csv(f"{args.output}_{key}_{sub_key}.csv", index=False)
for output_id, content in data.items():
if isinstance(content, dict):
for series_name, df in content.items():
safe_name = series_name.replace("->", "_").replace(" ", "_")
df.to_csv(f"{args.output}_{output_id}_{safe_name}.csv", index=False)
elif isinstance(content, pd.DataFrame):
content.to_csv(f"{args.output}_{output_id}.csv", index=False)
print(f"Data exported to {args.output}_*.csv")
else:
result = {}
serializable_data = {}
for k, v in data.items():
if isinstance(v, pd.DataFrame):
result[k] = v.to_dict()
elif isinstance(v, dict):
result[k] = {sk: sv.to_dict() for sk, sv in v.items() if isinstance(sv, pd.DataFrame)}
print(json.dumps(result, indent=2, default=str))
if isinstance(v, dict):
serializable_data[k] = {sk: sv.to_dict() for sk, sv in v.items() if isinstance(sv, pd.DataFrame)}
elif isinstance(v, pd.DataFrame):
serializable_data[k] = v.to_dict()
print(json.dumps(serializable_data, indent=2, default=str))


def detect_anomalies(args):
Expand All @@ -101,14 +101,30 @@ def detect_anomalies(args):
print("No outputs found matching criteria")
return

ad = AnomalyDetection(client, experiment, outputs)
ad = AnomalyDetection(client, experiment, outputs, resample_freq=args.resample_freq, min_size=args.min_size)
result = ad.find_anomalies(method=args.method)

if args.plot:
ad.plot_anomalies(result)
else:
total = sum(len(df) for df in result.anomalies.values())
total = sum(len(df[df.filter(regex="_is_anomaly$").any(axis=1)]) for df in result.anomalies.values())
print(f"Found {total} anomalies across {len(result.anomalies)} outputs")

if total > 0:
print("\nTop 3 Anomalies:")
all_anomalies = []
for name, df in result.anomalies.items():
is_anomaly = df.filter(regex="_is_anomaly$").any(axis=1)
anomaly_df = df[is_anomaly].copy()
anomaly_df["source"] = name
all_anomalies.append(anomaly_df)

if all_anomalies:
combined_anomalies = pd.concat(all_anomalies)
if "anomaly_score" in combined_anomalies.columns:
top_3 = combined_anomalies.sort_values("anomaly_score", ascending=False).head(3)
for i, (idx, row) in enumerate(top_3.iterrows(), 1):
print(f"{i}. Time: {idx}, Source: {row['source']}, Score: {row['anomaly_score']:.4f}")


def detect_memory_leak(args):
Expand Down Expand Up @@ -281,6 +297,8 @@ def main():
anomaly_parser.add_argument("-k", "--keywords", nargs="+", default=["cpu usage"], help="Output keywords")
anomaly_parser.add_argument("-m", "--method", default="iforest", help="Detection method")
anomaly_parser.add_argument("-p", "--plot", action="store_true", help="Plot anomalies")
anomaly_parser.add_argument("-H", "--resample-freq", default="1s", help="Resampling frequency")
anomaly_parser.add_argument("-s", "--min-size", type=int, default=10, help="Minimum data points")
anomaly_parser.set_defaults(func=detect_anomalies)

# memory-leak command
Expand Down
Loading
Loading