#
tokens: 6666/50000 11/11 files
lines: off (toggle) GitHub
raw markdown copy
# Directory Structure

```
├── .gitignore
├── .python-version
├── main.py
├── mcp_client.py
├── mcp_server.py
├── pyproject.toml
├── README_MCP.md
├── README.md
├── requirements.txt
├── server.py
├── test.py
└── uv.lock
```

# Files

--------------------------------------------------------------------------------
/.python-version:
--------------------------------------------------------------------------------

```
3.10

```

--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------

```
# Python-generated files
__pycache__/
*.py[oc]
build/
dist/
wheels/
*.egg-info

# Virtual environments
.venv

temp_files/
```

--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------

```markdown
# Mermaid Diagram Generator Server

A simple Flask server that generates diagrams from Mermaid syntax using mermaid-cli.

## Prerequisites

- Python 3.7+
- Node.js and npm (for mermaid-cli)
- mermaid-cli installed globally: `npm install -g @mermaid-js/mermaid-cli`

## Installation

1. Clone this repository
2. Install Python dependencies:
   ```
   pip install -r requirements.txt
   ```
3. Ensure mermaid-cli is installed globally:
   ```
   npm install -g @mermaid-js/mermaid-cli
   ```

## Running the Server

Start the server with:

```
python server.py
```

By default, the server runs on `http://localhost:5000`.

### Temporary Files

The server creates a local directory called `temp_files` in the project folder for storing temporary files. This approach:

- Avoids permission issues with system temp directories
- Works better in virtual environments
- Automatically cleans up files older than 30 minutes

## API Usage

### Web Interface

Open your browser and navigate to `http://localhost:5000` to use the web interface.

### API Endpoint

Send a POST request to `/generate` with a JSON body containing your Mermaid diagram:

```json
{
  "mermaid": "graph TD\nA[Client] --> B[Load Balancer]\nB --> C[Server1]\nB --> D[Server2]",
  "theme": "default",  // optional: default, dark, forest, neutral
  "background": "white" // optional: white, transparent
}
```

The server will return a PNG image of the rendered diagram.

Example using curl:

```bash
curl -X POST http://localhost:5000/generate \
  -H "Content-Type: application/json" \
  -d '{"mermaid":"graph TD\nA[Client] --> B[Load Balancer]"}' \
  --output diagram.png
```

## Testing

Run the included test script to verify everything is working:

```
python test.py
```

This will generate a sample diagram and save it as `output_diagram.png`.

## Troubleshooting

If you encounter errors:

1. Ensure mermaid-cli (mmdc) is installed and accessible in your PATH
2. Check server logs for specific error messages
3. Make sure your Mermaid syntax is valid
4. Verify the `temp_files` directory exists and has appropriate permissions

```

--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------

```
flask==2.3.3
Werkzeug==2.3.7
requests==2.31.0
mcp>=0.1.0 
```

--------------------------------------------------------------------------------
/main.py:
--------------------------------------------------------------------------------

```python
def main():
    print("Hello from test-mcp!")


if __name__ == "__main__":
    main()

```

--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------

```toml
[project]
name = "test-mcp"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.10"
dependencies = [
    "mcp[cli]>=1.4.1",
]

```

--------------------------------------------------------------------------------
/test.py:
--------------------------------------------------------------------------------

```python
#!/usr/bin/env python3
import requests
import os
import sys

# Mermaid diagram text
mermaid_text = """
graph TD
    A[Client] --> B[Load Balancer]
    B --> C[Server 1]
    B --> D[Server 2]
    B --> E[Server 3]
    C --> F[Database]
    D --> F
    E --> F
"""

# Base URL of the server
base_url = "http://localhost:5000"

def test_generate_diagram():
    """Test generating a diagram via the API"""
    
    print("Testing diagram generation API...")
    
    # Prepare the request data
    data = {
        "mermaid": mermaid_text,
        "theme": "default",
        "background": "white"
    }
    
    try:
        # Send the request
        print(f"Sending request to {base_url}/generate...")
        response = requests.post(f"{base_url}/generate", json=data)
        
        # Check if the request was successful
        if response.status_code == 200:
            # Save the image to a file
            output_file = "output_diagram.png"
            with open(output_file, "wb") as f:
                f.write(response.content)
            
            print(f"Diagram generated successfully and saved to {output_file}")
            file_size = os.path.getsize(output_file)
            print(f"File size: {file_size} bytes")
            
            if file_size == 0:
                print("Warning: Generated file is empty!")
                return False
                
            return True
        else:
            print(f"Error generating diagram. Status code: {response.status_code}")
            print(f"Error message: {response.text}")
            return False
    except requests.exceptions.ConnectionError:
        print(f"Error: Could not connect to server at {base_url}")
        print("Make sure the server is running and accessible.")
        return False
    except Exception as e:
        print(f"Unexpected error: {str(e)}")
        return False

