Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
project-*.md
.venv
build/
__pycache__/
*.egg-info/
4 changes: 4 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
include LICENSE
include README.md
include requirements.txt
Copy link

Copilot AI May 23, 2025

Choose a reason for hiding this comment

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

Remove or update the reference to requirements.txt—that file doesn’t exist at the project root.

Suggested change
include requirements.txt

Copilot uses AI. Check for mistakes.
recursive-include templates *
60 changes: 60 additions & 0 deletions MODULAR_REFACTORING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Summary of Modular Refactoring

## Overview

We've refactored the original `generator.py` into a proper Python package structure while ensuring backward compatibility. This makes the code more maintainable and easier to use as a library.

## Key Aspects of the Modular Design

1. **Preserved Original Script**: The original `generator.py` script still works exactly as before.

2. **Same Templates Directory**: The refactored code uses the exact same `/templates` directory, with no changes needed.

3. **Backward Compatible**: Users can continue using the script as they always have.

4. **Package Structure**: Added proper Python package structure for better maintainability.

5. **Docker Support**: All Docker-related functionality is preserved without changes.

## File Structure and Relations

```
generator.py # Original entry point (unchanged functionality)
mcp_generator.py # Alternative entry point using modular code
openapi_mcp_generator/ # Package containing modular components
__init__.py # Package initialization
cli.py # Command-line interface
generator.py # Main generator module
generators.py # Code generators
http.py # HTTP client utilities
parser.py # OpenAPI parser
project.py # Project builder (uses templates/)
templates/ # Original templates directory (unchanged)
...
```

## How the Modular Code Uses the Original Templates

The `ProjectBuilder` class in `project.py` initializes with the path to the templates directory:

```python
# In generator.py in the modular package
TEMPLATE_DIR = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "templates")
```

This ensures that the modular code uses the exact same templates as the original script.

## Advantages of This Approach

1. **Better Organization**: Each component has a single responsibility
2. **Testability**: Components can be tested independently
3. **Reusability**: Functions can be imported and used programmatically
4. **Packageability**: Can be installed as a proper Python package

## Using the Modular Code

You can use the refactored code in multiple ways:

1. Continue using `generator.py` exactly as before
2. Install as a package and use the `mcp-generator` command
3. Import functions for use in your own Python code
119 changes: 108 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,24 @@ A Python tool that automatically converts OpenAPI specifications into fully func
- 🔐 Multiple authentication methods
- ⚡ Async operations & rate limiting
- 📡 SSE/IO communication protocols
- 📦 Modular code structure with package support

## Overview
## Modular Code Structure

This generator creates a fully functional MCP server implementation that exposes API operations defined in an OpenAPI specification as MCP tools and resources. The generated server is packaged with Docker for easy deployment and supports both SSE and IO communication protocols.
The generator has been refactored into a proper Python package while maintaining backward compatibility:

1. **Original Entry Point**: The `generator.py` script still works exactly as before
2. **Modular Organization**: Code is now split into focused modules
3. **Package Installation**: Can be installed as a proper Python package
4. **Same Templates**: Uses the exact same templates in the `/templates` directory
5. **Docker Support**: Preserves all Docker functionality

You can use the tool in whatever way you prefer:
1. Run `generator.py` directly (original approach)
2. Install as a package and use `mcp-generator` command
3. Use the module programmatically in your own Python code

For more details on the modular code structure, see [MODULAR_REFACTORING.md](MODULAR_REFACTORING.md).

## Features

Expand All @@ -29,25 +43,43 @@ This generator creates a fully functional MCP server implementation that exposes

- Python 3.10+
- Docker (for running the generated server)
- uv (Python package manager)
- pip or uv (Python package manager)

## Installation

### From Source

```bash
# Clone the repository
git clone https://github.com/abutbul/openapi-mcp-generator.git
cd openapi-mcp-generator

# Install dependencies using uv
# Install as a package (development mode)
pip install -e .

# Or using uv
uv venv
source .venv/bin/activate
uv pip install -r requirements.txt
uv pip install -e .
```

### Using pip (once published)

```bash
pip install openapi-mcp-generator
```

## Usage

