Skip to main content
Glama
@proof-holdings/mcp-server

@proof-holdings/mcp-server

Official

start_2fa

Starts a two-factor authentication challenge for sensitive operations, sending a verification code via the selected channel and returning a session ID to poll for verification status.

Instructions

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.

The user does not see tool results — most clients fold them away, render_auth_link's output included. Before you wait or poll, put what the user must act on into your own reply text: the link itself (not a sentence announcing it), the SMS text and number, or a note to check their inbox.

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

NameRequiredDescriptionDefault
channelYesChannel to receive the verification code
targetsNoThe ids the step-up is FOR — the grant is bound to exactly these and refused for any other request (`reason: target_mismatch`). revocation_bulk: the asset id you will pass to revoke_asset (one code per asset); phone_remove / email_remove: the phone or email record id; domain_remove: the domain id; profile_delete: the sub-account id; account_delete: your own user id (get_current_user). Leave out for the other action types.
email_idNoSpecific email ID for email channel (optional)
phone_idNoOptional: specific UserPhone id for phone-channel 2FA
single_useNoWhether the grant is consumed on first use. Server forces true for destructive action types. Defaults to true.
action_typeYesThe sensitive action requiring 2FA: any action type the API documents
ttl_secondsNoRequested grant lifetime in seconds. Server caps to 300s for destructive action types, 86400s for configuration scopes. Defaults to 300 if omitted.

Output Schema

