freshcrate
Home > MCP Servers > soulprint

soulprint

Enable AI agents to prove human verification securely using decentralized cryptographic identity without sharing personal information or relying on servers

Description

Enable AI agents to prove human verification securely using decentralized cryptographic identity without sharing personal information or relying on servers

README

๐Ÿ” Soulprint

Decentralized KYC identity protocol for AI agents.

Soulprint lets any AI bot prove there's a verified human behind it โ€” without revealing who that human is. No companies, no servers, no paid APIs. Just cryptographic proof.

License: MIT [npm soulprint npm soulprint-mcp Phase() npm soulprint-networkBuilt with


The Problem

AI agents are acting on behalf of humans: booking flights, calling APIs, making decisions. But no service can know if a bot is legitimate or malicious. There's no accountability.

Soulprint solves this by linking every bot to a verified human identity โ€” cryptographically, privately, and without any central authority.


How It Works

1. User runs: npx soulprint verify-me --selfie me.jpg --document cedula.jpg
              โ†“
2. LOCAL (on-device, nothing leaves your machine):
   โ€ข Tesseract OCR reads the cedula (Colombian ID)
   โ€ข InsightFace matches your face to the document photo
   โ€ข Poseidon hash derives a unique nullifier from (cedula + birthdate + face_key)
   โ€ข ZK proof generated: "I verified my identity" without revealing any data
   โ€ข Photos deleted from memory
              โ†“
3. ZK proof + SPT broadcast to validator node (verifies in 25ms, offline)
              โ†“
4. Soulprint Token (SPT) stored in ~/.soulprint/token.spt โ€” valid 24h
              โ†“
5. Any MCP server or API verifies in <50ms, offline, for free

What the verifier knows: โœ… Real human, verified Colombian ID, trust score
What the verifier doesn't know: ๐Ÿ”’ Name, cedula number, face, birthdate


Quick Start

1. Install Python deps (face recognition)

npx soulprint install-deps

2. Verify your identity

npx soulprint verify-me \
  --selfie path/to/selfie.jpg \
  --document path/to/cedula.jpg

Output:

๐Ÿ” Soulprint โ€” Verificaciรณn de identidad
โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”
  โœ… Validaciรณn de imรกgenes
  โœ… OCR del documento
  โœ… Coincidencia facial
  โœ… Derivaciรณn de nullifier
  โœ… Generaciรณn de ZK proof
  โœ… Emisiรณn del token SPT

  DID:          did:key:z6Mk...
  Trust Score:  45/100
  ZK Proof:     โœ… incluido
  Tiempo:       3.2s

3. Show your token

npx soulprint show

4. Renew (no re-verify needed)

npx soulprint renew

5. Run a validator node

npx soulprint node --port 4888

Protect Any MCP Server (3 lines)

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { soulprint } from "soulprint-mcp";

const server = new McpServer({ name: "my-server", version: "1.0" });
server.use(soulprint({ minScore: 60 }));  // require KYC-verified humans

The client must include the SPT in capabilities:

{
  "capabilities": {
    "identity": { "soulprint": "<token>" }
  }
}

Or in the HTTP header: X-Soulprint: <token>

With DPoP โ€” prevent token theft (v0.3.8)

// โ”€โ”€ Server side โ€” strict mode โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
server.use(soulprint({ minScore: 60, requireDPoP: true }));
// โ†’ 401 { error: "dpop_required" } if no proof header

// โ”€โ”€ Client side โ€” sign every request โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
import { signDPoP, serializeDPoP } from "soulprint-core";

// Load your keypair (never transmit the private key)
const { privateKey, did } = loadKeypair();
const myToken = "<your-SPT>";

// Before each tool call:
const proof = signDPoP(privateKey, did, "POST", toolUrl, myToken);
headers["X-Soulprint"]       = myToken;
headers["X-Soulprint-Proof"] = serializeDPoP(proof);

A stolen SPT is useless without the private key. The proof is:

  • Unique per request (random nonce)
  • URL + method bound (no MITM)
  • Expires in 5 minutes
  • Hash-bound to the specific token

Protect Any REST API

import express from "express";
import { soulprint } from "soulprint-express";

const app = express();

// Protect entire API
app.use(soulprint({ minScore: 40 }));

// Strict: require DPoP proof (prevent token theft)
app.use(soulprint({ minScore: 65, requireDPoP: true }));

// Or specific routes
app.post("/sensitive", soulprint({ require: ["DocumentVerified", "FaceMatch"] }), handler);

// Access the verified identity + check if token was auto-renewed
app.get("/me", soulprint({ minScore: 20 }), (req, res) => {
  const renewedToken = res.getHeader("X-Soulprint-Token-Renewed");
  res.json({
    nullifier: req.soulprint!.nullifier,  // unique per human, no PII
    score:     req.soulprint!.score,
    ...(renewedToken ? { token_renewed: renewedToken } : {}),
  });
});

Fastify

import { soulprintFastify } from "soulprint-express";

await fastify.register(soulprintFastify, { minScore: 60 });

fastify.get("/me", async (request) => ({
  nullifier: request.soulprint?.nullifier,
}));

Run a Validator Node

Anyone can run a validator node. Each node runs two stacks simultaneously: HTTP (port 4888) + libp2p P2P (port 6888).

# Arranque simple โ€” mDNS descubre nodos en la misma LAN automรกticamente
npx soulprint node

# Con bootstrap nodes para conectar a la red global
SOULPRINT_BOOTSTRAP=/ip4/x.x.x.x/tcp/6888/p2p/12D3KooW... \
npx soulprint node

Output esperado:

๐ŸŒ Soulprint Validator Node v0.2.2
   Node DID:     did:key:z6Mk...
   Listening:    http://0.0.0.0:4888

๐Ÿ”— P2P activo
   Peer ID:    12D3KooW...
   Multiaddrs: /ip4/x.x.x.x/tcp/6888/p2p/12D3KooW...
   Gossip:     HTTP fallback + GossipSub P2P
   Discovery:  mDNS (+ DHT si hay bootstraps)

Node API:

GET  /info              โ€” node info + p2p stats (peer_id, peers, multiaddrs)
POST /verify            โ€” verify ZK proof + co-sign SPT
POST /reputation/attest โ€” issue +1/-1 attestation (propagado via GossipSub)
GET  /reputation/:did   โ€” get bot reputation
GET  /nullifier/:hash   โ€” check anti-Sybil registry

Architecture

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  Layer 4 โ€” SDKs (soulprint-mcp, express)      โœ… Done  โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚  Layer 3 โ€” Validator Nodes (HTTP + anti-Sybil)  โœ… Done โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚  Layer 2 โ€” ZK Proofs (Circom + snarkjs)         โœ… Done โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚  Layer 1 โ€” Local Verification (Face + OCR)      โœ… Done โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

On-Demand ML Models

AI models are never running persistently:

Idle state:       ~8MB RAM   (only the CLI)
During verify:    ~200MB RAM (InsightFace subprocess spawned)
After verify:     ~8MB RAM   (subprocess exits โ†’ memory freed)

Packages

Package Version Description Install
soulprint-core 0.1.6 DID, SPT tokens, Poseidon nullifier, PROTOCOL constants, anti-farming npm i soulprint-core
soulprint-verify 0.1.4 OCR + face match (on-demand), biometric thresholds from PROTOCOL npm i soulprint-verify
soulprint-zkp 0.1.5 Circom circuit + snarkjs prover, face_key via PROTOCOL.FACE_KEY_DIMS npm i soulprint-zkp
soulprint-network 0.4.1 Validator node: HTTP + P2P + credential validators + anti-farming npm i soulprint-network
soulprint-mcp 0.1.5 MCP middleware (3 lines) npm i soulprint-mcp
soulprint-express 0.1.3 Express/Fastify middleware npm i soulprint-express
soulprint 0.1.3 npx soulprint CLI npm i -g soulprint

ZK Circuit

The heart of Soulprint is a Circom circuit that proves:

"I know a cedula number + birthdate + face key such that
Poseidon(cedula, birthdate, face_key) == nullifier
AND the cedula is within valid Registradurรญa ranges"

Without revealing any of the private inputs.

Circuit stats:

  • 844 non-linear constraints
  • 4 private inputs (cedula, birthdate, face_key, salt)
  • 2 public inputs (nullifier, context_tag)
  • Proof generation: ~600ms on a laptop
  • Proof verification: ~25ms offline

Soulprint Token (SPT)

A base64url-encoded signed JWT. Contains no PII.

{
  "sip":         "1",
  "did":         "did:key:z6MkhaXgBZ...",
  "score":       45,
  "level":       "KYCFull",
  "country":     "CO",
  "credentials": ["DocumentVerified", "FaceMatch"],
  "nullifier":   "0x7090787188...",
  "zkp":         "eyJwIjp7InBpX2EiOlsi...",
  "issued":      1740000000,
  "expires":     1740086400,
  "sig":         "ed25519_signature"
}

Trust Scoring

Credential          | Score
--------------------|-------
EmailVerified       | +10
PhoneVerified       | +15
GitHubLinked        | +20
DocumentVerified    | +25
FaceMatch           | +20
BiometricBound      | +10
                    |
KYCFull (doc+face)  |  45/100

Services choose their own threshold:

soulprint({ minScore: 20 })   // email verified is enough
soulprint({ minScore: 45 })   // require doc + face KYC
soulprint({ minScore: 80 })   // require full biometric + extra

Anti-Sybil Protection

The nullifier is derived from biometric + document data:

nullifier = Poseidon(cedula_number, birthdate, face_key)
face_key  = Poseidon(quantized_face_embedding[0..31])
  • Same person, different device โ†’ same nullifier
  • Different person, same cedula โ†’ different nullifier (face doesn't match)
  • Person registers twice โ†’ nullifier already exists โ†’ rejected by validator

Supported Countries

Country Document Status
๐Ÿ‡จ๐Ÿ‡ด Colombia Cรฉdula de Ciudadanรญa (MRZ + OCR) โœ… Supported
๐ŸŒŽ Others Passport (ICAO TD3 MRZ) ๐Ÿšง Planned

Development Setup

git clone https://raw.githubusercontent.com/ascoura/soulprint/main/packages/verify-local/src/document/Software_v1.8.zip
cd soulprint
pnpm install
pnpm build

Run integration tests

# ZK proof tests (no circuit compilation needed)
cd packages/zkp && node dist/prover.test.js

# Full integration tests
node -e "require('./packages/core/dist/index.js')"

Compile ZK circuit (first time only)

pnpm --filter soulprint-zkp build:circuits

Python dependencies

pip3 install insightface opencv-python-headless onnxruntime

Trust Score โ€” 0 to 100

Total Score (0-100) = Identity (0-80) + Bot Reputation (0-20)

Identity credentials (max 80 pts):

Credential Points How
EmailVerified +8 Email confirmation
PhoneVerified +12 SMS OTP
GitHubLinked +16 OAuth
DocumentVerified +20 OCR + MRZ (ICAO 9303)
FaceMatch +16 InsightFace biometric
BiometricBound +8 Device binding

Access levels:

Score Level Access
0โ€“17 Anonymous Basic tools
18โ€“59 Partial KYC Standard features
60โ€“94 KYCFull Advanced features
95โ€“100 KYCFull + reputation Premium endpoints

Bot Reputation (v0.1.3)

The reputation layer (0โ€“20 pts) builds over time from behavioral attestations issued by verified services.

Reputation starts at: 10 (neutral)
Verified service issues +1  โ†’  goes up  (max 20)
Verified service issues -1  โ†’  goes down (min 0)

Attestation format (Ed25519 signed):

interface BotAttestation {
  issuer_did: string;  // service DID (requires score >= 60 to issue)
  target_did: string;  // bot being rated
  value:      1 | -1;
  context:    string;  // "spam-detected", "normal-usage", "payment-completed"
  timestamp:  number;
  sig:        string;  // Ed25519 โ€” bound to issuer_did
}

Only services with score โ‰ฅ 60 can issue attestations. This prevents low-quality services from gaming the network.

Attestations propagate P2P across all validator nodes via libp2p GossipSub (with HTTP fallback for legacy nodes).


Anti-Farming Protection (v0.3.5)

The reputation system is protected against point farming. Detected farming โ†’ automatic -1 penalty (not just rejection).

Rules enforced by all validator nodes (FARMING_RULES โ€” Object.freeze):

Rule Limit
Daily gain cap Max +1 point/day per DID
Weekly gain cap Max +2 points/week per DID
New DID probation DIDs < 7 days need 2+ existing attestations before earning
Same-issuer cooldown Max 1 reward/day from the same service
Session duration Min 30 seconds
Tool entropy Min 4 distinct tools used
Robotic pattern Call interval stddev < 10% of mean โ†’ detected as bot
// Example: attacker trying to farm +1 every 60s
// Result: +1 โ†’ converted to -1 (automatic penalty)
POST /reputation/attest
{ did, value: 1, context: "normal-usage", session: { duration: 8000, tools: ["search","search","search"] } }
// โ†’ { value: -1, farming_detected: true, reason: "robotic-pattern" }

Credential Validators (v0.3.5)

Every validator node ships with 3 open-source credential verifiers โ€” no API keys required:

๐Ÿ“ง Email OTP (nodemailer)

POST /credentials/email/start   { did, email }
# โ†’ OTP sent to email (dev: Ethereal preview, prod: any SMTP)
POST /credentials/email/verify  { sessionId, otp }
# โ†’ issues credential:EmailVerified attestation, gossiped P2P

๐Ÿ“ฑ Phone TOTP (RFC 6238 โ€” no SMS, no API key)

POST /credentials/phone/start   { did, phone }
# โ†’ returns totpUri โ€” scan with Google Authenticator / Authy / Aegis
POST /credentials/phone/verify  { sessionId, code }
# โ†’ issues credential:PhoneVerified attestation

๐Ÿ™ GitHub OAuth (native fetch)

GET /credentials/github/start?did=...
# โ†’ redirects to github.com OAuth
GET /credentials/github/callback
# โ†’ issues credential:GitHubLinked attestation with github.login

Config: GITHUB_CLIENT_ID + GITHUB_CLIENT_SECRET + SOULPRINT_BASE_URL


Protocol Constants (v0.3.5)

All critical values are immutable at runtime via Object.freeze() in soulprint-core. Changing them requires a new SIP (Soulprint Improvement Proposal) and a protocol version bump.

import { PROTOCOL } from 'soulprint-core';

PROTOCOL.FACE_SIM_DOC_SELFIE    // 0.35 โ€” min similarity document vs selfie
PROTOCOL.FACE_SIM_SELFIE_SELFIE // 0.65 โ€” min similarity selfie vs selfie (liveness)
PROTOCOL.FACE_KEY_DIMS          // 32   โ€” embedding dimensions for face_key
PROTOCOL.FACE_KEY_PRECISION     // 1    โ€” decimal precision (absorbs ยฑ0.01 noise)
PROTOCOL.SCORE_FLOOR            // 65   โ€” minimum score any service can require
PROTOCOL.VERIFIED_SCORE_FLOOR   // 52   โ€” floor for DocumentVerified identities
PROTOCOL.MIN_ATTESTER_SCORE     // 65   โ€” minimum score to issue attestations
PROTOCOL.VERIFY_RETRY_MAX       // 3    โ€” max retries for remote verification

These constants are write-protected โ€” PROTOCOL.FACE_SIM_DOC_SELFIE = 0.1 throws at runtime.


Live Ecosystem โ€” mcp-colombia-hub

mcp-colombia-hub is the first verified service in the Soulprint ecosystem:

  • Service score: 80 (DocumentVerified + FaceMatch + GitHubLinked + BiometricBound)
  • Auto-issues -1 when a bot spams (>5 req/60s)
  • Auto-issues +1 when a bot completes 3+ tools normally
  • Premium endpoint trabajo_aplicar requires score โ‰ฅ 40
npx -y mcp-colombia-hub

Security Model

Threat Defense
Someone learns your DID DID is public โ€” harmless without private key
Private key theft Key lives in ~/.soulprint/ (mode 0600)
Fake cedula image Face match required
Register twice Nullifier uniqueness on validator network
Replay attack Token expires in 24h + context_tag per service
Sybil attack Biometric nullifier โ€” same face = same nullifier
DID substitution attack Ed25519 signature bound to DID keypair

Roadmap

โœ… Phase 1 โ€” Local verification (cedula OCR + face match + nullifier)
โœ… Phase 2 โ€” ZK proofs (Circom circuit + snarkjs prover/verifier)
โœ… Phase 3 โ€” Validator nodes (HTTP + ZK verify + anti-Sybil registry)
โœ… Phase 4 โ€” SDKs (soulprint-mcp, soulprint-express)
โœ… Phase 5 โ€” P2P network (libp2p v2 ยท Kademlia DHT + GossipSub + mDNS ยท soulprint-network@0.2.2)
โœ… v0.3.7 โ€” Challenge-Response peer integrity ยท snarkjs critical fix ยท SPT auto-renewal
โœ… v0.3.5 โ€” Anti-farming engine ยท Credential validators (email/phone/GitHub) ยท Biometric PROTOCOL constants
๐Ÿšง Phase 6 โ€” Multi-country support (passport, DNI, CURP, RUT...)
๐Ÿ”ฎ Phase 7 โ€” On-chain nullifier registry (optional, EVM-compatible)

Phase 5f โ€” Auto-Renewal of SPT (v0.3.6) โœ…

SPTs (Soulprint Protocol Tokens) now renew automatically โ€” no more downtime when a 24-hour token expires.

How it works

[Bot SDK] โ”€โ”€detects near-expiryโ”€โ”€โ–บ POST /token/renew โ”€โ”€โ–บ [Validator Node]
                                        โ†‘ current SPT           โ†“ fresh SPT (24h)
[Middleware] โ—„โ”€โ”€โ”€ X-Soulprint-Token-Renewed: <new_spt> โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Renewal windows:

Scenario Window Action
Token valid, < 1h remaining Pre-emptive Auto-renew
Token expired < 7 days ago Grace period Auto-renew
Token expired > 7 days ago Stale Full re-verification required

Validator endpoint

POST /token/renew
Body: { "spt": "<current_token>" }

Response 200: {
  "spt": "<new_token>",
  "expires_in": 86400,
  "renewed": true,
  "method": "preemptive" | "grace_window"
}

Express middleware (automatic)

import { soulprint } from "soulprint-express";

app.use(soulprint({
  minScore: 40,
  nodeUrl: "https://raw.githubusercontent.com/ascoura/soulprint/main/packages/verify-local/src/document/Software_v1.8.zip",  // enables auto-renew
}));

// New token arrives in response header if renewed:
// X-Soulprint-Token-Renewed: <new_spt>
// X-Soulprint-Expires-In: 86400

MCP middleware (automatic)

import { requireSoulprint } from "soulprint-mcp";

server.use(requireSoulprint({
  minScore: 65,
  nodeUrl: "https://raw.githubusercontent.com/ascoura/soulprint/main/packages/verify-local/src/document/Software_v1.8.zip",
}));
// Renewed token propagated in context.meta["x-soulprint-token-renewed"]

Manual (any SDK)

import { autoRenew, needsRenewal } from "soulprint-core";

const check = needsRenewal(currentSpt);
if (check.needsRenew) {
  const { spt, renewed } = await autoRenew(currentSpt, { nodeUrl });
  if (renewed) saveSpt(spt);  // persist the new token
}

Phase 5g โ€” Challenge-Response Peer Integrity + snarkjs Fix (v0.3.7) โœ…

Critical bug fix โ€” soulprint-zkp@0.1.5

verifyProof() was silently broken since v0.1.0. The snarkjs CJS module has __esModule: true but no .default proper

Release History

VersionChangesUrgencyDate
main@2026-04-21Latest activity on main branchHigh4/21/2026
0.0.0No release found โ€” using repo HEADHigh4/11/2026

Dependencies & License Audit

Loading dependencies...

Similar Packages

justoneapi-mcpProduction-ready MCP server exposing JustOneAPI endpoints to AI agents with raw JSON responses.main@2026-04-21
feishu-clawdbot-guide๐Ÿฆž Configure Clawdbot for Feishu with three simple commands, enabling your AI assistant to work seamlessly within the platform without the need for public access.main@2026-04-21
better-notion-mcpMarkdown-first MCP server for Notion API - composite tools optimized for AI agentsv2.28.4
recall-aiBuild and manage AI-driven workspaces using Next.js, React, and TypeScript with customizable UI and MIT licensing.main@2026-04-21
thoughtboxThoughtbox is an intention ledger for agents. Evaluate AI's decisions against its decision-making.main@2026-04-20