# MCP Owner Guide — Sewapedia / RentApp

**Canonical guide for vendor (owner) AI agents** connecting via hosted Model Context Protocol.

| Resource | URL |
|----------|-----|
| **This guide (web)** | `https://sewapedia.id/mcp-owner-guide.md` |
| Owner MCP manifest | `https://sewapedia.id/.well-known/mcp-owner` |
| Owner MCP endpoint | `https://sewapedia.id/api/v1/mcp-owner` |
| Renter MCP manifest | `https://sewapedia.id/.well-known/mcp` |
| Platform summary | `https://sewapedia.id/llms.txt` |
| Developer page | `https://sewapedia.id/id/developers` |

**Related:** [`docs/MCP_FEATURE_LIST.md`](MCP_FEATURE_LIST.md) (canonical inventory — §2 owner tools) · [`docs/MCP_AGENT_GUIDE.md`](MCP_AGENT_GUIDE.md) (renter/customer tools)

---

## Quick start

Owner MCP is **separate** from renter MCP for security clarity. **62 tools** (5 public, 57 authenticated); `register_vendor_account` is public, other write tools require **VENDOR** auth.

```bash
# 1. Discover owner manifest (includes authentication.deviceFlow)
curl -s https://sewapedia.id/.well-known/mcp-owner | jq .

# 2a. Browser login (recommended) — no password in agent
curl -s -X POST https://sewapedia.id/api/v1/mcp-owner \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"create_login_link","arguments":{"clientLabel":"My Owner Agent"}}}'
# → open verificationUrl in browser; vendor signs in and confirms grant
# Poll until granted:
curl -s -X POST https://sewapedia.id/api/v1/mcp-owner \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"get_login_status","arguments":{"deviceCode":"DEVICE_CODE_FROM_STEP_2a"}}}'
# → store apiKey.secret once; use X-Api-Key on owner MCP requests (90 days until logout)

# 2b. Password login (alternative)
curl -s -X POST https://sewapedia.id/api/v1/mcp-owner \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"owner_login","arguments":{"email":"VENDOR_EMAIL","password":"PASSWORD"}}}'

# 3. List pending requests
curl -s -X POST https://sewapedia.id/api/v1/mcp-owner \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: sp_live_YOUR_VENDOR_KEY" \
  -d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"list_owner_requests","arguments":{}}}'
```

---

## Registration (pemilik aset)

| Path | Steps |
|------|-------|
| **A — Direct vendor signup** | Owner MCP `register_vendor_account` (public) → admin approves → `owner_login` or `create_login_link` |
| **B — Upgrade from penyewa** | Consumer MCP `register_account` → `login` → `activate_vendor` → owner MCP after approval |

`register_vendor_account` parameters: `email`, `password` (min 8), `name`, `phone?`, `displayName`, `vendorType?` (`INDIVIDUAL`\|`COMPANY`). Rate limit: 5/hour per IP (`auth:register`). ADMIN emails blocked.

Manifest: `authentication.register` on `/.well-known/mcp-owner`.

---

## Authentication

> **Security:** Method A (device flow) keeps the password out of agent context. Method B (direct login) works when the user explicitly provides vendor email/password to the agent, but credentials may persist in conversation history.

| Method | Details |
|--------|---------|
| **Method A — Device flow (recommended)** | `create_login_link` → user opens `verificationUrl` in browser → poll `get_login_status` with `deviceCode` → `apiKey.secret` once. VENDOR grant yields `read:owner` + `write:owner` scopes; valid 90 days until logout. REST: `POST /api/v1/auth/device` + `POST /api/v1/auth/device/poll`. |
| **Method B — Direct login** | User provides vendor email/password to agent → agent calls `owner_login` → `accessToken`. Rejects CUSTOMER accounts (403). Use `Authorization: Bearer {accessToken}` on subsequent requests. |
| **JWT Bearer** | `Authorization: Bearer {accessToken}` from `owner_login` or web login. Role must be `VENDOR`. |
| **API key** | `X-Api-Key: sp_live_…` with scopes `read:owner` / `write:owner`. Created by VENDOR at `/akun/pengaturan/api-keys` or via Method A device flow. |

**Blocked:**
- CUSTOMER role JWT on owner tools → 403
- CUSTOMER API keys on owner tools → 403 (authenticate rejects mismatched role)
- ADMIN role on owner MCP → 403 (use admin portal, not MCP)
- Mixing customer + owner scopes in one API key → rejected at creation

---

## Tool inventory (62 tools)

