Skip to content
verify mcp Beta VerifyMCP is currently in beta. If you notice any issues, get in touch and we’ll put it right.

Proof Holdings

NPM · @PROOF-HOLDINGS/MCP-SERVER · 2 COMPONENTS · SCANNED SEP 25

One API, all things verified — control, delegation, human approval, anti-impersonation.

+4 this week 73 Trust /100
Trust breakdown (7 categories)

How this component scores in each security and reliability category. Every signal is checked automatically from public evidence about the published package, including repeated runs of it in an isolated sandbox, and we only credit what we can confirm. How we score → Why this is hard to score →

Supply Chain Security98
  • No malware found by supply-chain analysis.Pass
  • No known CVEs affecting this package version or its production dependencies.Pass
  • No install/post-install scripts declared.Pass
  • 42 of 126 dependencies flagged as unhealthy. View diagnostics → Partial
Provenance & Transparency45
Schema Quality & AI Usability74
  • AI-judged instruction clarity (excellent).Pass
  • Context-footprint check failed: tool/resource definitions use about 22726 tokens (~129/item across 176 items; 176 tools + 0 resources), over budget; trim descriptions and params. See how to fix → Fail
  • Usage-examples check failed: none of the tools include examples. See how to fix → Fail
Stability & Change Management53
  • Stability observed for 16 of 30 days with no destabilising changes; credit accrues until the full window elapses.Partial
Tool Coverage100
  • 100% of tools have a non-trivial description (not blank, and not just the tool's name).Pass
  • 100% of tool parameters carry a description.Pass
Tool Safety25
  • Injection-marker check failed: the description of tool "send_account_email" contains an instruction to conceal the call from the user, the text "Do not tell the user", at byte 959 of that field. See how to fix → Fail
  • 0 of 21 tool(s) whose name or description implies an irreversible operation declare an MCP destructiveHint annotation; "revoke_proof" implies "revoke" and declares no destructiveHint at all, which the MCP spec reads as destructive by default. See how to fix → Fail
  • An AI judge read all 177 captured unit(s) of tool text and found none that tries to manipulate the model reading it.Pass
Capabilities100
  • Implements a supported MCP spec version (2025-11-25); the latest is 2026-07-28.Pass
Install

How do I install the Proof Holdings MCP server?

Proof Holdings runs locally as an npm package, launched with npx -y @proof-holdings/mcp-server. Ready-made configuration for Claude, Cursor, VS Code, Codex and 5 more is on this page, copied from each client's own documentation.

npm · @proof-holdings/mcp-server

# add to Claude Code
claude mcp add holdings-proof-mcp-server -- npx -y @proof-holdings/mcp-server
// .cursor/mcp.json
{
  "mcpServers": {
    "holdings-proof-mcp-server": {
      "command": "npx",
      "args": [
        "-y",
        "@proof-holdings/mcp-server"
      ]
    }
  }
}
// .vscode/mcp.json
{
  "servers": {
    "holdings-proof-mcp-server": {
      "command": "npx",
      "args": [
        "-y",
        "@proof-holdings/mcp-server"
      ]
    }
  }
}
# add to Codex CLI
codex mcp add holdings-proof-mcp-server -- npx -y @proof-holdings/mcp-server
// opencode.json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "holdings-proof-mcp-server": {
      "type": "local",
      "command": [
        "npx",
        "-y",
        "@proof-holdings/mcp-server"
      ],
      "enabled": true
    }
  }
}
# add to OpenClaw
openclaw mcp add holdings-proof-mcp-server --command npx --arg -y --arg @proof-holdings/mcp-server
# ~/.hermes/config.yaml
mcp_servers:
  holdings-proof-mcp-server:
    command: "npx"
    args: ["-y", "@proof-holdings/mcp-server"]
// ~/.netclaw/config/netclaw.json
{
  "McpServers": {
    "holdings-proof-mcp-server": {
      "Transport": "stdio",
      "Command": "npx",
      "Arguments": [
        "-y",
        "@proof-holdings/mcp-server"
      ]
    }
  }
}
# add to Vellum
assistant mcp add holdings-proof-mcp-server -t stdio -c npx -a -y @proof-holdings/mcp-server
// mcp.json
{
  "mcpServers": {
    "holdings-proof-mcp-server": {
      "command": "npx",
      "args": [
        "-y",
        "@proof-holdings/mcp-server"
      ]
    }
  }
}
Changelog

