Skip to main content
Glama
pandeussilvae

Panda Odoo MCP Server

README.md
# Panda Odoo MCP Server

<div align="center">
  <img src="assets/Odoo MCP Server.png" alt="Odoo MCP Server Logo" width="100%"/> 
</div>

## Developed by

This module was developed by [Paolo Nugnes](https://github.com/pandeussilvae) and [TechLab](https://www.techlab.it).

TechLab is a company specialized in custom software development and enterprise system integration. Visit our website [www.techlab.it](https://www.techlab.it) for more information about our services.

## Overview

The Odoo MCP Server is a standardized interface for interacting with Odoo instances through the MCP (Model Context Protocol). It provides support for:

- **Communication Protocols**:
  - stdio: Direct communication via stdin/stdout
  - streamable_http: HTTP communication with streaming response support

- **Resource Management**:
  - Odoo records (single and list)
  - Binary fields
  - Real-time updates

- **Tools**:
  - Search and read records
  - Create and update records
  - Delete records
  - Call custom methods

- **Security**:
  - Authentication and session management
  - Rate limiting
  - CORS for streamable_http connections

## System Requirements

### Hardware Requirements
- CPU: 2+ cores
- RAM: 4GB minimum (8GB recommended)
- Disk Space: 1GB minimum

### Software Requirements
- Python 3.9+
- Odoo 15.0+
  - Required modules: base, web, bus
  - Database configured with admin user
- Docker (optional)

### Network Requirements
- Port 8069 (Odoo)
- Port 8080 (streamable_http, optional)
- Port 5432 (PostgreSQL, if local)

### Security Requirements
- SSL certificate for HTTPS (production)
- Configured firewall
- VPN access (optional)

## Installation

### Direct Installation

```bash
# Clone the repository
git clone https://github.com/pandeussilvae/mcp-odoo-panda.git
cd mcp-odoo-panda

# Install dependencies
pip install .

# To install with caching support
pip install .[caching]

# To install with development tools
pip install .[dev]

# Copy the example configuration file
cp odoo_mcp/config/config.example.json odoo_mcp/config/config.json

# Edit config.json with your settings
# nano odoo_mcp/config/config.json
```

### Docker Installation

```bash
# Clone the repository
git clone https://github.com/pandeussilvae/mcp-odoo-panda.git
cd mcp-odoo-panda

# Start with Docker Compose
docker-compose up -d
```

## Configuration

The server can be configured through a JSON file. Several configuration templates are available:

- `config.example.json`: Main template to copy and modify
- `config.dev.json`: Development environment template (optional)
- `config.prod.json`: Production environment template (optional)

To get started:

```bash
# Copy the example configuration file
cp odoo_mcp/config/config.example.json odoo_mcp/config/config.json

# Edit config.json with your settings
# nano odoo_mcp/config/config.json
```

### Selecting the Connection Type

The Odoo MCP server supports several connection types, configurable via the `connection_type` field in `config.json`. Supported values:

- `stdio`: Default, direct communication via stdin/stdout
- `streamable_http`: HTTP with streaming/chunked responses (real-time data flows)
- `http`: Classic HTTP POST (stateless, single request/response)

Example configuration:
```json
{
  "connection_type": "streamable_http",  // or "http" or "stdio"
  "http": {
    "host": "0.0.0.0",
    "port": 8080
  }
}
```

- Use `streamable_http` for real-time streaming over HTTP (endpoint: `POST /mcp`)
- Use `http` for classic REST requests (endpoint: `POST /mcp`)
- Use `stdio` for direct communication (default)

Example of complete configuration:

```json
{
    "mcpServers": {
        "mcp-odoo-panda": {
            "command": "/usr/bin/python3",
            "args": [
                "--directory",
                "/path/to/mcp-odoo-panda",
                "mcp/server.py",
                "--config",
                "/path/to/mcp-odoo-panda/odoo_mcp/config/config.json"
            ]
        }
    },
    "odoo_url": "http://localhost:8069",
    "database": "my_database",
    "username": "admin",
    "api_key": "admin",
    "protocol": "xmlrpc",
    "connection_type": "streamable_http",
    "requests_per_minute": 120,
    "rate_limit_max_wait_seconds": 5,
    "pool_size": 5,
    "timeout": 30,
    "session_timeout_minutes": 60,
    "http": {
        "host": "0.0.0.0",
        "port": 8080,
        "streamable": true
    },
    "logging": {
        "level": "INFO",
        "format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s",
        "handlers": [
            {
                "type": "StreamHandler",
                "level": "INFO"
            },
            {
                "type": "FileHandler",
                "filename": "server.log",
                "level": "DEBUG"
            }
        ]
    }
}
```

### Configuration

You can configure the server via environment variables in your `.env` file or directly in `docker-compose.yml`.

**Note:** Environment variables (from `.env` or the container environment) always take precedence over values in `config.json`.

Main variables:
- `ODOO_URL`, `ODOO_DB`, `ODOO_USER`, `ODOO_PASSWORD` (Odoo connection)
- `PROTOCOL`, `CONNECTION_TYPE`, `LOGGING_LEVEL` (MCP server)
- `REQUESTS_PER_MINUTE`, `SSE_QUEUE_MAXSIZE`, `ALLOWED_ORIGINS` (advanced)

Example `.env`:
```
ODOO_URL=http://host.docker.internal:8069
ODOO_DB=odoo
ODOO_USER=admin
ODOO_PASSWORD=admin
PROTOCOL=xmlrpc
CONNECTION_TYPE=streamable_http
LOGGING_LEVEL=INFO
```

## Starting the Server

The server can be started in two modes: stdio (default) and streamable_http. The configuration file is optional and, if not specified, the server will automatically look for the file in `odoo_mcp/config/config.json`.

### stdio Mode (default)

```bash
# Start the server in stdio mode without specifying the configuration file
python -m odoo_mcp.server

# Start the server in stdio mode with a specific configuration file
python -m odoo_mcp.server /path/to/config.json
```

### streamable_http Mode

```bash
# Start the server in streamable_http mode without specifying the configuration file
python -m odoo_mcp.server streamable_http

# Start the server in streamable_http mode with a specific configuration file
python -m odoo_mcp.server streamable_http /path/to/config.json
```

### HTTP Modes

The Odoo MCP server supports two HTTP modes:

1. **HTTP Streaming Chunked** (`streamable_http`):
   - Endpoint: `POST /mcp`
   - Keeps the connection open and streams data
   - Ideal for real-time data flows
   - Required headers:
     ```
     Content-Type: application/json
     Connection: keep-alive
     ```

2. **Classic HTTP POST** (`http`):
   - Endpoint: `POST /mcp`
   - Handles a single request/response (stateless)
   - Standard REST behavior
   - Required headers:
     ```
     Content-Type: application/json
     ```

3. **Server-Sent Events** (SSE):
   - Endpoint: `GET /sse`
   - Server-push event support
   - Required headers:
     ```
     Accept: text/event-stream
     ```

To configure the HTTP mode, set `connection_type` in `config.json`:
```json
{
  "connection_type": "streamable_http",  // or "http"
  "http": {
    "host": "0.0.0.0",
    "port": 8080
  }
}
```

### Example Calls

1. **HTTP Streaming Chunked**:
```bash
curl -X POST http://localhost:8080/mcp \
  -H "Content-Type: application/json" \
  -H "Connection: keep-alive" \
  -d '{"jsonrpc": "2.0", "method": "initialize", "id": 1}'
```

2. **Classic HTTP POST**:
```bash
curl -X POST http://localhost:8080/mcp \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc": "2.0", "method": "initialize", "id": 1}'
```

3. **Server-Sent Events**:
```bash
curl -N http://localhost:8080/sse \
  -H "Accept: text/event-stream"
```

## Server Verification

### stdio Mode

```bash
# Test a request without specifying the configuration file
echo '{"method": "get_resource", "params": {"uri": "odoo://res.partner/1"}}' | python -m odoo_mcp.server

# Test a request with a specific configuration file
echo '{"method": "get_resource", "params": {"uri": "odoo://res.partner/1"}}' | python -m odoo_mcp.server /path/to/config.json
```

### streamable_http Mode

```bash
curl -X POST http://localhost:8080/mcp \
  -H "Content-Type: application/json" \
  -H "Connection: keep-alive" \
  -d '{"jsonrpc": "2.0", "method": "initialize", "params": {}, "id": 1}'
```

### http Mode (Classic HTTP POST)

```bash
curl -X POST http://localhost:8080/mcp \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc": "2.0", "method": "initialize", "params": {}, "id": 1}'
```

### Server-Sent Events (SSE)

```bash
curl -N http://localhost:8080/sse \
  -H "Accept: text/event-stream"
```

## Usage

### stdio Connection

```python
import asyncio
from mcp import Client

async def main():
    client = Client(connection_type="stdio")
    await client.initialize()
    
    # Example: Read a record
    resource = await client.get_resource("odoo://res.partner/1")
    print(resource.data)

if __name__ == "__main__":
    asyncio.run(main())
```

### streamable_http Connection

```python
import asyncio
from mcp import Client

async def main():
    client = Client(connection_type="streamable_http")
    await client.initialize()
    
    # Example: Read a record
    resource = await client.get_resource("odoo://res.partner/1")
    print(resource.data)

if __name__ == "__main__":
    asyncio.run(main())
```

### Connecting Claude Desktop to the Odoo MCP server (stdio)

To connect Claude Desktop to the Odoo MCP server using the stdio protocol:

1. Make sure the Odoo MCP server is installed and working.
2. Open Claude Desktop settings (Claude menu → Settings → Developer → Edit Config).
3. Add the following configuration to the `mcpServers` section of your `claude_desktop_config.json` file:

```json
{
  "mcpServers": {
    "odoo-mcp": {
      "command": "python",
      "args": [
        "-m",
        "odoo_mcp.server",
        "C:/absolute/path/to/your/config.json"
      ]
    }
  }
}
```
> Replace `C:/absolute/path/to/your/config.json` with the actual path to your configuration file.

4. Save and restart Claude Desktop. You should see the MCP tools available.

**Note:** Claude Desktop only communicates via stdio. Do not use `streamable_http` for connecting with Claude Desktop.

## Documentation

Complete documentation is available in the `docs/` directory:

- `mcp_protocol.md`: MCP protocol documentation
- `odoo_server.md`: Odoo server documentation
- `server_usage.md`: Server usage guide

## Contributing

1. Fork the repository
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
3. Commit your changes (`git commit -m 'Add amazing feature'`)
4. Push to the branch (`git push origin feature/amazing-feature`)
5. Open a Pull Request

## License

This project is released under the MIT License. See the `LICENSE` file for details.

## Update

### Update from Source
```bash
# Update the repository
git pull origin main

# Reinstall the package
pip install --upgrade .

# Restart the server
systemctl restart odoo-mcp-server
```

### Update with Docker
```bash
# Update images
docker-compose pull

# Restart containers
docker-compose up -d
```

## Uninstallation

### Uninstall from Source
```bash
# Uninstall the package
pip uninstall odoo-mcp-server

# Remove configuration files
rm -rf ~/.odoo-mcp-server
```

### Uninstall with Docker
```bash
# Stop and remove containers
docker-compose down

# Remove images
docker-compose rm -f
```

## Advanced Configuration

### Environment Configuration

#### Development
```json
{
    "protocol": "xmlrpc",
    "connection_type": "stdio",
    "odoo_url": "http://localhost:8069",
    "database": "dev_db",
    "username": "admin",
    "api_key": "admin",
    "logging": {
        "level": "DEBUG",
        "handlers": [
            {
                "type": "FileHandler",
                "filename": "logs/dev.log",
                "level": "DEBUG"
            }
        ]
    }
}
```

#### Production
```json
{
    "protocol": "jsonrpc",
    "connection_type": "streamable_http",
    "odoo_url": "https://odoo.example.com",
    "database": "prod_db",
    "username": "admin",
    "api_key": "your-secure-api-key",
    "http": {
        "host": "0.0.0.0",
        "port": 8080,
        "streamable": true
    },
    "logging": {
        "level": "INFO",
        "handlers": [
            {
                "type": "FileHandler",
                "filename": "logs/prod.log",
                "level": "INFO"
            }
        ]
    }
}
```

### Configuration Backup
```bash
# Backup configuration
cp odoo_mcp/config/config.json odoo_mcp/config/config.json.backup

# Restore configuration
cp odoo_mcp/config/config.json.backup odoo_mcp/config/config.json
```

## Advanced Usage

### Error Handling
```python
from odoo_mcp.error_handling.exceptions import (
    AuthError, NetworkError, ProtocolError
)

try:
    await client.get_resource("odoo://res.partner/1")
except AuthError as e:
    logger.error(f"Authentication error: {e}")
    # Error handling
except NetworkError as e:
    logger.error(f"Network error: {e}")
    # Error handling
except ProtocolError as e:
    logger.error(f"Protocol error: {e}")
    # Error handling
```

### Best Practices

1. **Connection Management**:
   ```python
   async with Client() as client:
       await client.initialize()
       # Operations
   ```

2. **Cache Management**:
   ```python
   # Cache configuration
   cache_config = {
       'enabled': True,
       'ttl': 300,
       'max_size': 1000
   }
   ```

3. **Session Management**:
   ```python
   # Create session
   session = await client.create_session()
   
   # Validate session
   if await client.validate_session(session_id):
       # Operations
   ```

## Troubleshooting

### Common Issues

1. **Connection Error**:
   ```
   ERROR: Could not connect to Odoo server
   ```
   Solution:
   - Verify that Odoo is running on port 8069
   - Check that the firewall allows access to port 8069
   - Verify that the Odoo URL in the configuration file is correct
   - Check that the database is accessible

2. **Authentication Error**:
   ```
   ERROR: Authentication failed
   ```
   Solution:
   - Verify that username and api_key in the configuration file are correct
   - Check that the user has the necessary permissions in the Odoo database
   - Verify that the specified database exists
   - Check that the base, web, and bus modules are installed

3. **Protocol Error**:
   ```
   ERROR: Protocol error
   ```
   Solution:
   - Verify that the specified protocol (xmlrpc/jsonrpc) is supported
   - Check that the Odoo version is compatible (15.0+)
   - Verify that the connection type (stdio/streamable_http) is correct
   - Check the logs for specific error details

4. **Rate Limiting Error**:
   ```
   ERROR: Rate limit exceeded
   ```
   Solution:
   - Increase the `requests_per_minute` value in the configuration file
   - Implement a retry mechanism with backoff
   - Optimize requests to reduce the number of calls

5. **Cache Error**:
   ```
   ERROR: Cache error
   ```
   Solution:
   - Verify that the configured cache type is supported
   - Check that there is sufficient space for the cache
   - Temporarily disable the cache if necessary

### Error Logs

**Important note:** In the current version, the Odoo MCP server can write logs to multiple destinations depending on configuration:

- If the `logging` section in `config.json` includes a `StreamHandler`, logs are written to the **console** (stderr).
- If a `FileHandler` is present, logs are also written to a **file** at the path specified by `filename`.
- If there is no `logging`, logs are written only to stderr (console).

**Example:**
```json
"logging": {
    "level": "INFO",
    "format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s",
    "handlers": [
        {
            "type": "StreamHandler",
            "level": "INFO"
        },
        {
            "type": "FileHandler",
            "filename": "server.log",
            "level": "DEBUG"
        }
    ]
}
```
- In this example, logs go both to the console and to the file `server.log` in the directory where you start the server.
- You can change the log file path by editing the `filename` field (e.g., `"filename": "logs/dev.log"` or an absolute path).

### Support

For technical support:
1. Check the [documentation](docs/)
2. Open an [issue](https://github.com/pandeussilvae/mcp-odoo-panda/issues)
3. Contact [support@techlab.it](mailto:support@techlab.it)

## Running with Docker

You can run the Odoo MCP Server in a Docker container using the provided `Dockerfile` and `docker-compose.yml`.

### Quick Start

```bash
docker-compose up -d
```

This will:
- Build the image from the Dockerfile.
- Start the MCP server on port 8080 (default).
- Persist logs in the `./logs` directory.

### Configuration

You can configure the server via environment variables in your `.env` file or directly in `docker-compose.yml`.

Main variables:
- `ODOO_URL`, `ODOO_DB`, `ODOO_USER`, `ODOO_PASSWORD` (Odoo connection)
- `PROTOCOL`, `CONNECTION_TYPE`, `LOGGING_LEVEL` (MCP server)
- `REQUESTS_PER_MINUTE`, `SSE_QUEUE_MAXSIZE`, `ALLOWED_ORIGINS` (advanced)

Example `.env`:
```
ODOO_URL=http://host.docker.internal:8069
ODOO_DB=odoo
ODOO_USER=admin
ODOO_PASSWORD=admin
PROTOCOL=xmlrpc
CONNECTION_TYPE=streamable_http
LOGGING_LEVEL=INFO
```

#### Custom Configuration File

You can mount your own config file:
```yaml
volumes:
  - ./odoo_mcp/config/config.json:/app/odoo_mcp/config/config.json
```

#### Accessing the Server

- HTTP streaming: `POST http://localhost:8080/mcp`
- SSE: `GET http://localhost:8080/sse`

#### Stopping the Server

```bash
docker-compose down
```