Skip to main content
Glama
mhdarifsetiawan01

mcp-dummy-server

README.md
# mcp-dummy-server

MCP server dengan data dari **PostgreSQL**, transport **Streamable HTTP** mode **stateless** — cocok untuk multi-instance/replica di Fly.io.

## Struktur

```
src/
  data/
    db.js                  # koneksi pool PostgreSQL (pg)
    hariRepository.js      # query ke tabel `hari`
    kodeposRepository.js   # query ke tabel `kodepos`
    apiKeysRepository.js   # auth: bcrypt.compare ke tabel `api_keys`
  tools/
    index.js               # definisi & registrasi semua MCP tools
  server.js                # express + StreamableHTTPServerTransport + auth middleware
db/
  migrations/
    001_create_tables.sql  # schema: hari, kodepos, api_keys
  seed.js                  # isi data awal (jalankan sekali setelah db:up)
docker-compose.yml         # Postgres 16-alpine lokal, port 5435
```

**Pindah Provider DB (Dinamis):** Cukup ganti nilai `DATABASE_URL` di `.env` (Docker Lokal ↔ Supabase ↔ Neon ↔ Fly Postgres) tanpa perlu mengubah kode sumber sama sekali.

## Tools yang tersedia

| Tool | Input | Fungsi |
|---|---|---|
| `list_hari` | - | Semua hari Senin-Minggu |
| `get_hari` | `id` (1-7) | Detail 1 hari |
| `list_kodepos` | - | Semua data kodepos |
| `search_kodepos_by_kota` | `kota` (string) | Cari kodepos berdasarkan nama kota |
| `get_kodepos` | `kodepos` (5 digit) | Detail exact match kodepos |

## Jalan lokal (dengan Postgres via Docker)

```bash
npm install
cp .env.example .env   # isi MCP_API_KEY, sesuaikan DATABASE_URL dll.

# 1. Jalankan Postgres Docker (port 5435 — hindari conflict 5432/5433/5434)
npm run db:up

# 2. Seed: buat tabel + isi data awal + hash API key ke DB
npm run db:seed

# 3. Jalankan server
npm start
# server listen di http://localhost:8080/mcp
```

Test cepat:

```bash
curl -X POST http://localhost:8080/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "x-api-key: $(grep MCP_API_KEY .env | cut -d= -f2)" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'
```

Stop Postgres:

```bash
npm run db:down
```

## Auth

Server dilindungi API key berbasis database (tabel `api_keys`, key disimpan sebagai **bcrypt hash** — tidak pernah plaintext).

- Kalau `DATABASE_URL` **tidak di-set** → auth otomatis nonaktif (dev mode), muncul warning di log. **Jangan biarkan di production.**
- Kalau `DATABASE_URL` di-set → semua request ke `/mcp` wajib bawa header `x-api-key` yang cocok (diverifikasi via bcrypt.compare ke DB).
- `last_used_at` di tabel `api_keys` otomatis diupdate setiap kali key dipakai (fire-and-forget).

Jalankan lokal dengan auth aktif:

```bash
# Pastikan DATABASE_URL sudah di-.env dan db:seed sudah dijalankan
MCP_API_KEY=<your-key> npm start
```

## Deploy ke Fly.io

```bash
# install flyctl kalau belum: https://fly.io/docs/flyctl/install/
fly auth login

# dari folder project ini
fly launch --no-deploy   # generate app, JANGAN overwrite fly.toml yang sudah ada

# WAJIB: set secrets (jangan taruh di fly.toml / git)
fly secrets set MCP_API_KEY="ganti-dengan-string-random-yang-panjang"
fly secrets set DATABASE_URL="postgresql://user:pass@host:5432/dbname"

fly deploy
```

> **Catatan:** Untuk production, gunakan Postgres yang dihosting (mis. Fly Postgres, Supabase, Neon). Jalankan `npm run db:seed` sekali saja terhadap DB production untuk inisialisasi tabel dan API key pertama.

Setelah deploy, endpoint MCP ada di:

```
https://<nama-app-kamu>.fly.dev/mcp
```

## Konek dari Antigravity IDE

```json
{
  "mcpServers": {
    "dummy-data-mcp": {
      "url": "https://<nama-app-kamu>.fly.dev/mcp",
      "headers": {
        "x-api-key": "ganti-dengan-string-random-yang-panjang"
      }
    }
  }
}
```

Kalau Antigravity IDE hanya mendukung MCP via stdio, pakai proxy `mcp-remote`:

```json
{
  "mcpServers": {
    "dummy-data-mcp": {
      "command": "npx",
      "args": [
        "-y", "mcp-remote", "https://<nama-app-kamu>.fly.dev/mcp",
        "--header", "x-api-key:ganti-dengan-string-random-yang-panjang"
      ]
    }
  }
}
```

## Manajemen API Key

API key disimpan di tabel `api_keys` sebagai bcrypt hash. Untuk menambah key baru:

```bash
# Contoh: tambah key baru langsung ke DB
node -e "
import('bcrypt').then(async ({default: bcrypt}) => {
  const hash = await bcrypt.hash('key-baru-kamu', 12);
  console.log('INSERT INTO api_keys (key_hash, label) VALUES (\'' + hash + '\', \'nama-label\');');
});
"
# Salin output INSERT-nya, jalankan di psql atau DB client
```

## Catatan keamanan

- API key tidak pernah disimpan plaintext — hanya bcrypt hash di DB.
- `MCP_API_KEY` di `.env` hanya dipakai saat `db:seed` (untuk generate hash pertama kali). Selebihnya tidak dipakai server.
- Untuk revoke key: `UPDATE api_keys SET is_active = false WHERE id = <id>;`