**Canonical inventory:** [`docs/MCP_FEATURE_LIST.md` §2](MCP_FEATURE_LIST.md#2-owner-mcp) — every tool name, scope, and REST mapping from `src/lib/mcp/owner-tools.ts`. Call `tools/list` on `POST /api/v1/mcp-owner` for JSON schemas.

### By category

| Category | Count | Access | Representative tools |
|----------|-------|--------|----------------------|
| Auth | 4 | Public | `register_vendor_account`, `owner_login`, `create_login_link`, `get_login_status` |
| Booking | 13 | Auth | `list_owner_requests`, `approve_booking`, `reject_booking`, `create_counter_offer`, `review_renter_documents`, `respond_extension`, `confirm_offline_payment`, `manage_booking_condition`, `manage_booking_incidents`, `manage_booking_dispute` |
| Catalog | 11 | Auth | `list_my_assets`, `create_asset`, `update_asset`, `delete_asset`, `upload_asset_image`, `delete_asset_image`, `get_pricing_recommendation`, `manage_blackout`, `manage_maintenance`, `manage_duration_rules` |
| Calendar | 1 | Auth | `get_owner_calendar` |
| Finance | 18 | Auth | `get_finance_summary`, `list_finance_entries`, `get_finance_entry`, `create_finance_entry`, `get_finance_pnl`, `manage_finance_tax`, `manage_opex_recurring`, `manage_repair_expenses`, `export_finance_csv`, `get_portfolio_pricing` |
| Payout | 4 | Auth | `list_owner_payouts`, `manage_payout_bank`, `manage_owner_commissions`, `upload_commission_proof` |
| Storefront | 5 | 1 public · 4 auth | `get_storefront`, `update_storefront`, `manage_storefront_slug`, `get_vendor_theme_presets`, `update_vendor_type` |
| Analytics | 3 | Auth | `get_owner_analytics`, `get_seo_listings`, `get_chat_metrics` |
| Chat | 2 | Auth | `manage_booking_chat`, `list_conversations` |
| Platform | 1 | Auth | `manage_owner_feedback` |

**Total:** 5 public · 57 auth = **62 tools**

#### Full inventory (all 62 tools)

### Auth

| Tool | Tier | Scope | Deskripsi (ID) |
|------|------|-------|----------------|
| `register_vendor_account` | Publik | — | Daftar pemilik aset (VENDOR, PENDING) sekaligus; rate limit 5/jam per IP |
| `owner_login` | Publik | — | Login Method B vendor: email/password → accessToken |
| `create_login_link` | Publik | — | Login Method A (disarankan): OAuth device flow tanpa password di agent |
| `get_login_status` | Publik | — | Poll device authorization; dapat apiKey.secret sekali (90 hari) |

### Booking

| Tool | Tier | Scope | Deskripsi (ID) |
|------|------|-------|----------------|
| `list_owner_requests` | Auth | read:owner | Booking menunggu persetujuan pemilik (PENDING_OWNER_APPROVAL) |
| `list_owner_bookings` | Auth | read:owner | Daftar booking vendor (filter: all/pending/active/completed/cancelled) |
| `get_owner_booking_detail` | Auth | read:owner | Detail lengkap booking untuk keputusan vendor |
| `approve_booking` | Auth | write:owner | Setujui permintaan booking pending |
| `reject_booking` | Auth | write:owner | Tolak booking dengan alasan |
| `create_counter_offer` | Auth | write:owner | Kirim counter-offer (harga, tanggal, syarat) |
| `review_renter_documents` | Auth | read:owner, write:owner | Lihat atau approve/reject dokumen KTP/selfie penyewa |
| `respond_extension` | Auth | write:owner | Terima/tolak permintaan perpanjangan sewa |
| `confirm_offline_payment` | Auth | write:owner | Konfirmasi atau tolak bukti transfer offline penyewa |
| `get_renter_snapshot` | Auth | read:owner | Snapshot profil trust penyewa untuk permintaan pending |
| `manage_booking_condition` | Auth | read:owner, write:owner | Submit laporan kondisi check-in/out atau acknowledge check-in |
| `manage_booking_incidents` | Auth | read:owner, write:owner | List, laporkan, acknowledge, atau resolve insiden booking |
| `manage_booking_dispute` | Auth | read:owner, write:owner | Lihat atau buka dispute booking |

### Catalog

| Tool | Tier | Scope | Deskripsi (ID) |
|------|------|-------|----------------|
| `list_my_assets` | Auth | read:owner | Daftar aset milik vendor (default limit 100) |
| `create_asset` | Auth | write:owner | Buat aset sewa baru (pricing, spesifikasi, gambar base64/URL) |
| `get_owner_asset_detail` | Auth | read:owner | Detail lengkap aset untuk editing vendor |
| `update_asset` | Auth | write:owner | Patch section aset (pricing, requirements, kategori, dll.) |
| `delete_asset` | Auth | write:owner | Soft-delete aset (status INACTIVE, unfeatured) |
| `upload_asset_image` | Auth | write:owner | Upload atau attach gambar ke aset (max 5 per aset) |
| `delete_asset_image` | Auth | write:owner | Hapus gambar aset berdasarkan imageId |
| `get_pricing_recommendation` | Auth | read:owner | Rekomendasi harga AI untuk satu aset |
| `manage_blackout` | Auth | read:owner, write:owner | Kelola tanggal blackout: list, create, delete |
| `manage_maintenance` | Auth | read:owner, write:owner | Catatan maintenance aset: list, create |
| `manage_duration_rules` | Auth | read:owner, write:owner | Aturan durasi sewa vendor: get atau update |

### Calendar

| Tool | Tier | Scope | Deskripsi (ID) |
|------|------|-------|----------------|
| `get_owner_calendar` | Auth | read:owner | Kalender vendor (blackout, booking, maintenance) |

### Finance

| Tool | Tier | Scope | Deskripsi (ID) |
|------|------|-------|----------------|
| `get_finance_summary` | Auth | read:owner | Ringkasan dashboard keuangan (revenue, opex, P&L) |
| `list_finance_entries` | Auth | read:owner | Daftar entri ledger dengan filter opsional |
| `create_finance_entry` | Auth | write:owner | Buat entri ledger manual (income/expense) |
| `get_finance_entry` | Auth | read:owner | Detail satu entri ledger berdasarkan id |
| `update_finance_entry` | Auth | write:owner | Patch entri ledger |
| `delete_finance_entry` | Auth | write:owner | Void entri ledger |
| `duplicate_finance_entry` | Auth | write:owner | Duplikasi entri ledger |
| `get_finance_pnl` | Auth | read:owner | Laporan laba rugi vendor |
| `get_finance_categories` | Auth | read:owner | Daftar slug kategori keuangan |
| `export_finance_csv` | Auth | read:owner | Export ledger ke CSV |
| `manage_finance_tax` | Auth | read:owner, write:owner | Profil pajak, deadline, export |
| `manage_acquisitions` | Auth | read:owner, write:owner | Akuisisi aset: list, create, confirm |
| `manage_opex_recurring` | Auth | read:owner, write:owner | Template OpEx berulang: list, create |
| `manage_opex_checklist` | Auth | read:owner | Checklist OpEx bulanan |
| `opex_quick_add` | Auth | write:owner | Quick-add entri OpEx |
| `get_portfolio_pricing` | Auth | read:owner | Alert harga portofolio aset |
| `get_asset_finance` | Auth | read:owner | Ringkasan keuangan per aset |
| `manage_repair_expenses` | Auth | read:owner, write:owner | Biaya perbaikan: list, create, prefill, confirm |

### Payout

| Tool | Tier | Scope | Deskripsi (ID) |
|------|------|-------|----------------|
| `list_owner_payouts` | Auth | read:owner | Riwayat payout vendor |
| `manage_payout_bank` | Auth | read:owner, write:owner | Lihat atau update rekening bank payout |
| `manage_owner_commissions` | Auth | read:owner | Daftar kewajiban komisi platform |
| `upload_commission_proof` | Auth | write:owner | Upload bukti pembayaran komisi |

### Storefront

| Tool | Tier | Scope | Deskripsi (ID) |
|------|------|-------|----------------|
| `get_storefront` | Auth | read:owner | Pengaturan branding dan slug storefront |
| `update_storefront` | Auth | write:owner | Update branding (tagline, warna, layout preset) |
| `manage_storefront_slug` | Auth | read:owner, write:owner | Username storefront: update atau cek ketersediaan |
| `get_vendor_theme_presets` | Publik | — | Daftar preset warna tema vendor |
| `update_vendor_type` | Auth | write:owner | Ubah tipe vendor INDIVIDUAL atau COMPANY |

### Analytics

| Tool | Tier | Scope | Deskripsi (ID) |
|------|------|-------|----------------|
| `get_owner_analytics` | Auth | read:owner | Ringkasan dashboard analytics vendor |
| `get_seo_listings` | Auth | read:owner | Performa SEO listing pemilik |
| `get_chat_metrics` | Auth | read:owner | Metrik waktu respons chat pemilik |

### Chat

| Tool | Tier | Scope | Deskripsi (ID) |
|------|------|-------|----------------|
| `manage_booking_chat` | Auth | read:owner, write:owner | List atau kirim pesan chat booking |
| `list_conversations` | Auth | read:owner | Daftar percakapan booking + inquiry |

### Platform

| Tool | Tier | Scope | Deskripsi (ID) |
|------|------|-------|----------------|
| `manage_owner_feedback` | Auth | read:owner, write:owner | Feedback platform: list atau submit |


#### Examples — finance & commissions

**manage_owner_commissions:**

```json
{"name":"manage_owner_commissions","arguments":{"limit":20}}
```

**export_finance_csv:**

```json
{"name":"export_finance_csv","arguments":{"from":"2026-01-01","to":"2026-12-31","includePii":false}}
```

**manage_finance_tax:**

```json
// Get tax profile
{"name":"manage_finance_tax","arguments":{"action":"get_profile"}}

// List upcoming deadlines
{"name":"manage_finance_tax","arguments":{"action":"list_deadlines","year":2026}}

// Export tax report
{"name":"manage_finance_tax","arguments":{"action":"export","year":2026}}
```

### create_asset parameters

Required fields match `POST /owner/assets`: `categoryId`, `title`, `brand`, `model`, `year`, `rentalModes`, `city`, `assetValue`, `dayRate`. Optional: `transmission`, `specs`, `amenities`, `withDriverRate`, `images` (max 5).

```json
{
  "categoryId": "clx…",
  "title": "Toyota Avanza 2024",
  "brand": "Toyota",
  "model": "Avanza",
  "year": 2024,
  "rentalModes": "BOTH",
  "city": "Jakarta",
  "assetValue": 250000000,
  "dayRate": 350000,
  "withDriverRate": 450000,
  "specs": { "seats": 7, "fuel": "Bensin" },
  "images": [
    {
      "fileBase64": "<base64-no-data-url-prefix>",
      "fileName": "front.jpg",
      "mimeType": "image/jpeg",
      "isPrimary": true
    },
    { "url": "https://cdn.example.com/side.jpg", "isPrimary": false }
  ]
}
```

Each image entry needs **`fileBase64`** (upload to MinIO, ~10 MB decoded) **or** **`url`** (attach existing public URL). First image is primary unless `isPrimary` is set.

### manage_blackout parameters

```json
{ "action": "list", "assetId": "..." }
{ "action": "create", "assetId": "...", "startDate": "2026-09-01", "endDate": "2026-09-07", "reason": "Maintenance" }
{ "action": "delete", "assetId": "...", "blackoutId": "..." }
```

---

## Owner agent flow

1. **Authenticate** — Method A: `create_login_link` + browser grant (recommended) **or** Method B: `owner_login` (user provides vendor email/password to agent)
2. **Inbox** — `list_owner_requests` for `PENDING_OWNER_APPROVAL`
3. **Review** — `get_owner_booking_detail` + `review_renter_documents` (KTP/selfie) before deciding
4. **Decide** — `approve_booking`, `reject_booking`, or `create_counter_offer` (negotiate price/dates)
5. **Communicate** — `manage_booking_chat` for renter messages; `respond_extension` for active rentals
6. **Calendar** — `get_owner_calendar` for availability overview; `manage_blackout` to block dates
7. **Catalog** — `create_asset`, `update_asset`, `upload_asset_image` / `delete_asset_image`
8. **Storefront** — `get_storefront` / `update_storefront` for branding and layout
9. **Finance** — `get_finance_summary`, `list_finance_entries`, `create_finance_entry`
10. **Analytics** — `get_owner_analytics` for dashboard summary

---

## Security notes

| Control | Behavior |
|---------|----------|
| **Role gate** | All auth tools require `VENDOR` JWT or vendor API key — `CUSTOMER` → 403 |
| **Scope gate** | API keys must have `read:owner` (read tools) or `write:owner` (approve/reject/blackout mutate) |
| **Rate limits** | `mcp-owner:public:{tool}` 60/min; auth tools 120/min per vendor user; `owner_login` 5/15min per IP; `register_vendor_account` 5/hour per IP; `create_login_link` 10/hour per IP |
| **Discovery** | `GET /.well-known/mcp-owner` returns `X-RateLimit-*` headers (60/min) |
| **List caps** | `list_owner_bookings` defaults to 50 rows; `list_my_assets` defaults to 100 |
| **Secrets** | Manifests never include API keys, passwords, or tokens |

**Smoke test:** `./scripts/test-mcp-production.sh http://localhost:3000`

---

## Local stdio (optional)

`packages/mcp-sewapedia` supports owner tools via `SEWAPEDIA_MCP_MODE=owner` env. See package README.
