auto-mcp-tool 0.2.1
Automatically generate MCP servers from Python modules using LLM-powered documentation
Requires Python: >=3.10
Keywords: ai, anthropic, automation, claude, code-generation, llm, mcp, model-context-protocol, ollama, openai, server, tools

# auto-mcp

[![PyPI version](https://badge.fury.io/py/auto-mcp-tool.svg)](https://pypi.org/project/auto-mcp-tool/)
[![Python versions](https://img.shields.io/pypi/pyversions/auto-mcp-tool.svg)](https://pypi.org/project/auto-mcp-tool/)
[![License](https://img.shields.io/pypi/l/auto-mcp-tool.svg)](https://github.com/krajasek/auto-mcp-framework/blob/main/LICENSE)

Automatically generate MCP (Model Context Protocol) servers from Python modules using LLM-powered documentation.

## Table of Contents

- [Features](#features)
- [Installation](#installation)
- [Quick Start](#quick-start)
- [MCP Transports](#mcp-transports)
- [Package Analysis](#package-analysis)
- [Manifest-Based Generation](#manifest-based-generation)
- [Wrapper for C Extensions](#wrapper-for-c-extensions)
- [Type Serialization System](#type-serialization-system)
- [CLI Reference](#cli-reference)
- [Python API Reference](#python-api-reference)
- [Decorators](#decorators)
- [Session Lifecycle](#session-lifecycle)
- [LLM Providers](#llm-providers)
- [Configuration](#configuration)
- [Hot Reload](#hot-reload)
- [Examples](#examples)
  - [Simple Math](#simple-math-examplessimple_math)
  - [Async API](#async-api-examplesasync_api)
  - [Class Service](#class-service-examplesclass_service)
  - [Pandas Analytics](#pandas-analytics-examplespandas_analytics)
  - [SQLite Database](#sqlite-database-examplessqlite_database)
- [Pandas MCP Server Setup Guide](#pandas-mcp-server-setup-guide)
- [SQLite MCP Server Setup Guide](#sqlite-mcp-server-setup-guide)
- [Integration with Claude Desktop](#integration-with-claude-desktop)
- [Development](#development)
- [License](#license)

---

## Features

- **Automatic Tool Generation**: Exposes public functions as MCP tools
- **Package Analysis**: Recursively analyze installed packages (requests, pandas, etc.)
- **LLM-Powered Descriptions**: Uses local (Ollama) or cloud (OpenAI, Anthropic) LLMs to generate tool descriptions
- **Multiple Output Formats**: Standalone file, Python package, or in-memory server
- **Multiple Transports**: stdio and SSE for different deployment scenarios
- **Type Serialization**: Handle complex Python types (datetime, Path, UUID, pandas DataFrames, etc.)
- **Compression Support**: Automatic compression for large data with gzip, zlib, or lz4
- **Object Store**: Server-side handle-based storage for stateful objects (sessions, connections)
- **Decorator Support**: Fine-grained control with `@mcp_tool`, `@mcp_exclude`, `@mcp_resource`, `@mcp_prompt`
- **Session Lifecycle**: Explicit session management with `create_session`/`close_session` tools and automatic `SessionContext` injection
- **Async Support**: Full support for async functions
- **Hot Reload**: Watch for file changes during development
- **Caching**: File-based caching to avoid redundant LLM calls
- **Type Safety**: Full type hints and mypy strict mode

## Installation

```bash
# Using uv (recommended)
uv add auto-mcp-tool

# Using pip
pip install auto-mcp-tool
```

## Quick Start

### 1. Create a Python module with functions to expose

```python
# math_utils.py
def add(a: float, b: float) -> float:
    """Add two numbers together."""
    return a + b

def multiply(a: float, b: float) -> float:
    """Multiply two numbers."""
    return a * b

def _private_helper():
    """This won't be exposed (starts with underscore)."""
    pass
```

### 2. Generate and run an MCP server

**Using the CLI:**
```bash
# Generate a standalone server file
auto-mcp-tool generate math_utils.py -o server.py

# Or serve directly
auto-mcp-tool serve math_utils.py
```

**Using the Python API:**
```python
from auto_mcp import AutoMCP
import math_utils

auto = AutoMCP(use_llm=False)
server = auto.create_server([math_utils])
server.run()
```

### 3. Or generate from an installed package

```bash
# Check what would be exposed from the requests package
auto-mcp-tool package check requests

# Generate a server from an installed package (json stdlib)
auto-mcp-tool generate json -o json_server.py --no-llm

# Serve directly
auto-mcp-tool package serve json --no-llm

# For packages like pandas/numpy that re-export from submodules:
auto-mcp-tool generate pandas -o pandas_server.py --no-llm --include-reexports
```

---

## MCP Transports

auto-mcp supports multiple transport protocols for MCP communication.

### stdio (Default)

Standard input/output transport. Used by Claude Desktop and most MCP clients.

**CLI:**
```bash
# Explicit (default)
auto-mcp-tool serve mymodule.py --transport stdio

# Implicit (stdio is default)
auto-mcp-tool serve mymodule.py
```

**Python API:**
```python
server = auto.create_server([mymodule])
server.run()  # stdio by default
server.run(transport="stdio")  # explicit
```

**Claude Desktop configuration:**
```json
{
  "mcpServers": {
    "my-tools": {
      "command": "auto-mcp-tool",
      "args": ["serve", "mymodule.py", "--no-llm"]
    }
  }
}
```

### SSE (Server-Sent Events)

HTTP-based transport using Server-Sent Events. Useful for web clients.

**CLI:**
```bash
# Basic SSE server
auto-mcp-tool serve mymodule.py --transport sse

# Custom host and port
auto-mcp-tool serve mymodule.py --transport sse --host 127.0.0.1 --port 3000
```

**Python API:**
```python
server = auto.create_server([mymodule])
server.run(transport="sse")
```

**Client connection:**
```bash
# The SSE endpoint will be available at:
# http://localhost:8080/sse
```

### Transport Comparison

| Transport | Protocol | Streaming | Use Case |
|-----------|----------|-----------|----------|
| `stdio` | stdin/stdout | Yes | CLI tools, Claude Desktop |
| `sse` | HTTP + SSE | Yes | Web clients, browsers |

### Environment Variables for Transports

```bash
# Default transport
AUTO_MCP_TRANSPORT=stdio

# HTTP settings (for sse transport)
AUTO_MCP_HOST=0.0.0.0
AUTO_MCP_PORT=8080
```

---

## Package Analysis

Generate MCP servers from installed Python packages without writing any code.

### CLI Commands

#### Check a Package

Preview what would be exposed without generating anything:

```bash
# Basic check
auto-mcp-tool package check requests

# With verbose output (shows module tree)
auto-mcp-tool package check requests -v

# Check only public API (__all__ exports)
auto-mcp-tool package check requests --public-api-only

# Limit recursion depth
auto-mcp-tool package check boto3 --max-depth 2

# Filter modules with patterns
auto-mcp-tool package check requests --include 'requests.api.*' --exclude 'requests.compat.*'
```

#### Generate from a Package

Use the main `generate` command - it works with both files and installed packages:

```bash
# Generate server file from an installed package
auto-mcp-tool generate json -o json_server.py --no-llm

# With LLM descriptions
auto-mcp-tool generate requests -o requests_server.py --llm-provider ollama

# Only public API
auto-mcp-tool generate pandas -o pandas_server.py --public-api-only

# With filtering
auto-mcp-tool generate boto3 -o s3_tools.py \
    --include 'boto3.s3.*' \
    --max-depth 2 \
    --no-llm
```

#### Serve a Package Directly

```bash
# Serve with stdio transport (for Claude Desktop)
auto-mcp-tool package serve json --no-llm

# Serve with SSE transport
auto-mcp-tool package serve requests --transport sse --port 3000

# With options
auto-mcp-tool package serve requests \
    --name "HTTP Tools" \
    --public-api-only \
    --no-llm
```

### Python API

```python
from auto_mcp import AutoMCP, quick_server_from_package

# Quick one-liner
server = quick_server_from_package("json", name="JSON Tools")
server.run()

# With more control
auto = AutoMCP(
    use_llm=False,
    public_api_only=True,
    max_depth=2,
    include_patterns=["requests.api.*"],
    exclude_patterns=["requests.compat.*"],
)

# Analyze a package
metadata = auto.analyze_package("requests")
print(f"Found {metadata.module_count} modules")
print(f"Found {metadata.method_count} methods")

# Create server from package
server = auto.create_server_from_package("requests")
server.run()

# Generate file from package
auto.generate_file_from_package("json", "json_server.py")

# For packages with re-exported functions (pandas, numpy, etc.)
auto = AutoMCP(
    use_llm=False,
    include_reexports=True,  # Include functions from submodules
    max_depth=0,
)
server = auto.create_server_from_package("pandas")
```

### Package Analysis Options

| Option | Description |
|--------|-------------|
| `--max-depth` | Maximum recursion depth for submodule discovery |
| `--public-api-only` | Only expose functions in `__all__` |
| `--include-private` | Include private modules (starting with `_`) |
| `--include PATTERN` | Glob patterns for modules to include |
| `--exclude PATTERN` | Glob patterns for modules to exclude |
| `--include-reexports` | Include functions re-exported in `__all__` from submodules |

### Re-exported Functions

Many large packages like `pandas`, `numpy`, and `requests` define functions in submodules but re-export them at the package level via `__all__`. By default, these re-exported functions are not discovered because their `__module__` attribute points to the original submodule.

Use `--include-reexports` to include these functions:

```bash
# Without --include-reexports: 0 tools found (pandas uses re-exports)
auto-mcp-tool package check pandas --max-depth 0

# With --include-reexports: 530+ tools found
auto-mcp-tool package check pandas --max-depth 0 --include-reexports

# Generate pandas server with all re-exported functions
auto-mcp-tool generate pandas -o pandas_server.py --no-llm --include-reexports
```

**Common packages that need `--include-reexports`:**
- `pandas` - DataFrame operations, I/O functions (read_csv, concat, merge, etc.)
- `numpy` - Array operations, mathematical functions
- `requests` - HTTP functions (get, post, put, etc.)
- `scipy` - Scientific computing functions

### Example: Creating a JSON Tools Server

```bash
# 1. Check what's available
auto-mcp-tool package check json -v

# Output:
# Package: json
# Modules discovered: 3
#
# Tools (4)
# ┏━━━━━━━━┳━━━━━━━━┳━━━━━━━┳━━━━━━━━━━━━━━━━┓
# ┃ Name   ┃ Module ┃ Async ┃ Parameters     ┃
# ┡━━━━━━━━╇━━━━━━━━╇━━━━━━━╇━━━━━━━━━━━━━━━━┩
# │ dump   │ json   │       │ obj, fp, ...   │
# │ dumps  │ json   │       │ obj, ...       │
# │ load   │ json   │       │ fp, ...        │
# │ loads  │ json   │       │ s, ...         │
# └────────┴────────┴───────┴────────────────┘

# 2. Generate and run
auto-mcp-tool package serve json --no-llm

# 3. Or for Claude Desktop, add to config:
```

```json
{
  "mcpServers": {
    "json-tools": {
      "command": "auto-mcp-tool",
      "args": ["package", "serve", "json", "--no-llm"]
    }
  }
}
```

---

## Manifest-Based Generation

Manifests provide fine-grained control over which functions from a module or package are exposed as MCP tools. Instead of exposing everything, you can selectively choose specific functions and provide custom descriptions.

### Manifest File Format

Create a YAML manifest file to define your server:

```yaml
# sqlite3_manifest.yaml
server_name: sqlite-server

# Automatically include functions that return types used by listed tools
auto_include_dependencies: true

tools:
  # Top-level functions
  - function: connect
    description: "Open a connection to an SQLite database. Use ':memory:' for in-memory."

  # Instance methods with custom names
  - function: Connection.execute
    name: connection_execute
    description: "Execute a single SQL statement. Returns a Cursor."

  - function: Connection.commit
    name: connection_commit
    description: "Commit the current transaction."

  - function: Cursor.fetchall
    name: cursor_fetchall
    description: "Fetch all remaining rows from the query result."

  - function: Cursor.fetchone
    name: cursor_fetchone
    description: "Fetch the next row, or None if no more rows."
```

### Using Manifests

**CLI:**
```bash
# Generate from manifest
auto-mcp-tool generate sqlite3 --manifest sqlite3_manifest.yaml -o sqlite_server.py

# The manifest selects which functions to expose
# Only the listed tools will be in the generated server
```

**Manifest Fields:**

| Field | Description |
|-------|-------------|
| `server_name` | Name for the generated MCP server |
| `auto_include_dependencies` | Auto-include functions that produce types needed by listed tools |
| `tools` | List of tool definitions |

**Tool Entry Fields:**

| Field | Required | Description |
|-------|----------|-------------|
| `function` | Yes | Function path (e.g., `connect`, `Connection.execute`, `Cursor.fetchall`) |
| `name` | No | Custom tool name (defaults to function name) |
| `description` | No | Custom description (defaults to docstring) |

### Handle-Based Object Storage

When exposing instance methods (like `Connection.execute`), the generator automatically:

1. Stores non-serializable objects (connections, cursors) in an in-memory object store
2. Returns handles (like `"Connection_1"`) that reference the stored objects
3. Accepts handles as parameters to retrieve and use the original objects

```python
# Generated code pattern:
_object_store: dict[str, Any] = {}

def connect(database: str) -> str:
    result = sqlite3.connect(database)
    return _store_object(result, "Connection")  # Returns "Connection_1"

def connection_execute(connection: str, sql: str) -> str:
    _instance = _get_object(connection)  # Retrieves actual Connection
    result = _instance.execute(sql)
    return _store_object(result, "Cursor")  # Returns "Cursor_1"
```

### Example: SQLite Manifest

See `examples/sqlite3_manifest.yaml` for a complete SQLite database server manifest with:
- Connection management (connect, close)
- Transaction control (commit, rollback)
- Query execution (execute, executemany, executescript)
- Cursor operations (fetchone, fetchall, fetchmany)

### Example: Pandas Manifest

See `examples/pandas_manifest.yaml` for a comprehensive pandas data analysis manifest with:
- Data reading (read_csv, read_excel, read_json, read_parquet)
- DataFrame operations (head, tail, describe, groupby)
- Data transformation (merge, concat, pivot_table, melt)
- Statistics (sum, mean, median, std, corr)

---

## Wrapper for C Extensions

Some Python modules (like `sqlite3`, `_json`, certain parts of `numpy`) are implemented as C extensions and cannot be directly introspected. The wrapper generator creates pure Python wrappers that delegate to these modules.

### When to Use Wrappers

Use the wrapper command when:
- The module is a C extension (built-in or compiled)
- Direct `generate` command fails due to unintrospectable callables
- You need MCP tools from stdlib modules like `sqlite3`

### Generating Wrappers

**CLI:**
```bash
# Generate wrapper for sqlite3 (stdlib)
auto-mcp-tool wrapper generate sqlite3 -o sqlite3_wrapper.py

# Then generate MCP server from the wrapper
auto-mcp-tool generate sqlite3_wrapper.py -o sqlite_server.py

# Or use --wrapper flag directly on generate
auto-mcp-tool generate sqlite3 --wrapper -o sqlite_server.py
```

**Check for C extension callables:**
```bash
# See which callables in a module are C extensions
auto-mcp-tool wrapper check sqlite3
```

**Options:**
| Option | Description |
|--------|-------------|
| `-o, --output` | Output path for generated wrapper file |
| `--with` | Package name if different from module (e.g., `--with Pillow` for `PIL`) |
| `--version` | Specific package version for uvx isolation |
| `--no-isolated` | Disable uvx isolation (requires local installation) |
| `--include-private` | Include private methods (starting with `_`) |
| `--include-dunder` | Include dunder methods (`__init__`, etc.) |

### How It Works

The wrapper generator:

1. **Inspects the C extension** - Examines callable objects in the module
2. **Infers signatures** - Uses docstrings and heuristics to determine parameters
3. **Generates delegating code** - Creates Python functions that call the original C functions
4. **Adds type hints** - Provides type annotations where possible

**Example generated wrapper:**
```python
# sqlite3_wrapper.py (generated)
import sqlite3 as _original_module

def connect(
    database: str,
    timeout: float = 5.0,
    detect_types: int = 0,
    isolation_level: str | None = "",
    check_same_thread: bool = True,
    cached_statements: int = 128,
    uri: bool = False,
) -> "Connection":
    """Open a connection to an SQLite database."""
    return _original_module.connect(
        database=database,
        timeout=timeout,
        detect_types=detect_types,
        isolation_level=isolation_level,
        check_same_thread=check_same_thread,
        cached_statements=cached_statements,
        uri=uri,
    )
```

### Combining with Manifests

For maximum control, combine wrappers with manifests:

```bash
# 1. Generate wrapper for C extension
auto-mcp-tool wrapper generate sqlite3 -o sqlite3_wrapper.py

# 2. Create manifest selecting specific functions
# (see examples/sqlite3_manifest.yaml)

# 3. Generate server from manifest
auto-mcp-tool generate sqlite3 --manifest sqlite3_manifest.yaml -o server.py
```

---

## Type Serialization System

auto-mcp includes a powerful type serialization system for handling complex Python types in MCP contexts. This enables tools to accept and return types like `datetime`, `Path`, `UUID`, pandas DataFrames, and more.

### Quick Start

```python
from auto_mcp.types import TypeRegistry, register_stdlib_adapters

# Create a registry with standard library adapters
registry = TypeRegistry()
register_stdlib_adapters(registry)

# Now datetime, Path, UUID, etc. are automatically serialized
from datetime import datetime

# Serialize a datetime to JSON-compatible format
serialized = registry.serialize(datetime.now())
print(serialized)  # "2024-01-15T10:30:00"

# Deserialize back to datetime
dt = registry.deserialize("2024-01-15T10:30:00", datetime)
print(dt)  # datetime(2024, 1, 15, 10, 30, 0)
```

### Built-in Type Adapters

The following types are supported out of the box:

| Type | Serialized Format | Example |
|------|-------------------|---------|
| `datetime` | ISO 8601 string | `"2024-01-15T10:30:00"` |
| `date` | ISO 8601 string | `"2024-01-15"` |
| `time` | ISO 8601 string | `"10:30:00"` |
| `timedelta` | Total seconds (float) | `3600.5` |
| `Path` | String path | `"/home/user/file.txt"` |
| `UUID` | String UUID | `"550e8400-e29b-41d4-a716-446655440000"` |
| `Decimal` | String number | `"123.456"` |
| `bytes` | Base64 string | `"SGVsbG8gV29ybGQ="` |
| `set` | Sorted list | `[1, 2, 3]` |
| `frozenset` | Sorted list | `[1, 2, 3]` |
| `complex` | Dict with real/imag | `{"real": 3.0, "imag": 4.0}` |

**Optional adapters** (require additional packages):

| Type | Package | Serialized Format |
|------|---------|-------------------|
| `pandas.DataFrame` | pandas | Dict with columns, data, shape |
| `PIL.Image` | pillow | Base64 PNG with metadata |
| `numpy.ndarray` | numpy | Dict with data, shape, dtype |

### Using Type Adapters

#### Register Standard Library Adapters

```python
from auto_mcp.types import TypeRegistry, register_stdlib_adapters

registry = TypeRegistry()
register_stdlib_adapters(registry)
```

#### Register All Available Adapters

```python
from auto_mcp.types import TypeRegistry, register_all_adapters

registry = TypeRegistry()
register_all_adapters(registry)  # Includes pandas, PIL, numpy if installed
```

#### Create Custom Adapters

```python
from auto_mcp.types import TypeAdapter, FunctionAdapter
from dataclasses import dataclass

# Option 1: Using FunctionAdapter (simple)
@dataclass
class Point:
    x: float
    y: float

point_adapter = FunctionAdapter(
    target_type=Point,
    serializer=lambda p: {"x": p.x, "y": p.y},
    deserializer=lambda d: Point(d["x"], d["y"]),
    schema={"type": "object", "properties": {"x": {"type": "number"}, "y": {"type": "number"}}},
)

registry.register_adapter(point_adapter)

# Option 2: Using TypeAdapter class (more control)
class PointAdapter(TypeAdapter[Point]):
    target_type = Point

    def serialize(self, obj: Point) -> dict:
        return {"x": obj.x, "y": obj.y}

    def deserialize(self, data: dict) -> Point:
        return Point(data["x"], data["y"])

    def json_schema(self) -> dict:
        return {
            "type": "object",
            "properties": {
                "x": {"type": "number"},
                "y": {"type": "number"},
            },
            "required": ["x", "y"],
        }

registry.register_adapter(PointAdapter())
```

#### Quick Registration

```python
from datetime import datetime

registry.register(
    datetime,
    serialize=lambda dt: dt.isoformat(),
    deserialize=lambda s: datetime.fromisoformat(s),
    schema={"type": "string", "format": "date-time"},
)
```

### Function Wrappers

Automatically transform function inputs and outputs:

```python
from auto_mcp.types import FunctionWrapper, TypeRegistry, register_stdlib_adapters
from datetime import datetime
from pathlib import Path

registry = TypeRegistry()
register_stdlib_adapters(registry)

def process_file(path: Path, modified_after: datetime) -> dict:
    """Process a file if modified after the given time."""
    stat = path.stat()
    return {
        "path": str(path),
        "size": stat.st_size,
        "modified": datetime.fromtimestamp(stat.st_mtime).isoformat(),
    }

# Wrap the function for automatic type conversion
wrapper = FunctionWrapper(process_file, registry=registry)

# Call with JSON-compatible inputs - types are auto-converted
result = wrapper.call({
    "path": "/etc/hosts",
    "modified_after": "2024-01-01T00:00:00"
})
# path is converted from string to Path
# modified_after is converted from string to datetime
```

### Object Store

For stateful objects that can't be serialized (database connections, sessions, etc.), use the Object Store:

```python
from auto_mcp.types import ObjectStore, TypeRegistry

# Create store and registry
store = ObjectStore()
registry = TypeRegistry()

# Register a type for server-side storage
class DatabaseSession:
    def __init__(self, connection_string: str):
        self.connection_string = connection_string
        self.connected = True

    def query(self, sql: str) -> list:
        return [{"id": 1, "name": "Example"}]

registry.register_stored_type(
    DatabaseSession,
    ttl=3600,  # Auto-expire after 1 hour
    max_instances=10,  # Limit concurrent sessions
)

# Store an object and get a handle
session = DatabaseSession("postgresql://localhost/mydb")
handle = store.store(session, ttl=3600)
print(handle)  # "obj_a1b2c3d4..."

# Retrieve by handle
retrieved = store.get(handle)
result = retrieved.query("SELECT * FROM users")

# Clean up
store.remove(handle)
```

#### Object Store with Function Wrapper

```python
from auto_mcp.types import FunctionWrapper, ObjectStore, TypeRegistry

registry = TypeRegistry()
store = ObjectStore()

class Session:
    pass

registry.register_stored_type(Session, ttl=3600)

def create_session() -> Session:
    """Create a new session."""
    return Session()

def use_session(session: Session) -> str:
    """Use an existing session."""
    return f"Using session: {session}"

# Wrap functions
create_wrapper = FunctionWrapper(create_session, registry=registry, store=store)
use_wrapper = FunctionWrapper(use_session, registry=registry, store=store)

# create_session returns a handle string
handle = create_wrapper.call({})
print(handle)  # "obj_..."

# use_session accepts the handle and retrieves the object
result = use_wrapper.call({"session": handle})
```

### Deployment Considerations for Handle-Based Storage

The object store uses in-memory storage within a single Python process. This design has important implications for how you deploy MCP servers.

#### When Handle-Based Storage Works

| Transport/Deployment | Supported | Notes |
|---------------------|-----------|-------|
| stdio | Yes | Single process, used by Claude Desktop |
| SSE (single process) | Yes | Persistent connection to single server |
| HTTP (single process) | Yes | All requests handled by same process |
| HTTP (multi-worker) | No | Workers have separate object stores |
| Serverless (Lambda, Cloud Functions) | No | New process per invocation |
| Load-balanced cluster | No* | Requests may hit different servers |

*Can work with sticky sessions that route all requests from a client to the same backend.

#### The Problem Explained

When you call `connect()`, it returns a handle like `"Connection_1"`. This handle references an object stored in the server's memory:

```python
# Request 1 to Worker A:
handle = connect(":memory:")  # Returns "Connection_1", stored in Worker A

# Request 2 to Worker B:
connection_execute("Connection_1", "SELECT ...")  # Worker B doesn't have this handle!
```

#### Recommended Solutions

**1. Single-Process Deployment (Recommended)**

For most use cases, run your MCP server as a single process:

```bash
# This works - single process handles all requests
python my_server.py
```

The default `mcp.run()` runs a single-process server, which is suitable for:
- Local development
- Claude Desktop integration
- Single-user deployments
- Tools that don't need horizontal scaling

**2. Sticky Sessions for Load Balancing**

If you need multiple server instances, configure your load balancer to use sticky sessions (session affinity). This ensures all requests from the same client go to the same backend server.

**3. Write Custom Stateless Methods**

For truly stateless deployments, you can write wrapper methods that combine multiple operations:

```python
# Instead of: connect() -> execute() -> fetchall() -> close()
# Write a single stateless function:

def query_database(database: str, sql: str, parameters: list = None) -> list:
    """Execute a query and return results (stateless)."""
    conn = sqlite3.connect(database)
    try:
        cursor = conn.execute(sql, parameters or [])
        return cursor.fetchall()
    finally:
        conn.close()
```

This approach:
- Works in serverless environments
- Works with any load balancer
- No handle management needed
- Each call is independent

**4. Extend Generated Servers**

You can add custom stateless methods to generated servers:

```python
# my_sqlite_server.py
from generated_sqlite_server import mcp, connect, connection_execute, cursor_fetchall, connection_close

@mcp.tool(name="query")
def query(database: str, sql: str) -> list:
    """Execute a query and return all results (stateless convenience method)."""
    conn_handle = connect(database)
    try:
        cursor_handle = connection_execute(conn_handle, sql)
        return cursor_fetchall(cursor_handle)
    finally:
        connection_close(conn_handle)

if __name__ == "__main__":
    mcp.run()
```

### Compression

For large data, auto-mcp supports automatic compression:

```python
from auto_mcp.types import (
    CompressedAdapter,
    CompressionConfig,
    CompressionAlgorithm,
    with_compression,
    DateTimeAdapter,
)

# Method 1: Wrap any adapter with compression
adapter = DateTimeAdapter()
compressed = with_compression(
    adapter,
    threshold=1024,  # Only compress if > 1KB
    algorithm=CompressionAlgorithm.GZIP,
    level=6,
)

# Method 2: Using CompressedAdapter directly
config = CompressionConfig(
    enabled=True,
    algorithm=CompressionAlgorithm.GZIP,
    threshold=1024,  # Minimum size to trigger compression
    level=6,  # Compression level (1-9)
)
compressed = CompressedAdapter(adapter, config)

# Serialized data includes compression metadata
result = compressed.serialize(datetime.now())
# {
#     "compressed": True,
#     "algorithm": "gzip",
#     "original_size": 2048,
#     "compressed_size": 512,
#     "compression_ratio": 0.25,
#     "data": "H4sIAAAAAAAA..."
# }
```

#### Compression Algorithms

| Algorithm | Description | Use Case |
|-----------|-------------|----------|
| `GZIP` | Standard gzip (default) | General purpose, good compression |
| `ZLIB` | zlib compression | Slightly faster than gzip |
| `LZ4` | Very fast compression | When speed is critical (requires `lz4` package) |
| `NONE` | No compression | Disabled |

#### Auto-Compress Registry

Automatically apply compression to types that typically produce large output:

```python
from auto_mcp.types import AutoCompressRegistry, CompressionConfig

# Create auto-compress registry
config = CompressionConfig(threshold=10240)  # 10KB threshold
auto_compress = AutoCompressRegistry(config)

# Register types known to produce large output
auto_compress.register_large_type(pandas.DataFrame)
auto_compress.register_large_type(numpy.ndarray)

# Wrap adapters
df_adapter = create_pandas_dataframe_adapter()
compressed_adapter = auto_compress.wrap_adapter(df_adapter)
```

### Integration with MCP Generator

The type system integrates automatically with the MCP generator:

```python
from auto_mcp import AutoMCP
from auto_mcp.types import TypeRegistry, register_stdlib_adapters

# Create registry with adapters
registry = TypeRegistry()
register_stdlib_adapters(registry)

# Pass to AutoMCP
auto = AutoMCP(
    use_llm=False,
    type_registry=registry,  # Use custom registry
    enable_type_transforms=True,  # Enable automatic transforms
)

# Now your tools can use complex types
server = auto.create_server([mymodule])
```

### Class Wrapper

Wrap entire classes for MCP exposure:

```python
from auto_mcp.types import ClassWrapper, TypeRegistry, register_stdlib_adapters
from datetime import datetime

registry = TypeRegistry()
register_stdlib_adapters(registry)

class DateService:
    def parse_date(self, date_str: str) -> datetime:
        """Parse a date string."""
        return datetime.fromisoformat(date_str)

    def format_date(self, dt: datetime, fmt: str = "%Y-%m-%d") -> str:
        """Format a datetime."""
        return dt.strftime(fmt)

    def _private_method(self):
        """Not exposed."""
        pass

# Wrap the class
wrapper = ClassWrapper(DateService, registry=registry)

# Get available methods (excludes private)
print(wrapper.get_method_names())  # ['parse_date', 'format_date']

# Create instance and call methods
instance = wrapper.create()
result = wrapper.call_method(instance, "format_date", {
    "dt": "2024-01-15T10:30:00",
    "fmt": "%B %d, %Y"
})
print(result)  # "January 15, 2024"
```

### Type Strategies

The registry uses different strategies based on the type:

| Strategy | Description | Example Types |
|----------|-------------|---------------|
| `PASSTHROUGH` | Already JSON-compatible | `str`, `int`, `float`, `bool`, `list`, `dict` |
| `ADAPTER` | Serialize/deserialize via adapter | `datetime`, `Path`, `UUID`, custom types |
| `OBJECT_STORE` | Store server-side with handle | Sessions, connections, file handles |
| `UNSUPPORTED` | Cannot be handled | Unregistered complex types |

```python
from auto_mcp.types import TypeRegistry, TypeStrategy

registry = TypeRegistry()
register_stdlib_adapters(registry)

# Check strategy for a type
strategy = registry.get_strategy(datetime)
print(strategy)  # TypeStrategy.ADAPTER

strategy = registry.get_strategy(str)
print(strategy)  # TypeStrategy.PASSTHROUGH

# Get full type info
info = registry.get_type_info(datetime)
print(info.strategy)  # TypeStrategy.ADAPTER
print(info.adapter)  # DateTimeAdapter instance
print(info.json_schema)  # {"type": "string", "format": "date-time"}
```

---

## CLI Reference

### `auto-mcp-tool generate`

Generate MCP server code from Python files or installed packages.

```bash
# Generate from a Python file
auto-mcp-tool generate mymodule.py -o server.py

# Generate from an installed package
auto-mcp-tool generate pandas -o pandas_server.py --no-llm

# Generate with custom server name
auto-mcp-tool generate mymodule.py -o server.py --name my-server

# Use a manifest for selective tool exposure
auto-mcp-tool generate sqlite3 --manifest sqlite3_manifest.yaml -o server.py

# Use wrapper mode for C extension modules
auto-mcp-tool generate sqlite3 --wrapper -o sqlite_server.py

# Use LLM for better descriptions
auto-mcp-tool generate mymodule.py -o server.py --llm-provider ollama --llm-model qwen2.5-coder:7b

# Include re-exported functions (for pandas, numpy, etc.)
auto-mcp-tool generate pandas -o server.py --no-llm --include-reexports
```

**Options:**
| Option | Description |
|--------|-------------|
| `-o, --output` | Output file path (required) |
| `--manifest` | YAML manifest for selective tool exposure |
| `--name` | Server name (default: auto-mcp-server) |
| `--wrapper` | Use wrapper generator for C extension modules |
| `--llm-provider` | LLM provider: ollama, openai, anthropic |
| `--llm-model` | Model name for the LLM provider |
| `--no-llm` | Disable LLM description generation |
| `--no-cache` | Disable caching |
| `--include-private` | Include private functions (starting with _) |
| `--max-depth` | Maximum recursion depth for package submodule discovery |
| `--public-api-only` | Only expose functions in `__all__` |
| `--include-reexports` | Include functions re-exported from submodules |
| `--enable-sessions` | Enable session lifecycle support |
| `--session-ttl` | Session TTL in seconds (default: 3600) |
| `--max-sessions` | Maximum concurrent sessions (default: 100) |

### `auto-mcp-tool serve`

Run an MCP server directly from Python modules.

```bash
# Basic usage (stdio transport)
auto-mcp-tool serve mymodule.py

# With SSE transport
auto-mcp-tool serve mymodule.py --transport sse --port 8080

# With hot-reload for development
auto-mcp-tool serve mymodule.py --watch

# With LLM-enhanced descriptions
auto-mcp-tool serve mymodule.py --llm-provider ollama --llm-model qwen2.5-coder:7b
```

**Options:**
| Option | Description |
|--------|-------------|
| `--name` | Server name |
| `--transport` | Transport: stdio, sse (default: stdio) |
| `--port` | Port for HTTP transports (default: 8080) |
| `--host` | Host for HTTP transports (default: 0.0.0.0) |
| `--watch` | Enable hot-reload on file changes |
| `--llm-provider` | LLM provider |
| `--llm-model` | Model name |
| `--enable-sessions` | Enable session lifecycle support |
| `--session-ttl` | Session TTL in seconds (default: 3600) |
| `--max-sessions` | Maximum concurrent sessions (default: 100) |

### `auto-mcp-tool check`

Validate modules without generating output (dry-run).

```bash
# Check what tools would be generated
auto-mcp-tool check mymodule.py

# Verbose output with descriptions
auto-mcp-tool check mymodule.py --verbose
```

### `auto-mcp-tool inspect`

Inspect modules and display detailed MCP component information. This command provides deep visibility into what an MCP server exposes, including tools, resources, prompts, JSON schemas, and parameter details.

```bash
# Basic inspection (table format)
auto-mcp-tool inspect mymodule.py

# Verbose output with full JSON schemas
auto-mcp-tool inspect mymodule.py -v

# JSON output for tooling integration
auto-mcp-tool inspect mymodule.py -f json

# Tree view for hierarchical overview
auto-mcp-tool inspect mymodule.py -f tree

# Filter by name pattern (glob)
auto-mcp-tool inspect mymodule.py --filter "get_*"
auto-mcp-tool inspect mymodule.py --filter "*user*"

# Filter by component type
auto-mcp-tool inspect mymodule.py -t tools
auto-mcp-tool inspect mymodule.py -t resources

# Show source code
auto-mcp-tool inspect mymodule.py --show-source

# Include private methods
auto-mcp-tool inspect mymodule.py --include-private

# Inspect multiple modules
auto-mcp-tool inspect module1.py module2.py
```

**Example Output (table format):**
```
Module: calculator.py

Tools (3)
┌────────────┬─────────────────────────────┬───────┬──────────────┐
│ Name       │ Description                 │ Async │ Parameters   │
├────────────┼─────────────────────────────┼───────┼──────────────┤
│ add        │ Add two numbers together    │       │ a, b         │
│ multiply   │ Multiply two numbers        │       │ x, y         │
│ fetch_rate │ Fetch exchange rate         │ ✓     │ currency     │
└────────────┴─────────────────────────────┴───────┴──────────────┘
```

**Example Output (verbose mode):**
```
Tool: add
Description: Add two numbers together
Async: No  |  Session: No

Parameters:
┌──────┬───────┬──────────┬─────────────────────┐
│ Name │ Type  │ Default  │ Schema              │
├──────┼───────┼──────────┼─────────────────────┤
│ a    │ int   │ required │ {"type": "integer"} │
│ b    │ int   │ required │ {"type": "integer"} │
└──────┴───────┴──────────┴─────────────────────┘

Returns: int
```

**Example Output (tree format):**
```
calculator
├── Tools
│   ├── add(a: int, b: int) -> int
│   │   └── Add two numbers together
│   └── multiply(x: int, y: int) -> int
│       └── Multiply two numbers
└── Resources
    └── (none)
```

**Options:**
| Option | Description |
|--------|-------------|
| `-f, --format` | Output format: table (default), json, tree |
| `--filter` | Filter components by name (glob pattern) |
| `-t, --type` | Component type: tools, resources, prompts, all (default) |
| `-s, --show-schema` | Display full JSON schemas |
| `--show-source` | Display function source code |
| `--include-private` | Include private methods (starting with _) |
| `-v, --verbose` | Verbose output (implies --show-schema) |

### `auto-mcp-tool cache`

Manage the description cache.

```bash
# Show cache statistics
auto-mcp-tool cache stats

# Clear cache for specific modules
auto-mcp-tool cache clear mymodule.py

# Clear all cache
auto-mcp-tool cache clear
```

### `auto-mcp-tool config`

View configuration settings.

```bash
# Show current configuration
auto-mcp-tool config show

# Show environment variable reference
auto-mcp-tool config env
```

### `auto-mcp-tool package`

Commands for working with installed Python packages.

#### `auto-mcp-tool package check`

Analyze a package and show what would be exposed.

```bash
auto-mcp-tool package check requests
auto-mcp-tool package check requests -v
auto-mcp-tool package check boto3 --max-depth 2 --public-api-only
auto-mcp-tool package check pandas --include-reexports  # For packages with re-exports
```

**Options:**
| Option | Description |
|--------|-------------|
| `--max-depth` | Maximum recursion depth |
| `--public-api-only` | Only show `__all__` exports |
| `--include-private` | Include private modules |
| `--include PATTERN` | Glob pattern for modules to include |
| `--exclude PATTERN` | Glob pattern for modules to exclude |
| `--include-reexports` | Include functions re-exported from submodules |
| `-v, --verbose` | Show module tree and details |

> **Note**: To generate a server from a package, use `auto-mcp-tool generate <package>` - the main generate command works with both files and installed packages.

#### `auto-mcp-tool package serve`

Run an MCP server from a package.

```bash
auto-mcp-tool package serve json --no-llm
auto-mcp-tool package serve requests --transport sse --port 3000
auto-mcp-tool package serve pandas --no-llm --includ