About
Identity and fraud infrastructure for AI agents.
Remote endpoints: streamable-http: https://mcp.didit.me/mcp
Security Report
Valid MCP server (2 strong, 3 medium validity signals). 1 known CVE in dependencies Imported from the Official MCP Registry.
Endpoint verified · Requires authentication · 2 issues found
Security scores are indicators to help you make informed decisions, not guarantees. Always review permissions before connecting any MCP server.
Permissions Found in Source Code
Found by scanning the linked source code. This listing connects to a hosted endpoint, so none of this runs on your machine: it describes what the server software does where it is hosted.
How to Connect
Remote Plugin
No local installation needed. Your AI client connects to the remote endpoint directly.
Add this to your MCP configuration to connect:
{
"mcpServers": {
"me-didit-mcp": {
"url": "https://mcp.didit.me/mcp"
}
}
}Documentation
View on GitHubFrom the project's GitHub README.
Didit MCP Server
The official Model Context Protocol server for Didit — bring KYC, KYB, AML screening, transaction monitoring, biometrics, and full workspace operations to Claude, Cursor, VS Code, Windsurf, Zed, and any MCP client.
- 140+ tools across sessions, workflows, vendor users/businesses, transactions, networks, the standalone verification APIs, lists, cases, reports, webhooks, and billing.
- Auth is "Log in with Didit" (OAuth 2.1 + PKCE) — the MCP acts as the signed-in user with their role's permissions. There is no API-key mode: every tool calls the user-scoped console endpoints, which only accept a Bearer token.
- Tools call Didit REST endpoints. Session PDF generation returns a temporary download URL for the original PDF.
Full documentation: https://docs.didit.me/integration/mcp/overview
Session PDF downloads
didit_session_generate_pdf returns download_url, expires_at (UTC), and
expires_in (300 seconds). Fetch the URL without an Authorization header to save
the original Didit PDF. The server checks PDF access before issuing the link and
fetches the original report again at download time using the same user and organization.
It does not reconstruct the report from session data. If the session changes between
issuance and download, the download reflects the current report. Revoked or expired
user access can invalidate a link before its five-minute expiry.
Deployments must set MCP_PDF_DOWNLOAD_KEY to 32 cryptographically random bytes
encoded as 64 hexadecimal characters, shared across all replicas, and set
MCP_RESOURCE_URI to the public HTTPS MCP endpoint. Route
/downloads/session-report.pdf to this HTTP server. The authenticated-encryption
key protects the credentials embedded in the session-scoped link; rotating it
invalidates outstanding links. Treat links as secrets and redact the token query
parameter in proxy/access logs. Responses use Cache-Control: no-store.
Stdio deployments need a reachable HTTP deployment with the same key, API base URL,
and MCP_RESOURCE_URI; stdio alone cannot serve download links. Missing key
configuration produces an actionable tool error instead of inline PDF data.
Quick start
Hosted (recommended)
No install, no API key — point your client at the hosted URL and sign in via the browser:
https://mcp.didit.me/mcp
Claude Code
claude mcp add --transport http didit https://mcp.didit.me/mcp
Cursor (~/.cursor/mcp.json)
{ "mcpServers": { "didit": { "url": "https://mcp.didit.me/mcp" } } }
Windsurf / Zed (via the mcp-remote bridge)
{ "mcpServers": { "didit": { "command": "npx", "args": ["-y", "mcp-remote@latest", "https://mcp.didit.me/mcp"] } } }
See per-client setup for Claude Desktop and VS Code.
Authentication
The MCP is an OAuth 2.1 resource server; the Didit console (business.didit.me) is the authorization server. On first connect your client opens a browser, you Log in with Didit and approve the scopes, and the MCP then acts as you — across every organization you belong to, with your role's permissions. Tokens are short-lived and refreshed automatically.
Scopes: didit:management (workspace operations), didit:verification (running checks) and didit:staff (Didit staff accounts only; the authorization server never issues it to anyone else). Your console role is enforced server-side on every call.
There is no API-key mode. Every tool targets the user-scoped console endpoints (
/organization/{org}/application/{app}/…), which authorize a Bearer token with per-role privileges and rejectx-api-key. (For raw REST access with an application API key — e.g. creating sessions from your backend — use the REST API directly, not this server.)
See Authentication.
Tools
140+ tools, grouped by area. The full catalogue with read/write/destructive markers is in docs/TOOLS.md and at docs.didit.me. Highlights:
- Discovery & cross-app:
didit_context_get,didit_session_search,didit_transaction_search,didit_vendor_user_search,didit_analytics— aggregate across every org/app in one call. - Sessions: create, list, get decision, update status, reviews, bulk import, webhook delivery log + resend (
didit_session_webhookswaits for a sandbox session's webhook so an integration can be verified end to end). - Verification APIs:
didit_verify_id,didit_verify_aml,didit_verify_face_match,didit_verify_kyb_search, … - Workflows (incl. branching graphs):
didit_workflow_search,didit_workflow_get_graph,didit_workflow_edit_graph— build conditional/branching workflows (fuzzy-match conditions, Document-AI steps) by sending small ops; large feature configs are kept server-side, never resent.didit_workflow_get_id_verification_methods_cataloganddidit_workflow_get_kyb_registry_cataloganswer the server-driven questions a config write depends on (which countries offer non-doc lookup / wallets, which KYB data tiers and monitoring a country's registries sell). - Compliance: transaction monitoring, custom and preset rule management with backtesting, lists/blocklist/allowlist, cases, reports, audit logs, alerts.
- Workspace: questionnaires, webhooks, members, billing, branding.
File inputs
Tools that consume files (face upload, ID/PoA/liveness/face/age verification, branding) accept the file in one of two forms:
*_path— an absolute path on the machine running the MCP server. Only works for local/stdio runs (e.g. Claude Code with a local server), where your files and the server share a filesystem.*_base64— the file content inline, as raw base64 or adata:URL. Use this against the hosted endpoint; it is how the Didit Console Copilot passes chat attachments (its agent resolves attachment references likeatt_1into base64 before the call reaches the MCP).
Both forms enforce the same 15MB cap and magic-bytes allow-list (png/jpg/jpeg/webp/gif/bmp/ico/pdf). The hosted transport's JSON body limit is 25MB (MCP_JSON_BODY_LIMIT).
Run it yourself
The hosted server above is the easy path — no install. To self-host, clone this repo and run it with Docker or Node. It authenticates the user the same way (OAuth, or a user Bearer token for headless runs); there is no API-key mode.
git clone https://github.com/didit-protocol/mcp.git && cd mcp
# Docker (recommended) — serves /mcp and /healthz on port 3000
docker build -t didit-mcp . && docker run -p 3000:3000 --env-file .env didit-mcp
# …or with Node
npm install && npm run build
node dist/http.js # hosted HTTP/OAuth
DIDIT_ACCESS_TOKEN=<user-access-token> node dist/index.js # stdio (headless)
All Didit base URLs and OAuth endpoints are environment variables with public defaults (verification.didit.me, apx.didit.me, business.didit.me) — override them for a private deployment. See ARCHITECTURE.md and .env.example for the full reference.
Workflow feature configuration
Every workflow feature node takes a config object. The tables below are the complete
contract - what didit_workflow_create, didit_workflow_update, didit_workflow_validate_graph,
didit_workflow_set_graph and didit_workflow_edit_graph accept, and what the API stores.
A key that is not listed here is not part of the contract and is dropped silently on save.
didit_workflow_get_feature_config_schema returns the same data as JSON at runtime.
Generated from schema/feature-config-schema.json (contract sha256:a2c413a50107faf3ea47fa187089a930ac17d3d04893e24176f494a58470e982, schema version 1), which is a copy of the artifact service-didit-verification generates from its feature-config serializers. Do not edit by hand — run npm run schema:readme.
AGE_ESTIMATION
Configuration for Age Estimation feature.
| Key | Type | Accepts | Meaning |
|---|---|---|---|
borderline_maximum_age_threshold | integer | null | integer >=1 <=100 | |
borderline_minimum_age_threshold | integer | null | integer >=1 <=100 | |
enable_id_verification_fallback | boolean | null | boolean | |
external_capture_device_action | string | null | 'NO_ACTION'|'REVIEW'|'DECLINE' | Verdict when an external capture device is detected. |
face_audio_recording_enabled | boolean | null | boolean | Record the microphone during the selfie capture, so a reviewer can hear the session. Off by default. |
face_liveness_duplicated_face_document_mismatch_action | string | null | 'NO_ACTION'|'REVIEW'|'DECLINE' | Verdict when a duplicate face is found on a user verified with a different date of birth. Another document of the same person (a passport after an identity card, a renewal, a document of a second country) is not flagged. |
face_liveness_duplicated_face_name_mismatch_action | string | null | 'NO_ACTION'|'REVIEW'|'DECLINE' | Verdict when a duplicate face is found under a different name. |
face_liveness_flash_mode | string | null | string | |
face_liveness_max_attempts | integer | null | integer >=1 <=3 | |
face_liveness_method | string | null | 'ACTIVE_3D'|'FLASHING'|'PASSIVE' | |
face_liveness_multiple_faces_action | string | null | 'NO_ACTION'|'REVIEW'|'DECLINE' | Verdict when more than one face is present in the capture. |
face_liveness_possible_duplicated_face_action | string | null | 'NO_ACTION'|'REVIEW'|'DECLINE' | Verdict when this face matches a previously seen user. |
face_liveness_score_decline_threshold | number | null | number | |
face_liveness_score_review_threshold | number | null | number | |
face_liveness_uncertain_retry_enabled | boolean | null | boolean | Native SDK active liveness only. On, a capture whose liveness score falls strictly between face_liveness_score_decline_threshold and face_liveness_score_review_threshold is never decided, whichever verdict the engine attached to it: the person is told the result was unclear and asked to capture again, every time, outside the face_liveness_max_attempts budget (which still applies to captures the engine could not score). Off by default; the web flow ignores it. |
face_liveness_video_anomaly_action | string | null | 'NO_ACTION'|'REVIEW'|'DECLINE' | Verdict when the stored liveness recording contains a repeated moving sequence consistent with a looped video feed, measured server-side from the video itself, independently of the liveness score. It deliberately does NOT flag a frozen or near-motionless capture: frame statistics cannot separate an injected still from a genuine one (a subject holding still, or a flash that clips the exposure), so acting on that would decline real users. A frozen or pre-recorded injected feed is instead defeated by strict flash liveness (set face_liveness_flash_mode to "1" for strict), which binds the capture to a per-session colour-sequence challenge a recording cannot reproduce. Defaults to NO_ACTION (evidence is recorded, the verdict is unchanged). |
face_luminance_max_action | string | null | 'NO_ACTION'|'REVIEW'|'DECLINE' | Verdict when the selfie is brighter than face_luminance_max_threshold. |
face_luminance_max_threshold | integer | null | integer >=0 <=100 | |
face_luminance_min_action | string | null | 'NO_ACTION'|'REVIEW'|'DECLINE' | Verdict when the selfie is darker than face_luminance_min_threshold. |
face_luminance_min_threshold | integer | null | integer >=0 <=100 | |
face_privacy_mode_enabled | boolean | null | boolean | |
face_quality_decline_threshold | integer | null | integer >=0 <=100 | |
face_quality_review_threshold | integer | null | integer >=0 <=100 | |
face_search_enabled | boolean | null | boolean | Run the 1:N Face Search on the selfie: match it against previously verified users, the face blocklist and allowlist, and store its biometric template for later matching. On by default. Off skips the search, keeps no face template, and leaves the duplicate-face actions with nothing to act on. |
frame_injection_action | string | null | 'NO_ACTION'|'REVIEW'|'DECLINE' | Verdict when injected video frames are detected. |
minimum_age_threshold | integer | null | integer >=1 <=100 | |
screen_capture_action | string | null | 'NO_ACTION'|'REVIEW'|'DECLINE' | Verdict when the selfie is a photo of a screen. |
status_rules | array | array | |
virtual_camera_action | string | null | 'NO_ACTION'|'REVIEW'|'DECLINE' | Verdict when a virtual camera feed is detected. |
AML
Configuration for AML feature (used for both KYC AML and KYB Company AML).
| Key | Type | Accepts | Meaning |
|---|---|---|---|
aml_country_weight | integer | null | integer >=0 <=100 | |
aml_dob_weight | integer | null | integer >=0 <=100 | |
aml_entity_type | string | null | 'company'|'person' | Whether this node screens a person or a company. Defaults to person on a person (KYC) workflow and to company on a business (KYB) workflow. Set it to company to screen the business named in an uploaded document (via aml_field_sources) without a KYB Registry step - the provider searches company records instead of people, and the match score is scored as a company. |
aml_field_sources | json | null | {"full_name"|"date_of_birth"|"nationality"|"document_number": {"source": "document_ai"|"questionnaire"|"expected_data", "key": "||expected_details.<expected_details field>|metadata."}} | Where this node reads the entity it screens, when the workflow has no ID Verification or KYB Registry step to supply it - a Document AI workflow over non-standardised documents (a tax certificate, an acta constitutiva). Same contract as database_validation_field_sources: source names the producer and key names the value inside it - a Document AI field key for document_ai, a questionnaire node id for questionnaire, and expected_details.<field> or metadata.<key> for expected_data. The map's KEY is one of the four AML screening inputs: full_name, date_of_birth, nationality, document_number - read for a company as legal name, incorporation date, country and registration number. A Document AI field already keyed as one of those four maps automatically and is deliberately not persisted, so renaming it never freezes a stale mapping. An explicit mapping wins over both the auto-map and the ID document, and a mapping that resolves to nothing at runtime leaves the input empty rather than falling back. With no ID Verification and no KYB Registry upstream, full_name must be fillable or the graph is rejected on save: there is no search without a name. |
aml_incomplete_data_action | string | null | 'NO_ACTION'|'REVIEW'|'DECLINE' | Verdict when the screening ran on less than a full identity (name, date of birth and country). REVIEW is the default and the historical behaviour; NO_ACTION proceeds on reduced data for a workflow that knowingly holds only a name. The screening still runs either way, and the partial-data log is still recorded - this only decides what it does to the status. |
aml_match_score_threshold | integer | null | integer >=0 <=100 | |
aml_name_weight | integer | null | integer >=0 <=100 | |
aml_score_approve_threshold | integer | null | integer >=0 <=100 | |
aml_score_review_threshold | integer | null | integer >=0 <=100 | |
case_blueprint | uuid | null | uuid | Which case blueprint the automatically-created case is built from. Only meaningful with create_cases_on_hit; the account default is used when unset. |
create_cases_on_hit | boolean | null | boolean | Open a case automatically when the screening returns a hit, instead of leaving the hit to be triaged from the session. Off by default. |
fallback_to_native | boolean | null | boolean | |
is_aml_ongoing_monitoring_enabled | boolean | null | boolean | Keep screening the PERSON after the session is approved, raising a new hit when they later appear on a watchlist. Off by default. |
kyb_company_aml_country_weight | integer | null | integer >=0 <=100 | |
kyb_company_aml_dob_weight | integer | null | integer >=0 <=100 | |
kyb_company_aml_match_score_threshold | integer | null | integer >=0 <=100 | |
kyb_company_aml_name_weight | integer | null | integer >=0 <=100 | |
kyb_enable_ongoing_monitoring | boolean | null | boolean | The same, for the COMPANY on a KYB workflow. The two switches are independent. |
kyb_score_approve_threshold | integer | null | integer >=0 <=100 | |
kyb_score_review_threshold | integer | null | integer >=0 <=100 | |
provider_key | string | null | string | |
status_rules | array | array |
BANK_VERIFICATION
Configuration for Bank Verification feature.
Bank Verification confirms who owns a bank account against an identity ANOTHER step established - it is not identity proof on its own. Put ID Verification, Database Validation or a questionnaire before it; first in a graph it has nothing to compare against and can only return
unknown. The node is opt-in and runs nothing whilebank_countriesis empty.
| Key | Type | Accepts | Meaning |
|---|---|---|---|
bank_account_selection | string | null | 'auto'|'user' | Whether the user picks which of the connected accounts is verified (user) or the first eligible one is taken (auto). |
bank_allow_skip | boolean | null | boolean | Let the user skip the step instead of connecting a bank. A skip is then decided by bank_skipped_action. |
bank_attempts_exhausted_action | string | null | 'REVIEW'|'DECLINE' | Verdict when the user spent bank_max_attempts without a successful connection. |
bank_business_account_action | string | null | 'NO_ACTION'|'REVIEW'|'DECLINE' | Verdict when the institution types the holder as a business rather than a person. |
bank_connection_timeout_minutes | integer | null | integer >=5 <=60 | How long a started connection stays open before the attempt is abandoned, 5 to 60 minutes. |
bank_consent_expired_action | string | null | 'NO_ACTION'|'REVIEW'|'DECLINE' | Verdict when the bank consent lapses after the step was already decided. Only meaningful with bank_refresh_enabled. |
bank_countries | json | null | {"": {"enabled": true|false, "institutions": ["<institution_id>", ...] | "all"}} | Which countries a user may connect a bank in - a WHITELIST, so an empty map means the node offers nothing and runs nothing. institutions narrows the picker to specific provider institution ids; "all" offers every identity-capable bank in the country. Coverage belongs to the route the node selected in provider_key: a country the native route or the connected marketplace provider cannot establish account ownership in is REFUSED on save rather than dropped, because connecting to a bank that returns no holder identity spends an attempt and a charge to end at not_verifiable. |
bank_country_mismatch_action | string | null | 'NO_ACTION'|'REVIEW'|'DECLINE' | Verdict when the institution's country differs from the expected/document country. |
bank_currency_mismatch_action | string | null | 'NO_ACTION'|'REVIEW'|'DECLINE' | Verdict when the account currency is not in bank_expected_currencies. |
bank_eligible_account_types | array | null | array | Which account types the user may pick. Credit cards, loans and investment accounts are never eligible - they do not establish ownership of a payment account. Defaults to current/checking. |
bank_expected_currencies | array | null | array | ISO 4217 currencies the account is expected to be in. Empty means any; a mismatch is reported through bank_currency_mismatch_action. |
bank_field_sources | json | null | {"full_name"|"first_name"|"last_name"|"address": {"source": "document_ai"|"questionnaire"|"expected_data", "key": "||expected_details.<expected_details field>|metadata."}} | Where to read a reference-identity field when no earlier step in the graph can fill it. The map's KEY is one of full_name, first_name, last_name, address; source names the producer and key names the value inside it - a Document AI field key for document_ai, a questionnaire node id for questionnaire, and expected_details.<field> or metadata.<key> for expected_data. An expected_details.<field> VALUE may only name a field the session-create payload actually carries - address, country, date_of_birth, first_name, gender, id_country, identification_number, ip_address, last_name, nationality or poa_country. A malformed entry is refused on save, not dropped. |
bank_joint_account_action | string | null | 'NO_ACTION'|'REVIEW'|'DECLINE' | Verdict when the account has more than one holder. |
bank_low_balance_action | string | null | 'NO_ACTION'|'REVIEW'|'DECLINE' | Verdict when the available balance is below bank_min_balance. Needs the balances scope. |
bank_max_attempts | integer | null | integer >=1 <=5 | How many connection attempts the user gets, 1 to 5. Spending them all without a successful connection is bank_attempts_exhausted_action. |
bank_min_balance | number | null | number >=0 | Minimum available balance, in the account's own currency. Below it bank_low_balance_action fires. Needs the balances scope and the save is refused without it. 0 is a real cutoff - it triggers the action for an overdrawn account - but the action defaults to NO_ACTION, so the verdict is unchanged unless another action is configured. This is not the same as leaving the key out. |
bank_name_match_threshold | integer | null | integer >=50 <=100 | At or above this score the holder name is a match. 50 to 100, defaults to 85. |
bank_no_match_action | string | null | 'REVIEW'|'DECLINE' | Verdict when the account holder is demonstrably not the verified person (best name score below bank_partial_match_floor). |
bank_not_verifiable_action | string | null | 'NO_ACTION'|'REVIEW'|'DECLINE' | Verdict when the institution connected but returned no holder identity to compare. |
bank_partial_match_action | string | null | 'NO_ACTION'|'REVIEW'|'DECLINE' | Verdict when the holder name lands between bank_partial_match_floor and bank_name_match_threshold. Never approves by default. |
bank_partial_match_floor | integer | null | integer >=0 <=99 | Below this score the holder name is a no-match. 0 to 99, defaults to 70. The band between the floor and the threshold is the partial match, so the floor must be strictly below bank_name_match_threshold or the save is refused. An explicit null means "use the default" here too, which is why a threshold of 50 with no floor is refused: it is checked against the default floor of 70. |
bank_reference_identity | string | null | 'auto'|'database_validation'|'expected_details'|'kyc'|'questionnaire' | Which earlier step supplies the identity the account holder is compared against: kyc (ID Verification), database_validation, expected_details (the session-create payload), questionnaire, or auto to use whichever one the workflow produced. The step that actually supplied it is recorded on the result as reference_identity_source. |
bank_reference_identity_missing_action | string | null | 'NO_ACTION'|'REVIEW'|'DECLINE' | Verdict when no earlier step produced an identity to compare the holder against, so ownership can only be unknown. |
bank_refresh_enabled | boolean | null | boolean | Re-fetch the account's financial data after the step has already been decided, for as long as the bank consent lasts. Needs at least one of the balances, transactions or income scopes and the save is refused without one. A consent that lapses afterwards is bank_consent_expired_action. |
bank_require_address_match | boolean | null | boolean | Also require the holder's address to match. A name that reached the threshold but whose address scores below it drops to a partial match. An institution that returns no address waives the requirement; a session with no address of its own to compare against does not, and lands on a partial match. Off by default. |
bank_require_oauth_only | boolean | null | boolean | Offer only institutions reachable over OAuth / app-to-app, never a provider's legacy credential-capture surface. Where open banking already makes OAuth the only route, this changes nothing. |
bank_scopes | json | null | {"ownership": true, "identifiers": true|false, "balances": true|false, "transactions": true|false, "income": true|false} | What the user is asked to consent to sharing. ownership is what the product verifies and cannot be turned off. identifiers unmasks the IBAN / account number; balances, transactions and income read real financial data, are each billed separately, and are refused on save unless the application carries the bank_financial_data entitlement. A scope that is off is never requested from the provider, so the bank never shows it on its consent screen. |
bank_show_match_result_to_user | boolean | null | boolean | Show the ownership result to the user inside the verification flow. Off means it is recorded on the session but never shown to them. |
bank_skipped_action | string | null | 'REVIEW'|'DECLINE' | Verdict when the user skipped the step. Only reachable with bank_allow_skip. |
bank_store_full_identifiers | boolean | null | boolean | Store the account identifiers unmasked rather than masked. Needs the identifiers scope and the save is refused without it. Even then the unmasked form is only served to a caller holding the bank-verification read permission. |
bank_store_raw_owner_data | boolean | null | boolean | Keep the holder details the institution returned next to the ownership evidence. Off means only the comparison itself is retained: scores, match method and reason codes. |
bank_transactions_history_days | integer | null | integer >=30 <=365 | How far back transaction history is read, 30 to 365 days, defaulting to 90. Needs the transactions scope and the save is refused without it. |
bank_unknown_action | string | null | 'NO_ACTION'|'REVIEW'|'DECLINE' | Verdict when the evidence could not be fetched after retries - a transient failure. |
bank_unsupported_action | string | null | 'NO_ACTION'|'REVIEW'|'DECLINE' | Verdict when the user's bank is not supported and the node does not allow skipping. |
bank_use_provider_score | boolean | null | boolean | Also read the institution's own holder-name score, and let it decide when it is higher than Didit's or when Didit had no holder name to score at all. A result decided that way reports provider_only as its match method, and a connection that returned no such score records a provider_score_unavailable warning. On by default. |
fallback_to_native | boolean | null | boolean | Whether a marketplace connection that cannot be established falls back to Didit's native route. Off by default: a silent fallback would spend your Didit balance on a session you expected to run on your own provider contract. A fallback connection is recorded as credential_source = native and billed at the native price. |
provider_key | string | null | string | Which route runs the step. Empty (the default) is Didit's native Bank Verification, a provider-independent product Didit routes to the regional open-banking vendor that serves the user's country and institution, on Didit's contracts and billing. A value names a MARKETPLACE provider whose own credentials this application has connected - the session then runs, is billed and is revoked on your provider account, and Didit charges only the marketplace platform fee. A provider that is not connected is refused on save. |
status_rules | array | array |
DATABASE_VALIDATION
Configuration for Database Validation feature.
The node is opt-in and does nothing while
database_validation_countriesis empty - the editor blocks publishing in that state and the compliance check reports it as a gap. Place it after the step that produces its inputs (usually OCR), and usedatabase_validation_field_sourcesonly for inputs no upstream step can fill.
| Key | Type | Accepts | Meaning |
|---|---|---|---|
database_validation_countries | json | null | {"": {"services": ["<service_id>", ...]}} | The databases to check, per country - this node runs NOTHING until at least one country carries at least one service id. Service ids come from the country's live catalog (e.g. bra_cpf for BRA); ids that do not belong to the named country, and countries with no live service, are dropped on save. The legacy {"<ISO3>": "one_by_one"|"two_by_two"|"not_enabled"} shape is still accepted and auto-expanded to that country's live services. |
database_validation_field_sources | json | null | {"<db_validation_input_field>": {"source": "document_ai"|"questionnaire"|"expected_data", "key": "||expected_details.<expected_details field>|metadata."}} | Where to read a database input that no earlier step in the graph can fill. source names the producer and key names the value inside it: a Document AI field key for document_ai, a questionnaire node id for questionnaire, and expected_details.<field> or metadata.<key> for expected_data. The two halves speak different vocabularies: the map's KEY is a Database Validation input field (tax_id, document_number, ...), while an expected_details.<field> VALUE may only name a field the session-create payload actually carries - address, country, date_of_birth, first_name, gender, id_country, identification_number, ip_address, last_name, nationality or poa_country. Anything else under expected_details. is rejected on save; metadata.<key> takes any non-empty whitespace-free customer key. Exact-key matches against an upstream step resolve automatically and are deliberately not persisted, so renaming a Document AI field never freezes a stale mapping into the config. A malformed entry is dropped on save rather than rejected, which un-satisfies its service and drops it from the selection. |
database_validation_no_match_action | string | null | 'NO_ACTION'|'REVIEW'|'DECLINE' | Verdict when the database returns no match at all. |
database_validation_not_applicable_action | string | null | 'NO_ACTION'|'REVIEW'|'DECLINE' | Verdict when no selected database covers the holder's country or document. |
database_validation_partial_match_action | string | null | 'NO_ACTION'|'REVIEW'|'DECLINE' | Verdict when the database matches some, but not all, of the submitted fields. |
status_rules | array | array |
DOCUMENT_AI
Configuration for the Document AI feature.
At most 3 documents per node, field keys unique within a document, and at most one field per document may set
is_full_name(it is optional - a document may mark none).
| Key | Type | Accepts | Meaning |
|---|---|---|---|
document_ai_document_tampering_action | string | null | 'REVIEW'|'DECLINE' | Verdict when the document looks tampered with. |
document_ai_documents | array | array | |
document_ai_max_attempts_exceeded_action | string | null | 'REVIEW'|'DECLINE' | Verdict when the user runs out of document_ai_max_retry_attempts. |
document_ai_max_retry_attempts | integer | null | integer >=2 <=5 | |
document_ai_missing_required_fields_action | string | null | 'NO_ACTION'|'REVIEW'|'DECLINE' | Verdict when a field marked required could not be extracted. |
document_ai_name_match_score_threshold | integer | null | integer >=0 <=100 | |
document_ai_name_mismatch_action | string | null | 'NO_ACTION'|'REVIEW'|'DECLINE' | Verdict when the field flagged is_full_name disagrees with the verified identity's full name, scored against document_ai_name_match_score_threshold. |
document_ai_unreadable_document_action | string | null | 'NO_ACTION'|'REVIEW'|'DECLINE' | Verdict when the uploaded document cannot be read at all. |
document_ai_unsupported_file_action | string | null | 'NO_ACTION'|'REVIEW'|'DECLINE' | Verdict when the uploaded file type is not supported. |
status_rules | array | array |
EMAIL_VERIFICATION
Configuration for Email Verification feature.
| Key | Type | Accepts | Meaning |
|---|---|---|---|
breached_email_action | string | null | 'NO_ACTION'|'REVIEW'|'DECLINE' | Verdict when the address appears in a known credential breach. |
cross_org_fraud_email_action | string | null | 'NO_ACTION'|'REVIEW'|'DECLINE' | Verdict when this address was flagged as fraudulent by another organization in the network. |
disposable_email_action | string | null | 'NO_ACTION'|'REVIEW'|'DECLINE' | Verdict when the address belongs to a disposable-mail provider. |
duplicated_email_action | string | null | 'NO_ACTION'|'REVIEW'|'DECLINE' | Verdict when the address was already verified for this application. |
email_alphanumeric_code | boolean | null | boolean | |
email_code_size | integer | null | integer >=4 <=8 | |
email_enrichment_enabled | boolean | null | boolean | |
email_intelligence_score_action | string | null | 'NO_ACTION'|'REVIEW'|'DECLINE' | Verdict when the enrichment score is worse than email_intelligence_score_threshold. |
email_intelligence_score_threshold | integer | null | integer >=0 <=100 | |
email_max_check_attempts | integer | null | integer >=1 <=5 | |
email_max_retries | integer | null | integer >=1 <=5 | |
email_no_social_presence_action | string | null | 'NO_ACTION'|'REVIEW'|'DECLINE' | Verdict when the social footprint check (email_social_enabled) finds the address registered on none of the platforms it covers. |
email_social_enabled | boolean | null | boolean | |
frequent_email_breach_action | string | null | 'NO_ACTION'|'REVIEW'|'DECLINE' | Verdict when the address appears in many breaches. |
only_corporate_emails_allowed | boolean | null | boolean | |
recent_email_breach_action | string | null | 'NO_ACTION'|'REVIEW'|'DECLINE' | Verdict when the address appears in a recent breach. |
status_rules | array | array |
FACE_MATCH
Configuration for Face Match feature.
| Key | Type | Accepts | Meaning |
|---|---|---|---|
face_match_eyes_covered_action | string | 'NO_ACTION'|'REVIEW'|'DECLINE' | Verdict when calibrated evidence says the eyes region is covered in the selfie. NO_ACTION records evidence without changing Face Match; REVIEW sends Face Match to review; DECLINE declines it. The signal remains shadow-only until the region reports calibrated=true. |
face_match_face_covered_action | string | 'NO_ACTION'|'REVIEW'|'DECLINE' | Verdict when calibrated evidence says the face region is covered in the selfie. NO_ACTION records evidence without changing Face Match; REVIEW sends Face Match to review; DECLINE declines it. The signal remains shadow-only until the region reports calibrated=true. |
face_match_max_attempts | integer | null | integer >=1 <=3 | |
face_match_mouth_covered_action | string | 'NO_ACTION'|'REVIEW'|'DECLINE' | Verdict when calibrated evidence says the mouth region is covered in the selfie. NO_ACTION records evidence without changing Face Match; REVIEW sends Face Match to review; DECLINE declines it. The signal remains shadow-only until the region reports calibrated=true. |
face_match_not_computed_action | string | null | 'REVIEW'|'DECLINE' | Verdict when no face-match score could be produced (missing portrait or selfie). |
face_match_score_decline_threshold | integer | null | integer >=0 <=100 | |
face_match_score_review_threshold | integer | null | integer >=0 <=100 | |
status_rules | array | array |
GEOLOCATION
Configuration for the Precise Location (GEOLOCATION) feature. Every threshold is bounded here rather than in the client: the browser and the native SDKs are told what to collect by the step data this config produces, and a value the server would refuse must never reach a user as a request their device cannot satisfy. The action keys all default to Review rather than Decline. A denied permission, a wide radius or a stale fix is not evidence of fraud, and a default that declined them would make the step a conversion trap.
Documentation truncated — see the full README on GitHub.
Reviews
No reviews yet
Be the first to review this server!
More Developer Tools MCP Servers
Rea
Freeby Morluto · Developer Tools
Reverse engineer anything from your terminal or agent with one CLI and MCP server.
Paperclip
Freeby Paperclipai · Developer Tools
Trending hip-hop artist momentum scores across four cultural dimensions.
Git
Freeby Modelcontextprotocol · Developer Tools
Read, search, and manipulate Git repositories programmatically
Fetch
Freeby Modelcontextprotocol · Developer Tools
Web content fetching and conversion for efficient LLM usage
Toleno
Freeby Toleno · Developer Tools
Toleno Network MCP Server — Manage your Toleno mining account with Claude AI using natural language.
MCP Marketplace
Freeby mcp-marketplace · Developer Tools
Search and install MCP servers from inside your AI client.
