# MCP Agent Guide — Sewapedia / RentApp

**Canonical guide for external AI agents** connecting via hosted Model Context Protocol (MCP) or local stdio wrapper.

| Resource | URL |
|----------|-----|
| **This guide (web)** | `https://sewapedia.id/mcp-agent-guide.md` |
| MCP manifest | `https://sewapedia.id/.well-known/mcp` |
| MCP endpoint | `https://sewapedia.id/api/v1/mcp` |
| **Owner MCP manifest** | `https://sewapedia.id/.well-known/mcp-owner` |
| **Owner MCP endpoint** | `https://sewapedia.id/api/v1/mcp-owner` |
| Owner MCP guide | [`docs/MCP_OWNER_GUIDE.md`](MCP_OWNER_GUIDE.md) |
| Platform summary | `https://sewapedia.id/llms.txt` |
| REST agent guide | [`docs/API_AGENT_GUIDE.md`](API_AGENT_GUIDE.md) |
| OpenAPI (agent) | `https://sewapedia.id/openapi-agent.yaml` |
| Developer page | `https://sewapedia.id/id/developers` |
| Local stdio package | [`packages/mcp-sewapedia/README.md`](../packages/mcp-sewapedia/README.md) |

**Related:** [`docs/MCP_FEATURE_LIST.md`](MCP_FEATURE_LIST.md) (canonical inventory — 69 consumer + 62 owner = 131 tools) · [`docs/AI_AGENT_PLAN_V2.md`](AI_AGENT_PLAN_V2.md) · [`docs/MCP_REGISTRY_SUBMISSION.md`](MCP_REGISTRY_SUBMISSION.md)

---

## English

### 1. Quick start

Sewapedia exposes **69 MCP tools** (24 public, 45 authenticated) over **Streamable HTTP**. All tools delegate to existing `GET/POST /api/v1/*` REST endpoints — no duplicate business logic.

```bash
# 1. Discover manifest (no auth)
curl -s https://sewapedia.id/.well-known/mcp | jq .

# 2. List tools (JSON-RPC)
curl -s -X POST https://sewapedia.id/api/v1/mcp \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'

# 3. Call public tool
curl -s -X POST https://sewapedia.id/api/v1/mcp \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"search_assets","arguments":{"q":"avanza","limit":5}}}'

# 4. Login → store accessToken
curl -s -X POST https://sewapedia.id/api/v1/mcp \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"login","arguments":{"email":"YOUR_EMAIL","password":"YOUR_PASSWORD"}}}'

# 5. Authenticated tool call
curl -s -X POST https://sewapedia.id/api/v1/mcp \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -d '{"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"list_my_bookings","arguments":{"limit":10}}}'
```

**Transport:** `streamable-http` (stateless per request). **CORS:** enabled for external runtimes (Hermes, Claude Desktop remote).

### 2. Entry points for arriving agents

| Priority | Resource | Purpose |
|----------|----------|---------|
| 1 | `/llms.txt` | Platform summary, auth, 6-step booking flow, tool tiers |
| 2 | `/.well-known/mcp` | MCP manifest: endpoint, public/auth tool names, scopes |
| 3 | `/mcp-agent-guide.md` | This document (auth, flows, Hermes config) |
| 3b | `docs/MCP_FEATURE_LIST.md` | **Canonical tool inventory** — all 69 consumer tools by category |
| 4 | `/{locale}/developers` | Human-readable quick start (id, en, ms, zh) |
| 5 | `/openapi-agent.yaml` | REST subset (use MCP tools or REST — same backend) |
| 6 | `/.well-known/ucp` | Universal Commerce Protocol merchant manifest |

### 3. Authentication & login flow

> **Security:** Method A (device flow) keeps the password out of agent context. Method B (direct login) works when the user explicitly provides email/password to the agent, but credentials may persist in conversation history.

#### Method A — Device flow (recommended)

No password in agent — user signs in via browser.