```bash
# Using the original script (still works the same way)
python generator.py openapi.yaml --output-dir ./output --api-url https://api.example.com

# Using the new modular CLI tool after installation
mcp-generator openapi.yaml --output-dir ./output --api-url https://api.example.com

# Using the python module directly
python -m openapi_mcp_generator.cli openapi.yaml --output-dir ./output
```

### Command Line Options
Expand Down Expand Up @@ -81,14 +113,44 @@ The generated `docker.sh` script supports the following commands:
- `--log-level=LEVEL`: Set logging level (default: info)
- `stop`: Stop the container
- `clean`: Remove the container and image
- `test`: Run the test suite (TBD)
- `logs`: View container logs

## Documentation
## Project Structure

The modular generator has the following structure:

For more detailed information, see:
```
openapi-mcp-generator/
├── generator.py # Original entry point (maintained for backward compatibility)
├── mcp_generator.py # New entry point (uses the modular structure)
├── openapi_mcp_generator/ # Main package (new modular structure)
│ ├── __init__.py # Package initialization
│ ├── cli.py # Command-line interface
│ ├── generator.py # Main generator module
│ ├── generators.py # Code generators for tools/resources
│ ├── http.py # HTTP client utilities
│ ├── parser.py # OpenAPI parser
│ └── project.py # Project builder
├── templates/ # Original templates directory (used by the modular code)
│ ├── config/
│ ├── docker/
│ ├── server/
│ ├── pyproject.toml
│ └── requirements.txt
├── samples/ # Sample implementations
├── tests/ # Test cases
├── LICENSE # License file
├── README.md # This file
├── pyproject.toml # Project metadata
└── setup.py # Package setup
```

TBD
The modular structure preserves all the existing functionality while making the code more maintainable:

1. The original entry point (`generator.py`) can still be used as before
2. The existing templates in `/templates` are used by the new modular code
3. All Docker-related functionality is preserved exactly as it was
4. The project can now be installed as a proper Python package

## Sample Implementations

Expand All @@ -104,7 +166,42 @@ Check out our sample implementations to see the generator in action:
4. Run the test suite
5. Submit a pull request


## License

This project is licensed under the MIT License - see the (./LICENSE) file for details.
This project is licensed under the MIT License - see the LICENSE file for details.

## Usage Examples

### 1. Using the library without installing (direct from source)

To generate an MCP server from the Elasticsearch 6.1 spec folder:

```bash
# Run the original script directly
python generator.py samples/elasticsearch_6.1/api

# Or use the modular entry point
python mcp_generator.py samples/elasticsearch_6.1/api
```

### 2. Using the library after installing with pip

First, install the package (from the project root):

```bash
pip install .
```

Then use the CLI tool to convert the Trilium ETAPI spec:

```bash
mcp-generator samples/TriliumNext/etapi.openapi.yaml
```

Or use it programmatically in your own Python code:

```python
from openapi_mcp_generator import generator

generator.generate('samples/TriliumNext/etapi.openapi.yaml')
Copy link

Copilot AI May 23, 2025

Choose a reason for hiding this comment

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

Update the example to call generate_mcp_server (not generate), matching the actual API function name.

Suggested change
generator.generate('samples/TriliumNext/etapi.openapi.yaml')
generator.generate_mcp_server('samples/TriliumNext/etapi.openapi.yaml')

Copilot uses AI. Check for mistakes.
```
69 changes: 69 additions & 0 deletions examples/compatibility_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#!/usr/bin/env python3
"""
Compatibility example showing how to use both the original and modular approaches.

This script demonstrates that both the original and modular code can be used
interchangeably with the same templates and functionality.
"""

import os
import sys
from pathlib import Path

Comment on lines +11 to +12
Copy link

Copilot AI May 23, 2025

Choose a reason for hiding this comment

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

The Path import is unused—remove it to clean up imports.

Suggested change
from pathlib import Path

Copilot uses AI. Check for mistakes.
# Get the project root directory
project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

# Example OpenAPI file path - use a sample from the samples directory
sample_openapi_file = os.path.join(project_root, "tests", "openapi.yaml")

# Create output directories
original_output_dir = os.path.join(project_root, "output", "original")
modular_output_dir = os.path.join(project_root, "output", "modular")

os.makedirs(original_output_dir, exist_ok=True)
os.makedirs(modular_output_dir, exist_ok=True)

