Files
2026-03-30 19:17:56 -05:00

7.9 KiB

MCP Transport Mode — Usage Guide

This document describes the proposed dual-transport capability for server/odoo_mcp.py. No code changes have been made yet. Review this guide to evaluate viability before proceeding.


Overview

The server currently runs in stdio mode exclusively — it is launched as a subprocess by Claude Code and communicates over stdin/stdout. The proposed change adds an HTTP mode that allows the same server, with the same tools and zero logic changes, to be reached by any HTTP-capable client independently of Claude.

The change is controlled by a single environment variable: MCP_TRANSPORT.


How the Two Modes Work

stdio (current default — no change)

Claude Code reads .mcp.json and spawns the server as a subprocess. The server blocks on stdin, waiting for JSON-RPC messages from Claude. All 30+ Odoo tools are available to Claude as native function calls.

Claude Code → spawns process → odoo_mcp.py (stdio) → XML-RPC → mpmedia.odoo.com

This mode is not affected by the transport change. Claude Code does not set MCP_TRANSPORT, so it always gets stdio.

streamable-http (new, opt-in)

When MCP_TRANSPORT=http is set, the server binds to a TCP port and accepts MCP JSON-RPC over HTTP instead of stdin/stdout. Any MCP-compatible client or HTTP client can call it directly.

HTTP client → POST /mcp → odoo_mcp.py (HTTP) → XML-RPC → mpmedia.odoo.com

The Code Change (proposed)

Replace the last two lines of server/odoo_mcp.py:

# Before (line 570-571):
if __name__ == "__main__":
    mcp.run()

# After:
if __name__ == "__main__":
    transport = os.environ.get("MCP_TRANSPORT", "stdio")
    if transport == "http":
        mcp.run(
            transport="streamable-http",
            host=os.environ.get("MCP_HOST", "0.0.0.0"),
            port=int(os.environ.get("MCP_PORT", "8080")),
        )
    else:
        mcp.run()

No other files change. No tools change. No helper functions change.


Environment Variables

Variable Default Purpose
MCP_TRANSPORT stdio Set to http to enable HTTP mode
MCP_HOST 0.0.0.0 Bind address in HTTP mode
MCP_PORT 8080 Bind port in HTTP mode
ODOO_URL https://mpmedia.odoo.com Odoo instance URL
ODOO_DB mpmedia-odoo-sh-main-13285275 Odoo database name
ODOO_USERNAME bgilliom@mpmedia.tv Odoo login
ODOO_API_KEY (empty) Odoo API key — required

Usage Scenarios

1. Claude Code — unchanged

.mcp.json does not set MCP_TRANSPORT, so nothing changes. Claude Code continues to spawn the server as a stdio subprocess exactly as today.

{
  "mcpServers": {
    "odoo-mpm": {
      "command": "uv",
      "args": ["run", "--with", "mcp[cli]", "server/odoo_mcp.py"],
      "env": {
        "ODOO_URL": "https://mpmedia.odoo.com",
        "ODOO_DB": "mpmedia-odoo-sh-main-13285275",
        "ODOO_USERNAME": "bgilliom@mpmedia.tv",
        "ODOO_API_KEY": "your-api-key"
      }
    }
  }
}

2. Run HTTP server manually (local development)

ODOO_API_KEY=your-api-key MCP_TRANSPORT=http uv run --with mcp[cli] server/odoo_mcp.py

Server starts on http://localhost:8080. Use a different port if needed:

ODOO_API_KEY=your-api-key MCP_TRANSPORT=http MCP_PORT=9000 uv run --with mcp[cli] server/odoo_mcp.py

3. Cursor or other MCP-compatible AI tools

Add to Cursor's MCP config (~/.cursor/mcp.json or workspace .cursor/mcp.json):

{
  "mcpServers": {
    "odoo-mpm": {
      "url": "http://localhost:8080/mcp"
    }
  }
}

The server must already be running in HTTP mode before Cursor connects.

