MOHAN 198b5f1b90 Migrate MCP transport to Streamable HTTP, add session sweeper, CORS, public URL config
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>
2026-07-01 13:43:34 +05:30

257 lines
8.3 KiB
Markdown

# 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 | `frontend/src/lib/api.ts` |
| ✅ | `.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.py`
- `src/mt_odoo_mcp/config.py`
- `src/mt_odoo_mcp/api/routes.py`
**Add these 2 lines to the server `.env` file:**
```env
PUBLIC_URL=https://odoo-mcp.thedomainnest.com
CORS_ORIGINS=http://localhost:3000,https://YOUR-FRONTEND-DOMAIN.com
```
Then restart the service:
```bash
# 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.
```env
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`:
```env
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:
```sql
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:
```python
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
```bash
cd frontend
npm install -g vercel
vercel --prod
```
- Set all env vars from `frontend/.env.local` inside Vercel project settings
- After deploy, add the Vercel domain to `CORS_ORIGINS` in the server `.env` and restart
---
## How to Run Locally
### Backend (already running on server — skip if not developing backend)
```bash
pip install -e .
cp .env.example .env # fill in values
python -m mt_odoo_mcp
```
### Frontend
```bash
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)
```json
{
"mcpServers": {
"odoo-mcp": {
"type": "sse",
"url": "https://odoo-mcp.thedomainnest.com/mcp/sse",
"headers": {
"Authorization": "Bearer YOUR_API_KEY"
}
}
}
}
```
Or via CLI:
```bash
claude mcp add --transport sse odoo-mcp https://odoo-mcp.thedomainnest.com/mcp/sse \
-H "Authorization: Bearer YOUR_API_KEY"
```
---
## Implementation Priority for Colleague
1. **Deploy backend changes + update `.env` on server → restart** ← unblocks everything
2. **Test signup → dashboard → add Odoo connection** end to end
3. **Set up Stripe**, fill in price IDs in `frontend/.env.local`
4. **Add subscription columns** to SQLite + `/api/admin/subscription` endpoint
5. **Wire webhook** to backend endpoint
6. **Deploy frontend** to Vercel
7. **Build remaining dashboard pages** (guides, tools, usage, logs, tokens, settings)