# Method 1: Use the original generator.py directly
print("Method 1: Using the original generator.py directly")
print("=" * 60)
original_command = f"python {os.path.join(project_root, 'generator.py')} {sample_openapi_file} --output-dir={original_output_dir} --api-url=http://localhost:8000"
print(f"Running: {original_command}")
print("-" * 60)
os.system(original_command)
print("\n")

# Method 2: Import and use the modular generator
print("Method 2: Using the modular package programmatically")
print("=" * 60)
sys.path.insert(0, project_root)
from openapi_mcp_generator.generator import generate_mcp_server

print("Calling generate_mcp_server function from the modular package...")
project_dir = generate_mcp_server(
sample_openapi_file,
modular_output_dir,
api_url="http://localhost:8000",
auth_type="bearer",
api_token="your-token"
)
print(f"MCP server generated successfully in: {project_dir}")
print(f"To build and run the Docker container:")
print(f" cd {project_dir}")
print(f" ./docker.sh build")
print(f" ./docker.sh start --transport=sse")
print("\n")

# Method 3: Use the CLI script if installed
print("Method 3: Using the CLI tool (if installed with pip install -e .)")
print("=" * 60)
print("This would normally be run as:")
print(f"mcp-generator {sample_openapi_file} --output-dir={modular_output_dir} --api-url=http://localhost:8000")
print("Or as:")
print(f"python -m openapi_mcp_generator.cli {sample_openapi_file} --output-dir={modular_output_dir} --api-url=http://localhost:8000")
print("\n")

print("Summary")
print("=" * 60)
print("All methods use the exact same templates in the /templates directory")
print("All methods generate Docker-ready MCP servers with identical functionality")
print("All the core features remain the same regardless of which approach you use")
28 changes: 28 additions & 0 deletions examples/programmatic_usage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#!/usr/bin/env python3
"""
Example of using the openapi_mcp_generator package programmatically.

This script shows how to use the modular package in your own Python code.
"""

from openapi_mcp_generator import generate_mcp_server, parse_openapi_spec

def main():
"""Example of using the generator programmatically."""
# Generate an MCP server for an OpenAPI spec
project_dir = generate_mcp_server(
openapi_file="path/to/openapi.yaml",
output_dir="./output",
api_url="https://api.example.com",
auth_type="bearer",
api_token="your-token"
)

print(f"Server generated at: {project_dir}")

# Example of parsing an OpenAPI spec
spec = parse_openapi_spec("path/to/openapi.yaml")
print(f"API title: {spec.get('info', {}).get('title', 'Unknown')}")

if __name__ == "__main__":
main()
26 changes: 26 additions & 0 deletions generator.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,15 @@
TEMPLATE_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "templates")
env = Environment(loader=FileSystemLoader(TEMPLATE_DIR))

# Try to import from the modular version - if it fails, we'll use the original implementation
try:
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from openapi_mcp_generator.generator import generate_mcp_server as modular_generate
USE_MODULAR = True
except ImportError:
USE_MODULAR = False


def parse_openapi_spec(filepath: str) -> Dict[str, Any]:
"""
Parse an OpenAPI specification file.
Expand Down Expand Up @@ -259,6 +268,23 @@ def generate_mcp_server(
Returns:
Path to the generated project directory
"""
# Use the modular implementation if available
if USE_MODULAR:
try:
return modular_generate(
openapi_file,
output_dir,
api_url,
auth_type,
api_token,
api_username,
api_password
)
except Exception as e:
print(f"Warning: Error using modular implementation: {e}")
print("Falling back to original implementation...")

# Original implementation
# Parse the OpenAPI specification
spec = parse_openapi_spec(openapi_file)

Expand Down
16 changes: 16 additions & 0 deletions mcp_generator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/usr/bin/env python3
"""
OpenAPI to MCP Server Generator

This is the new modular entry point for generating a fully functional MCP server
implementation based on an OpenAPI specification. It uses the same functionality
as the original generator.py but packaged in a more modular way.

You can also use the original generator.py which will continue to work exactly as before.
"""

import sys
from openapi_mcp_generator.cli import main

if __name__ == "__main__":
sys.exit(main())
Loading