MCP server for FunPay.com. Bun + @modelcontextprotocol/sdk. Lets Claude Code (or any MCP client) read, create, update, and clone FunPay lots using a seller's golden_key cookie.
Companion to gitlab-mcp — same shape, same ergonomics.
- Auth via
golden_keycookie. PHPSESSID + CSRF persisted in-memory across calls (FunPay rotates sessions on every cookie-less hit — jar is required). - Profile storage in the OS keychain via
Bun.secrets(macOS Keychain / Linux libsecret / Windows Credential Manager). Falls back to config file if keychain is unavailable. - Multi-profile support + env-var override.
- Read any lot you own.
- Inspect a subcategory's form schema (select options like
fields[type],fields[time],fields[method]) before posting — so the POST won't fail on an unknown value. - Create, update, and batch-clone lots across multiple subcategories in one call.
git clone https://github.com/DKeken/funpay-mcp.git
cd funpay-mcp
bun installBun ≥ 1.3 required (uses Bun.secrets + Bun.file + native Response.headers.getSetCookie()).
Edit ~/.claude.json:
{
"mcpServers": {
"funpay": {
"type": "stdio",
"command": "bun",
"args": ["run", "/absolute/path/to/funpay-mcp/index.ts"],
"env": {}
}
}
}Restart the client. Then save your key — it goes straight to the OS keychain:
set_golden_key name="default" goldenKey="<paste golden_key>" makeActive=true
whoami
Expected whoami:
Profile: default
User ID: 258369
Locale: ru
CSRF: ...
golden_key: hnik***wzjg
FUNPAY_GOLDEN_KEY=... FUNPAY_PROFILE=ci bun run index.tsFUNPAY_GOLDEN_KEY always overrides saved profiles.
- Sign in at
https://funpay.com/. - DevTools → Application → Cookies →
funpay.com. - Copy
golden_keyvalue.
Expires on logout or when FunPay invalidates sessions. Re-run set_golden_key when it stops working.
| Tool | Purpose |
|---|---|
set_golden_key |
Save/update a profile. Secret goes to OS keychain. |
list_profiles |
List saved profiles — masked keys, storage backend, active flag. |
use_profile |
Switch active profile. |
delete_profile |
Remove a profile + its keychain entry. |
whoami |
Verify key, return user ID / CSRF. |
get_lot |
Compact view of a lot's offerEdit form. |
get_lot_raw |
Full JSON dump (higher token cost). |
get_node_schema |
List select-field options for a subcategory. Call before create_lot in game-ish nodes. |
create_lot |
POST /lots/offerSave — new offer in a node. |
update_lot |
Edit an existing offer (price, stock, text, images, flags). |
clone_lot |
Copy one source lot into N target nodes with per-target overrides. |
clone_lot sourceOfferId=68907961 copyImages=true copySecrets=false targets='[
{"nodeId": 4187},
{"nodeId": 3734, "fields": {"fields[type]": "Pro"}},
{"nodeId": 3735, "fields": {"fields[type]": "Pro", "fields[time]": "1 месяц", "fields[method]": "Без захода на аккаунт"}},
{"nodeId": 3736}
]'
copySecrets=false by default — auto-delivery secrets don't get duplicated unless you opt in.
- Restricted subcategories. Some nodes (e.g.
3173"Подписка Claude") require a video interview with FunPay support before you can post. Server surfaces this asAccess denied. Resolve viasupport.funpay.com, then retry. - CSRF is per-form. FunPay rotates
csrf_token+form_created_aton everyofferEditfetch. Server grabs a fresh pair percreate_lot/update_lot— don't cache them. - Two CSRF tokens.
csrf_tokenin the POST body comes from the form;x-csrf-tokenheader comes from the homepagedata-app-data(csrf-tokenkey). Both are sent on every save. Mixing them up →"Обновите страницу и повторите попытку." - Cookie jar is mandatory. FunPay hands out a new
PHPSESSIDevery time you arrive without one. Server keeps a per-profile in-memory jar and feedsSet-Cookieback in. If you integrate manually, do the same. - Field-name brackets. Field keys like
fields[summary][ru]contain literal[and]. Pass them verbatim in thefieldsobject.
~/.config/funpay-mcp-server/config.json:
{
"activeProfile": "default",
"profiles": [
{ "name": "default", "userAgent": "..." }
]
}Secrets are not stored here when Bun.secrets is available. Legacy configs with inline goldenKey still work; re-saving the profile migrates the secret into the keychain and wipes the inline copy.
Bun.secrets— OS credential storage.Bun.file/Bun.write— config I/O.- Native
fetch+response.headers.getSetCookie()— cookie jar withouttough-cookie.
MIT.