igun997

paper-invoice-mcp

Community igun997
Updated

Paper.id MCP

paper-invoice-mcp

MCP (Model Context Protocol) server for Paper.id — Indonesian invoicing & accounting platform.

Exposes 31 tools covering partner CRUD, invoice CRUD, send invoice, QRIS payment, and reporting. Token is persisted in SQLite and auto-refreshed on 401 — no manual token management needed.

Quick Setup

Option A — JWT token only

Best for quick testing or CI. No password stored — just paste your token.

1. Get your token from Chrome DevTools:

  • Open app.paper.id → DevTools (F12) → Network tab
  • Click any request to api.paper.id → Headers → Request Headers
  • Copy the value after Authorization: Bearer (the eyJ... part)

2. Get your Company ID and User ID:

  • Same DevTools window → Response tab of any request
  • Look for body.user.uuid (User ID) and body.user.company_id (Company ID)
  • Or: set PAPERID_TOKEN first, then call tool paperid_get_current_user — it returns both

3. Add to your MCP client config:

Claude Desktop (~/Library/Application Support/Claude/claude_desktop_config.json)

{
  "mcpServers": {
    "paperid": {
      "command": "node",
      "args": ["/absolute/path/to/paper-invoice-mcp/dist/index.js"],
      "env": {
        "PAPERID_TOKEN":      "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.your.token",
        "PAPERID_COMPANY_ID": "37e0eae0-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
        "PAPERID_USER_ID":    "3f5a9896-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
      }
    }
  }
}

Cursor (.cursor/mcp.json or ~/.cursor/mcp.json)

{
  "mcpServers": {
    "paperid": {
      "command": "node",
      "args": ["/absolute/path/to/paper-invoice-mcp/dist/index.js"],
      "env": {
        "PAPERID_TOKEN":      "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.your.token",
        "PAPERID_COMPANY_ID": "37e0eae0-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
        "PAPERID_USER_ID":    "3f5a9896-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
      }
    }
  }
}

VS Code (.vscode/mcp.json)

{
  "servers": {
    "paperid": {
      "type": "stdio",
      "command": "node",
      "args": ["/absolute/path/to/paper-invoice-mcp/dist/index.js"],
      "env": {
        "PAPERID_TOKEN":      "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.your.token",
        "PAPERID_COMPANY_ID": "37e0eae0-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
        "PAPERID_USER_ID":    "3f5a9896-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
      }
    }
  }
}

JWT expires in ~30 days. When it does, copy a fresh token from DevTools and update the config. Full step-by-step with troubleshooting: examples/jwt-only.md

Option B — Phone + Password (auto-refresh)

Best for long-running assistants. Token saved to SQLite, silently refreshed on 401.

Claude Desktop / Cursor / VS Code:

{
  "mcpServers": {
    "paperid": {
      "command": "node",
      "args": ["/absolute/path/to/paper-invoice-mcp/dist/index.js"],
      "env": {
        "PAPERID_PHONE":    "08xxxxxxxxxx",
        "PAPERID_PASSWORD": "your_password_here"
      }
    }
  }
}

First run — call paperid_login (or paperid_refresh_token) once to store the JWT in SQLite. After that, the server handles everything automatically.

Token persisted at ~/.paperid-mcp/tokens.db. Override path with PAPERID_DB_PATH.

Features

  • Partner management — create, read, list, search, update, delete
  • Invoice management — create, read, list, send (WA/email/SMS), generate QRIS, delete
  • Notes & Termsnotes (Keterangan) and terms (Syarat & Ketentuan) support plain text or HTML
  • Token persistence — JWT stored in SQLite (~/.paperid-mcp/tokens.db)
  • Auto token refresh — re-logins on 401 when PAPERID_PHONE + PAPERID_PASSWORD are set
  • Reporting — account receivable/payable insights, profit & loss

Requirements

  • Node.js ≥ 18 (uses built-in FormData)
  • Bun (recommended) or npm

Installation

git clone [email protected]:igun997/paper-invoice-mcp.git
cd paper-invoice-mcp
bun install
bun run build

Configuration

Create a .env file (or set environment variables):

# Required for auto token refresh
PAPERID_PHONE=08xxxxxxxxxx
PAPERID_PASSWORD=your_password_here

# Optional overrides (loaded from SQLite if omitted)
PAPERID_TOKEN=            # JWT token (leave blank to use SQLite)
PAPERID_COMPANY_ID=       # Company UUID
PAPERID_USER_ID=          # User UUID

# Optional: custom SQLite path (default: ~/.paperid-mcp/tokens.db)
PAPERID_DB_PATH=/path/to/tokens.db

Security: Never commit .env to version control. The .gitignore excludes it.

Token Lifecycle

First run: PAPERID_PHONE + PAPERID_PASSWORD set
    → paperid_login  (or paperid_refresh_token tool)
    → JWT saved to SQLite

Subsequent runs:
    → JWT loaded from SQLite automatically
    → On 401: re-login silently, retry request

Manual refresh:
    → Call paperid_refresh_token tool
    → Or: set PAPERID_TOKEN env var for one-time use

MCP Client Configuration

Claude Desktop (claude_desktop_config.json)

{
  "mcpServers": {
    "paperid": {
      "command": "node",
      "args": ["/absolute/path/to/paper-invoice-mcp/dist/index.js"],
      "env": {
        "PAPERID_PHONE": "08xxxxxxxxxx",
        "PAPERID_PASSWORD": "your_password_here"
      }
    }
  }
}

