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:
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:
get_organization(api_key="<org api key>")— confirms identity. The response includes astatusfield:TEST/DEMOorgs are sandboxes;PRODUCTIONorgs run against live integrations.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_idsare the UUIDs returned bylist_subscription_technologies, not the short codes.success_redirect_urlandfailure_redirect_urlare 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_configsentry,create_flowfirst 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_configsfor every technology see no elicitations at all. Non-interactive callers (CI, headless agents) can drivecreate_flowby 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:
- Create a one-shot session via MCP:
create_flow_session(flow_api_key="<flow's api_key>")→ returns{ session_id, technologies }. - Walk through the verification UI in a browser at
https://remote.biometric.kz/flow/<session_id>. - Fetch the result via MCP:
get_flow_session_light_result(session_id="<session_id>"). Inspectstatus(expectFINISHEDon a clean pass),overall_result, each per-technology result block, andfailure_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— callsPOST https://kyc.biometric.kz/api/v1/flows/session/create/with body{ "api_key": "<flow's api_key>" }, persists the returnedsession_idkeyed by the end-user id, and returns the redirect URL orsession_idto 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(orPOSTfor widget / webview pings) — looks upsession_idfrom the server-side binding (not from the URL query string) and callsGET 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.