Every change we have recorded for this component, newest first. Security-relevant changes are always shown. ▲ marks a change for the better, ▼ a change for the worse; unmarked changes are neutral.

  • 25 Sept 26 +1
    • We updated how we score, so this day's move reflects our rubric, not a change to the server See what changed → functional
  • 23 Sept 26 +1

    No change was recorded against any check on this day. Stability & Change Management went from 43 to 47. That category is still filling its 30-day observation window: 13 days of observed history at the previous scan, 14 at this one. The score rises as the window fills, whether or not the server changes.

  • 21 Sept 26 +1

    No change was recorded against any check on this day. Stability & Change Management went from 37 to 40. That category is still filling its 30-day observation window: 11 days of observed history at the previous scan, 12 at this one. The score rises as the window fills, whether or not the server changes.

  • 19 Sept 26 +1

    No change was recorded against any check on this day. Stability & Change Management went from 30 to 33. That category is still filling its 30-day observation window: 9 days of observed history at the previous scan, 10 at this one. The score rises as the window fills, whether or not the server changes.

  • 17 Sept 26 +4
    • Stability: unverified → 0.27 ▲ functional
  • 9 Sept 26 65

    First indexed and scored.

Diagnostics

Diagnostic detail from the automated scan of this channel: what the scanner observed at each step, so you can see exactly where a check passed or failed. It is informational only and never changes the trust score.

Captured 25 Sept 2026 · Analysed npm/@proof-holdings/mcp-server@1.1.0

Provenance No attestation

The registry publishes no build provenance for this version, so there is nothing to verify.

Result No attestation
Ecosystem npm

Background: How many MCP packages publish verified provenance →

Dependencies 126 packages
Packages resolved 126
Stale 42
Tree resolution Complete

Background: SBOMs and build attestations, explained →

MCP tools · 176 exposed · ~22,440 tokens

The tools this component advertises to a client, with an estimated token cost for each. Expand a tool to see its parameters and schema. The per-tool counts are indicative and are not scored directly; the schema's total context footprint is one signal in Schema Quality & AI Usability. A tool's description is untrusted text the model reads on every call, which is what makes this list a security surface and not just an inventory: how tool poisoning works →

Tool Tokens
list_phones ~55

List all phone numbers associated with the authenticated account. ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.

Input schema present but exposes no named parameters.

No output schema declared.

No examples provided.

list_profile_templates ~70

List all templates for a profile. Returns templates organized by channel and message type, merged with defaults. ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.

NameTypeReqDescription
profile_idstringyesProfile ID

No output schema declared.

No examples provided.

list_profiles ~55

List all profiles for the authenticated account. Returns all profiles including primary and secondary. ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.

Input schema present but exposes no named parameters.

No output schema declared.

No examples provided.

list_revoked_proofs ~38

Get the revocation list for offline proof validation. Returns a signed list of all revoked proof IDs, cacheable for 5 minutes.

Input schema present but exposes no named parameters.

No output schema declared.

No examples provided.

list_templates ~58

List all custom message templates for the authenticated account. Returns templates organized by channel and message type. ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.

Input schema present but exposes no named parameters.

No output schema declared.

No examples provided.

list_verification_requests ~117

List verification requests with optional filters. Returns paginated results. ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.

NameTypeReqDescription
limitinteger–Items per page
pageinteger–Page number
reference_idstring–Filter by reference ID
statusstring–Filter by status. 'active' = live (not-yet-expired) pending or partial requests; persisted statuses are time-aware.

No output schema declared.

No examples provided.

list_verifications ~105

List verifications with optional filters. Returns paginated results. ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.

NameTypeReqDescription
channelstring–Filter by channel
external_user_idstring–Filter by external user ID
limitinteger–Items per page
pageinteger–Page number
statusstring–Filter by status

No output schema declared.

No examples provided.

list_verified_users ~75

List verified users grouped by external_user_id. Shows all verifications per user. ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.

NameTypeReqDescription
limitinteger–Items per page
pageinteger–Page number

No output schema declared.

No examples provided.

list_webhook_deliveries ~110