if __name__ == "__main__":
    success = test_generate_diagram()
    if not success:
        sys.exit(1)  # Exit with error code if test failed 
```

--------------------------------------------------------------------------------
/README_MCP.md:
--------------------------------------------------------------------------------

```markdown
# Mermaid Diagram Generator for MCP

This project provides a Mermaid diagram generator tool for the Model Control Protocol (MCP) framework. It allows you to generate diagrams from Mermaid syntax through MCP tools and resources.

## Features

- Generate diagrams from Mermaid syntax using MCP tools
- Multiple theme options (default, dark, forest, neutral)
- Background options (white, transparent)
- Access example diagrams through resources
- Automatic cleanup of temporary files
- Native image handling using MCP's `Image` class

## Prerequisites

- Python 3.7+
- Node.js and npm (for mermaid-cli)
- mermaid-cli installed globally: `npm install -g @mermaid-js/mermaid-cli`
- MCP Python package: `pip install mcp`

## Installation

1. Clone this repository
2. Install Python dependencies:
   ```
   pip install mcp
   ```
3. Ensure mermaid-cli is installed globally:
   ```
   npm install -g @mermaid-js/mermaid-cli
   ```

## Usage

### Running the MCP Server

Start the MCP server with:

```
python mcp_server.py
```

By default, the server runs on port 7000.

### Using the Client

The `mcp_client.py` file demonstrates how to use the MCP client to interact with the server:

```python
from mcp_client import MermaidClient

# Create client
client = MermaidClient()

# Get example diagrams
examples = client.get_examples()

# Generate a diagram
client.generate_diagram(
    mermaid_code="""
    graph TD
        A[Client] --> B[Load Balancer]
        B --> C[Server]
    """,
    output_path="diagram.png",
    theme="dark",
    background="transparent"
)
```

### Running the Example Client

```
python mcp_client.py
```

This will generate example diagrams in the `output` directory.

## MCP Server API

### Tools

- **generate_mermaid_diagram**: Generates a PNG image from Mermaid code
  - Parameters:
    - `mermaid_code` (str): The Mermaid diagram code
    - `theme` (str, optional): Theme to use (default, dark, forest, neutral)
    - `background` (str, optional): Background color (white, transparent)
  - Returns: `Image` object containing the diagram

### Resources

- **mermaid://examples**: Returns a dictionary of example Mermaid diagrams
  - Examples include: flowchart, sequence diagram, class diagram, state diagram

## Image Handling

The server uses MCP's `Image` class from `FastMCP` to return images, providing:

- Direct handling of binary image data
- Proper format specification (PNG)
- Alt text for accessibility
- Automatic serialization by the MCP framework

The client code demonstrates how to handle the `Image` object returned by the server and save it to a file. The MCP client automatically converts the `Image` object to a format that can be easily processed by client applications.

## Temporary Files

The server creates a local directory called `temp_files` in the project folder for storing temporary files. This directory is cleaned up automatically to remove files older than 30 minutes.

## Troubleshooting

If you encounter errors:

1. Ensure mermaid-cli (mmdc) is installed and accessible in your PATH
2. Check server logs for specific error messages
3. Make sure your Mermaid syntax is valid
4. Verify the `temp_files` directory exists and has appropriate permissions 
```

--------------------------------------------------------------------------------
/mcp_client.py:
--------------------------------------------------------------------------------

```python
from mcp.client import MCPClient
import os
import logging
from typing import Optional

# Set up logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

