product-crud-mcp
by saurabhx04
README.md
# Product CRUD — FastAPI + Strawberry GraphQL + MCP
A small learning/demo project with one CRUD entity (`Product`) and one shared
business-logic layer (`app/crud.py`). The same business logic is exposed through
both:
- `/graphql` — a Strawberry GraphQL API
- `/mcp` — MCP tools and a resource for AI hosts
This repo uses SQLite by default so it runs with zero external services. It is
also designed so the database backend can be swapped later, for example to
Oracle via `python-oracledb`.
## Why this project exists
The main goal is to show how to keep core business logic separate from
transport and API adapters:
- `app/crud.py` contains plain CRUD functions and SQLAlchemy access
- `app/graphql_schema.py` wraps that logic in a GraphQL schema
- `app/mcp_server.py` wraps the same logic in MCP tools and resources
- `app/main.py` mounts both the GraphQL router and a Streamable HTTP MCP app
That makes it easy for the same operations to support different clients and
deployment modes without duplicating business rules.
## Project layout
```
app/
database.py SQLAlchemy engine/session setup
models.py Product ORM model
crud.py Plain CRUD functions, used by both interfaces
graphql_schema.py Strawberry GraphQL query/mutation schema
mcp_server.py MCP tools and resource adapter
main.py FastAPI app mounting GraphQL and MCP
Dockerfile
docker-compose.yml
k8s/deployment.yaml
k8s/service.yaml
README.md
requirements.txt
.gitignore
```
## Key files for contributors and tools
- `app/crud.py` — core business logic for products
- `app/models.py` — SQLAlchemy `Product` model
- `app/database.py` — database engine and session setup
- `app/graphql_schema.py` — GraphQL query/mutation definitions
- `app/mcp_server.py` — MCP tool/resource definitions
- `app/main.py` — FastAPI app and route mounting
- `Dockerfile` / `docker-compose.yml` — containerized deployment
## Prerequisites
- macOS with Python 3.11+ installed
- Docker and Docker Compose installed if you want to run in Docker
- Optional: `uv` or `claude` if using the MCP CLI/Inspector workflows
## Run locally on macOS
From the repository root:
```bash
cd "/Users/sauvi/Developer/2026 Job Switch/Coding Main Folder/mcp-crud-demo"
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
pip install -r requirements.txt
```
Start the app on a specific host and port:
```bash
uvicorn app.main:app --reload --host 127.0.0.1 --port 8000
```
If you want a different port, replace `8000` with any available port.
### Verify it is running
Open in your browser:
- `http://127.0.0.1:8000/health`
- `http://127.0.0.1:8000/graphql`
Example GraphQL mutation:
```graphql
mutation {
createProduct(name: "Keyboard", description: "Mechanical", price: 49.99, quantity: 10) {
id
}
}
```
Then query:
```graphql
query {
products {
id
name
price
quantity
}
}
```
## Run in Docker
Build and start the service with Docker Compose:
```bash
docker compose up --build
```
Then open:
- `http://127.0.0.1:8000/health`
- `http://127.0.0.1:8000/graphql`
- `http://127.0.0.1:8000/mcp`
### Optional persistence
By default the SQLite file lives inside the container and resets when the
container is rebuilt. To keep data across restarts, uncomment or add a volume
mapping in `docker-compose.yml`:
```yaml
services:
product-crud-mcp:
build: .
ports:
- "8000:8000"
volumes:
- product-data:/app
volumes:
product-data:
```
## Run with MCP tools
**Option A — MCP Inspector**
```bash
uv run mcp dev app/mcp_server.py
```
This opens a browser UI where you can call `create_product`, `list_products`,
`update_product`, and `delete_product`.
**Option B — Claude Desktop / Claude Code**
```bash
uv run mcp install app/mcp_server.py
```
or for Claude Code:
```bash
claude mcp add product-crud -- uv run --with "mcp[cli]" mcp run /absolute/path/to/app/mcp_server.py
```
**Option C — Mounted Streamable HTTP**
With `uvicorn app.main:app` running, the same MCP tools are available at
`http://127.0.0.1:8000/mcp`.
## Kubernetes
To build the image and deploy to Kubernetes:
```bash
docker build -t product-crud-mcp:latest .
kubectl apply -f k8s/deployment.yaml
kubectl apply -f k8s/service.yaml
kubectl port-forward svc/product-crud-mcp 8000:80
```
The K8s YAML includes `/health` readiness and liveness probes.
## Swap in Oracle
To use Oracle instead of SQLite, update `app/database.py`:
```python
from sqlalchemy import create_engine
DATABASE_URL = "oracle+oracledb://user:password@host:1521/?service_name=FREEPDB1"
engine = create_engine(DATABASE_URL)
```
Add `oracledb` to `requirements.txt`. No other application code needs to change.
## Notes for new contributors or AI tools
- The repository is intentionally small and designed for exploration.
- `app/crud.py` is the single source of truth for product operations.
- GraphQL and MCP are adapters on top of that single core.
- If you want to add a new interface, follow the same pattern: keep logic in
`crud.py` and add a thin adapter layer.
- Start by reading `app/main.py`, `app/crud.py`, and `app/mcp_server.py`.
## Support files
- `.gitignore` excludes virtual environments, editor settings, caches, and
local SQLite files.
- `requirements.txt` lists runtime dependencies.
- `Dockerfile` and `docker-compose.yml` define container behavior.
This server cannot be deployed
Maintenance
ActivitySlowing
ResponsivenessNo issues