List webhook delivery attempts with pagination and filtering. Shows delivery status, response codes, and timestamps. ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.

NameTypeReqDescription
event_typestring–Filter by event type (e.g. verification.completed)
limitinteger–Items per page
pageinteger–Page number
statusstring–Filter by delivery status

No output schema declared.

No examples provided.

poll_chat_id_discovery ~84

Poll a chat ID discovery token. Returns the discovered Telegram chat ID, user ID, and username once the user interacts with the bot. ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.

NameTypeReqDescription
tokenstringyesDiscovery token from create_chat_id_discovery

No output schema declared.

No examples provided.

preview_profile_template ~133

Preview a profile template with sample data before saving. Shows how the message will look with placeholder variables filled in. ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.

NameTypeReqDescription
bodystringyesTemplate body text
button_textstring–Button text
button_url_templatestring–Button URL template
channelstringyesMessage channel
message_typestringyesMessage type
profile_idstringyesProfile ID
subjectstring–Email subject line

No output schema declared.

No examples provided.

preview_template ~121

Preview a template with sample data before saving. Shows how the message will look with placeholder variables filled in. ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.

NameTypeReqDescription
bodystringyesTemplate body text
button_textstring–Button text
button_url_templatestring–Button URL template
channelstringyesMessage channel
message_typestringyesMessage type
subjectstring–Email subject line

No output schema declared.

No examples provided.

regenerate_api_key ~175

Regenerate an API key, issuing a new secret while keeping the same ID and settings. The old key stops working immediately. The new secret is returned ONLY in this response. Note: the secret will be visible in the AI conversation context. Agent usage: This operation requires 2FA. Before calling, complete the 2FA flow: (1) call start_2fa with action_type "api_key_regenerate", (2) wait for user to verify the code, (3) poll get_2fa_status until "verified", (4) then call regenerate_api_key. ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.

NameTypeReqDescription
idstringyesAPI key ID to regenerate

No output schema declared.

No examples provided.

remove_challenger ~88

Remove a Proof-Me challenger from a HITL config. Removing the last challenger disables Proof-Me on the config. ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.

NameTypeReqDescription
challenger_idstringyesChallenger ID to remove
hitl_idstringyesHITL config ID

No output schema declared.

No examples provided.

remove_circle_member ~85

Remove a member from a Circle. Deletes the member's channels and revokes any live authorizations that routed through them. ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.

NameTypeReqDescription
idstringyesCircle ID
member_idstringyesMember ID to remove

No output schema declared.

No examples provided.

remove_circle_member_channel ~93

Remove a channel from a Circle member. Removing the last channel is allowed (the member simply becomes unreachable). ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.

NameTypeReqDescription
channel_idstringyesChannel ID to remove
idstringyesCircle ID
member_idstringyesMember ID

No output schema declared.

No examples provided.

remove_email ~74

Remove an email address from the account by ID. May require 2FA verification for sensitive operations. ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.

NameTypeReqDescription
idstringyesEmail record ID

No output schema declared.

No examples provided.

remove_phone ~74

Remove a phone number from the account by ID. May require 2FA verification for sensitive operations. ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.

NameTypeReqDescription
idstringyesPhone record ID

No output schema declared.

No examples provided.

render_auth_link ~278

Render an authorization or verification URL as a clickable link followed by a scannable QR code inside a fenced code block. This is a local computation tool — no HTTP request is made. Agent usage: pass a LINK field from an earlier response — `deep_link` (create_session, create_chat_id_discovery always; start_login, create_account, start_2fa, start_2fa_for_action on telegram/whatsapp ONLY, where on sms and email that field is empty or absent altogether and this tool rejects it either way), `challenge.deep_link` (create_verification, messenger channels only), or `telegram_deep_link` / `whatsapp_deep_link`. Do NOT pass `qr_text` to this tool: that field is a QR code already rendered as text, and this tool takes a link. When a response gives you `qr_text` and no link, print it verbatim inside a fenced code block instead — its rows only scan while they stay adjacent, so a blank line or wrapped row destroys the code.

NameTypeReqDescription
labelstring–Optional label to display above the link (e.g. "Verify your phone number")
urlstringyesThe link to render — e.g. a deep_link response field. Never a qr_text value: that is the link already rendered as QR art.

No output schema declared.

No examples provided.

render_template ~85

