@imazhar101/paypal-mcp
# @imazhar101/paypal-mcp
A lite [Model Context Protocol](https://modelcontextprotocol.io) server for PayPal.
Unlike PayPal's official `@paypal/mcp` (which pulls in the entire LangChain / Vercel-AI agent-toolkit and expects a pre-minted, short-lived access token), this server is intentionally small:
- **No heavy dependencies** — just `@modelcontextprotocol/sdk` + `zod`. Calls the PayPal REST API directly with `fetch`.
- **Owns its token lifecycle** — you give it a durable **client id + secret**; it mints, caches, and refreshes the `client_credentials` access token itself. Proactive refresh (expiry skew) + reactive refresh (re-mint + retry once on a 401). A long-lived host (e.g. an MCP gateway) can spawn one child per merchant with only the static client-id/secret in its env and never babysit token expiry.
- **Read-only by default** — this server handles money. Write/refund/payout tools are not registered unless you opt in with `PAYPAL_READONLY=0`.
## Install
```bash
npm install -g @imazhar101/paypal-mcp
```
## Configure
| Env var | Required | Default | Notes |
| ---------------------- | -------- | --------- | ---------------------------------------- |
| `PAYPAL_CLIENT_ID` | yes | — | PayPal REST app client id |
| `PAYPAL_CLIENT_SECRET` | yes | — | PayPal REST app secret |
| `PAYPAL_ENVIRONMENT` | no | `SANDBOX` | `SANDBOX` or `PRODUCTION` |
| `PAYPAL_READONLY` | no | `1` | `1`/`true` = read tools only; `0` = also write tools |
Create a REST app and obtain credentials at the [PayPal Developer Dashboard](https://developer.paypal.com/dashboard/applications). The app must have the relevant **features enabled** (Invoicing, Transaction Search, etc.) or those tools will return `403 NOT_AUTHORIZED`.
## Run (stdio)
```bash
PAYPAL_CLIENT_ID=... PAYPAL_CLIENT_SECRET=... PAYPAL_ENVIRONMENT=SANDBOX paypal-mcp
```
### Claude Code / MCP client config
```json
{
"mcpServers": {
"paypal": {
"command": "npx",
"args": ["-y", "@imazhar101/paypal-mcp"],
"env": {
"PAYPAL_CLIENT_ID": "...",
"PAYPAL_CLIENT_SECRET": "...",
"PAYPAL_ENVIRONMENT": "SANDBOX"
}
}
}
}
```
## Tools
Read-only (always registered):
| Tool | PayPal API |
| -------------------------- | ----------------------------------------- |
| `paypal_verify_connection` | mints a token; reports environment |
| `paypal_list_transactions` | `GET /v1/reporting/transactions` |
| `paypal_get_balances` | `GET /v1/reporting/balances` |
| `paypal_list_invoices` | `GET /v2/invoicing/invoices` |
| `paypal_get_invoice` | `GET /v2/invoicing/invoices/{id}` |
| `paypal_get_order` | `GET /v2/checkout/orders/{id}` |
| `paypal_get_capture` | `GET /v2/payments/captures/{id}` |
| `paypal_list_disputes` | `GET /v1/customer/disputes` |
| `paypal_get_dispute` | `GET /v1/customer/disputes/{id}` |
| `paypal_list_plans` | `GET /v1/billing/plans` |
| `paypal_get_subscription` | `GET /v1/billing/subscriptions/{id}` |
Write tools (create/send invoice, refund, …) are a deliberate follow-up gated behind `PAYPAL_READONLY=0`.
## License
MIT
TDQS
Scored across 11 tools
Each tool targets a distinct resource or action (e.g., get_ vs list_), and all resource types are clearly separated (balances, captures, disputes, invoices, orders, subscriptions, plans, transactions). No two tools have overlapping purposes.
All tools follow a consistent 'paypal_verb_noun' pattern in snake_case, with clear verbs like get, list, and verify. No mixing of conventions or vague verbs.
With 11 tools, the server covers a reasonable breadth of PayPal operations without being excessive. Each tool addresses a clear use case, and the count feels appropriate for a focused integration.
The server is entirely read-only except for credentials verification. Missing create, update, or delete operations for any resource (e.g., orders, invoices, disputes) severely limits its utility for typical payment workflows.