Replaces the old SseServerTransport (broken against current MCP clients — 405s on POST, session-id redirects, no protocol negotiation) with StreamableHTTPServerTransport. Adds an idle-session sweeper to prevent abandoned client connections from leaking memory indefinitely, CORS middleware for browser-based frontend access, and PUBLIC_URL/CORS_ORIGINS settings so signup responses show the correct connection URL instead of a placeholder. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
8.3 KiB
Multi-Tenant ODOO MCP — Project Handoff
Live Server
- Backend URL:
https://odoo-mcp.thedomainnest.com/ - Stack: Python 3.11, FastAPI, uvicorn, SQLite, MCP (SSE transport)
- Local repo path:
e:\MCS_Repos\nodejs_web_dev\mcp_multitenant\Multi-Tenant-ODOO-MCP
Project Structure
Multi-Tenant-ODOO-MCP/
├── src/mt_odoo_mcp/
│ ├── api/routes.py # REST API endpoints (signup, login, credentials)
│ ├── auth/ # Auth service, models, crypto (bcrypt + Fernet)
│ ├── client/ # Odoo XML-RPC connection + RPC helpers
│ ├── tools/ # 60+ MCP tools (connection, discovery, CRUD, workflow, smart)
│ ├── config.py # Settings loaded from .env
│ ├── server.py # FastAPI app + MCP SSE transport
│ ├── database.py # SQLite init
│ └── registry.py # Per-user connection manager registry
├── frontend/ # Next.js 14 frontend (see below)
├── .env # Server environment variables
├── pyproject.toml # Python dependencies
└── HANDOFF.md # This file
What's Been Done
Backend (Python/FastAPI)
| # | Fix / Feature | File |
|---|---|---|
| ✅ | Fixed bcrypt 5.0 compatibility — replaced passlib with direct bcrypt | auth/service.py |
| ✅ | Fixed missing email-validator dependency |
pyproject.toml |
| ✅ | Fixed bad config import in auth service | auth/service.py |
| ✅ | Added CORSMiddleware — allows browser requests from frontend |
server.py |
| ✅ | Added public_url and cors_origins config fields |
config.py |
| ✅ | Fixed hardcoded http://<your-vps-host>:<port>/mcp/sse in signup & regen-key API responses |
api/routes.py |
Frontend (Next.js 14)
Location: frontend/
| # | Page / File | Description |
|---|---|---|
| ✅ | Landing page | Hero, Features, How It Works, Pricing, Footer |
| ✅ | Navbar | Responsive with mobile menu |
| ✅ | Pricing section | 4 tiers — Starter $19, Pro $49, Agency $149, Enterprise Custom |
| ✅ | Signup page | Form → API key reveal with copy-to-clipboard |
| ✅ | Login page | Email + password form |
| ✅ | Dashboard layout | Dark sidebar, all nav items, mobile responsive |
| ✅ | Dashboard home | Stats cards, usage chart, quick actions, recent activity log |
| ✅ | Odoo Connections page | List, add, and delete Odoo instances |
| ✅ | MCP Endpoints page | URL + token copy buttons, Claude/Codex/Cursor setup JSON config |
| ✅ | Billing page | Current plan, plan switcher, invoice history |
| ✅ | Stripe Checkout API route | Creates Stripe Checkout session with 7-day trial |
| ✅ | Stripe Webhook API route | Handles subscription created/updated/cancelled events |
| ✅ | Typed API client | All calls wired to live backend |
| ✅ | .env.local |
Configured to point to https://odoo-mcp.thedomainnest.com |
| ✅ | Production build | next build passes with zero errors |
What Still Needs To Be Done
🔴 Critical — Must Do Before Frontend Works
1. Deploy backend changes to the server
Three Python files were changed locally and must be pushed to the server:
src/mt_odoo_mcp/server.pysrc/mt_odoo_mcp/config.pysrc/mt_odoo_mcp/api/routes.py
Add these 2 lines to the server .env file:
PUBLIC_URL=https://odoo-mcp.thedomainnest.com
CORS_ORIGINS=http://localhost:3000,https://YOUR-FRONTEND-DOMAIN.com
Then restart the service:
# whichever process manager is used on the server:
systemctl restart odoo-mcp
# or
pm2 restart odoo-mcp
2. Change SECRET_KEY on the server
The current SECRET_KEY in .env is still the default placeholder — this is a security risk.
SECRET_KEY=<replace with a long random string, e.g. output of: openssl rand -hex 32>
🟡 Stripe Integration
3. Create Stripe products and prices
In the Stripe Dashboard → Products, create 3 recurring monthly products:
| Product | Price |
|---|---|
| Starter | $19/month |
| Pro | $49/month |
| Agency | $149/month |
Copy the price_xxx IDs and fill in frontend/.env.local:
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_live_...
STRIPE_SECRET_KEY=sk_live_...
STRIPE_WEBHOOK_SECRET=whsec_...
STRIPE_PRICE_STARTER=price_...
STRIPE_PRICE_PRO=price_...
STRIPE_PRICE_AGENCY=price_...
4. Add subscription fields to the backend users table
Add these columns to the SQLite users table:
ALTER TABLE users ADD COLUMN plan TEXT DEFAULT 'free';
ALTER TABLE users ADD COLUMN subscription_status TEXT DEFAULT 'inactive';
ALTER TABLE users ADD COLUMN stripe_customer_id TEXT;
Add a new API endpoint PATCH /api/admin/subscription (internal, called by the webhook) that updates these fields when Stripe confirms payment.
5. Wire Stripe webhook to backend
The webhook handler at frontend/src/app/api/stripe/webhook/route.ts already parses Stripe events. Add a fetch() call inside the switch cases to hit the backend endpoint from step 4.
6. Gate MCP access on subscription status
In server.py, inside the /mcp/sse endpoint, after the user is looked up, add a check:
if user.subscription_status not in ('active', 'trialing'):
raise HTTPException(status_code=403, detail="Active subscription required.")
🟢 Remaining Dashboard Pages
| Page | Route | Description |
|---|---|---|
| AI Setup Guides | /dashboard/guides |
Step-by-step setup for Claude, Codex, Cursor, Windsurf |
| Tools & Permissions | /dashboard/tools |
Toggle which Odoo tools are enabled per module |
| Usage | /dashboard/usage |
Detailed usage graphs with date range filter |
| Logs | /dashboard/logs |
Activity log table with search and filters |
| API Tokens | /dashboard/tokens |
View key prefix, rotate API key button |
| Team | /dashboard/team |
Invite team members (needs backend multi-user support) |
| Settings | /dashboard/settings |
Change password, account preferences |
🟢 Deploy Frontend
cd frontend
npm install -g vercel
vercel --prod
- Set all env vars from
frontend/.env.localinside Vercel project settings - After deploy, add the Vercel domain to
CORS_ORIGINSin the server.envand restart
How to Run Locally
Backend (already running on server — skip if not developing backend)
pip install -e .
cp .env.example .env # fill in values
python -m mt_odoo_mcp
Frontend
cd frontend
npm install
npm run dev
# → http://localhost:3000
# API calls go to https://odoo-mcp.thedomainnest.com
API Reference (Backend)
| Method | Endpoint | Auth | Description |
|---|---|---|---|
GET |
/health |
None | Health check |
POST |
/api/signup |
None | Create account, returns API key |
POST |
/api/login |
None | Verify credentials |
GET |
/api/me |
Bearer | Current user + Odoo instances |
POST |
/api/api-key/regenerate |
Bearer | Rotate API key |
POST |
/api/credentials |
Bearer | Add/update Odoo instance |
GET |
/api/credentials |
Bearer | List Odoo instances |
DELETE |
/api/credentials/{name} |
Bearer | Remove Odoo instance |
GET |
/mcp/sse |
Bearer | MCP SSE connection (used by AI clients) |
Auth header format: Authorization: Bearer mtom_xxxxx...
MCP Client Config (Claude Code / Claude Desktop)
{
"mcpServers": {
"odoo-mcp": {
"type": "sse",
"url": "https://odoo-mcp.thedomainnest.com/mcp/sse",
"headers": {
"Authorization": "Bearer YOUR_API_KEY"
}
}
}
}
Or via CLI:
claude mcp add --transport sse odoo-mcp https://odoo-mcp.thedomainnest.com/mcp/sse \
-H "Authorization: Bearer YOUR_API_KEY"
Implementation Priority for Colleague
- Deploy backend changes + update
.envon server → restart ← unblocks everything - Test signup → dashboard → add Odoo connection end to end
- Set up Stripe, fill in price IDs in
frontend/.env.local - Add subscription columns to SQLite +
/api/admin/subscriptionendpoint - Wire webhook to backend endpoint
- Deploy frontend to Vercel
- Build remaining dashboard pages (guides, tools, usage, logs, tokens, settings)