Render a template with provided variables. Returns the fully rendered message content. ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.

NameTypeReqDescription
channelstringyesMessage channel
message_typestringyesMessage type
variablesobject–Variables to substitute into the template

No output schema declared.

No examples provided.

request_hitl_authorization ~313

Request authorization for a HITL config. Sends consent requests to all configured channels (Telegram/WhatsApp). Users must approve before confirmations can be sent. Agent usage: This must be completed before create_confirmation will work for this HITL config. The consent request is DELIVERED to each channel — the response carries no link to show. It returns `authorizations` — one entry per resolved recipient, each with its `channel`, `recipient`, `authorization_id` and `status` — plus a `message`. Read the entries rather than assuming: `status: 'pending'` means consent was just sent and the user must approve in Telegram/WhatsApp itself, while `status: 'active'` means that recipient had already authorized and nothing was sent to them. An EMPTY array does not mean everyone is authorized — it means no recipient could be resolved at all (usually a HITL config bound to a missing or inactive circle, or channels whose recipient is blank), so nobody was asked and waiting for an approval would hang forever. Do not relay `message` on that branch: it reads 'All channels already have active or pending authorizations', which is exactly the wrong conclusion. Read the array. After requesting, you can proceed once the user confirms they have approved. ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.

NameTypeReqDescription
idstringyesHITL config ID to request authorization for

No output schema declared.

No examples provided.

resend_domain_email ~84

Resend the domain verification email. Rate limited to 3 requests per minute. ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.

NameTypeReqDescription
email_prefixstring–Email prefix to resend verification to
idstringyesDomain ID

No output schema declared.

No examples provided.

resend_email_otp ~70

Resend the OTP code for an in-progress email addition. ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.

NameTypeReqDescription
session_idstringyesAdd-email session ID

No output schema declared.

No examples provided.

resend_verification ~66

Resend a verification message (email channel only). Generates and sends a new code. ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.

NameTypeReqDescription
idstringyesVerification ID

No output schema declared.

No examples provided.

retry_webhook_delivery ~74

Retry a failed webhook delivery. Creates a new delivery attempt with the same payload to the configured endpoint. ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.

NameTypeReqDescription
idstringyesWebhook delivery ID to retry

No output schema declared.

No examples provided.

revoke_api_key ~148

Revoke an API key by ID. The key will immediately stop working. This action cannot be undone. Agent usage: This operation requires 2FA. Before calling, complete the 2FA flow: (1) call start_2fa with action_type "api_key_revoke", (2) wait for user to verify the code, (3) poll get_2fa_status until "verified", (4) then call revoke_api_key. ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.

NameTypeReqDescription
idstringyesAPI key ID to revoke

No output schema declared.

No examples provided.

revoke_asset ~71

Revoke a verified asset by ID. The asset will be marked as revoked and associated proofs will no longer validate. ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.

NameTypeReqDescription
idstringyesAsset ID

No output schema declared.

No examples provided.

revoke_auth_session ~84

Revoke a specific authentication session by ID. When called via JWT, cannot revoke the current session. When called via API key, any session can be revoked. ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.

NameTypeReqDescription
session_idstringyesSession ID to revoke

No output schema declared.

No examples provided.

revoke_authorization ~86

Revoke an active or pending authorization. Only authorizations with status "active" or "pending" can be revoked. ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.

NameTypeReqDescription
idstringyesAuthorization ID to revoke
reasonstring–Reason for revocation

No output schema declared.

No examples provided.

revoke_delegation ~174

Revoke ONE delegation. The domain control proof and sibling delegations stay valid; the revocation is mirrored into the proof registry so the CRL, status list and public status lookup all see it. Idempotent: a repeat revoke answers success with the same body, both here and through revoke_proof with the ph_dlg_ handle — unlike a PROOF, where a repeat answers already_revoked. The result carries the DERIVED effective_status/is_valid beside the stored status. ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.

NameTypeReqDescription
idstringyesDelegation ID (24-hex Mongo id or ph_dlg_<32 hex> handle)
reasonstring–Reason for revocation

No output schema declared.

No examples provided.

revoke_proof ~164

