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.pytool logic — zero changes.mcp.json— zero changesskills/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.