Upmind Mcp Server — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited Upmind Mcp Server (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Model Context Protocol server for the Upmind platform: bundled API documentation search plus 97 live admin tools covering the daily operations of a hosting business — tickets, billing, services, clients, orders, provisioning, promotions, security, and reporting.
Built for and verified against a production Upmind organisation.
upmind-mcp token set imports a fresh token straight from your clipboardUPMIND_READ_ONLY=true) blocks every write toolfull: true for raw records)npm run update-docs pulls the latest reference from apidocs.upmind.com (1,270+ endpoints incl. the web hosting module)claude mcp add --transport stdio --scope user upmind -- npx -y github:spidyhost-crm/upmind-mcp-servernpx fetches and builds the server automatically; your config and tokens live in ~/.upmind-mcp/ + the Keychain, so updates never touch them.
git clone [email protected]:spidyhost-crm/upmind-mcp-server.git && cd upmind-mcp-server
npm install && npm run build
claude mcp add --transport stdio --scope user upmind -- node $(pwd)/dist/index.jsYour admin token controls the whole business — treat it accordingly. Two modes:
Nothing long-lived is ever stored. Session tokens expire after ~1 hour.
api.upmind.io request → copy the Bearer tokennpx upmind-mcp token set — reads the clipboard, validates against the live API, stores in the macOS KeychainWhen it expires, tools return a clear error telling you to repeat step 2–3.
upmind-mcp login (email + password + 2FA) stores a session and refresh token in the Keychain; the server renews access tokens itself and rotates the stored pair. Revoke anytime by logging that session out in Upmind or upmind-mcp token clear.
upmind-mcp token set|show|clear manage the stored token (Keychain-backed)
upmind-mcp login full login with auto-renewal
upmind-mcp whoami verify credentials against the live API
upmind-mcp status show config, backend, token expiryUPMIND_TOKEN_BACKEND=file falls back to ~/.upmind-mcp/tokens.json chmod 600list/add/remove_whitelisted_ip tools to restrict org admin access to known IPs — a leaked token becomes useless elsewhere. Add your current IP first!UPMIND_READ_ONLY=true hard-blocks all 48 write tools server-sidedestructiveHint so MCP clients can require confirmation.env, .tokens.json are gitignored; the CLI clipboard flow avoids bothConfig is layered: real env vars → project .env → ~/.upmind-mcp/config.env.
| Env | Effect |
|---|---|
UPMIND_ORIGIN | Your admin URL (e.g. https://secure.spidyhost.com) — required for OAuth flows |
UPMIND_API_BASE | Default https://api.upmind.io/api/admin |
UPMIND_READ_ONLY=true | Every write tool refuses to run |
UPMIND_DEFAULT_BRAND_ID | Applied when tools accept brand_id and none is given |
UPMIND_TOOLSETS=tickets,billing | Expose only selected toolsets (docs always on) |
UPMIND_TOKEN_BACKEND | keychain / file (default auto) |
UPMIND_API_TOKEN / UPMIND_REFRESH_TOKEN / UPMIND_USERNAME+UPMIND_PASSWORD | Env-based auth alternatives to the CLI |
UPMIND_TIMEOUT_MS / UPMIND_MAX_RETRIES / UPMIND_DEBUG | Client tuning |
docs — search_endpoints, get_endpoint_details, list_api_groups, get_group_endpoints
brands — list_brands, get_brand
catalog — list_categories, create_category, list_products, get_product, create_product, update_product, duplicate_product, copy_product_to_brand, reorder_products, list_pricelists, get_product_prices, sync_pricing, list_currencies, get_upgrade_paths, set_upgrade_paths, remove_upgrade_path
provisioning — list_provision_fields, get_provision_field_values, update_provision_field_values, list_provision_configs, list_provision_functions
contracts (services) — list_contracts, get_contract, count_active_services, cancel_contract, cancel_contract_product, activate_contract_product, set_contract_product_renewal, update_contract_product_dates, update_contract_product_price, change_contract_product (upgrades, with dry_run), trigger_provision
clients — list_clients, get_client, create_client, update_client, list_client_accounts, reset_client_password, resend_client_verification
orders — list_orders, get_order, create_order (quick order → invoice), cancel_order, convert_order_to_invoice
billing — list_invoices, get_invoice, credit_invoice, apply_client_credit, refund_invoice, create_renewal_invoice, refresh_invoice, list_payments, add_payment, refund_payment, list_gateways, get_wallet_balance, list_wallet_transactions, refund_from_wallet
tickets — list_tickets, get_ticket, get_ticket_messages, create_ticket, reply_ticket (incl. private staff notes), update_ticket, assign_ticket, list_ticket_departments
marketing — list_promotions, get_promotion, create_promotion, update_promotion, disable_promotion, list_leads, create_lead, update_lead, convert_lead_to_client
emails — list_email_history, get_email, resend_email
webhooks — list_webhooks, list_webhook_events, create_webhook, update_webhook, delete_webhook
users — list_users, get_user
reports — get_stats, list_reports, run_report
security — list_whitelisted_ips, add_whitelisted_ip, remove_whitelisted_ip
Verified against production:
https://api.upmind.io/api/admin/...; doc URLs starting admin/ map to the same path with the prefix stripped.limit/offset; responses carry total. The client's getAll() auto-paginates (capped at 1,000 items).filter[field]=value, e.g. filter[status.code], filter[product.id], filter[contract.client_id]. ⚠️ filter[status]=... on invoices causes a 500 database error — always filter status via status.code.contract_active, contract_suspended, invoice_unpaid, invoice_paid, ticket_in_progress, ticket_waiting_response (short forms like unpaid also match).with=a,b,c; raw list rows only carry *_id fields (e.g. tickets have status_id but no status object without with=status).POST https://api.upmind.io/oauth/access_token with admin_password / admin_twofa / refresh_token grants; the Origin header of your admin domain is required when no oauth client id is sent. Access tokens live ~1 hour; refresh tokens rotate on every use.sent, bounced, error_message) but not rendered bodies.src/
├── index.ts # stdio server entry (existing MCP registrations)
├── cli.ts # upmind-mcp CLI: token/login/whoami/status + serve
├── serve.ts # shared server bootstrap
├── server.ts # assembles McpServer from the tool registry
├── registry.ts # ToolDef type + shared schema fragments
├── config.ts # layered env/.env/~/.upmind-mcp config
├── api/
│ ├── client.ts # HTTP client: retries, timeouts, error shaping
│ ├── auth.ts # TokenManager: OAuth renewal, expiry handling
│ └── token-store.ts # Keychain (macOS) / file token storage
├── docs/ # documentation cache, search, and doc tools
├── tools/ # one file per domain, exporting ToolDef[]
└── utils/compact.ts # response summarisation helpers
scripts/
├── update-docs.mjs # refresh bundled docs (npm run update-docs)
└── smoke.mjs # read-only live smoke test (npm run smoke)
data/ # bundled apidoc JSON (refreshable)Adding a tool = adding one entry to a domain file. server.ts handles registration, read-only enforcement, annotations, and error shaping centrally.
npm run build # compile
npm run typecheck # type check only
npm run smoke # read-only smoke test against the live API
npm run update-docs # refresh bundled API docsMIT
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.