NameRequiredDescriptionDefault
emailNoThe address the code went to, masked (`email` only)
statusNo
channelNo
messageNo
qr_codeNoBase64-encoded PNG QR code for `deep_link`
qr_textNoUTF-8 text QR for `deep_link`, for terminal/agent rendering
sms_codeNoThe short code the person texts (`sms` only)
sms_didsNoOur SMS numbers, one entry per region and always all three. A region with no number configured carries an empty `did` and no QR code.
deep_linkNoOpens Telegram or WhatsApp with what the person sends (`telegram`, `whatsapp`)
email_sentNo`true` when the code was emailed (`email` only)
expires_atNo
session_idNo
sms_messageNoThe message to send (`sms` only)
instructionsNoOne line telling the person what to do
available_emailsNoThe addresses the code may go to; call again with one of their ids as `email_id`
requires_email_selectionNoAlways `true`: no session was started, pick an address and start again
second_method_recommendedNoPresent (true) when the step-up uses the channel the account signed in with, because the account has no other; adding a second channel is recommended

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed8 schema fields changedv1.7.2
    • removedInput schema / additionalProperties
      Removed value: -false
    • changedInput schema / properties / action_type / description
      Previous value: -"The sensitive action requiring 2FA"New value: +"The sensitive action requiring 2FA: any action type the API documents"
    • changedInput schema / properties / action_type / enum
      Previous value: -[
      -  "api_key_view",
      -  "api_key_create",
      -  "api_key_revoke",
      -  "api_key_regenerate",
      -  "phone_add",
      -  "phone_remove",
      -  "email_add",
      -  "email_remove",
      -  "account_delete",
      -  "revocation_bulk",
      -  "domain_remove",
      -  "profile_delete",
      -  "phone_primary",
      -  "email_primary"
      -]New value: +[
      +  "api_key_view",
      +  "api_key_create",
      +  "api_key_revoke",
      +  "api_key_regenerate",
      +  "phone_add",
      +  "phone_remove",
      +  "phone_primary",
      +  "email_add",
      +  "email_remove",
      +  "email_primary",
      +  "account_delete",
      +  "master_key_change",
      +  "hitl_key_rotate",
      +  "revocation_bulk",
      +  "settings_write",
      +  "profile_update",
      +  "templates_write",
      +  "webhook_write",
      +  "delegation_lifecycle",
      +  "company_update",
      +  "domain_remove",
      +  "profile_delete",
      +  "account_delete_cancel",
      +  "plan_change",
      +  "auto_top_up_change"
      +]
    • addedInput schema / properties / phone_id
      Added value: +{
      +  "description": "Optional: specific UserPhone id for phone-channel 2FA",
      +  "type": "string"
      +}
    • addedInput schema / properties / single_use
      Added value: +{
      +  "description": "Whether the grant is consumed on first use. Server forces true for destructive action types. Defaults to true.",
      +  "type": "boolean"
      +}
    • changedInput schema / properties / targets / description
      Previous value: -"The ids the step-up is FOR — the grant is bound to exactly these and refused for any other request (`reason: target_mismatch`). revocation_bulk: the asset id you will pass to revoke_asset (one code per asset); phone_remove / email_remove: the phone or email record id; domain_remove: the domain id; profile_delete: the project id; account_delete: your own user id (get_current_user). Leave out for the other action types."New value: +"The ids the step-up is FOR — the grant is bound to exactly these and refused for any other request (`reason: target_mismatch`). revocation_bulk: the asset id you will pass to revoke_asset (one code per asset); phone_remove / email_remove: the phone or email record id; domain_remove: the domain id; profile_delete: the sub-account id; account_delete: your own user id (get_current_user). Leave out for the other action types."
    • addedInput schema / properties / ttl_seconds
      Added value: +{
      +  "description": "Requested grant lifetime in seconds. Server caps to 300s for destructive action types, 86400s for configuration scopes. Defaults to 300 if omitted.",
      +  "maximum": 86400,
      +  "minimum": 60,
      +  "type": "integer"
      +}
    • changedOutput schema / (root)
      Previous value: -nullNew value: +{
      +  "$schema": "http://json-schema.org/draft-07/schema#",
      +  "additionalProperties": {},
      +  "properties": {
      +    "available_emails": {
      +      "description": "The addresses the code may go to; call again with one of their ids as `email_id`"
      +    },
      +    "channel": {},
      +    "deep_link": {
      +      "description": "Opens Telegram or WhatsApp with what the person sends (`telegram`, `whatsapp`)"
      +    },
      +    "email": {
      +      "description": "The address the code went to, masked (`email` only)"
      +    },
      +    "email_sent": {
      +      "description": "`true` when the code was emailed (`email` only)"
      +    },
      +    "expires_at": {},
      +    "instructions": {
      +      "description": "One line telling the person what to do"
      +    },
      +    "message": {},
      +    "qr_code": {
      +      "description": "Base64-encoded PNG QR code for `deep_link`"
      +    },
      +    "qr_text": {
      +      "description": "UTF-8 text QR for `deep_link`, for terminal/agent rendering"
      +    },
      +    "requires_email_selection": {
      +      "description": "Always `true`: no session was started, pick an address and start again"
      +    },
      +    "second_method_recommended": {
      +      "description": "Present (true) when the step-up uses the channel the account signed in with, because the account has no other; adding a second channel is recommended"
      +    },
      +    "session_id": {},
      +    "sms_code": {
      +      "description": "The short code the person texts (`sms` only)"
      +    },
      +    "sms_dids": {
      +      "description": "Our SMS numbers, one entry per region and always all three. A region with no number configured carries an empty `did` and no QR code."
      +    },
      +    "sms_message": {
      +      "description": "The message to send (`sms` only)"
      +    },
      +    "status": {}
      +  },
      +  "type": "object"
      +}
  2. Changed2 schema fields changedv1.6.0
    • changedInput schema / properties / action_type / enum
      Previous value: -[
      -  "api_key_view",
      -  "api_key_create",
      -  "api_key_revoke",
      -  "api_key_regenerate",
      -  "phone_add",
      -  "phone_remove",
      -  "email_add",
      -  "email_remove",
      -  "account_delete"
      -]New value: +[
      +  "api_key_view",
      +  "api_key_create",
      +  "api_key_revoke",
      +  "api_key_regenerate",
      +  "phone_add",
      +  "phone_remove",
      +  "email_add",
      +  "email_remove",
      +  "account_delete",
      +  "revocation_bulk",
      +  "domain_remove",
      +  "profile_delete",
      +  "phone_primary",
      +  "email_primary"
      +]
    • addedInput schema / properties / targets
      Added value: +{
      +  "description": "The ids the step-up is FOR — the grant is bound to exactly these and refused for any other request (`reason: target_mismatch`). revocation_bulk: the asset id you will pass to revoke_asset (one code per asset); phone_remove / email_remove: the phone or email record id; domain_remove: the domain id; profile_delete: the project id; account_delete: your own user id (get_current_user). Leave out for the other action types.",
      +  "items": {
      +    "maxLength": 256,
      +    "minLength": 1,
      +    "type": "string"
      +  },
      +  "maxItems": 25,
      +  "minItems": 1,
      +  "type": "array"
      +}
  3. First observedv1.1.0

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With annotations only declaring non-read-only/non-destructive, the description supplies substantive behavior: dispatch only on email, user-sent messages on other channels, requires_email_selection meaning no session, polling until verified/expired, and user-visible output handling. This is well beyond annotation-level detail.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with purpose and then uses numbered steps and channel-specific notes; the structure is strong. It is long, but most of the length corresponds to genuine multi-channel flow complexity and edge cases.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a complex multi-step 2FA starter with an output schema, the description covers initiation, channel dispatch, polling handoff, expiration, access prerequisites, and user-facing caveats. Nothing essential to correct invocation appears missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the schema already documents action_type, targets, single_use, ttl_seconds, and optional IDs. The description adds operational context for channel/email_id and the email-selection retry, but it does not add meaning for the remaining parameters; baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The first sentence states a specific verb ('Start') and resource ('two-factor authentication challenge') and scope ('sensitive operation'). It also separates this tool's role from get_2fa_status by explicitly placing polling in step 3, so an agent can distinguish start from status-check.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides a numbered full flow from start through polling and post-verification action, plus channel-specific handling for telegram/whatsapp/sms/email and the email-selection edge case. It names alternatives like get_2fa_status and render_auth_link, though it does not discuss start_2fa_for_action.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Deploy Server

Other Tools