Cursor / VS Code (.cursor/mcp.json or .vscode/mcp.json)

{
  "mcpServers": {
    "paperid": {
      "command": "node",
      "args": ["/absolute/path/to/paper-invoice-mcp/dist/index.js"],
      "env": {
        "PAPERID_PHONE": "08xxxxxxxxxx",
        "PAPERID_PASSWORD": "your_password_here"
      }
    }
  }
}

Using Bun directly

{
  "mcpServers": {
    "paperid": {
      "command": "bun",
      "args": ["run", "/absolute/path/to/paper-invoice-mcp/src/index.ts"],
      "env": {
        "PAPERID_PHONE": "08xxxxxxxxxx",
        "PAPERID_PASSWORD": "your_password_here"
      }
    }
  }
}

Available Tools (31 total)

Auth & Token

Tool Description
paperid_login Login with phone + password
paperid_refresh_token Re-login and update SQLite token
paperid_get_token_info Check token expiry (does not expose raw JWT)
paperid_get_current_user Get authenticated user info

Partners

Tool Description
paperid_get_partners List partners with pagination
paperid_search_partners Search partners by name
paperid_get_partner Get partner by UUID
paperid_create_partner Create new partner
paperid_update_partner Update existing partner
paperid_delete_partner Delete partner
paperid_get_partner_contacts Get partner contacts
paperid_get_partner_bank_accounts Get partner bank accounts
paperid_get_next_partner_number Get next auto-generated partner number

Invoices

Tool Description
paperid_get_sales_invoices List invoices with filters + pagination
paperid_create_invoice Create invoice (supports notes + terms)
paperid_get_invoice Get invoice by UUID
paperid_get_invoice_pdf Get invoice PDF data
paperid_send_invoice Send via WhatsApp / Email / SMS
paperid_generate_invoice_qris Generate QRIS payment QR code
paperid_delete_invoice Delete invoice

Reporting

Tool Description
paperid_get_account_receivable AR insight (unpaid, overdue)
paperid_get_account_payable AP insight
paperid_get_profit_loss Profit & Loss report
paperid_get_company Company details
paperid_get_kyc_status KYC verification status
paperid_get_user_package Subscription package info
paperid_get_onboarding_status Onboarding completion
paperid_get_referral_link Referral code & link
paperid_get_notifications User notifications
paperid_get_dashboard_todos Dashboard to-do list
paperid_get_banners Promotional banners

Usage Examples

Create Invoice with Notes & Terms

{
  "tool": "paperid_create_invoice",
  "arguments": {
    "partner_id": "uuid-of-partner",
    "partner_name": "PT Mitra Sejati",
    "number": "INV/2026/0012",
    "invoice_date": "2026-05-14",
    "due_date": "2026-06-13",
    "items": [
      {
        "item_name": "Jasa Konsultasi",
        "item_description": "Konsultasi IT bulan Mei 2026",
        "quantity": 1,
        "price": 5000000
      }
    ],
    "notes": "Transfer ke BCA 1234567890 a/n PT Cipta Dua Saudara",
    "terms": "Pembayaran jatuh tempo 30 hari. Keterlambatan dikenakan denda 2%/bulan.",
    "status": 4
  }
}

notes and terms accept plain text (auto-wrapped in <p> tags) or raw HTML.

Send Invoice via WhatsApp

{
  "tool": "paperid_send_invoice",
  "arguments": {
    "invoiceId": "uuid-of-invoice",
    "whatsapp": { "number": "6281234567890" }
  }
}

Refresh Token

{
  "tool": "paperid_refresh_token",
  "arguments": {}
}

Returns expiry info. Raw JWT is never returned by any tool.

MCP Resources

The server exposes 6 resources AI clients can read for accurate tool usage:

URI Description
paperid://docs/overview Overview, tool groups, typical workflow
paperid://docs/auth Login flow, SQLite persistence, auto-refresh
paperid://docs/jwt-only JWT-only setup, config examples, expiry handling
paperid://docs/partners Partner schema, field types, phone format, base paths
paperid://docs/invoices Invoice schema, line items, notes/terms, status codes
paperid://docs/api-reference All 31 HTTP endpoints with methods and paths

Project Structure

paper-invoice-mcp/
├── src/
│   ├── index.ts              # Entrypoint — connects MCP server to stdio
│   ├── server-factory.ts     # createMcpServer() — all tools, handlers, resources
│   ├── client.ts             # Paper.id API client (axios)
│   └── token-store.ts        # SQLite token persistence (better-sqlite3)
├── examples/
│   └── jwt-only.md           # JWT-only setup guide (step-by-step + all client configs)
├── .github/
│   └── workflows/ci.yml      # CI: build+resources (all PRs), e2e (merge to master)
├── dist/                     # Compiled JS (gitignored)
├── .env.example              # Sample env vars (no real credentials)
├── tsconfig.json
└── package.json

Development

bun run build     # Compile TypeScript → dist/
bun run dev       # Run with tsx (no compile step)

SQLite Schema

CREATE TABLE tokens (
  phone       TEXT PRIMARY KEY,
  token       TEXT NOT NULL,
  user_id     TEXT NOT NULL,
  company_id  TEXT NOT NULL,
  expires_at  INTEGER NOT NULL,  -- Unix timestamp
  created_at  INTEGER NOT NULL,
  updated_at  INTEGER NOT NULL
);

Token auto-refreshes when expired (with 5-minute buffer) if credentials are in env.

License

MIT

MCP Server · Populars

MCP Server · New