class MermaidClient:
    def __init__(self, server_url: str = "http://localhost:7000"):
        """
        Initialize the Mermaid client.
        
        Args:
            server_url: URL of the MCP server
        """
        self.client = MCPClient(server_url)
        logging.info(f"Connected to MCP server at {server_url}")
    
    def get_examples(self) -> dict:
        """
        Get example Mermaid diagrams.
        
        Returns:
            Dictionary of example diagrams
        """
        try:
            examples = self.client.get_resource("mermaid://examples")
            logging.info(f"Retrieved {len(examples)} example diagrams")
            return examples
        except Exception as e:
            logging.error(f"Error getting examples: {str(e)}")
            raise
    
    def generate_diagram(
        self, 
        mermaid_code: str, 
        output_path: str, 
        theme: Optional[str] = "default", 
        background: Optional[str] = "white"
    ) -> str:
        """
        Generate a diagram from Mermaid code and save it to a file.
        
        Args:
            mermaid_code: The Mermaid diagram code
            output_path: Path to save the image
            theme: The theme to use (default, dark, forest, neutral)
            background: The background color (white, transparent)
            
        Returns:
            Path to the saved image
        """
        try:
            logging.info(f"Generating diagram with theme '{theme}' and background '{background}'")
            
            # Call the MCP tool to generate the diagram
            # The result is now an Image object from FastMCP which contains raw image data
            image_result = self.client.call_tool(
                "generate_mermaid_diagram", 
                mermaid_code=mermaid_code, 
                theme=theme, 
                background=background
            )
            
            # The client already handles the Image object conversion, 
            # so we should get raw image data directly
            if hasattr(image_result, 'data') and isinstance(image_result.data, bytes):
                # Handle Image object with direct data attribute
                image_data = image_result.data
            elif isinstance(image_result, dict) and 'data' in image_result:
                # Handle dict response with data field
                image_data = image_result['data']
                if not isinstance(image_data, bytes):
                    logging.warning("Converting data to bytes")
                    image_data = bytes(image_data)
            elif isinstance(image_result, bytes):
                # Handle direct bytes response
                image_data = image_result
            else:
                # Log the actual type for debugging
                logging.error(f"Unexpected result type: {type(image_result)}")
                logging.error(f"Result content: {str(image_result)[:200]}...")
                raise ValueError(f"Unexpected image format returned from server")
            
            # Save the image to a file
            with open(output_path, 'wb') as f:
                f.write(image_data)
                
            logging.info(f"Saved diagram to {output_path} ({len(image_data)} bytes)")
            return output_path
            
        except Exception as e:
            logging.error(f"Error generating diagram: {str(e)}")
            raise

def main():
    # Create the client
    client = MermaidClient()
    
    try:
        # Get example diagrams
        examples = client.get_examples()
        
        # Create output directory
        os.makedirs("output", exist_ok=True)
        
        # Generate diagrams for each example
        for name, mermaid_code in examples.items():
            output_path = f"output/{name}_diagram.png"
            client.generate_diagram(mermaid_code, output_path)
            print(f"Generated {name} diagram: {output_path}")
            
        # Generate a custom diagram
        custom_code = """
        graph LR
            A[Start] --> B{Is it working?}
            B -->|Yes| C[Great!]
            B -->|No| D[Debug]
            D --> B
        """
        
        client.generate_diagram(
            custom_code,
            "output/custom_diagram.png",
            theme="dark",
            background="transparent"
        )
        print("Generated custom diagram: output/custom_diagram.png")
        
    except Exception as e:
        print(f"Error: {str(e)}")

if __name__ == "__main__":
    main() 
```

--------------------------------------------------------------------------------
/mcp_server.py:
--------------------------------------------------------------------------------

```python
from mcp.server.fastmcp import FastMCP, Image
import base64
import subprocess
import os
import uuid
import logging
import sys
from typing import Optional
from mcp.types import ImageContent

# Set up logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

# Create a local temp directory in the project folder
TEMP_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'temp_files')
os.makedirs(TEMP_DIR, exist_ok=True)
logging.info(f"Temporary directory at: {TEMP_DIR}")

# Create an MCP server
mcp = FastMCP("Mermaid Diagram Generator")

