subscribe-mcp
by Sharifa26
README.md
# Subscribe MCP - SaaS Subscription Backend
A TypeScript/Express backend for a SaaS subscription workflow with Razorpay test payments, PostgreSQL persistence, Redis-backed background jobs, invoice emails, cached platform statistics, and an MCP server that exposes subscription insights to AI clients.
## What This Project Includes
- Plan catalog seeded with Basic, Pro, and Premium subscription plans.
- Checkout API that creates Razorpay test orders.
- Verified Razorpay webhook endpoint for successful payment events.
- Subscription lifecycle handling with trial, active, failed, refunded, and expired states.
- PDF invoice generation and Mailtrap email delivery.
- Daily renewal scanner plus a BullMQ worker for renewal reminder emails.
- Redis-cached platform statistics.
- MCP tools for AI clients:
- `get_platform_stats`
- `get_plans`
## Tech Stack
| Area | Technology |
| --------------------- | --------------------------------- |
| Runtime | Node.js, TypeScript |
| API | Express |
| Database | PostgreSQL, Prisma |
| Cache and jobs | Redis, BullMQ |
| Payments | Razorpay test mode |
| Email testing | Mailtrap SMTP |
| Background scheduling | node-cron |
| AI integration | Model Context Protocol over stdio |
## Prerequisites
Install these before running the project:
- [Node.js 20 or newer](https://nodejs.org/en/download)
- [npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm), which is installed with Node.js
- [Docker Desktop](https://www.docker.com/products/docker-desktop/)
- [A free Razorpay test account](https://razorpay.com/)
- [A free Mailtrap account](https://mailtrap.io/)
- [ngrok](https://ngrok.com/download), only if you want to test live webhooks from Razorpay
## Local Setup
1. Install dependencies:
```bash
npm install
```
2. Start PostgreSQL and Redis:
```bash
docker compose up -d
```
The Compose file starts:
| Service | Host URL |
| ---------- | ---------------- |
| PostgreSQL | `localhost:5433` |
| Redis | `localhost:6379` |
3. Create your local environment file:
```bash
cp .env.example .env
```
On Windows PowerShell:
```powershell
Copy-Item .env.example .env
```
4. Fill in `.env` using the credential guide below.
5. Apply database migrations:
```bash
npx prisma migrate deploy
```
6. Seed the subscription plans:
```bash
npx prisma db seed
```
7. Start the API server:
```bash
npm run dev
```
The server runs at:
```text
http://localhost:3000
```
## Environment Configuration
Use `.env.example` as the safe template. Never commit your real `.env` file.
### Database and Redis
These values work with the included Docker Compose setup:
```env
DATABASE_URL="postgresql://saas_user:saas_password@localhost:5433/saas_db?schema=public"
REDIS_URL="redis://localhost:6379"
```
### Razorpay Test Credentials
1. Create or log in to a Razorpay account.
2. Switch to test mode in the Razorpay dashboard.
3. Go to Account & Settings > API Keys.
4. Generate a test key pair.
5. Copy the values into `.env`:
```env
RAZORPAY_KEY_ID="rzp_test_xxxxxxxxxxxxx"
RAZORPAY_KEY_SECRET="your_test_secret"
```
For webhook testing, first run the API and ngrok tunnel. For the complete payment test, see [Webhook Flow](#webhook-flow). ngrok prints a public `Forwarding` URL in the terminal, for example:
```text
Forwarding https://abc123.ngrok-free.app -> http://localhost:3000
```
Copy that HTTPS URL and add `/api/webhooks/payment` at the end. Then add the full URL in the Razorpay dashboard:
```text
Webhook URL: https://abc123.ngrok-free.app/api/webhooks/payment
Events: payment.captured, payment.failed
```
You can also see the full step-by-step Razorpay webhook instructions in `.env.example`.
Then copy the webhook signing secret into:
```env
RAZORPAY_WEBHOOK_SECRET="your_webhook_secret"
```
### Mailtrap SMTP Credentials
1. Create or log in to Mailtrap.
2. Open an Email Testing inbox.
3. Copy the SMTP host, port, username, and password.
4. Add them to `.env`:
```env
MAILTRAP_HOST="sandbox.smtp.mailtrap.io"
MAILTRAP_PORT="2525"
MAILTRAP_USER="your_mailtrap_username"
MAILTRAP_PASS="your_mailtrap_password"
MAILTRAP_FROM="billing@taskflow-demo.test"
```
## Running the Application
Always open Docker Desktop first. PostgreSQL and Redis must be running before the app starts:
```bash
docker compose up -d
```
For the complete local demo, run everything together with one command:
```bash
npm run dev:all
```
This starts:
- API server on `http://localhost:3000`
- ngrok tunnel for Razorpay webhooks
- renewal reminder worker
If you want to run each process separately, use the commands below.
Run the API only:
```bash
npm run dev
```
Run the renewal reminder worker in a separate terminal:
```bash
npm run worker
```
Run the ngrok tunnel in another terminal:
```bash
npm run tunnel
```
Open Prisma Studio to view database tables in the browser:
```bash
npx prisma studio
```
Build and run production output:
```bash
npm run build
npm start
```
## Verify Everything Works
### 1. Check infrastructure
```bash
docker compose ps
```
You should see `saas_postgres` and `saas_redis` running.
### 2. Check the API
```bash
curl http://localhost:3000/health
```
Expected response:
```json
{
"status": "ok",
"timestamp": "..."
}
```
You can also open the application in your browser:
```text
http://localhost:3000
```
From there, select a plan and complete a Razorpay test payment. After payment succeeds, Razorpay sends the webhook to the ngrok URL, and the backend activates the subscription, generates the invoice, and sends the confirmation email.
### 3. Confirm plans were seeded
```bash
curl http://localhost:3000/api/plans
```
You should see the Basic, Pro, and Premium plans.
### 4. Create a checkout order
```bash
curl -X POST http://localhost:3000/api/checkout \
-H "Content-Type: application/json" \
-d "{\"name\":\"Demo User\",\"email\":\"demo@example.com\",\"planName\":\"Pro\"}"
```
Expected result:
- A new pending subscription is stored in PostgreSQL.
- A Razorpay test order is returned.
- The response includes the public Razorpay key id.
### 5. Verify platform stats
```bash
curl http://localhost:3000/api/stats
```
The first request computes stats from PostgreSQL. Repeated requests within 30 seconds should return cached stats from Redis.
### 6. Verify background processes
Start the worker:
```bash
npm run worker
```
In another terminal, manually trigger the renewal scanner:
```bash
curl -X POST http://localhost:3000/api/dev/trigger-renewal-scan
```
Expected behavior:
- The API activates any expired trials.
- Subscriptions expiring within 3 days are queued in Redis.
- The worker processes queued renewal reminders.
- Renewal emails appear in Mailtrap.
## Webhook Flow
For a full payment test:
1. Start the API:
```bash
npm run dev
```
2. Start ngrok:
```bash
npm run tunnel
```
3. Copy the HTTPS `Forwarding` URL printed by ngrok:
```text
Forwarding https://abc123.ngrok-free.app -> http://localhost:3000
```
4. Add `/api/webhooks/payment` to that URL and paste it into the Razorpay webhook settings:
```text
https://abc123.ngrok-free.app/api/webhooks/payment
```
5. Select these webhook events:
```text
payment.captured
payment.failed
```
6. Save the webhook and copy the webhook signing secret into `RAZORPAY_WEBHOOK_SECRET` in `.env`.
7. Restart the API after changing `.env`.
8. Create a checkout order through `POST /api/checkout`.
9. Complete the payment in Razorpay test mode.
10. Razorpay sends the webhook to the public ngrok URL, and ngrok forwards it to `http://localhost:3000/api/webhooks/payment`.
11. The API verifies the signature, activates the subscription, generates an invoice, and sends a confirmation email through Mailtrap.
## API Reference
| Method | Endpoint | Purpose |
| ------ | ------------------------------- | ---------------------------------------- |
| `GET` | `/health` | Health check |
| `GET` | `/api/plans` | List available plans |
| `POST` | `/api/checkout` | Create a subscription and Razorpay order |
| `POST` | `/api/webhooks/payment` | Receive Razorpay webhook events |
| `GET` | `/api/stats` | Get cached platform statistics |
| `POST` | `/api/dev/trigger-renewal-scan` | Manually run the renewal scanner |
Checkout request body:
```json
{
"name": "Demo User",
"email": "demo@example.com",
"planName": "Pro"
}
```
## Expose the MCP Tool to an AI Client
The MCP server runs over stdio and uses the same `.env` values as the API.
Run it directly:
```bash
npm run mcp
```
You do not need to run this every time. Run `npm run mcp` only when you want to test the MCP server directly or connect it to an AI client.
### Supported AI Desktop Clients
The easiest desktop app for this setup is [Claude Desktop](https://claude.ai/download), because it supports local stdio MCP servers with an `mcpServers` JSON config.
Other MCP-compatible tools may also work, such as Claude Code, Cursor, Windsurf, VS Code MCP extensions, or any AI client that supports local stdio MCP servers. Their setup screens may be different, but the same `command`, `args`, and `cwd` values are used.
### Add This MCP Server in Claude Desktop
1. Make sure the backend setup is complete:
```bash
docker compose up -d
npx prisma migrate deploy
npx prisma db seed
```
2. Make sure `.env` exists and has the required database, Redis, Razorpay, and Mailtrap values.
3. Open Claude Desktop.
4. Open Settings > Developer > Edit Config.
On Windows, Claude Desktop opens this file:
```text
%APPDATA%\Claude\claude_desktop_config.json
```
5. Add this MCP server config:
```json
{
"mcpServers": {
"saas-platform-stats": {
"command": "npm",
"args": ["run", "mcp"],
"cwd": "/absolute/path/to/saas-backend" // your project path
}
}
}
```
On this machine, the project path is:
```text
D:\Bitcot-Task\saas-backend
```
For Windows-based clients, use escaped backslashes:
```json
{
"mcpServers": {
"saas-platform-stats": {
"command": "npm",
"args": ["run", "mcp"],
"cwd": "D:\\Bitcot-Task\\saas-backend" // your project path
}
}
}
```
6. Save the config file.
7. Fully quit and reopen Claude Desktop.
8. Start a new Claude chat and ask:
```text
Use the saas-platform-stats MCP server and show me the available subscription plans.
```
You should see Claude use the `get_plans` tool.
Example AI prompts you can ask:
```text
How many active subscribers do we have right now?
What subscription plans do we offer?
What's the price of the Pro plan?
How much total revenue have we generated so far?
```
You do not need to run `npm run mcp` manually when Claude Desktop is configured. Claude Desktop starts the MCP server automatically from the config. Run `npm run mcp` manually only when you want to test the MCP server directly from the terminal.
Available MCP tools:
| Tool | Description |
| -------------------- | ------------------------------------------------------------------------------------ |
| `get_platform_stats` | Returns active subscribers, trialing subscribers, total revenue, and revenue by plan |
| `get_plans` | Returns the available subscription plans with pricing, trials, and features |
Before using MCP, make sure PostgreSQL and Redis are running and the database has been migrated and seeded.
## Autmated Tests
Run `npm run test` to run unit tests and integration tests.
## Test file layout
```text
tests/
├── setup-env.ts # fake env vars for test runs
├── helpers/
│ └── prismaMock.ts # shared mocked Prisma client
├── unit/
│ ├── subscription.service.test.ts
│ ├── stats.service.test.ts
│ ├── invoice.service.test.ts
│ └── cron.test.ts
└── integration/
├── checkout.test.ts
├── webhook.test.ts
└── plansAndStats.test.ts
```
## Project Structure
```text
saas-backend/
├── docker-compose.yml # Postgres + Redis
├── .env.example
├── README.md
├── public/
│ └── index.html # Pricing page (served at localhost:3000)
├── prisma/
│ ├── schema.prisma # User, Plan, Subscription, Invoice models
│ └── seed.ts # Seeds the 3 subscription plans
├── src/
│ ├── index.ts # Express app entrypoint
│ ├── config/
│ │ ├── env.ts # Centralized, validated env vars
│ │ └── redis.ts # Shared Redis connection (BullMQ + cache)
│ ├── db/
│ │ └── prisma.ts # Prisma client singleton
│ ├── routes/ # checkout, webhook, plan, stats, dev
│ ├── controllers/ # HTTP request/response handling
│ ├── services/ # Business logic (payment, subscription,
│ │ invoice, email, plan, stats, cache)
│ ├── jobs/
│ │ ├── queue.ts # BullMQ queue definition
│ │ ├── cron.ts # Daily renewal scan
│ │ └── renewal.worker.ts # Standalone worker process
│ └── mcp/
│ └── server.ts # MCP server (get_platform_stats, get_plans)
└── storage/
└── invoices/ # Generated PDF invoices
```
## Troubleshooting
| Problem | Fix |
| --------------------------------------- | ----------------------------------------------------------------------------------------- |
| `Missing required environment variable` | Confirm `.env` exists and all required keys from `.env.example` are filled in |
| Cannot connect to PostgreSQL | Run `docker compose up -d` and confirm the database is on port `5433` |
| Cannot connect to Redis | Confirm `saas_redis` is running and `REDIS_URL` is `redis://localhost:6379` |
| No plans returned | Run `npx prisma migrate deploy` and `npx prisma db seed` |
| Razorpay webhook rejected | Confirm `RAZORPAY_WEBHOOK_SECRET` matches the webhook secret in Razorpay |
| Emails not appearing | Confirm Mailtrap SMTP credentials and keep `npm run worker` running for renewal reminders |
| MCP client cannot start server | Use an absolute `cwd`, confirm `.env` is present, and test `npm run mcp` manually |
## Author
For any queries, contact [sharifasheriff26@gmail.com](mailto:sharifasheriff26@gmail.com).
LinkedIn: [sharifa-sheriff](https://www.linkedin.com/in/sharif-asheriff/)
This server cannot be deployed
Maintenance
ActivitySlowing
ResponsivenessNo issues