Revoke a proof by its public handle (ph_ctl_* / ph_dlg_*) or a verification ID — the same addresses get_proof_status takes. The proof token will no longer validate anywhere: the status endpoint, the public validator, the revocation list and the Token Status List all report it revoked. This action is irreversible. It revokes the PROOF only — the asset, consent or delegation the proof is about is not withdrawn. ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.

NameTypeReqDescription
idstringyesPublic proof handle (ph_ctl_* / ph_dlg_*) or verification ID
reasonstring–Reason for revocation

No output schema declared.

No examples provided.

search ~160

Prefix-anchored global account search across six resource buckets (verification_requests, verifications, hitl, confirmations, authorizations, api_keys). Case-sensitive prefix match over indexed plaintext fields only; recipient identifiers are masked. Results are scoped to the authenticated account. ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.

NameTypeReqDescription
environmentstring–Scope results to test or production data (default: production)
limitinteger–Max results per bucket (default 10, max 25)
qstringyesPrefix-anchored search query (minimum 3 characters)
typestring–Narrow the search to a single result bucket

No output schema declared.

No examples provided.

send_account_email ~269

Deliver the verification email for an account-bootstrap session created with channel "email". Public endpoint (no API key required). Why this is a separate call: create_account deliberately sends NOTHING. A message from proof.holdings arriving in someone's inbox is an act with a person on the other end, so it takes an explicit second step rather than being a side effect of creating a session. ASK THE USER to confirm the address is theirs before calling this — do not call it automatically after create_account. The other channels (telegram, whatsapp, sms) never need this: the user sends the first message themselves (reverse OTP), so nothing is dispatched to them at all. One session sends at most one email, including under concurrent calls. A repeat answers 410 already_sent, which means the material backing the send is gone: usually because the email went out, occasionally because an attempt was interrupted mid-send and nothing was delivered. Do not tell the user a message was sent on the strength of a 410 — create a new session instead. (A session the recipient cancelled via the decline link, or an expired one, answers 404, not 410.) If delivery fails the response carries email_sent=false and the call can be retried.

NameTypeReqDescription
idstringyesAccount session id from create_account

No output schema declared.

No examples provided.

set_primary_email ~71

Set an email address as the primary email for the account. ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.

NameTypeReqDescription
idstringyesEmail record ID to set as primary

No output schema declared.

No examples provided.

set_primary_phone ~71

Set a phone number as the primary phone for the account. ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.

NameTypeReqDescription
idstringyesPhone record ID to set as primary

No output schema declared.

No examples provided.

set_primary_profile ~69

Set a profile as the primary profile. The previous primary profile becomes secondary. ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.

NameTypeReqDescription
profile_idstringyesProfile ID to set as primary

No output schema declared.

No examples provided.

setup_domain_email ~91

Set up email sending for a verified domain. Configures the domain for sending verification emails from a custom address. ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.

NameTypeReqDescription
from_emailstring–Custom from email address for the domain
idstringyesDomain ID

No output schema declared.

No examples provided.

share_request_email ~67

Send an email notification to the subject of a verification request. ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.

NameTypeReqDescription
idstringyesVerification request ID

No output schema declared.

No examples provided.

start_2fa ~442

Start a two-factor authentication challenge for a sensitive operation. Sends a verification code via the chosen channel. Returns a session ID, and for messaging channels: deep_link, qr_code (base64 PNG), and qr_text (UTF-8 text QR for terminal display). Agent usage — full 2FA flow: (1) Call start_2fa with the appropriate action_type and channel. (2) Present the challenge, and do NOT announce a message the server did not send: email is the ONLY channel it dispatches on. On telegram/whatsapp the user opens `deep_link` and sends the message themselves; on sms they send `sms_message` to a number from `sms_dids`; the response's own `instructions` field says which. On email, a 200 carrying `requires_email_selection: true` and `available_emails` means nothing was sent and no session exists — ask which address and call again with `email_id`. For telegram/whatsapp, pass `deep_link` to render_auth_link; for sms, show `sms_message`. Never hand `qr_text` to a link renderer — it is the link already rendered as QR art, so print it verbatim inside a fenced code block only when a real terminal needs the QR. (3) Poll get_2fa_status with the returned session_id until status is "verified" (the user enters the code on their device) or "expired". (4) If verified, proceed with the protected operation (e.g. create_api_key). If expired, inform the user and offer to restart. Typical channels: "telegram" or "email". For email, the user may receive a magic link instead of a code — the backend handles this automatically. ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.

