Skip to content

Guide

Description#

MCP (Model Context Protocol) is an integration channel for AI coding agents. Our MCP server lets an agent in Claude Code, Cursor, Codex or any other spec-compliant client browse subscriptions, design Flows, and smoke-test sessions on the customer's behalf — without writing a line of glue code by hand.

The server speaks MCP over Streamable HTTP at https://kyc.biometric.kz/mcp/, authenticated with the organization API key (Authorization: Bearer <key> or X-Org-API-Key: <key>).

Rate limit

The MCP server enforces a per-IP rate limit on /mcp/* of 60 requests per minute. The limit is applied before authentication, so anonymous probes and admin-key brute-force attempts are capped too. Exceeding it returns HTTP 429 Too Many Requests with a Retry-After header (in seconds) and X-RateLimit-Limit / X-RateLimit-Remaining headers. Wait the indicated time and retry — well-behaved agents stay far under this budget.

MCP is integration-time only

The MCP server is the integrator's channel — used once, by an agent, to set up the customer's Flow and wire the customer's backend. It is not a runtime channel: production end users never reach MCP. Every per-user call (creating a session, fetching a result) goes over the regular REST API.

Do not write mcp.call_tool(...) into controllers, route handlers, or background jobs. Use the REST integrations (Flow Remote, Flow Widget, Flow WebView) for that.

sequenceDiagram
    title MCP integration — agent-led setup, REST runtime

    participant AGENT as Integrator agent<br/>(Claude Code / Cursor / Codex)
    participant BIO as Biometric.Vision (KYC)
    participant APP as Customer app<br/>(backend + frontend)
    participant USER as End user

    note over AGENT: Precondition:<br/>org API key in hand

    note over AGENT,BIO: Step 1 — Connect (MCP)
    AGENT->>+BIO: initialize (Streamable HTTP)<br/>Authorization: Bearer <org_api_key>
    BIO-->>-AGENT: tools/resources advertised

    note over AGENT,BIO: Step 2 — Discover (MCP)
    AGENT->>+BIO: get_organization, list_subscription_technologies
    BIO-->>-AGENT: org status + licensed technology codes

    note over AGENT,BIO: Step 3 — Design (MCP)
    AGENT->>+BIO: create_flow(technology_ids, configs)
    BIO-->>-AGENT: { id, api_key, technology_configs }

    note over AGENT,BIO: Step 4 — Smoke test (MCP, one-shot)
    AGENT->>+BIO: create_flow_session + walk-through
    AGENT->>BIO: get_flow_session_light_result(session_id)
    BIO-->>-AGENT: FINISHED / FAILED

    note over AGENT,APP: Step 5 — Wire production code
    AGENT->>APP: Add POST /kyc/start + GET /kyc/return<br/>using flow's api_key

    note over APP,USER: From this point onward — REST only
    USER->>+APP: signup / verification trigger
    APP->>+BIO: POST /api/v1/flows/session/create/
    BIO-->>-APP: { session_id }
    APP->>USER: redirect to https://remote.biometric.kz/flow/{session_id}
    USER->>BIO: walk through verification UI
    BIO-->>APP: GET /api/v1/flows/session/result/light/
    APP->>USER: apply decision

Stages#

1. Install the MCP server in your agent#

Register the server in whichever AI agent the integrator is using. The config block is the same in every client:

{
  "mcpServers": {
    "kyc": {
      "url": "https://kyc.biometric.kz/mcp/",
      "headers": {
        "Authorization": "Bearer <PASTE_ORG_API_KEY_HERE>"
      }
    }
  }
}

Where to put it:

Either the user-global config at ~/.claude.json, or a per-project .mcp.json in the repo root. Or run from a shell:

claude mcp add kyc https://kyc.biometric.kz/mcp/ \
  --header "Authorization: Bearer <PASTE_ORG_API_KEY_HERE>"

Settings → MCP → "Add new MCP server" → paste the JSON. Alternatively edit ~/.cursor/mcp.json directly.

Each agent has an equivalent "MCP servers" config (JSON or TOML). Locate it in the agent's own docs and paste the same mcpServers.kyc block.

~/Library/Application Support/Claude/claude_desktop_config.json on macOS, or %APPDATA%\Claude\claude_desktop_config.json on Windows.

Restart after editing

Most agents need to be restarted (or the MCP server reloaded) before the new tool list appears.

Where the org API key comes from

The organization API key is the same secret you use to authenticate against the API for Backend Integration. Copy it from the [Cabinet](https://cabinet.biometric.kz: Settings -> Company's Data -> API KEY. It stays in the integrator's agent config — never deploy it to production.

2. Verify the connection#

Before doing anything else, run a connectivity probe so any later failure isn't ambiguous. The integrator agent calls two tools:

  1. get_organization(api_key="<org api key>") — confirms identity. The response includes a status field: TEST / DEMO orgs are sandboxes; PRODUCTION orgs run against live integrations.
  2. list_subscription_technologies() — enumerates the technology codes the organization has a subscription to put in a Flow.

If either call fails:

Symptom Likely cause
401 Unauthorized (WWW-Authenticate: Bearer realm="kyc-mcp") Wrong / expired org API key.
429 Too Many Requests (Retry-After: <seconds>) Per-IP rate limit hit (60 req/min). Wait the indicated number of seconds and retry.
get_organization not in the agent's tool list Agent didn't reload after the config change.
Connection refused / DNS failure URL typo, missing scheme, wrong port.

3. Design and create the Flow#

A Flow is the ordered pipeline of verification technologies an end user goes through. The integrator agent designs it once via MCP; from then on, every end user gets a session against this Flow over REST.

Before composing a create_flow call, read the four reference resources:

URI What it gives you
kyc://reference/flow-config-defaults Defaults for the Flow-level config (redirect URLs, fingerprint check, QR display, mobile-only, etc.).
kyc://reference/technology-config-defaults Defaults for every per-technology config, keyed by config-field name (liveness_config, edocument_config, …).
kyc://reference/document-recognition-countries Country ids usable in doc_recognition_config.allowed_countries.
kyc://reference/document-recognition-document-types Document-type ids usable in doc_recognition_config.allowed_document_types.

See Technologies for what each technology does and where it can be used.

A typical create_flow call with non-default per-technology overrides:

// MCP tool: create_flow
{
  "request_data": {
    "name": "kyc-prod-v1",
    "display_name": "KYC verification",
    "technology_ids": [
      "<liveness-core-uuid>",
      "<edocument-uuid>",
      "<face2face-uuid>"
    ],
    "flow_config": {
      "success_redirect_url": "https://myapp.example.com/kyc/return?outcome=success",
      "failure_redirect_url": "https://myapp.example.com/kyc/return?outcome=failure",
      "show_qr": true,
      "always_mobile": false
    },
    "technology_configs": {
      "liveness_config": {
        "max_attempts": 3,
        "eye_open_check": true,
        "mask_attack_check_required": true
      },
      "edocument_config": {
        "document_type": "IdentityCard",
        "max_retry_attempts": 3,
        "allow_retry": true
      },
      "face2face_config": {
        "threshold": 0.85,
        "fail_on_several_faces": true
      }
    }
  }
}

Notes:

  • technology_ids are the UUIDs returned by list_subscription_technologies, not the short codes.
  • success_redirect_url and failure_redirect_url are the completion signals you will wire into the customer's app in Step 5. The ?outcome=... query string is a hint only — never trust it as proof of the outcome.
  • If at least one technology lacks an explicit technology_configs entry, create_flow first sends a single "override per-technology defaults?" elicitation:
    • Decline to use platform defaults for every technology — no further per-tech prompts fire.
    • Accept to step through each technology with a typed prompt for its overrides; decline any individual prompt to keep that technology's defaults.
    • Cancel anywhere aborts the tool with "create_flow cancelled by user.".
  • Callers that supply technology_configs for every technology see no elicitations at all. Non-interactive callers (CI, headless agents) can drive create_flow by declining every prompt.

The response is the freshly created Flow. Two fields matter for the next steps:

  • id — the Flow's UUID.
  • api_key — the Flow's API key. This is the secret the production REST calls in Step 5 will use. Treat it like a database password.

Digital Signature flows must be built in the Cabinet UI

If list_subscription_technologies returns any technology with code equal to DSI, DSN, or DSS, do not include those ids in technology_ids on create_flow. Digital Signature flows have certificate-authority and signer-identity constraints that the MCP create path does not enforce — building one over MCP would produce a silently broken Flow.

Build the Digital Signature flow in the Cabinet instead. Once it exists, the integrator can pull its id with list_flows(), fetch it with get_flow(flow_id=…), and use its api_key for the production wiring.

4. Smoke-test the Flow#

Before wiring REST code into the customer's app, confirm the new Flow runs end-to-end:

  1. Create a one-shot session via MCP: create_flow_session(flow_api_key="<flow's api_key>") → returns { session_id, technologies }.
  2. Walk through the verification UI in a browser at https://remote.biometric.kz/flow/<session_id>.
  3. Fetch the result via MCP: get_flow_session_light_result(session_id="<session_id>"). Inspect status (expect FINISHED on a clean pass), overall_result, each per-technology result block, and failure_reasons[] on failure.

After the smoke test, MCP's job in the integration is essentially done.

5. Wire the Flow into the production app#

Production traffic goes over REST. The integrator agent writes two backend handlers and one frontend hook in the customer's repo:

  • POST /kyc/start — calls POST https://kyc.biometric.kz/api/v1/flows/session/create/ with body { "api_key": "<flow's api_key>" }, persists the returned session_id keyed by the end-user id, and returns the redirect URL or session_id to the frontend.
  • Frontend opens the verification UI — pick Flow Remote for web, Flow Widget for SPA embeds, or Flow WebView for native mobile.
  • GET /kyc/return (or POST for widget / webview pings) — looks up session_id from the server-side binding (not from the URL query string) and calls GET https://kyc.biometric.kz/api/v1/flows/session/result/light/?session_id=...&flow_api_key=.... The response is the authoritative decision.

The full REST request shapes, code samples and session.status table live in Flow Remote.


MCP tools#

Tool Purpose
get_organization(api_key) Organization identity and status.
list_subscription_technologies() Technologies the organization is licensed to put in a Flow, with combination rules.
list_flows(limit, offset) Paginated list of Flows the caller can see.
get_flow(flow_id) Single Flow with its flow_config and every per-technology config.
create_flow(request_data) Create a new Flow (conversational — uses elicitations for per-tech overrides).
update_flow(request_data) PATCH-style update of an existing Flow.
create_flow_session(flow_api_key) Smoke-test session against a Flow (integration-time only).
get_flow_session(session_id) Structured session view, no media URLs.
get_flow_session_light_result(session_id) Session view with short-lived signed URLs for captured media.
update_flow_session_status(session_id, request_data) Manually move a session to APPROVED or DECLINED (internal review tooling).
list_flow_session_reviews(session_id) Reviews audit trail for a session.
create_flow_session_review(session_id, request_data) Add a free-form MESSAGE review to a session.

MCP resources#

URI Purpose
kyc://reference/flow-config-defaults Current platform defaults for every flow_config field.
kyc://reference/technology-config-defaults Current platform defaults for every per-technology config block.
kyc://reference/document-recognition-countries Active countries usable in doc_recognition_config.allowed_countries.
kyc://reference/document-recognition-document-types Active document types usable in doc_recognition_config.allowed_document_types.

One-shot agent integration#

The whole flow above — connect → discover → design → smoke-test → wire — is documented as a single copy-pasteable system prompt the integrator can hand to an AI coding agent. Paste it into Claude Code / Cursor / Codex and the agent will run the integration end-to-end with minimal hand-holding.

See AI Integration Prompt.