@mcp.tool()
def generate_mermaid_diagram(
    mermaid_code: str, 
    theme: Optional[str] = "default", 
    background: Optional[str] = "white"
) -> Image:
    """
    Generate a diagram from Mermaid code and return it as an image.
    
    Args:
        mermaid_code: The Mermaid diagram code
        theme: The theme to use (default, dark, forest, neutral)
        background: The background color (white, transparent)
    
    Returns:
        An image of the generated diagram
    """
    logging.info(f"Generating diagram with theme '{theme}' and background '{background}'")
    logging.info(f"Mermaid code: {mermaid_code[:50]}...")
    
    try:
        # Create temporary files with unique names
        unique_id = str(uuid.uuid4())
        input_file = os.path.join(TEMP_DIR, f"{unique_id}.mmd")
        output_file = os.path.join(TEMP_DIR, f"{unique_id}.png")
        
        # Write mermaid text to the input file
        with open(input_file, 'w', encoding='utf-8') as f:
            f.write(mermaid_code)
        
        # Find mmdc executable
        mmdc_cmd = find_mmdc_executable()
        if not mmdc_cmd:
            raise Exception("mermaid-cli not found. Please ensure it's installed and in PATH")
        
        # Build the command
        cmd = [mmdc_cmd, '-i', input_file, '-o', output_file]
        
        # Add optional parameters
        if theme:
            cmd.extend(['-t', theme])
        if background:
            cmd.extend(['-b', background])
        
        logging.info(f"Running command: {' '.join(cmd)}")
        
        # Run the command
        result = subprocess.run(cmd, capture_output=True, text=True)
        
        if result.returncode != 0:
            logging.error(f"Error running mmdc: {result.stderr}")
            raise Exception(f"Error generating diagram: {result.stderr}")
        
        # Check if output file exists and has content
        if not os.path.exists(output_file):
            raise Exception("Failed to create diagram: output file not found")
        
        file_size = os.path.getsize(output_file)
        if file_size == 0:
            raise Exception("Generated image is empty")
        
        # Read the image file
        with open(output_file, 'rb') as f:
            image_data = f.read()
        
        # Create and return Image object
        # The Image class from FastMCP handles the image data directly
        return Image(data=image_data, format="png", alt_text=f"Mermaid diagram with theme {theme} and background {background}")
        
    except Exception as e:
        logging.exception("Error generating diagram")
        raise e
    
    finally:
        # Clean up temporary files
        try:
            if os.path.exists(input_file):
                os.remove(input_file)
            if os.path.exists(output_file):
                os.remove(output_file)
        except Exception as cleanup_error:
            logging.exception(f"Error during cleanup: {cleanup_error}")

def find_mmdc_executable():
    """
    Find the mmdc executable path.
    
    Returns:
        Path to mmdc executable or None if not found
    """
    mmdc_paths = [
        'mmdc',  # Default PATH
        os.path.join(os.path.expanduser('~'), 'AppData', 'Roaming', 'npm', 'mmdc.cmd'),
        os.path.join(os.path.expanduser('~'), 'AppData', 'Roaming', 'npm', 'mmdc'),
        os.path.join('C:', 'Program Files', 'nodejs', 'node_modules', '@mermaid-js', 'mermaid-cli', 'bin', 'mmdc'),
        os.path.join('C:', 'Program Files', 'nodejs', 'node_modules', '.bin', 'mmdc')
    ]
    
    for path in mmdc_paths:
        logging.info(f"Trying mmdc at: {path}")
        try:
            test_result = subprocess.run([path, '--version'], capture_output=True, text=True)
            if test_result.returncode == 0:
                logging.info(f"Found working mmdc at: {path}")
                return path
        except Exception as e:
            logging.info(f"Could not use mmdc at {path}: {str(e)}")
    
    return None

@mcp.resource("mermaid://examples")
def get_mermaid_examples() -> dict:
    """Get example Mermaid diagrams"""
    return {
        "flowchart": """
graph TD
    A[Client] --> B[Load Balancer]
    B --> C[Server 1]
    B --> D[Server 2]
    B --> E[Server 3]
    C --> F[Database]
    D --> F
    E --> F
""",
        "sequence": """
sequenceDiagram
    participant Browser
    participant API
    participant Database
    
    Browser->>API: GET /data
    API->>Database: SELECT * FROM data
    Database-->>API: Return data
    API-->>Browser: Return JSON
""",
        "class": """
classDiagram
    class Animal {
        +String name
        +move()
    }
    class Dog {
        +bark()
    }
    class Bird {
        +fly()
    }
    Animal <|-- Dog
    Animal <|-- Bird
""",
        "state": """
stateDiagram-v2
    [*] --> Idle
    Idle --> Processing: Start
    Processing --> Completed
    Processing --> Error
    Completed --> [*]
    Error --> Idle: Retry
"""
    }

