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>
257 lines
8.3 KiB
Markdown
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)
|