Skip to main content
Glama
JahzeelReyes30

majincleaning-ops

README.md
# MajinCleaningSolutions Ops MCP Server

An [MCP](https://modelcontextprotocol.io) server that connects an AI assistant (Claude Desktop, Claude Code, or any other MCP-compatible client) directly to the real, live Supabase database behind [MajinCleaningSolutions](https://website-project-theta-eight.vercel.app) — my production booking app for a real cleaning business.

Instead of logging into the site's `/admin` dashboard to check the schedule, you can just ask: *"What's my availability next Tuesday?"* or *"Show me pending bookings"* — and the assistant answers using real data, live, through this server.

## Why this exists

MCP is the emerging standard ("USB-C for AI") for connecting AI models to real tools and data instead of every app writing its own one-off integration. This server is a small, honest example of that pattern applied to a real system I already built and operate — not a toy dataset.

## Tools it exposes

| Tool | What it does |
|---|---|
| `list_services` | Returns current services and flat-rate pricing |
| `check_availability` | Given a date, returns open vs. taken appointment slots |
| `list_upcoming_bookings` | Lists upcoming bookings, optionally filtered by status |
| `update_booking_status` | Updates a booking's status, enforcing the same `pending → confirmed → completed`/`cancelled` rules the admin dashboard uses |

## A deliberate security decision

The live site's public booking form uses Supabase's **anon key**, which — by Row Level Security policy — can *submit* a booking but can never read anyone else's data back. That's correct for a public website.

This server is different: it runs **locally, under my own control**, standing in for the business owner using the admin dashboard. So it uses the **service role key** instead, which can read and update real booking data. That key lives only in a local, gitignored `.env` file — it's never committed, never shipped to a browser, and this server is never deployed publicly. Same database, two different trust levels depending on who's asking.

## Setup

```bash
npm install
cp .env.example .env
# fill in SUPABASE_URL and SUPABASE_SERVICE_ROLE_KEY from your Supabase
# project's Settings -> API page
npm run build
```

### Connect it to Claude Desktop

Add this to your Claude Desktop MCP config (`claude_desktop_config.json`):

```json
{
  "mcpServers": {
    "majincleaning-ops": {
      "command": "node",
      "args": ["/absolute/path/to/majincleaning-ops-mcp/dist/index.js"],
      "env": {
        "SUPABASE_URL": "https://your-project-ref.supabase.co",
        "SUPABASE_SERVICE_ROLE_KEY": "your-service-role-key"
      }
    }
  }
}
```

Restart Claude Desktop, and the four tools above become available for it to call directly against the real database.

## Tech

Node.js + TypeScript, the official [`@modelcontextprotocol/sdk`](https://www.npmjs.com/package/@modelcontextprotocol/sdk), and `@supabase/supabase-js`. Business-hours/slot logic mirrors [`lib/availability.ts`](https://github.com/JahzeelReyes30/WebsiteProject/blob/main/lib/availability.ts) and status-transition rules mirror [`lib/validation.ts`](https://github.com/JahzeelReyes30/WebsiteProject/blob/main/lib/validation.ts) from the main site's repo, so this server enforces the exact same business rules as the production app.

## Related

Built on top of [WebsiteProject](https://github.com/JahzeelReyes30/WebsiteProject) — the full-stack Next.js + Supabase + Vercel app this server connects to.

---
**By:** Jahzeel Reyes