Skip to main content
Glama
HassanGeesey

school-finance-mcp

by HassanGeesey
README.md
# SchoolFinance MCP Server

A production-grade [Model Context Protocol](https://modelcontextprotocol.io) server for **SchoolFinance**, a single-user desktop school finance application. It exposes the entire school finance domain — students, classes, payments, income/expenses, reports, settings, notifications and a recycle bin — as MCP **tools** and **resources**, backed by a local SQLite database.

- Single administrator (school owner), full access, no authentication
- Synchronous SQLite via `better-sqlite3` — no server, no runtime surprises
- Zod-validated tool inputs and resource data
- Structured JSON responses (`{ success, data }` / `{ success, error }`)
- Soft deletes + recycle bin + audit log
- CSV and JSON export

## Tech stack

| Piece            | Choice                                       |
| ---------------- | -------------------------------------------- |
| Language         | TypeScript (strict), ESModules               |
| MCP SDK          | `@modelcontextprotocol/sdk` (`McpServer`)    |
| Transport        | stdio (spec-compliant JSON-RPC messages)     |
| Database         | SQLite file (`schoolfinance.db`) + `better-sqlite3` |
| Validation       | `zod` v3                                     |

## Getting started

```bash
npm install
npm run build        # compile TypeScript to dist/
npm start            # run the compiled server (stdio)
```

For development you can run the server directly with tsx:

```bash
npm run dev
```

The server speaks MCP over stdio, so it is driven by an MCP client. In an MCP client config:

```json
{
  "mcpServers": {
    "school-finance": {
      "command": "node",
      "args": ["/path/to/school-finance-mcp/dist/index.js"],
      "env": { "DB_PATH": "/path/to/schoolfinance.db" }
    }
  }
}
```

## Configuration

All configuration is via environment variables (see `.env.example`):

| Variable     | Default              | Description                          |
| ------------ | -------------------- | ------------------------------------ |
| `DB_PATH`    | `./schoolfinance.db` | SQLite database file location        |
| `BACKUP_DIR` | `./backups`          | Where `backup_database` writes files |
| `LOG_LEVEL`  | `info`               | `debug` \| `info` \| `warn` \| `error` |

Logs are written to **stderr** (MCP best practice) so the stdout protocol stream stays clean.

## Tools

### Dashboard
- `get_dashboard_stats` — counts, outstanding balance, monthly revenue/expenses, recent activity
- `get_recent_activity` — last 10 audit-log entries
- `get_financial_summary` — month income/expenses/balance plus previous-month trend

### Students
- `create_student` / `update_student` / `delete_student` (soft) / `restore_student`
- `get_student` — detail incl. payments + balance
- `search_students` / `list_students` — query, filters, sort, pagination

### Classes
- `create_class` / `update_class` / `delete_class` / `assign_student_to_class` / `list_classes`

### Payments
- `record_payment` / `edit_payment` / `delete_payment` (soft)
- `get_payment_history` / `get_unpaid_students` / `get_overdue_students` / `get_student_balance`

### Income & Expenses
- `add_income` / `add_expense` / `update_transaction` / `delete_transaction`
- `get_transaction_history` / `get_monthly_summary`

### Reports
- `generate_financial_report` / `generate_student_balance_report` / `generate_class_report`
- `export_data` — CSV or JSON for any resource

### Settings
- `update_school_info` / `manage_payment_templates` / `set_academic_year`
- `backup_database` / `restore_database`

### Notifications
- `get_pending_reminders` / `mark_reminder_completed`

### Recycle Bin
- `list_deleted_items` / `restore_deleted_item` / `permanently_delete_item`

## Resources

The `schoolfinance://*` namespace exposes live data:

```
schoolfinance://dashboard
schoolfinance://students
schoolfinance://classes
schoolfinance://payments
schoolfinance://income
schoolfinance://expenses
schoolfinance://reports
schoolfinance://settings
schoolfinance://notifications
schoolfinance://recycle-bin
```

## Domain rules

- A student's **balance** = class fee − total active payments. Balances are recalculated whenever payments or class fees change.
- **Overdue** = outstanding balance **and** enrolment older than 30 days (documented heuristic for this single-user app).
- Deleting a class with enrolled students is blocked — reassign students first.
- `delete_student`, `delete_payment` and `delete_transaction` are **soft deletes**; items appear in the recycle bin.
- `income`/`expenses` carry a `deleted_at` column (slightly beyond the spec's table list) because they are soft-deletable and recyclable.

## Database

Schema is created idempotently on startup. Tables: `classes`, `students`, `payments`, `income`, `expenses`, `settings`, `notifications`, `audit_log`. WAL mode is enabled for durability and concurrent access safety.

## Testing

```bash
npm test          # spawns the server and speaks real MCP over stdio
```

Tests use a throwaway database in the OS temp directory (see `tests/setup.ts`).

## Project structure

```
src/
├── index.ts              # entry point
├── server.ts             # McpServer assembly, tool + resource registration
├── config/database.ts    # SQLite connection + schema
├── services/             # business logic (audit, students, classes, payments, ...)
├── schemas/              # Zod schemas for inputs and resource data
├── resources/templates/  # report template
├── utils/                # db, date, export, logging, response helpers
└── tools/                # MCP tool registrations
```

## Connecting to MCP Clients

The server runs as a **stdio process** — the client spawns it, sends JSON-RPC messages over stdin, and reads responses from stdout. Below are step-by-step instructions for each client.

### Prerequisites

Build the server first:
```bash
npm install
npm run build          # compiles to dist/index.js
```

Find the absolute path:
```bash
realpath dist/index.js   # e.g. /home/user/mcp-schoolfinance/dist/index.js
realpath schoolfinance.db # (or create a persistent DB path)
```

### Claude Desktop

1. Edit `claude_desktop_config.json`:
   - **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
   - **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
   - **Linux**: `~/.config/Claude/claude_desktop_config.json`

2. Add the server:
```json
{
  "mcpServers": {
    "school-finance": {
      "command": "node",
      "args": ["/absolute/path/to/school-finance-mcp/dist/index.js"],
      "env": {
        "DB_PATH": "/absolute/path/to/school-finance.db"
      }
    }
  }
}
```

3. Restart Claude Desktop. The server will appear in Claude's MCP settings.

### Claude Code (CLI / VS Code extension)

1. Edit `.opencode.jsonc` or `.claude.json` in your project root:
```json
{
  "mcp": {
    "school-finance": {
      "type": "stdio",
      "command": "node",
      "args": ["/absolute/path/to/school-finance-mcp/dist/index.js"],
      "env": { "DB_PATH": "/absolute/path/to/school-finance.db" }
    }
  }
}
```

2. Or add to `~/.config/.opencode/mcp.json` for all projects.

### Cursor

1. Open Settings → `Cursor Settings` → `MCP` tab (or search "MCP")
2. Click "Add MCP Server"
3. Enter:
   - **Name**: `school-finance`
   - **Type**: `stdio`
   - **Command**: `node /absolute/path/to/school-finance-mcp/dist/index.js`
   - **Environment Variables**: add `DB_PATH` → `/absolute/path/to/school-finance.db`

### ChatGPT (Desktop / web with ChatGPT Pro)

ChatGPT's desktop app supports MCP via `mcp_config.json`:
1. Edit `~/.chatgpt/mcp_config.json` (or the config path shown in-app)
2. Add:
```json
{
  "mcpServers": {
    "school-finance": {
      "command": "node",
      "args": ["/absolute/path/to/school-finance-mcp/dist/index.js"],
      "env": { "DB_PATH": "/absolute/path/to/school-finance.db" }
    }
  }
}
```
3. Restart the ChatGPT desktop app.

### VS Code (with MCP extension)

1. Install the `modelcontextprotocol.mcp` extension (or use Claude/Copilot with MCP support)
2. Edit `.vscode/mcp.json`:
```json
{
  "servers": {
    "school-finance": {
      "type": "stdio",
      "command": "node",
      "args": ["/absolute/path/to/school-finance-mcp/dist/index.js"],
      "env": { "DB_PATH": "/absolute/path/to/school-finance.db" }
    }
  }
}
```

### Using with OpenCode

Add to your OpenCode configuration to let the agent use SchoolFinance tools:
```jsonc
// ~/.config/opencode/opencode.jsonc
{
  "mcp": [
    {
      "name": "school-finance",
      "command": "node /absolute/path/to/school-finance-mcp/dist/index.js",
      "env": { "DB_PATH": "/absolute/path/to/school-finance.db" }
    }
  ]
}
```

### Available Tools

Once connected, AI assistants can call these tools, for example:

```
# Create a class and add students
create_class(name="Grade 10A", year_level=10, fee_amount=1200, description="Morning class")
create_student(name="Ahmed Hassan", email="ahmed@example.com", phone="+252612345678", 
  address="Mogadishu, Somalia", class_id=1, enrollment_date="2025-09-01")

# Record a payment
record_payment(student_id=1, amount=500, payment_date="2025-09-15", 
  method="cash", reference="REC-001", notes="Partial payment")

# Check student balance
get_student_balance(student_id=1)

# Generate reports
generate_financial_report(start_date="2025-01-01", end_date="2025-12-31")
export_data(resource="students", format="csv")
```

### Troubleshooting

| Problem | Fix |
|---------|-----|
| Server doesn't appear | Check absolute paths in config, ensure `npm run build` was run |
| Database errors | Ensure `DB_PATH` points to a writable directory, or omit to use `./schoolfinance.db` |
| "Cannot find module" | Run `npm install` in the project directory |
| Logs not visible | MCP clients may suppress stderr; check the client's log viewer |
| Port/resource conflicts | SQLite is file-based, no port conflicts — ensure the DB file is accessible |

## License

MIT