1. Call `create_login_link` (optional `clientLabel`) — **no** `Authorization` header.
2. Response includes `verificationUrl` and `deviceCode`.
3. **Human step:** user opens `verificationUrl` in a browser, signs in, confirms grant.
4. Poll `get_login_status` with `{ "deviceCode" }` every ~5 s until `status: "granted"`.
5. Store `apiKey.secret` once — valid 90 days until user logout.
6. Pass `X-Api-Key: sp_live_…` or `Authorization: Bearer sp_live_…` on subsequent MCP requests.

REST equivalent: `POST /api/v1/auth/device` + `POST /api/v1/auth/device/poll`.

#### Method B — Direct login (user provides email/password to agent)

1. User tells the agent their email and password.
2. Agent calls `login` with `{ "email", "password" }` — **no** `Authorization` header required.
3. Response includes `{ accessToken, refreshToken, expiresIn, user }`.
4. Pass `Authorization: Bearer {accessToken}` on **subsequent MCP HTTP requests**.
5. Refresh via MCP `refresh_token` or REST `POST /api/v1/auth/refresh` before expiry.

#### Option C — Scoped API key (manual)

1. User logs in on web → `/akun/pengaturan/api-keys` → create key with scopes.
2. Pass `X-Api-Key: sp_live_…` or `Authorization: Bearer sp_live_…` on MCP requests.
3. **CUSTOMER role only** — ADMIN/VENDOR cannot use agent API keys.

### 3b. Registration flows (penyewa & pemilik)

| Goal | Tool | Auth | REST | Notes |
|------|------|------|------|-------|
| **Penyewa baru** | `register_account` | Public | `POST /auth/register` (`accountType=customer`) | Rate limit 5/hour per IP. Returns user id/email/role — **no tokens**. Then `login` or `create_login_link`. |
| **Penyewa → pemilik** | `activate_vendor` | CUSTOMER Bearer/key | `POST /vendor/activate` | `displayName`, `vendorType?`. Rate limit 3/hour. Vendor status PENDING until admin approves. |
| **Pemilik baru (one-step)** | `register_vendor_account` | Public (owner MCP) | `POST /auth/register` (`accountType=vendor`) | See [`MCP_OWNER_GUIDE.md`](MCP_OWNER_GUIDE.md). |

**Blocked:** ADMIN registration via MCP (403). No CAPTCHA on MCP — same rate limits as web `/daftar`.

**After register:** always obtain tokens via `login`, `create_login_link`, or web sign-in before booking tools.

#### Option D — Pre-set env (local stdio)

| Variable | Description |
|----------|-------------|
| `SEWAPEDIA_ACCESS_TOKEN` | JWT from login |
| `SEWAPEDIA_API_KEY` | Scoped key `sp_test_…` / `sp_live_…` |
| `SEWAPEDIA_API_BASE` | REST base (default `https://sewapedia.id/api/v1`) |

**Scopes** (API keys only; JWT bypasses scope checks):

| Scope | Used by |
|-------|---------|
| `read:catalog` | Optional on public catalog tools when API key present |
| `read:booking` | list/get bookings, readiness, pay status |
| `write:booking` | create, promote, cancel, extension, upload |
| `write:payment` | initiate_payment, apply_credit |

### 4. Public vs authenticated tiers

| Tier | Count | Auth on MCP HTTP request | Notes |
|------|-------|--------------------------|-------|
| **Public** | 24 | None | Discovery, auth (register/login/device), UCP discover/quote, chat inquiry, platform health |
| **Authenticated** | 45 | Bearer JWT or API key | Booking, payment, trust, reviews, notifications, account, chat, UCP checkout, webhooks |

JWT sessions with role `CUSTOMER` only for write tools. Owner/admin routes are **not** exposed via MCP.

### 4b. Owner MCP (VENDOR)

Separate endpoint for asset owners — see [`docs/MCP_OWNER_GUIDE.md`](MCP_OWNER_GUIDE.md).

| Resource | URL |
|----------|-----|
| Manifest | `https://sewapedia.id/.well-known/mcp-owner` |
| Endpoint | `https://sewapedia.id/api/v1/mcp-owner` |