NameTypeReqDescription
action_typestringyesThe sensitive action requiring 2FA
channelstringyesChannel to receive the verification code
email_idstring–Specific email ID for email channel (optional)

No output schema declared.

No examples provided.

start_2fa_for_action ~646

Start a 2FA challenge that grants the authenticated user permission to perform a sensitive action. The 2FA must complete on a channel DIFFERENT from the user's last login channel (the backend enforces this). On success a grant is stored keyed by the user id and action_type; middleware on the protected endpoint reads the grant and allows the mutation. Destructive action types (api_key_create, api_key_revoke, api_key_regenerate, api_key_view, account_delete, phone_remove, email_remove, revocation_bulk) are capped at 5min TTL and forced single-use by server policy. Configuration scopes (settings_write, profile_update, templates_write) allow up to 24h TTL and caller-chosen single_use — useful for agents making multiple settings mutations in one session. Agent usage: (1) Attempt the sensitive call; if you get `403 2fa_required` note the `action_type`. (2) Call start_2fa_for_action with that action_type and a channel different from the login channel. (3) Present the challenge: on telegram/whatsapp pass `deep_link` to render_auth_link; on sms show `sms_message` and the number to send it to; on email check the response first: with more than one verified email and no `email_id` given, it answers 200 with `requires_email_selection: true` and `available_emails` — NO session was started and nothing was sent, so ask the user which address and call again with `email_id` rather than telling them to open a mailbox. Never hand `qr_text` to a link renderer — it is the link already rendered as QR art. Print it verbatim inside a fenced code block only when a real terminal needs the QR. (4) Call wait_for_2fa until the session is verified. (5) Retry the original sensitive call. ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.

NameTypeReqDescription
action_typestringyesThe sensitive action the 2FA grant will authorize. Destructive scopes (api_key_*, account_delete, phone_remove, email_remove, revocation_bulk) are capped at 5 min TTL + forced single-use. Configurati…
channelstringyesChannel for the 2FA challenge — must differ from the user's last login channel
email_idstring–Optional: specific UserEmail id for email-channel 2FA
phone_idstring–Optional: specific UserPhone id for phone-channel 2FA
single_useboolean–Whether the grant is consumed on first use. Server forces true for destructive action types. Defaults to true.
ttl_secondsinteger–Requested grant lifetime in seconds. Server caps to 300s for destructive action types, 86400s for configuration scopes. Defaults to 300 if omitted.

No output schema declared.

No examples provided.

start_add_email ~79

Start adding a new email address. Sends an OTP code to the email. Returns a session ID to verify with. ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.

NameTypeReqDescription
emailstringyesEmail address to add

No output schema declared.

No examples provided.

start_add_phone ~105

Start adding a new phone number. Uses reverse OTP: the system sends a message and the user replies. Returns a session ID, deep_link, qr_code (base64 PNG), and qr_text (UTF-8 text QR for terminal display). ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.

NameTypeReqDescription
channelstringyesChannel for phone verification

No output schema declared.

No examples provided.

start_domain_email_verification ~95

Start domain verification via corporate email. Sends a verification code to a standard admin email address at the domain. ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.

NameTypeReqDescription
email_prefixstring–Email prefix to send verification to (default: admin)
idstringyesDomain ID

No output schema declared.

No examples provided.

start_domain_verification ~111

Start a B2B domain verification. Creates a verification record and returns DNS/HTTP instructions for the customer to complete. ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.

NameTypeReqDescription
customer_idstring–Customer identifier for B2B tracking
domainstringyesDomain to verify (e.g. example.com)
verification_methodstring–Verification method (default: manual_dns)

No output schema declared.

No examples provided.

start_login ~470

