MCP Order Management with RBAC
by techakash32
README.md
# Order Management — RBAC with MCP
Role-Based Access Control enforced **inside the MCP server**, not the
FastAPI client. FastAPI only authenticates (issues/validates JWTs);
every permission decision is made by `permissions.py` and applied by
the MCP tools in `order_checking.py`.
```
Client -> FastAPI (auth: JWT) -> MCP Server (authz: RBAC) -> MySQL
```
## Roles
| Action | USER | MANAGER | ADMIN |
| ---------------------------- | ---- | ------------- | ----- |
| View own order | Y | Y | Y |
| View managed user's order | N | Y | Y |
| View another user's order | N | N | Y |
| Refund own order | Y | Y | Y |
| Refund managed user's order | N | Y | Y |
| Refund anyone | N | N | Y |
| Delete order | N | N | Y |
| Create manager | N | N | Y |
| View users | N | managed users | all |
## Setup
1. Create the database and tables:
```bash
mysql -u root -p < sql/schema.sql
```
2. Copy `.env.example` to `.env` and fill in real values (at minimum
set a strong `JWT_SECRET` and your real `DATABASE_URL`), then
export them into your shell / process manager.
3. Install dependencies:
```bash
pip install -r requirements.txt
```
4. Seed example users/orders (akash=ADMIN, raj=MANAGER, aman/vivek=USER
managed by raj):
```bash
python sql/seed.py
```
5. Run the MCP server:
```bash
python order_checking.py
```
6. Run the FastAPI app (separate process/terminal):
```bash
uvicorn main:app --reload
```
## Usage
```bash
# Log in, get a JWT
curl -X POST http://127.0.0.1:8000/login \
-H "Content-Type: application/json" \
-d '{"username": "raj", "password": "managerpass123"}'
# Use the token on protected routes
curl http://127.0.0.1:8000/order_status/ORD101 \
-H "Authorization: Bearer <token>"
curl -X POST http://127.0.0.1:8000/refund/ORD101 \
-H "Authorization: Bearer <token>"
```
## Files
| File | Responsibility |
| ------------------- | ------------------------------------------------- |
| `config.py` | Env-driven settings (DB URL, JWT secret, ports) |
| `auth.py` | Password hashing, JWT issuing/validation, `get_current_user` dependency |
| `permissions.py` | The RBAC rules -- the only place authorization decisions are made |
| `database.py` | SQL access: users, orders, audit log writes |
| `audit.py` | Logs every tool call (allowed or denied) to file + DB |
| `order_checking.py` | The MCP server -- tools call `permissions.authorize()` before touching data |
| `main.py` | FastAPI app: `/login` + JWT-protected routes that forward identity to MCP |
| `schemas.py` | Pydantic request/response models |
| `sql/schema.sql` | Table definitions (users, orders, audit_logs) |
| `sql/seed.py` | Creates example users/orders matching the permission matrix above |
## Security notes
- The MCP server trusts the `username`/`role` passed in from FastAPI.
In this design FastAPI is the only client allowed to reach the MCP
server (bind it to localhost / an internal network, not the public
internet) -- the JWT check happens once, at the FastAPI edge.
- Every tool call is written to `audit_logs` (and `logs/app.log`)
with the outcome and reason, whether allowed or denied.
- Rotate `JWT_SECRET` via environment variable / secret manager --
never commit it.
This server cannot be deployed
Maintenance
ActivitySlowing
ResponsivenessNo issues