X-EGO Human Proof
An MCP server that lets AI agents verify there is a real, present human on the other end — using passkeys and short-lived, EdDSA-signed proofs. No accounts, no personal data, no cross-service tracking.
What it is.
X-EGO Human Proof exposes the X-EGO proof-of-human verification as tools for AI agents over the Model Context Protocol (MCP). It gives any MCP-capable agent three tools: request a verification link for a user, verify the signed proof the user brings back, and check whether a returning user has been seen before.
The human side of the flow is a Planetary ID — a digital identity bound
to a person by their passkey (fingerprint or Face ID, WebAuthn). The human verifies
on x-ego.com/verify; their biometrics never leave their device.
What it proves: a person with a registered passkey, who paid for their ID, approved this verification — now, for your service specifically.
What it doesn't prove: global uniqueness. Sybil resistance is cost-bounded: one identity, one payment.
Endpoints
Three tools, one loop.
1 · xego_request_proof_url
Returns the URL the agent sends a human user to, so they can prove they are human. The user verifies on the page with their passkey and receives a short-lived signed token (JWT), which they hand back to the agent. This tool performs no verification itself — it only prepares the link. No personal data is transferred.
| Argument | Description |
|---|---|
| audience | Required. The domain of the service requesting verification (e.g. forum.example.com). A URL is accepted too — it is always normalized to a bare lowercase hostname (max 253 chars). It determines who the proof will be valid for. |
Returns: verification_url (link for the user),
audience (the normalized hostname — pass this exact value as
expected_audience to xego_verify_proof), and
instructions. A non-normalizable audience returns
invalid_audience.
2 · xego_verify_proof
Verifies the token (JWT) the user brought back. It cryptographically checks the Ed25519 signature against the X-EGO public keys, validates the claims, the expiry, and the audience. A valid result means: there is a verified human on the other end who holds the passkey.
Paid tool: $0.05 per call in USDC via the x402 protocol — or free with a pilot operator key. Invalid input is rejected before any payment. See 07 · Pricing.
| Argument | Description |
|---|---|
| token | Required. The JWT obtained by the user after X-EGO verification. Three dot-separated parts. |
| expected_audience | Required. Your own service's domain the token must have been issued for. Domain or URL — normalized to a bare hostname exactly like in xego_request_proof_url. A token issued for a different audience is rejected (wrong_audience). This prevents token reuse across services and preserves pairwise isolation. |
| mark_as_seen | Optional, default false. If true and the token is valid, the pairwise ID is recorded as seen for that audience — useful to immediately guard against repeat use. |
Returns on success: valid: true,
pairwise_id (anonymous ID, stable per user-and-audience),
audience, expires_at (Unix time),
human_verified: true, xego_verified (boolean — the
proof is backed by a paid Planetary ID), and rarity (string or
null — the rarity of the backing ID; low entropy, never the ID
number). When mark_as_seen was requested, marked_seen
(boolean) reports whether the permanent ledger write succeeded.
Onboarding signal: if the signature is valid but the token is
not backed by a paid Planetary ID (xego_verified: false — legacy
tokens), the result additionally carries
status: "planetary_id_required" and a
planetary_id_onboarding object with explanation,
registration_url, and next_step: send the user back to
the same verification URL — the page sells the Planetary ID inline (one-time €3)
and continues the verification automatically after purchase, so the agent just
repeats the flow with the fresh token. A user without any passkey hits the same
inline purchase directly on the verification page, with the audience preserved
end-to-end.
Returns on failure: valid: false with a
machine-readable code and a human-readable reason
(see error codes below).
Proofs are single-use. Verifying the same token twice returns
token_replayed.
3 · xego_check_pairwise_seen_before
Checks whether a given pairwise ID has already been seen within an audience.
It protects against one person acting as multiple different users — multiple
accounts, repeat voting, and similar. Only the pair
(audience, pairwise_id) and the time of first occurrence are recorded.
No personal data.
Paid tool: $0.01 per call in USDC via the x402 protocol — or free with a pilot operator key. Invalid input is rejected before any payment. See 07 · Pricing.
| Argument | Description |
|---|---|
| audience | Required. The service domain being asked about. |
| pairwise_id | Required. The user's pairwise identifier (from the xego_verify_proof result). |
| record_if_new | Optional, default false. If true and the user has not been seen yet, they are recorded immediately — an atomic "is new? then mark" in one call. |
Returns: seen_before (boolean),
first_seen (Unix time or null), recorded_now (boolean).
The ledger is persistent — records survive across sessions.
Protection is per audience — pairwise IDs never link across services, so this
is per-service protection, not a global registry of humans.
From request to proof.
- Agent calls
xego_request_proof_urlwith its service domain asaudienceand receives a verification URL. - Agent sends the URL to the human user.
- User opens
x-ego.com/verify?audience=…, sees exactly which service the proof is being issued for, and approves with their passkey (fingerprint / Face ID). The biometric check happens entirely on their device — WebAuthn with user verification required. A user without a Planetary ID buys one right on the page (one-time €3, Stripe Checkout), sets up their passkey, and the verification continues automatically — the audience is preserved through the whole purchase. - X-EGO validates the passkey assertion and signs a short-lived JWT.
- User copies the token and hands it to the agent. The page shows a live countdown of the token's validity.
- Agent calls
xego_verify_proofwith the token and itsexpected_audience. Optionally it callsxego_check_pairwise_seen_beforeto detect returning users.
Anatomy of a proof.
Proofs are JWTs signed with EdDSA (Ed25519). The verifier accepts
exclusively alg: EdDSA — a defense against algorithm-confusion and
none attacks. Claims:
| Claim | Meaning |
|---|---|
| iss | The X-EGO issuer. |
| aud | The audience — the bare lowercase hostname of the service the proof was issued for. |
| sub | An anonymous pairwise ID — stable per user-and-audience, different for every audience. |
| origin | The verified WebAuthn origin — taken from the validated client data, never from the request body. |
| iat / exp | Issued-at and expiry. Tokens live 180 seconds. Verification allows 30 s of clock skew. |
| jti | Unique token ID — the basis of single-use replay protection. |
Public keys are published at the JWKS endpoint (Ed25519).
Anonymous by construction.
Each service sees only a pairwise identifier — unique to your service, different for every audience. Two services can never link their users to each other, and no service ever learns the user's Planetary ID number, name, or any personal data — X-EGO stores none of it in the first place.
- Biometrics are processed on-device only (WebAuthn); nothing biometric is ever transmitted.
- The X-EGO database stores only an ID number and an irreversible hash of the passkey credential.
- The seen-users registry records only
(audience, pairwise_id, first_seen).
When verification says no.
| Code | Meaning |
|---|---|
| invalid_audience | The audience could not be normalized to a domain. |
| malformed_token | The token is not a well-formed JWT. |
| unsupported_algorithm | The token is not signed with EdDSA. |
| unknown_key | No JWKS key matches the token's kid. |
| bad_signature | The Ed25519 signature does not verify. |
| expired | The token is past its 180-second lifetime. |
| wrong_issuer | The iss claim is not X-EGO. |
| wrong_audience | The token was issued for a different audience than expected_audience. |
| missing_claims | A required claim (sub, aud, exp, jti) is absent. |
| token_replayed | This token has already been verified once. Proofs are single-use — the user must verify again. |
| jwks_unavailable | The public keys could not be fetched from the JWKS endpoint. |
What it costs.
For humans: a Planetary ID costs €3 once and includes unlimited self-verification, forever.
For services and agents: two lanes — pay per call with x402 (no account, no key), or a free pilot operator key.
Per-tool prices (x402 pay-per-call)
| MCP tool | Price per call |
|---|---|
| xego_request_proof_url | Free |
| xego_verify_proof | $0.05 in USDC |
| xego_check_pairwise_seen_before | $0.01 in USDC |
Paid calls settle through the x402 payment protocol (v2). Calling a paid
tool without payment returns an error whose _meta["x402/error"] carries the
payment requirements (accepts) and step-by-step instructions; official x402
clients pay and retry automatically. Payment settles before the tool runs, and
one payment authorizes exactly one execution — it cannot be reused. Invalid input
(bad audience, malformed token, server-side ledger misconfiguration) is rejected for
free, before any payment is taken.
Payments run on Base mainnet USDC (eip155:8453).
Anonymous callers are rate-limited to 30 requests per minute per IP.
Pilot operator lane (free)
Registered pilot operators send their key as an
Authorization: Bearer <key> HTTP header and call the paid tools
free of charge during the pilot. Operator traffic is rate-limited to
300 requests per minute per key; no aggregate quota is currently enforced. Usage is
metered per operator and endpoint — operators can read their own counters at
GET /stats with the same key. Keys are issued manually — get in touch.
Connect an agent.
Add the MCP endpoint as a connector in any MCP-capable client. In Claude: Settings → Connectors → Add custom connector, then paste the endpoint URL:
https://mcp.x-ego.com/mcp
The three tools appear automatically. A minimal integration is three calls:
1. xego_request_proof_url({ audience: "your-domain.com" })
2. — user verifies at the returned URL and brings back a token —
3. xego_verify_proof({ token, expected_audience: "your-domain.com",
mark_as_seen: true })