Start a login session by sending an authentication challenge to the user's chosen channel (Telegram, WhatsApp, SMS, or email). Returns a session ID and, FOR TELEGRAM AND WHATSAPP ONLY, deep_link, qr_code (base64 PNG) and qr_text (UTF-8 text QR for terminal display); on sms it returns sms_message with sms_dids instead, and on email nothing to display. Agent usage: (1) Call start_login with the desired channel and phone_number (for SMS) or email (for email). (2) Present the challenge, and WHICH FIELD depends on the channel. On telegram/whatsapp pass `deep_link` to render_auth_link, which prints the clickable link and a QR code; in a chat client the link is what the user acts on, since they are usually on the same machine. On sms `deep_link` is an EMPTY STRING and render_auth_link will reject it — show `sms_message` and let the user pick a number from `sms_dids`. `suggested_region` is always set, but the matching ENTRY in `sms_dids` may be missing (europe and israel appear only when a number is configured) or present with an empty `did`, so offer that region first only when `sms_dids[suggested_region]` exists and carries a number, and otherwise offer whatever the object does. On email there is no link either — check `email_sent` before telling the user to open their mail: on a delivery failure it is false and `email_error` says why, and waiting on an inbox nothing reached is the wrong next step. Never hand `qr_text` to a link renderer — it is the link already rendered as QR art, so print it verbatim inside a fenced code block or not at all, because its rows stop scanning the moment one wraps or a blank line lands between them. (3) Call wait_for_login with the returned session ID to poll until the user completes authentication. Terminal states: "verified" (login succeeded), "failed", "expired".

NameTypeReqDescription
channelstringyesAuthentication channel
emailstring–Email address (required for email channel)
phone_numberstring–Phone number in E.164 format (required for SMS channel)

No output schema declared.

No examples provided.

start_user_domain_verification ~98

Start a self-service domain verification session. The user proves ownership of a domain via DNS or HTTP challenge. ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.

NameTypeReqDescription
channelstring–Verification channel (default: dns)
domainstringyesDomain name to verify (e.g. example.com)

No output schema declared.

No examples provided.

submit_verification_code ~169

Submit an OTP/challenge code for a pending verification. Accepted ONLY where we delivered the code out-of-band to the party being verified: type "email", and type "domain" with channel "email". Any other pair answers 400 unsupported_for_type and completes elsewhere — use trigger_verification (POST /verifications/:id/verify) for a domain over dns/http/auto; a phone completes when the code reaches us FROM that number; social completes through its OAuth callback; a telegram_bot is already verified at creation. ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.

NameTypeReqDescription
codestringyesThe OTP or challenge code to submit
idstringyesVerification ID

No output schema declared.

No examples provided.

test_verify ~73

Auto-complete a verification in test mode (pk_test_* API keys only). Useful for testing flows without real OTP delivery. ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.

NameTypeReqDescription
idstringyesVerification ID

No output schema declared.

No examples provided.

trigger_drill ~103

Fire an on-demand Proof-Me drill against one enrolled challenger — a real cross-channel identity challenge carrying the scheduled-safety-check label. Complements the automated daily drill + monthly reinforcement sweeps. ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.

NameTypeReqDescription
challenger_idstringyesChallenger ID to drill
hitl_idstringyesHITL config ID

No output schema declared.

No examples provided.

trigger_verification ~62

Trigger a DNS/HTTP verification check for a pending domain verification. ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.

NameTypeReqDescription
idstringyesVerification ID

No output schema declared.

No examples provided.

Common questions

What is the Proof Holdings MCP server?

Proof Holdings is an MCP server listed in the public MCP registry as holdings.proof/mcp-server. One API, all things verified, control, delegation, human approval, anti-impersonation. This page covers its npm package (@proof-holdings/mcp-server).

Is the Proof Holdings MCP server safe to use?

Proof Holdings scores 73 out of 100 on VerifyMCP. We found no known CVEs affecting it as of 25 September 2026. It declares no install or post-install scripts. That is a record of what we were able to check automatically, not an endorsement. The category breakdown on this page shows every signal behind the number, including the ones we could not confirm.

What tools does the Proof Holdings MCP server expose?

Proof Holdings exposes 176 tools: create_verification, get_verification, list_verifications, trigger_verification, submit_verification_code, and 171 more. Their descriptions and schemas cost roughly 22,440 tokens of context every time the server is loaded.

Is the Proof Holdings MCP server still maintained?

Proof Holdings is still listed as active in the MCP registry. We last reached this channel on 25 September 2026. Those dates come from our own scans of the registry and the channel itself, not from anything the publisher announced.

What licence is the Proof Holdings MCP server under?

Proof Holdings declares the MIT licence, which is OSI-approved. That covers the source only, and says nothing about the cost of any service it calls.