MCP Server
Overview
The VerifEye MCP Server is a remotely-hosted Model Context Protocol (MCP) server that exposes VerifEye's face-analysis capabilities — apparent age and gender, plus momentary emotions and attention — as a tool an AI assistant (such as Claude) can call over Streamable HTTP.
The MCP server enables you to:
- Analyze the face(s) in an image for age, gender, emotions and attention, directly from an MCP client
- Authenticate once via OAuth — your client never sends an API key
- Choose where each image is processed — in the EU or the US — on every call (data residency)
The MCP server is a thin, OAuth-authenticated wrapper over the VerifEye Face API's Identify operation — its one tool is a single identify call with the attributes you request. The same attributes are available from your own backend by calling Identify directly with include.age, include.gender, include.emotions and include.attention — in a different shape: age.prediction rather than age.estimatedAge, emotions.happy rather than happiness, each signal as a nullable boolean rather than as present/undetermined lists, and the REST response also carries face.boundingBox, which this tool does not surface. Your account's API key is resolved server-side from your login — the client never sees or sends it.
Prerequisites
- A VerifEye Developer Console account — sign in at the VerifEye Developer Console.
- An MCP-capable client that supports remote MCP servers over OAuth — see
Connecting a client for the ones with worked configurations.
Server URL
https://verifeye-mcp-server.realeyes.ai/mcp
The server has a single global endpoint. You choose where each image is processed — in the EU or the US — on every call via the region parameter (eu/us) on the tool, for data residency and compliance. See
Authentication
The MCP server uses OAuth 2.1 (authorization code with PKCE). Authentication happens through a branded VerifEye login and consent screen — you never put an API key into your MCP client.
Authorization flow
- Your MCP client reads the MCP server's protected-resource metadata and discovers the VerifEye authorization server.
- The client starts an OAuth 2.1 authorization-code flow (with PKCE) and opens the VerifEye login in your browser.
- You sign in with your VerifEye Developer Console account and approve the Allow / Deny consent screen.
- The authorization server returns a short-lived, signed access token scoped to the MCP server. Your client refreshes it automatically until the refresh window lapses.
- The client calls the MCP server with that token. The server resolves your account's API key on the server side and calls VerifEye on your behalf — the key is never exposed to the client.
Connecting a client
Every client needs two things: the server URL
https://verifeye-mcp-server.realeyes.ai/mcp
and a way to identify itself. Claude Code, Claude, Cursor and the Gemini CLI use a pre-registered client ID — the name you will see on the consent screen — and their tab gives the exact value. ChatGPT, VS Code and Codex identify themselves instead by publishing a Client ID Metadata Document and sending its URL, so for those there is nothing to enter. The server offers no dynamic client registration, so a client that expects to register itself on the fly needs one of the IDs below. There is no client secret either way: every client here is a public client and the flow is secured with PKCE.
When you connect, VerifEye opens in your browser: sign in with your Developer Console account and approve the consent screen. An application VerifEye recognises is named there, with the logo it publishes for itself. An application that identified itself with a metadata document from an address VerifEye does not recognise is shown by that address alone — no name, no logo — because anyone who controls the address chooses what it claims. Either screen shows where the authorization will be delivered. Read it, and approve only if you have just started this sign-in yourself — that is the check that holds, because a name and a local address are the two things an application asking on another's behalf can copy.
claude mcp add --scope user --transport http \
--client-id verifeye-mcp-claude --callback-port 8080 \
verifeye https://verifeye-mcp-server.realeyes.ai/mcp
- Run
/mcpand select verifeye. - Authenticate in the browser window that opens.
- Run
/mcpagain — the VerifEye tools are listed.
Both flags are required. --client-id names the pre-registered client, and --callback-port 8080 makes the loopback redirect match the one registered for it. Without --client-id the client tries to register itself, which this server does not offer, and the sign-in ends with invalid_client. With a different callback port it ends with invalid_request and "The specified 'redirect_uri' is not valid for this client."
On claude.ai, and in Claude Desktop — a custom connector is brokered through your Claude account rather than from your own machine, so one entry serves both.
A custom connector is available on the Free, Pro, Max, Team and Enterprise plans, but not everyone on them can add one. On Pro and Max you add it yourself, and the Free plan allows one custom connector in total. On Team and Enterprise only an Owner can add it: the Owner adds it once for the organization under Organization settings → Connectors, and members then connect to it from Customize → Connectors. See Anthropic's guide to custom connectors for the current steps.
- Open Customize → Connectors (Settings → Connectors on some plans), click +, then Add custom connector.
- Enter the server URL:
https://verifeye-mcp-server.realeyes.ai/mcp - Open Advanced settings and enter the OAuth Client ID:
verifeye-mcp-claude. Leave the client secret empty. - Sign in with your VerifEye account when prompted.
ChatGPT sends a metadata document, so there is no client ID to enter.
A custom MCP connector needs ChatGPT Developer mode, which is available on the Pro, Plus, Business, Enterprise and Education plans on the web — not the Free plan. Turn it on first in Settings → Security and login; see OpenAI's Developer mode guide for the current steps.
- Go to Settings → Plugins → Browse plugins, then click the + button.
- Give it a Name and, under Connection, enter the Server URL:
https://verifeye-mcp-server.realeyes.ai/mcp - Leave Authentication on OAuth.
- Tick I understand and want to continue, then click Create.
- Sign in with your VerifEye account when prompted.
VS Code sends a metadata document, so there is no client ID to enter.
Or add .vscode/mcp.json to your project root:
{
"servers": {
"verifeye": { "type": "http", "url": "https://verifeye-mcp-server.realeyes.ai/mcp" }
}
}
Start the server from the MCP: List Servers command, then sign in when the browser opens.
Cursor's client ID goes under auth: verifeye-mcp-cursor.
Or add to ~/.cursor/mcp.json:
{
"mcpServers": {
"verifeye": {
"url": "https://verifeye-mcp-server.realeyes.ai/mcp",
"auth": { "CLIENT_ID": "verifeye-mcp-cursor" }
}
}
}
Restart Cursor if the server does not appear or the sign-in does not complete — Cursor picks a fixed callback port, and a stale one can leave it stuck.
The Gemini CLI's client ID goes under oauth: verifeye-mcp-gemini. By default it takes whatever loopback port the operating system hands it, which would match nothing registered here, so redirectUri below pins it to 7777 — keep it as shown. The authProviderType: dynamic_discovery below selects OAuth endpoint discovery — it does not mean the self-registration this server lacks. Add to ~/.gemini/settings.json, merging with any keys already there:
{
"mcpServers": {
"verifeye": {
"httpUrl": "https://verifeye-mcp-server.realeyes.ai/mcp",
"authProviderType": "dynamic_discovery",
"oauth": {
"clientId": "verifeye-mcp-gemini",
"redirectUri": "http://localhost:7777/oauth/callback",
"scopes": ["verifeye"]
}
}
}
}
- Run
/mcp auth verifeyeand sign in. - Run
/mcp— the VerifEye tools are listed.
The Codex desktop app uses your ChatGPT connectors. Add VerifEye once as a custom connector — the same steps as the ChatGPT tab above, and ChatGPT Developer mode is required — and it then appears in Codex under Apps, ready to call.
Do not add it from Codex's own MCPs → Add server list: that Authenticate step does not complete. Use the connector.
Providing the image
The tool takes the image as a public URL. The URL is passed through to the VerifEye Face API, which fetches the image itself — the MCP server never downloads it. The tool does not accept the image inline as base64. Inline base64 would mean the assistant writing the encoded image out token by token, which for any image large enough to be usable costs far more time and quota than fetching a URL.
This has one practical consequence: an image attached to the conversation cannot be passed to the tool. The assistant can see such an image but cannot hand the bytes to the tool as an argument. Put the image somewhere reachable and give the assistant that link. Prefer an object-storage pre-signed link that expires in minutes; a durably public URL works too, and exposes the face for as long as it is there. Where the client can reach the internet itself, it can upload the image instead — see If you have no URL: upload the image below.
For a usable result the image should also meet the image requirements: an RGB JPEG or PNG, 300x300 to 2000x2000 pixels and 50–2000 KB, with the face centered, upright, at least 150x150 pixels, and covering 20–80% of the frame.
If you have no URL: upload the image
Where the server offers verifeye_get_upload_url, a client can upload the image instead. The tool hands back a short-lived form, the client posts the file to VerifEye storage, and the analysis then takes the returned uploadId in place of imageUrl — see
This needs a client that can make an outbound HTTPS request of its own, and many cannot. An assistant that runs your tools inside a locked-down sandbox — a browser-based assistant, or a desktop app that runs commands in a container with no egress — does not reach storage at all, and fails with a DNS or connection error rather than a VerifEye one. A command-line client on your own machine has no such limit. A public URL works in both, which is why it stays the path to reach for first.
Consent and retention are your responsibility
This tool processes facial (biometric) data. You are responsible for obtaining valid, informed consent for that processing before a call runs, and for meeting the requirements of the privacy and biometric-data regulations that apply to the people in your images (e.g. GDPR, BIPA, CCPA). See the Realeyes Privacy Policy.
Two things follow from the image having to be reachable, and they are specific to this tool:
- Prefer a short-lived pre-signed link to a durably public URL. Publishing a face at a stable address exposes it to anyone who finds the address, for as long as it is there. A link that expires in minutes does not.
- Remove the image once the call has returned. VerifEye does not store it, and neither should the place you put it for the one call that needed it.
Available tools
verifeye_identify_face
Analyzes the face(s) in an image and returns the attributes you ask for — apparent age, apparent gender, momentary emotions and momentary attention — from a single VerifEye Face API Identify call. Age and gender are on by default. Emotions and attention are off by default and add a surcharge on every face the call answers about — a fraction of what that face already costs, not a second charge: requesting either emotions or attention applies it, and requesting both does not apply it twice. Turn them on only when you need them.
Input parameters:
Enable at least one of age, gender, emotions or attention — a call with all four turned off is rejected.
Result:
Only the attributes you request are included; age, gender, emotions and attention are each omitted when their flag is off.
{
"region": "eu",
"faces": [
{
"faceIndex": 0,
"faceConfidence": 0.999,
"age": { "estimatedAge": 27.5, "uncertainty": 0.2, "reliable": true },
"gender": "Female",
"emotions": { "present": ["happiness"], "undetermined": ["empathy"] },
"attention": { "present": ["presence", "eyesOnScreen"], "undetermined": [] }
}
],
"unprocessedFaceCount": 0
}
A face the Face API cannot answer for with sufficient confidence has no entry in faces at all, and is not counted in unprocessedFaceCount — so faces can hold fewer entries than the image holds faces even when unprocessedFaceCount is 0. See Face detection restrictions.
The result carries no position: there is no bounding box, and faceIndex is only an ordinal into the faces array. With maxFaces above 1 you therefore cannot tell which answer belongs to which person on the image. Call Identify directly if you need that — it returns faces[].face.boundingBox.
Absent versus undetermined
These are two different answers and the result keeps them apart.
An absent attribute was not analyzed. Either you did not request it, or the model that owns it had nothing to report for this face. The tool does not distinguish those two, and neither does the VerifEye Face API underneath it: in both cases the attribute is simply not there.
A signal named in a present group's undetermined list is the opposite claim: the analysis ran, and
could not decide that one signal. So "emotions": {"present": ["happiness"], "undetermined": ["surprise"]}
means surprise was looked for and could not be told, while no emotions key at all means nothing was
looked for. Do not treat a missing attribute as a set of undetermined signals.
Reading emotions and attention
emotions covers confusion, contempt, disgust, happiness, empathy and surprise; attention covers presence, eyesOnScreen and attention. Each is a momentary, single-frame observation — not a score, percentage or intensity. A signal appears under present when it was observed and under undetermined when it could not be determined reliably; a signal in neither list was looked for and determined not to be present on this frame — that is the "no". None of the three is a lasting emotional state.
verifeye_get_upload_url
Hands back a short-lived form for uploading one image to VerifEye storage, for a client that has an image but nowhere public to put it. It is registered only where the server serves uploads: a client that does not see it in tools/list has to supply a URL.
Input parameters:
Result:
Sending the image: one multipart/form-data POST to uploadUrl, with every entry of fields first, in the order returned, and the file last in a part named file. Storage refuses the upload if a field is missing, altered or sent after the file. The accepted size, 1–2000 KB, is inside the form's signature, so an over-size image is refused at ingress rather than after it is stored.
Then call verifeye_identify_face with uploadId instead of imageUrl; supplying both is rejected. The image is deleted the moment that analysis returns, so an uploadId is good for one call.
uploadUrl and fields together are a signed grant to write into VerifEye storage. Send them inline on the request that does the upload — do not save them to a file, and do not repeat them back into the conversation. Nothing needs them again: the analysis takes uploadId, which is only an identifier.
Under the hood
The tool wraps the VerifEye Face API's Identify operation, which analyzes a face without enrolling or storing it. Identify requires a collection to run against, so the first time your account calls the tool the server automatically creates a default collection named mcp-default-collection for you (a one-off, behind-the-scenes step). Because the tool only ever calls Identify, that collection stays empty — no face from an MCP call is added to it — and the Face API retains nothing of the image it analyzed. This is purely a technical detail of how the tool talks to the Face API; you never name or manage the collection yourself.
Notes & limitations
- Estimates, not legal proof. Age is an apparent-age estimate, not a legal proof of age; gender is a demographic estimate, not a self-declared identity attribute.
- Emotions and attention are momentary. Single-frame yes/no observations, never scores — see
Reading emotions and attention . - Honor the
reliableflag. For age, treat the result as unreliable whenreliableisfalse(the model's uncertainty exceeds 1.0). If the flag is absent there was nothing to judge the estimate by, so do not read that as reliable. - Images. JPEG or PNG only, supplied as a publicly reachable URL, or uploaded with
verifeye_get_upload_urlwhere the client can reach storage — seeProviding the image . Up to 4 faces per call; extra detected faces are reported inunprocessedFaceCount. - Region & residency.
region(eu/us) selects where the image is processed. Your account must be authorized in the chosen region. - Usage. Tool calls run as your VerifEye account and count against your account's usage limits. A call is charged per face it answers about, and a call that finds no face still counts as one, because the detector ran.
emotionsandattentionare an add-on: they do not add a second charge, they surcharge those same faces at the rate in your plan. Requesting either applies it; requesting both does not apply it twice.
Additional Resources
- Model Context Protocol specification — the open protocol the server implements.
- VerifEye Face API — the API the tool wraps; call Identify with
include.age,include.gender,include.emotionsandinclude.attentionfor the same attributes from your own backend, in the REST response's own shape. - Authentication — API key and bearer-token authentication for the REST APIs.
Last updated: 2026-09-10