**62 owner tools** (5 public, 57 authenticated). Full list: [`docs/MCP_FEATURE_LIST.md` §2](MCP_FEATURE_LIST.md#2-owner-mcp). See [`docs/MCP_OWNER_GUIDE.md`](MCP_OWNER_GUIDE.md). Recommended auth: `create_login_link` → vendor opens `verificationUrl` in browser → poll `get_login_status` with `deviceCode` → store `apiKey.secret` once (`read:owner`, `write:owner`, 90 days). Alternative: `owner_login` (email/password JWT).

### 5. Tool reference (69 tools)

**Canonical inventory:** [`docs/MCP_FEATURE_LIST.md`](MCP_FEATURE_LIST.md) — every tool name, scope, and Indonesian description from `src/lib/mcp/tools.ts`. Call `tools/list` on the live endpoint for JSON schemas.

#### By category

| Category | Count | Access | Representative tools |
|----------|-------|--------|----------------------|
| Discovery | 8 | Public | `search_assets`, `check_availability`, `pricing_quote`, `catalog_feed`, `get_asset_detail`, `list_categories`, `get_vendor`, `get_category_requirements` |
| Auth | 10 | 8 public · 2 auth | `register_account`, `login`, `create_login_link`, `get_login_status`, `refresh_token`, `logout`, `forgot_password`, `reset_password`, `activate_vendor`, `manage_api_keys` |
| Booking | 14 | Auth | `create_booking`, `promote_booking`, `cancel_booking`, `booking_readiness`, `request_extension`, `respond_counter_offer`, `manage_booking_condition`, `manage_booking_incidents`, `manage_booking_dispute` |
| Payment | 6 | Auth | `initiate_payment`, `apply_credit`, `get_pay_status`, `report_offline_payment`, `get_payment_options`, `get_payment_invoice` |
| Trust | 5 | 1 public · 4 auth | `get_trust_profile`, `get_verification_status`, `upload_document`, `assess_risk`, `verify_phone_otp` |
| Reviews | 2 | Auth | `list_reviews`, `submit_review` |
| Notifications | 3 | Auth | `list_notifications`, `mark_notification_read`, `manage_push_subscription` |
| UCP | 11 | 5 public · 6 auth | `ucp_discover`, `ucp_products`, `ucp_product`, `ucp_availability`, `ucp_quote`, `ucp_checkout`, `ucp_checkout_create`, `ucp_checkout_status`, `ucp_checkout_complete`, `ucp_webhook_register`, `list_ucp_webhooks` |
| Account | 4 | Auth | `get_profile`, `update_profile`, `change_password`, `get_account_credit` |
| Chat | 4 | 1 public · 3 auth | `manage_asset_inquiry`, `manage_booking_chat`, `list_conversations`, `manage_inquiry_thread` |
| Webhooks | 1 | Auth | `manage_agent_webhooks` |
| Platform | 1 | Public | `health_check` |

**Total:** 24 public · 45 auth = **69 tools**

#### Full inventory (all 69 tools)

### Discovery

| Tool | Tier | Scope | Deskripsi (ID) |
|------|------|-------|----------------|
| `search_assets` | Publik | — | Cari aset di katalog (discovery saja, tanpa jaminan tanggal) |
| `check_availability` | Publik | — | Cek ketersediaan kalender aset untuk rentang tanggal (from/to ISO) |
| `pricing_quote` | Publik | — | Hitung quote harga untuk aset dan tanggal sewa |
| `catalog_feed` | Publik | — | Feed discovery katalog terpaginasi (bulk) |
| `get_asset_detail` | Publik | — | Detail publik aset berdasarkan slug |
| `list_categories` | Publik | — | Daftar semua kategori katalog |
| `get_vendor` | Publik | — | Halaman storefront publik vendor berdasarkan slug |
| `get_category_requirements` | Publik | — | Persyaratan verifikasi per kategori (KTP, SIM, dll.) |

### Auth

| Tool | Tier | Scope | Deskripsi (ID) |
|------|------|-------|----------------|
| `register_account` | Publik | — | Daftar akun penyewa (CUSTOMER) baru; rate limit 5/jam per IP |
| `login` | Publik | — | Login Method B: email/password → accessToken + refreshToken |
| `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) |
| `refresh_token` | Publik | — | Refresh JWT access token; rate limited |
| `logout` | Publik | — | Revoke refresh token dan API key perangkat terkait |
| `forgot_password` | Publik | — | Minta email reset password |
| `reset_password` | Publik | — | Reset password via token email |
| `activate_vendor` | Auth | — | Upgrade CUSTOMER → pemilik aset (VENDOR, PENDING approval) |
| `manage_api_keys` | Auth | — | List, create, delete, rotate API key scoped; JWT only |

### Booking

| Tool | Tier | Scope | Deskripsi (ID) |
|------|------|-------|----------------|
| `list_my_bookings` | Auth | read:booking | Daftar booking penyewa (paginated) |
| `get_booking_detail` | Auth | read:booking | Detail booking untuk penyewa |
| `booking_readiness` | Auth | read:booking | Status booking, nextActions, blockers untuk AI agent |
| `get_active_booking` | Auth | read:booking | Booking aktif/pending untuk banner home |
| `create_booking` | Auth | write:booking | Buat permintaan sewa baru |
| `promote_booking` | Auth | write:booking | Promosikan booking PENDING_VERIFICATION ke inbox pemilik |
| `cancel_booking` | Auth | write:booking | Batalkan booking sebagai penyewa |
| `request_extension` | Auth | write:booking | Ajukan perpanjangan sewa saat booking ACTIVE |
| `list_booking_extensions` | Auth | read:booking | Daftar permintaan perpanjangan untuk satu booking |
| `respond_counter_offer` | Auth | write:booking | Terima/tolak counter-offer dari pemilik |
| `update_booking_collateral` | Auth | write:booking | Update item jaminan/kolateral booking |
| `manage_booking_condition` | Auth | read:booking, write:booking | Submit laporan kondisi check-in/out atau acknowledge check-in |
| `manage_booking_incidents` | Auth | read:booking, write:booking | List, laporkan, acknowledge, atau resolve insiden booking |
| `manage_booking_dispute` | Auth | read:booking, write:booking | Lihat atau buka dispute booking |

### Payment

| Tool | Tier | Scope | Deskripsi (ID) |
|------|------|-------|----------------|
| `initiate_payment` | Auth | write:payment | Inisiasi pembayaran Midtrans (redirectUrl — human checkout) |
| `apply_credit` | Auth | write:payment | Terapkan saldo kredit akun ke booking PENDING_PAYMENT |
| `get_pay_status` | Auth | read:booking | Sync/poll status pembayaran Midtrans per order |
| `report_offline_payment` | Auth | write:payment | Laporkan transfer bank offline dengan proof key |
| `get_payment_options` | Auth | read:booking | Opsi kanal pembayaran untuk booking |
| `get_payment_invoice` | Auth | read:booking | Invoice JSON untuk satu pembayaran booking |

### Trust

| Tool | Tier | Scope | Deskripsi (ID) |
|------|------|-------|----------------|
| `get_trust_profile` | Publik | — | Profil trust: tanpa userId = milik sendiri; dengan userId = publik |
| `get_verification_status` | Auth | — | Status verifikasi user dan dokumen yang dibutuhkan |
| `upload_document` | Auth | write:booking | Upload dokumen verifikasi (base64): KTP, SELFIE, SIM, dll. |
| `assess_risk` | Auth | — | Preview penilaian risiko dan deposit sebelum booking |
| `verify_phone_otp` | Auth | — | Kirim atau verifikasi OTP nomor telepon |

### Reviews

| Tool | Tier | Scope | Deskripsi (ID) |
|------|------|-------|----------------|
| `list_reviews` | Auth | read:booking | Daftar review untuk booking + apakah user bisa review |
| `submit_review` | Auth | write:booking | Kirim review setelah sewa selesai |

### Notifications

| Tool | Tier | Scope | Deskripsi (ID) |
|------|------|-------|----------------|
| `list_notifications` | Auth | — | Daftar notifikasi in-app user |
| `mark_notification_read` | Auth | — | Tandai satu atau semua notifikasi sudah dibaca |
| `manage_push_subscription` | Auth | — | Get, subscribe, atau unsubscribe push web/expo |

### UCP

| Tool | Tier | Scope | Deskripsi (ID) |
|------|------|-------|----------------|
| `ucp_discover` | Publik | — | Ambil manifest merchant UCP dari /.well-known/ucp |
| `ucp_products` | Publik | — | Discovery produk UCP (search atau feed) |
| `ucp_product` | Publik | — | Lookup satu produk UCP berdasarkan slug |
| `ucp_availability` | Publik | — | Ketersediaan produk UCP untuk rentang tanggal |
| `ucp_quote` | Publik | — | Quote harga UCP (productId = assetId); opsional kupon |
| `ucp_checkout` | Auth | read:booking, write:booking, write:payment | Alur checkout UCP: create session, status, atau complete |
| `ucp_checkout_create` | Auth | write:booking | Buat sesi checkout UCP (booking) |
| `ucp_checkout_status` | Auth | read:booking | Status sesi checkout + fulfillment + gate verifikasi |
| `ucp_checkout_complete` | Auth | write:booking, write:payment | Selesaikan checkout (promote atau initiate_payment) |
| `ucp_webhook_register` | Auth | write:booking | Daftar webhook callback status order UCP |
| `list_ucp_webhooks` | Auth | write:booking | Daftar webhook UCP terdaftar |

### Account

| Tool | Tier | Scope | Deskripsi (ID) |
|------|------|-------|----------------|
| `get_profile` | Auth | — | Profil user terautentikasi |
| `update_profile` | Auth | — | Update profil (nama, locale, avatar, alamat, dll.) |
| `change_password` | Auth | — | Ganti password; JWT only |
| `get_account_credit` | Auth | — | Saldo kredit akun dan ledger terbaru |

### Chat

| Tool | Tier | Scope | Deskripsi (ID) |
|------|------|-------|----------------|
| `manage_asset_inquiry` | Publik | — | List atau kirim pesan inquiry pra-booking (guest atau login) |
| `manage_booking_chat` | Auth | read:booking, write:booking | List atau kirim pesan chat booking |
| `list_conversations` | Auth | — | Daftar percakapan booking + inquiry |
| `manage_inquiry_thread` | Auth | — | List atau kirim pesan di thread inquiry; auth atau guestToken |

### Webhooks

| Tool | Tier | Scope | Deskripsi (ID) |
|------|------|-------|----------------|
| `manage_agent_webhooks` | Auth | — | List atau daftar webhook partner agent; register butuh JWT |

### Platform

| Tool | Tier | Scope | Deskripsi (ID) |
|------|------|-------|----------------|
| `health_check` | Publik | — | Health check platform; opsional deep=true untuk probe DB/Redis |


#### Examples — registration, profile, payment, chat

**register_account → login (new penyewa):**

```json
// 1. Public — no Authorization header
{"name":"register_account","arguments":{"email":"budi@example.com","password":"SecurePass123","name":"Budi Santoso","phone":"081234567890","locale":"id"}}
// Response: { user: { id, email, role: "CUSTOMER" } } — no tokens

// 2. Obtain tokens — Method A (recommended)
{"name":"create_login_link","arguments":{"clientLabel":"My Agent"}}
// → user opens verificationUrl → poll get_login_status

// 3. Or Method B
{"name":"login","arguments":{"email":"budi@example.com","password":"SecurePass123"}}
```

**get_payment_options** (before initiate_payment):

```json
{"name":"get_payment_options","arguments":{"bookingId":"clx_booking_id"}}
```

**update_profile:**

```json
{"name":"update_profile","arguments":{"name":"Budi Santoso","preferredLocale":"id","city":"Jakarta Selatan","preferWhatsapp":true}}
```

**list_conversations:**

```json
{"name":"list_conversations","arguments":{}}
```

#### Commonly used parameters

| Tool | REST | Example arguments |
|------|------|-------------------|
| `search_assets` | `GET /assets` | `{"q":"avanza","limit":5}` |
| `check_availability` | `GET /assets/{slug}/availability` | `{"slug":"mobil-avanza-jakarta","from":"2026-09-01","to":"2026-09-07"}` |
| `pricing_quote` | `POST /pricing/quote` | `{"assetId":"…","startDate":"2026-09-01","endDate":"2026-09-07"}` |
| `create_booking` | `POST /bookings` | `assetId`, `rentalMode`, `startDate`, `endDate`, `usageLocation`, `usagePurpose`, `idempotencyKey?` |
| `initiate_payment` | `POST /bookings/{id}/pay` | `bookingId`, `chargeType?`, `idempotencyKey?` |

Tool results are JSON text in MCP `content[0].text`. Errors return `isError: true` with message text.

### 6. Agent booking flow (6 steps)

**Critical:** Search ≠ availability. Always verify dates before booking.

1. **Discover** — `search_assets` or `catalog_feed` (no date guarantee)
2. **Availability** — `check_availability` per candidate slug
3. **Quote** — `pricing_quote` with confirmed dates
4. **Create plan** — `create_booking` → `PENDING_VERIFICATION`
5. **Verify & promote** — `upload_document`, `get_verification_status`, re-check availability, `promote_booking`
6. **Pay (human-in-the-loop)** — `booking_readiness` → `initiate_payment` → **human completes Midtrans** → poll `get_pay_status`

Use `booking_readiness` between steps for `nextActions[]` and `blockers[]`.

### 7. Payment (human-in-the-loop)

Midtrans checkout **cannot** be automated in production.

1. `initiate_payment` → response includes `redirectUrl`, `orderId`
2. **Stop** — send `redirectUrl` to the human user
3. Poll `get_pay_status` every 5–10 s (max ~15 min); do not exceed 1 req/sec
4. Confirm via `get_booking_detail` → `status: CONFIRMED`

**Sandbox only** (`NODE_ENV !== production` OR `AGENT_SANDBOX=true`): REST `POST /bookings/{id}/pay/mock-settle` — not exposed as MCP tool.

### 8. Rate limits

| Namespace | Limit | Applies to |
|-----------|-------|------------|
| `auth:login` | 5 / 15 min per IP | `login` tool |
| `mcp:well-known` | 60 / min | `GET /.well-known/mcp` (returns `X-RateLimit-*` headers) |
| `mcp:public:{tool}` | 60 / min | Each public tool |
| `mcp:auth:{tool}` | 120 / min | Each auth tool (per user when authenticated) |
| `booking:create` | 20 / hour | `create_booking` (REST-level) |

Discovery manifests (`/.well-known/mcp`, `/.well-known/mcp-owner`) include `X-RateLimit-Limit`, `X-RateLimit-Remaining`, and `X-RateLimit-Reset` on success responses.

On `429`, backoff using `Retry-After` header. MCP returns `isError: true` with `"Rate limit exceeded"`.

### 9. Idempotency

Pass `idempotencyKey` (UUID) in tool arguments for:

- `create_booking`
- `promote_booking`
- `cancel_booking`
- `initiate_payment`
- `apply_credit`
- `ucp_checkout` (create/complete)

Duplicate key + same user → identical JSON response replayed (hosted MCP caches in Redis; REST uses header `Idempotency-Replayed: true`).

Local stdio: set `SEWAPEDIA_IDEMPOTENCY_KEY` env for default.

**Smoke test:** `./scripts/test-mcp-production.sh http://localhost:3000` (or production URL).

### 10. Error handling

| HTTP / MCP | Meaning | Agent action |
|------------|---------|--------------|
| `401` / "Unauthorized" | Missing or expired token | Use `create_login_link` (Method A) or `login` (Method B); then Bearer or API key |
| `403` / "Scope … required" | API key missing scope | Ask user to recreate key |
| `403` / "CUSTOMER role" | Wrong role | Use consumer account |
| `404` | Asset/booking not found | Verify IDs/slugs |
| `429` | Rate limited | Exponential backoff |
| `isError: true` | Business/validation error | Surface message to user; do not blind-retry `400`-class errors |

Never log or expose JWT, API keys, or Midtrans `snapToken` in public channels.

### 11. External agent configuration

#### Hermes / Cursor / Claude Desktop (hosted)

```json
{
  "mcpServers": {
    "sewapedia": {
      "url": "https://sewapedia.id/api/v1/mcp",
      "transport": "streamable-http",
      "headers": {
        "Authorization": "Bearer YOUR_ACCESS_TOKEN"
      }
    }
  }
}
```

Use `login` tool first if no token; omit `Authorization` for public-only workflows.

#### API key instead of JWT

```json
{
  "mcpServers": {
    "sewapedia": {
      "url": "https://sewapedia.id/api/v1/mcp",
      "headers": {
        "X-Api-Key": "sp_live_YOUR_KEY"
      }
    }
  }
}
```

#### Local stdio (development)

Repo-root [`.mcp.json`](../.mcp.json):

```json
{
  "mcpServers": {
    "sewapedia": {
      "command": "npm",
      "args": ["run", "mcp:sewapedia"]
    }
  }
}
```

### 12. Troubleshooting

| Symptom | Likely cause | Fix |
|---------|--------------|-----|
| `tools/list` returns tools but call fails | Missing auth on auth tool | `create_login_link` (Method A) or `login` (Method B); then Bearer / `X-Api-Key` |
| `Scope 'write:booking' required` | API key too narrow | Add scope at `/akun/pengaturan/api-keys` |
| `Agent write tools require CUSTOMER role` | Vendor/admin account | Use renter (CUSTOMER) account |
| `Asset not found` on availability | Wrong slug | Use slug from `search_assets` / `get_asset_detail` |
| Dates available but booking blocked | Stale availability | Re-run `check_availability` before `promote_booking` |
| Payment stuck | Human did not complete Midtrans | Resend `redirectUrl`; poll `get_pay_status` |
| `Rate limit exceeded` on login | Brute-force protection | Wait 15 min; do not retry rapidly |
| Empty search results | Query too narrow | Broaden `q` or use `catalog_feed` |
| CORS errors from browser | Client-side fetch | Use server-side MCP client or stdio wrapper |
| OAuth discovery 501 | Not implemented | Use JWT login or API keys — see [`API_AGENT_GUIDE.md`](API_AGENT_GUIDE.md) |

**Verify deployment:**

```bash
curl -s https://sewapedia.id/.well-known/mcp | jq '.publicTools | length'   # expect 24
curl -s https://sewapedia.id/.well-known/mcp | jq '.authTools | length'    # expect 45
```

---

## Bahasa Indonesia

### 1. Mulai cepat

Sewapedia menyediakan **69 tool MCP** (24 publik, 45 butuh autentikasi) via **Streamable HTTP**. Semua tool memanggil REST `/api/v1/*` yang sama — tanpa duplikasi logika bisnis.

```bash
# Manifest (tanpa auth)
curl -s https://sewapedia.id/.well-known/mcp | jq .

# Daftar tool
curl -s -X POST https://sewapedia.id/api/v1/mcp \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'
```

### 2. Titik masuk untuk agen

| Prioritas | Resource | Fungsi |
|-----------|----------|--------|
| 1 | `/llms.txt` | Ringkasan platform, alur 6 langkah |
| 2 | `/.well-known/mcp` | Manifest MCP + daftar tool |
| 3 | `/mcp-agent-guide.md` | Panduan lengkap (dokumen ini) |
| 4 | `/{locale}/developers` | Halaman developer (id, en, ms, zh) |

### 3. Autentikasi & login

**Metode A (disarankan):** `create_login_link` → user buka `verificationUrl` di browser → polling `get_login_status` → simpan `apiKey.secret` (tanpa password di agent).

**Metode B (langsung):** User berikan email/password ke agent → agent panggil `login` → `accessToken` → `Authorization: Bearer` pada request berikutnya.

Alternatif: API key scoped (`sp_live_…`) via header `X-Api-Key` atau Bearer. Hanya role **CUSTOMER** yang boleh memakai tool transaksi.

**Scope API key:** `read:catalog`, `read:booking`, `write:booking`, `write:payment`.

### 4. Tier publik vs autentikasi

- **Publik (24):** discovery, auth (register/login/device), UCP discover/quote, chat inquiry, platform health.
- **Autentikasi (45):** booking, pembayaran, trust, ulasan, notifikasi, akun, chat, UCP checkout, webhooks.

Daftar lengkap per kategori: [`docs/MCP_FEATURE_LIST.md`](MCP_FEATURE_LIST.md) §1.

### 5. Referensi tool (69 tool)

Tabel lengkap semua tool (nama, tier, scope, deskripsi ID) ada di **English §5** di atas. Ringkasan kategori: [`docs/MCP_FEATURE_LIST.md`](MCP_FEATURE_LIST.md) §1.

#### Contoh tool baru

**register_account → login (penyewa baru):** panggil `register_account` (publik) → lalu `create_login_link` (Metode A) atau `login` (Metode B) untuk token.

**get_payment_options:** `{"bookingId":"clx_…"}` — cek kanal pembayaran sebelum `initiate_payment`.

**update_profile:** `{"name":"Budi","preferredLocale":"id","city":"Jakarta Selatan"}`.

**list_conversations:** `{}` — daftar percakapan booking + inquiry.

### 6. Alur booking agen

**Penting:** Pencarian ≠ ketersediaan tanggal.

1. `search_assets` / `catalog_feed`
2. `check_availability` per slug
3. `pricing_quote`
4. `create_booking`
5. `upload_document` + `promote_booking`
6. `initiate_payment` → **user menyelesaikan Midtrans** → `get_pay_status`

Gunakan `booking_readiness` untuk `nextActions` dan `blockers`.

### 7. Pembayaran (human-in-the-loop)

Agent **tidak boleh** mengotomatisasi checkout Midtrans di produksi. Kirim `redirectUrl` ke user, lalu polling `get_pay_status` setiap 5–10 detik.

### 8. Rate limit & idempotency

- Login: 5 req / 15 menit per IP.
- Tool publik: 60/menit; tool auth: 120/menit.
- Gunakan `idempotencyKey` (UUID) pada `create_booking`, `promote_booking`, `cancel_booking`, `initiate_payment`.

### 9. Konfigurasi agen eksternal (Hermes)

```json
{
  "mcpServers": {
    "sewapedia": {
      "url": "https://sewapedia.id/api/v1/mcp",
      "transport": "streamable-http",
      "headers": {
        "Authorization": "Bearer ACCESS_TOKEN_ANDA"
      }
    }
  }
}
```

### 10. Troubleshooting

| Gejala | Penyebab | Solusi |
|--------|----------|--------|
| 401 Unauthorized | Token habis/kosong | `create_login_link` (Metode A) atau `login` (Metode B) |
| 403 Scope required | API key kurang scope | Tambah scope di pengaturan akun |
| Asset not found | Slug salah | Ambil slug dari hasil pencarian |
| Rate limit | Terlalu banyak request | Tunggu; hormati `Retry-After` |

Daftar tool lengkap (nama, scope, deskripsi): [`docs/MCP_FEATURE_LIST.md`](MCP_FEATURE_LIST.md) §1. Contoh parameter umum di **English §5** di atas.

---

*Versi dokumen: 1.4.0 — sinkron dengan `src/lib/mcp/tools.ts` (69 consumer) + `owner-tools.ts` (62 owner) = 131 tools. Regenerate tables: `npx tsx docs/generate-mcp-feature-list.ts`.*