# Cleanup function for old temp files
def cleanup_old_files(max_age_minutes=30):
    """Remove files older than max_age_minutes from the temp directory"""
    import time
    try:
        current_time = time.time()
        for filename in os.listdir(TEMP_DIR):
            file_path = os.path.join(TEMP_DIR, filename)
            if os.path.isfile(file_path):
                # Check file age
                file_age_minutes = (current_time - os.path.getmtime(file_path)) / 60
                if file_age_minutes > max_age_minutes:
                    os.remove(file_path)
                    logging.info(f"Removed old file: {file_path}")
    except Exception as e:
        logging.exception(f"Error cleaning up old files: {e}")

if __name__ == "__main__":
    # Clean up old files before starting
    cleanup_old_files()
    
    # Start the MCP server
    mcp.run() 
```

--------------------------------------------------------------------------------
/server.py:
--------------------------------------------------------------------------------

```python
# server.py
from flask import Flask, request, send_file, Response
import subprocess
import tempfile
import os
import uuid
import logging
import shutil
import sys

app = Flask(__name__)
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

# Create a local temp directory in the project folder
TEMP_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'temp_files')
os.makedirs(TEMP_DIR, exist_ok=True)
logging.info(f"Temporary directory at: {TEMP_DIR}")
logging.info(f"Python executable: {sys.executable}")
logging.info(f"Current directory: {os.getcwd()}")

@app.route('/generate', methods=['POST'])
def generate_diagram():
    input_file = None
    output_file = None
    
    try:
        # Get mermaid text from the request
        if not request.is_json:
            return Response("Request must be JSON", status=400)
        
        data = request.get_json()
        if 'mermaid' not in data:
            return Response("Missing 'mermaid' field in JSON", status=400)
        
        mermaid_text = data['mermaid']
        logging.info(f"Received mermaid text: {mermaid_text[:50]}...")
        
        # Create temporary files with unique names in our local temp directory
        unique_id = str(uuid.uuid4())
        input_file = os.path.join(TEMP_DIR, f"{unique_id}.mmd")
        output_file = os.path.join(TEMP_DIR, f"{unique_id}.png")
        
        logging.info(f"Input file: {input_file}")
        logging.info(f"Output file: {output_file}")
        
        # Write mermaid text to the input file
        with open(input_file, 'w', encoding='utf-8') as f:
            f.write(mermaid_text)
        
        logging.info(f"Wrote mermaid text to input file, size: {os.path.getsize(input_file)} bytes")
        
        # Run mmdc command
        # Try to find mmdc in common locations if direct command fails
        mmdc_paths = [
            'mmdc',  # Default PATH
            os.path.join(os.path.expanduser('~'), 'AppData', 'Roaming', 'npm', 'mmdc.cmd'),
            os.path.join(os.path.expanduser('~'), 'AppData', 'Roaming', 'npm', 'mmdc'),
            os.path.join('C:', 'Program Files', 'nodejs', 'node_modules', '@mermaid-js', 'mermaid-cli', 'bin', 'mmdc'),
            os.path.join('C:', 'Program Files', 'nodejs', 'node_modules', '.bin', 'mmdc')
        ]
        
        # Try each path
        mmdc_cmd = None
        for path in mmdc_paths:
            logging.info(f"Trying mmdc at: {path}")
            try:
                # Just test if the command exists
                test_result = subprocess.run([path, '--version'], 
                                           capture_output=True, 
                                           text=True)
                if test_result.returncode == 0:
                    mmdc_cmd = path
                    logging.info(f"Found working mmdc at: {path}")
                    break
            except Exception as e:
                logging.info(f"Could not use mmdc at {path}: {str(e)}")
        
        if not mmdc_cmd:
            logging.error("Could not find mmdc executable in any location")
            return Response("mermaid-cli not found. Please ensure it's installed and in PATH", status=500)
        
        cmd = [mmdc_cmd, '-i', input_file, '-o', output_file]
        
        # Add optional parameters if provided
        if 'theme' in data:
            cmd.extend(['-t', data['theme']])
        if 'background' in data:
            cmd.extend(['-b', data['background']])
        
        logging.info(f"Running command: {' '.join(cmd)}")
        
        try:
            result = subprocess.run(cmd, capture_output=True, text=True)
            logging.info(f"Command exit code: {result.returncode}")
            logging.info(f"Command stdout: {result.stdout}")
            logging.info(f"Command stderr: {result.stderr}")
            
            if result.returncode != 0:
                logging.error(f"Error running mmdc: {result.stderr}")
                return Response(f"Error generating diagram: {result.stderr}", status=500)
        except Exception as cmd_error:
            logging.exception(f"Exception running command: {str(cmd_error)}")
            return Response(f"Error executing mmdc command: {str(cmd_error)}", status=500)
        
        # Check if output file exists
        if not os.path.exists(output_file):
            logging.error(f"Output file not created: {output_file}")
            return Response("Failed to create diagram: output file not found", status=500)
        
        file_size = os.path.getsize(output_file)
        logging.info(f"Output file size: {file_size} bytes")
        
        if file_size == 0:
            logging.error("Generated image has zero size")
            return Response("Generated image is empty", status=500)
            
        # Return the generated image
        return send_file(output_file, mimetype='image/png', as_attachment=False)
    
    except Exception as e:
        logging.exception("Error processing request")
        return Response(f"Server error: {str(e)}", status=500)
    
    finally:
        # Clean up temporary files
        try:
            if input_file and os.path.exists(input_file):
                os.remove(input_file)
                logging.info(f"Cleaned up input file: {input_file}")
            # We don't delete the output file here as send_file needs it
            # The cleanup function below will handle old files
        except Exception as cleanup_error:
            logging.exception(f"Error during cleanup: {cleanup_error}")