4. n8n automation

In n8n, use the MCP Client Tool node (or HTTP Request node) pointed at:

http://your-server:8080/mcp

Example workflow: trigger on a schedule → call search_helpdesk_tickets with stage=open → parse results → send Slack notification for unassigned tickets.

5. Custom Python script (no MCP at all)

The Odoo client functions (_search_read, _create, _write, etc.) can be imported directly. MCP is not involved:

import sys
sys.path.insert(0, "path/to/odoo-plugin-creation")

import os
os.environ["ODOO_API_KEY"] = "your-api-key"

from server.odoo_mcp import _search_read, _create

# Get all open helpdesk tickets
tickets = _search_read(
    "helpdesk.ticket",
    [["stage_id.name", "=", "New"]],
    ["id", "name", "partner_id", "create_date"],
    limit=50
)

for t in tickets:
    print(t["name"])

6. Windows Service / always-on background process

To run the HTTP server persistently on Windows:

# Using NSSM (Non-Sucking Service Manager)
nssm install odoo-mcp "uv"
nssm set odoo-mcp AppParameters "run --with mcp[cli] C:\path\to\server\odoo_mcp.py"
nssm set odoo-mcp AppEnvironmentExtra "MCP_TRANSPORT=http" "MCP_PORT=8080" "ODOO_API_KEY=your-api-key"
nssm start odoo-mcp

Or as a simple background process for development:

$env:MCP_TRANSPORT = "http"
$env:ODOO_API_KEY = "your-api-key"
Start-Process uv -ArgumentList "run --with mcp[cli] server/odoo_mcp.py" -WindowStyle Hidden

Available Tools in HTTP Mode

All 30 tools are available identically in both modes:

Module Tools
Products search_products, get_product, get_product_stock
Knowledge search_knowledge_articles, get_knowledge_article, create_knowledge_article, update_knowledge_article
Contacts search_contacts, get_contact, create_contact
Sales search_sales_orders, get_sales_order, create_sales_order
CRM search_crm_leads, get_crm_lead, create_crm_lead, update_crm_lead, list_crm_stages
Project list_projects, get_project, search_tasks, get_task, create_task, update_task, list_task_stages
Helpdesk search_helpdesk_tickets, get_helpdesk_ticket, create_helpdesk_ticket, update_helpdesk_ticket, list_helpdesk_teams
Purchase search_purchase_orders, get_purchase_order
Inventory search_inventory, get_stock_moves, list_internal_locations
Employees search_employees, get_employee, list_departments
Utility odoo_search, odoo_get_record

Calling Tools over HTTP

FastMCP's streamable-http transport uses the MCP JSON-RPC protocol over HTTP POST.

Endpoint: POST http://localhost:8080/mcp

Example — call search_tasks:

curl -X POST http://localhost:8080/mcp \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "search_tasks",
      "arguments": {
        "query": "website redesign",
        "limit": 10
      }
    }
  }'

Example — list all tools:

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

Security Considerations

In HTTP mode the server is network-accessible. Before exposing it beyond localhost:

  • Do not expose port 8080 to the internet without authentication in front of it. The MCP protocol itself has no built-in auth layer.
  • For internal network use: bind to MCP_HOST=127.0.0.1 (localhost only) or a specific internal interface.
  • For external access: put nginx or Caddy in front with Basic Auth or mTLS.
  • The Odoo API key grants the same permissions as the Odoo user — anyone who can reach the server can read and write Odoo data.

What Does Not Change

  • server/odoo_mcp.py tool logic — zero changes
  • .mcp.json — zero changes
  • skills/odoo/SKILL.md — zero changes
  • .claude-plugin/plugin.json — zero changes
  • Claude Code behavior — identical to today
  • All 30 Odoo tools — identical behavior in both modes

Rollback

If HTTP mode causes any issue, simply stop the HTTP process. Claude Code is unaffected because it never sets MCP_TRANSPORT. There is nothing to revert in .mcp.json or any config file.