MCPSafe.io
RegistryThreatsMethodologyDocsPricingScanSign in
⌘K
  • Getting Started
  • Quickstart

API Reference

  • Overview
  • POST /scan
  • GET /scan/:id
  • Private scans
  • Team & billing

Integrations

  • GitHub Actions
  • Cursor
  • Claude Code

Concepts

  • AIVSS Scoring
  • Findings
  • Severity Levels
  • CLI
  • Troubleshooting
  • FAQ
⌘K
MCPSafe.io

Security checks for MCP servers — public packages and private repos, fast or deep.

Legal

Privacy PolicyCookie PolicyTerms of ServiceSecurity disclosure

Resources

State of MCP SecuritySupportSystem statusMade in Germany 🇩🇪

© 2026 MCPSafe. All rights reserved.

GDPR — Privacy Policy

Team & billing

Endpoints for managing teams, members, invites, billing, and Stripe-portal sessions. Authenticated with a NextAuth session JWT.

These endpoints back the team-management UI in the dashboard. They authenticate with a NextAuth session JWT, not an API key — they're intended for the web app and for tools that drive a logged-in user session (e.g. Playwright integration tests against your own account).

Authentication

curl https://api.mcpsafe.io/team \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."

The token is the NextAuth session JWT issued at sign-in (HS256, signed with the frontend's AUTH_SECRET). API keys are not currently honoured on these routes; if you have a use case for programmatic team management via API key, open an issue.

Team

MethodPathDescription
GET/teamRead the caller's team (members, pending invites, plan, seat counts)
POST/teamCreate a team (caller becomes owner)
PATCH/teamRename or transfer ownership (owner only)
POST/team/inviteInvite a member by email
GET/team/invite-previewRead the invite as the recipient (called from the accept link)
POST/team/invite/acceptAccept an invite (must match the JWT email)
DELETE/team/invites/{email}Revoke a pending invite (owner / admin)
DELETE/team/members/{user_id}Remove a member; passing the caller's own user_id is "leave team"
GET/team/usagePer-member scan usage for the current calendar month (owner only)

Create a team

curl -X POST https://api.mcpsafe.io/team \
  -H "Authorization: Bearer ${SESSION_JWT}" \
  -H "Content-Type: application/json" \
  -d '{"name": "Acme Security"}'

Invite a member

curl -X POST https://api.mcpsafe.io/team/invite \
  -H "Authorization: Bearer ${SESSION_JWT}" \
  -H "Content-Type: application/json" \
  -d '{"email": "alice@acme.com", "role": "member"}'

role is member or admin. Invites are email-bound — the accepting user's JWT email must match the invite address (case-insensitive). Mismatched accepts return 403 EMAIL_MISMATCH so a forwarded invite link can't be redeemed by a different account.

Invite creation is rate-limited per team: 20 / hour and 100 / day across all owners and admins.

Accept an invite

curl -X POST https://api.mcpsafe.io/team/invite/accept \
  -H "Authorization: Bearer ${SESSION_JWT}" \
  -H "Content-Type: application/json" \
  -d '{"invite_token": "tok_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}'

Revoke or remove

# Pending invite — keyed by email (TEAM-19)
curl -X DELETE "https://api.mcpsafe.io/team/invites/alice@acme.com" \
  -H "Authorization: Bearer ${SESSION_JWT}"
 
# Existing member — owner-only; pass own user_id to leave the team
curl -X DELETE "https://api.mcpsafe.io/team/members/usr_xxxxxxxxxxxxxxxx" \
  -H "Authorization: Bearer ${SESSION_JWT}"

The owner cannot be removed by anyone (including themselves); transfer ownership via PATCH /team first.

Transfer ownership

curl -X PATCH https://api.mcpsafe.io/team \
  -H "Authorization: Bearer ${SESSION_JWT}" \
  -H "Content-Type: application/json" \
  -d '{"new_owner_user_id": "usr_xxxxxxxxxxxxxxxx"}'

The new owner must already be a team member. Self-transfer (passing your own user_id) returns 400 INVALID_FIELD.

Shared private scans

Members of a Team or Business plan see all private scans submitted by other members of the same org. This is intentional — it prevents owners from inviting strangers to anonymously consume the team's private-scan quota. Implementation:

  • Every private-scan row stamps both user_id (who ran the scan) and org_id (whose plan paid).
  • GET /user/scans and the SSE progress stream resolve the caller's org_id and route to the org-shared GSI.
  • Suspended orgs preserve read access to past private scans; new submissions return 402 SUBSCRIPTION_REQUIRED.

Per-member usage

curl https://api.mcpsafe.io/team/usage \
  -H "Authorization: Bearer ${SESSION_JWT}"

Owner-only. Returns the current calendar month's scan totals broken down per member:

{
  "period_start": "2026-05-01T00:00:00Z",
  "period_end":   "2026-05-31T23:59:59Z",
  "org": { "org_id": "org_xxx", "name": "Acme Security", "tier": "business" },
  "totals": { "scans_used": 412, "members_count": 8 },
  "members": [
    { "user_id": "usr_…", "email": "alice@acme.com", "role": "owner",  "scans_used": 187, "last_scan_at": "2026-05-06T11:21Z" },
    { "user_id": "usr_…", "email": "bob@acme.com",   "role": "admin",  "scans_used":  93, "last_scan_at": "2026-05-05T14:02Z" }
  ]
}

Billing

MethodPathDescription
POST/checkout/sessionStart a Stripe Checkout session for a paid plan
POST/billing/portalOpen a Stripe Customer Portal session (manage card, cancel)
POST/billing/upgradeSwitch plan immediately with proration
POST/billing/cancelCancel at period end
POST/billing/reactivateUndo a pending cancellation
GET/billing/invoicesList past invoices
GET/subscriptionRead current plan, renewal date, and entitlement features
GET/meRead the caller's profile (email, user_id, tier, org_id if any)
PUT/meUpdate caller's profile (display name, notification settings)

Start a checkout session

curl -X POST https://api.mcpsafe.io/checkout/session \
  -H "Authorization: Bearer ${SESSION_JWT}" \
  -H "Content-Type: application/json" \
  -d '{"tier": "team", "billing_cycle": "annual"}'

tier is dev / team / business. billing_cycle is monthly or annual. Optional promo_code and referral_code fields work like the dashboard form. Response: { checkout_url: "https://checkout.stripe.com/…" }.

Open the customer portal

curl -X POST https://api.mcpsafe.io/billing/portal \
  -H "Authorization: Bearer ${SESSION_JWT}"

Returns a single-use Stripe Customer Portal URL. From there the user can update payment method, download invoices, cancel, or change plan.

Error codes

CodeHTTPMeaning
EMAIL_MISMATCH403Accepting user's JWT email doesn't match the invite
ALREADY_IN_TEAM409Email is already a member
INVITE_ALREADY_PENDING409Email already has an open invite
CANNOT_REMOVE_OWNER403Removal target is the team owner
OWNER_CANNOT_LEAVE409Owner attempted to remove themselves; transfer first
NOT_A_MEMBER404Removal target is not in the team
INVALID_FIELD400Self-transfer of ownership, or other body validation failure
RETRY503Concurrent write conflict; retry from a fresh GET /team
←PreviousPrivate scansNextGitHub Actions→