# Cleanup function to remove old temp files
def cleanup_old_files(max_age_minutes=30):
    """Remove files older than max_age_minutes from the temp directory"""
    try:
        current_time = time.time()
        for filename in os.listdir(TEMP_DIR):
            file_path = os.path.join(TEMP_DIR, filename)
            if os.path.isfile(file_path):
                # Check file age
                file_age_minutes = (current_time - os.path.getmtime(file_path)) / 60
                if file_age_minutes > max_age_minutes:
                    os.remove(file_path)
                    logging.info(f"Removed old file: {file_path}")
    except Exception as e:
        logging.exception(f"Error cleaning up old files: {e}")

@app.route('/', methods=['GET'])
def index():
    return """
    <html>
        <head>
            <title>Mermaid Diagram Generator</title>
            <style>
                body { font-family: Arial, sans-serif; max-width: 800px; margin: 0 auto; padding: 20px; }
                textarea { width: 100%; height: 200px; margin-bottom: 10px; }
                button { padding: 10px 15px; background-color: #4CAF50; color: white; border: none; cursor: pointer; }
                #result { margin-top: 20px; }
                pre { background-color: #f5f5f5; padding: 10px; border-radius: 5px; }
            </style>
        </head>
        <body>
            <h1>Mermaid Diagram Generator</h1>
            <p>Enter your Mermaid diagram text below:</p>
            <textarea id="mermaidText">graph TD
A[Client] --> B[Load Balancer]
B --> C[Server1]
B --> D[Server2]</textarea>
            <div>
                <label for="theme">Theme:</label>
                <select id="theme">
                    <option value="default">Default</option>
                    <option value="dark">Dark</option>
                    <option value="forest">Forest</option>
                    <option value="neutral">Neutral</option>
                </select>
                <label for="background">Background:</label>
                <select id="background">
                    <option value="white">White</option>
                    <option value="transparent">Transparent</option>
                </select>
            </div>
            <button onclick="generateDiagram()">Generate Diagram</button>
            <div id="result"></div>
            
            <script>
                function generateDiagram() {
                    const mermaidText = document.getElementById('mermaidText').value;
                    const theme = document.getElementById('theme').value;
                    const background = document.getElementById('background').value;
                    const resultDiv = document.getElementById('result');
                    
                    resultDiv.innerHTML = 'Processing...';
                    
                    fetch('/generate', {
                        method: 'POST',
                        headers: {
                            'Content-Type': 'application/json'
                        },
                        body: JSON.stringify({
                            mermaid: mermaidText,
                            theme: theme,
                            background: background
                        })
                    })
                    .then(response => {
                        if (!response.ok) {
                            return response.text().then(text => { throw new Error(text) });
                        }
                        return response.blob();
                    })
                    .then(blob => {
                        const url = URL.createObjectURL(blob);
                        resultDiv.innerHTML = `<h3>Generated Diagram:</h3><img src="${url}" alt="Generated Diagram">`;
                    })
                    .catch(error => {
                        resultDiv.innerHTML = `<h3>Error:</h3><pre>${error.message}</pre>`;
                    });
                }
            </script>
        </body>
    </html>
    """

if __name__ == '__main__':
    # Import here to avoid issues when importing the app in other modules
    import time
    
    # Schedule cleanup of old files on startup
    cleanup_old_files()
    
    app.run(host='0.0.0.0', port=5000, debug=True)

```