Skip to main content
Glama

proofport-ai

Agent-native ZK proof infrastructure for ZKProofport, with a TEE-based proving architecture, SDK and local MCP package. Supported Nitro deployments encrypt inputs to the enclave; encryption and hardware-attestation guarantees depend on the selected endpoint and actual returned evidence. GIWA exact-action authorization remains EXPERIMENTAL on GIWA Sepolia (91342).

Architecture

The following diagram describes the Nitro deployment. Endpoints without an attested enclave key receive readable inputs over HTTPS; the current GCP Cloud Run deployments use that mode and do not supply hardware attestation. A valid proof alone is not evidence of enclave execution.

Client (AI Agent / SDK)
  │
  │  1. POST /api/v1/prove  →  402 { nonce, price, teePublicKey }
  │  2. Sign EIP-3009 USDC payment
  │  3. Encrypt inputs with TEE X25519 public key (ECIES)
  │  4. POST /api/v1/prove + X-Payment-TX + X-Payment-Nonce + encrypted_payload
  │
  ▼
┌─────────────────────────────────────┐
│  Node.js Server (port 4002)        │
│  ─ Verify USDC payment on-chain    │
│  ─ Blind relay: pass encrypted     │
│    payload to enclave via vsock     │
│  ─ Return proof + TEE attestation  │
└────────────┬────────────────────────┘
             │ vsock
             ▼
┌─────────────────────────────────────┐
│  AWS Nitro Enclave                  │
│  ─ X25519 key pair (bound to NSM)  │
│  ─ Decrypt inputs (AES-256-GCM)    │
│  ─ bb prove (Barretenberg CLI)     │
│  ─ NSM attestation of proof hash   │
└─────────────────────────────────────┘

Key properties:

  • E2E encryption — X25519 ECDH + AES-256-GCM. In nitro mode, plaintext inputs are rejected.

  • Blind relay in Nitro mode — The host forwards enclave-encrypted inputs. This property does not apply to an endpoint accepting plaintext circuit inputs.

  • x402 payment — Single-step flow: 402 challenge → USDC payment → proof generation. No middleware.

  • Hardware attestation in Nitro mode — An actual validated NSM document binds the TEE key to enclave measurements (PCRs); do not infer it from proof validity.

Related MCP server: AgentStamp

Directory Structure

proofport-ai/
├── src/
│   ├── index.ts                  # Express server entry (port 4002)
│   ├── logger.ts                 # Pino logger
│   ├── swagger.ts                # OpenAPI spec
│   ├── tracing.ts                # OpenTelemetry tracing
│   ├── a2a/
│   │   ├── agentCard.ts          # /.well-known/agent.json, agent-card.json
│   │   ├── proofportExecutor.ts  # A2A task executor
│   │   └── redisTaskStore.ts     # Redis-backed task persistence
│   ├── chat/
│   │   ├── geminiClient.ts       # Gemini API client
│   │   ├── llmProvider.ts        # LLM provider interface
│   │   ├── multiProvider.ts      # Multi-provider routing
│   │   └── openaiClient.ts       # OpenAI API client
│   ├── circuit/
│   │   └── artifactManager.ts    # Circuit artifact download/cache
│   ├── config/
│   │   ├── index.ts              # Environment config
│   │   ├── circuits.ts           # Circuit metadata
│   │   └── contracts.ts          # Deployed contract addresses
│   ├── identity/
│   │   ├── agentAuth.ts          # Agent JWT authentication
│   │   ├── autoRegister.ts       # ERC-8004 auto-registration
│   │   ├── register.ts           # Identity registration
│   │   └── reputation.ts         # Reputation management
│   ├── input/
│   │   ├── attestationFetcher.ts # EAS GraphQL attestation fetch
│   │   ├── inputBuilder.ts       # Circuit input construction
│   │   └── merkleTree.ts         # Merkle tree builder
│   ├── mcp/
│   │   ├── server.ts             # StreamableHTTP MCP server
│   │   └── stdio.ts              # stdio MCP server (local use)
│   ├── payment/
│   │   └── freeTier.ts           # Payment mode config
│   ├── proof/
│   │   ├── proofRoutes.ts        # x402 single-step proof API
│   │   ├── guideBuilder.ts       # Dynamic proof generation guide
│   │   ├── paymentVerifier.ts    # On-chain USDC payment verification
│   │   ├── sessionManager.ts     # Proof session/nonce management
│   │   └── types.ts
│   ├── prover/
│   │   ├── bbProver.ts           # bb CLI direct prover
│   │   ├── tomlBuilder.ts        # Prover.toml builder
│   │   └── verifier.ts           # On-chain verification (ethers v6)
│   ├── redis/
│   │   ├── client.ts             # Redis client
│   │   ├── cleanupWorker.ts      # Expired data cleanup
│   │   ├── constants.ts          # Redis key prefixes
│   │   ├── proofCache.ts         # Proof result caching
│   │   ├── proofResultStore.ts   # Proof result persistence
│   │   └── rateLimiter.ts        # Rate limiting
│   ├── skills/
│   │   ├── skillHandler.ts       # Skill routing
│   │   └── flowGuidance.ts       # Step-by-step flow guidance
│   ├── tee/
│   │   ├── index.ts              # TEE mode config
│   │   ├── attestation.ts        # NSM attestation validation (COSE Sign1)
│   │   ├── detect.ts             # TEE environment detection
│   │   ├── enclaveBuilder.ts     # Enclave image builder
│   │   ├── enclaveClient.ts      # Nitro Enclave vsock client
│   │   ├── encryption.ts         # AES-256-GCM encryption utilities
│   │   ├── teeKeyExchange.ts     # X25519 ECDH key exchange
│   │   └── validationSubmitter.ts # TEE validation on-chain
│   └── types/
│       └── index.ts
├── packages/
│   ├── sdk/                      # @zkproofport-ai/sdk (npm)
│   └── mcp/                      # @zkproofport-ai/mcp (npm)
├── aws/
│   ├── enclave-server.ts         # TypeScript TEE prover (Nitro Enclave)
│   ├── Dockerfile.enclave        # Enclave image
│   ├── deploy-blue-green.sh      # Zero-downtime deployment
│   ├── boot-active-slot.sh       # Systemd boot script
│   ├── stop-active-slot.sh       # Systemd stop script
│   ├── build-enclave.sh          # Enclave build helper
│   ├── ec2-setup.sh              # EC2 instance setup
│   ├── Caddyfile                 # Reverse proxy config
│   ├── docker-compose.aws.yml    # AWS Docker Compose
│   ├── vsock-bridge.py           # vsock-to-TCP bridge
│   └── systemd/                  # Systemd service files
├── sign-page/                    # Next.js signing page (WalletConnect)
├── tests/
│   ├── e2e/                      # Full E2E tests (REST, MCP, A2A, proof, verify)
│   ├── a2a/                      # A2A unit tests
│   ├── identity/                 # ERC-8004 identity tests
│   ├── integration/              # Integration tests
│   ├── payment/                  # Payment tests
│   ├── tee/                      # TEE tests
│   └── *.test.ts                 # Unit tests
├── docker-compose.yml            # Local dev: server + redis
├── docker-compose.test.yml       # Test stack: + a2a-ui + Phoenix
├── Dockerfile                    # Node.js server image
└── README.md

Quick Start

npm (Development)

npm install
npm run dev          # Hot reload with tsx
npm run build        # Build TypeScript
npm start            # Production
npm test             # Run tests
npm run test:e2e     # E2E tests against Docker stack

Docker Compose (Local)

docker compose up --build     # Start redis + server
docker compose down           # Stop
docker compose down -v        # Reset data
  • Port 4002: Node.js server

  • Port 6380 (host) → 6379 (container): Redis

E2E Encryption (Blind Relay)

For the supported Nitro deployment, proof inputs are encrypted between the client and the enclave. The host passes the encrypted blob without reading it. This section describes that protocol, not every endpoint.

Protocol: X25519 ECDH + AES-256-GCM (ECIES pattern)

  1. TEE generates X25519 key pair on startup, binds public key to NSM attestation

  2. Client fetches TEE public key from 402 response, verifies attestation

  3. Client generates ephemeral X25519 keypair, computes ECDH shared secret, derives AES key via SHA-256

  4. Client encrypts inputs with AES-256-GCM, sends { ephemeralPublicKey, iv, ciphertext, authTag, keyId }

  5. Server passes encrypted envelope to enclave via vsock (blind relay)

  6. Enclave decrypts, generates proof, returns proof + NSM attestation

Enforcement: In nitro mode, plaintext inputs are rejected with PLAINTEXT_REJECTED.

x402 Payment Flow

The live 402 challenge determines the offered routes, price, asset, recipient and signing domain. Select a compatible wallet and explicit route, obtain user approval, then sign the exact terms and retry the request using the SDK's payment headers. Do not assume every endpoint is free or that every wallet works on every offered chain.

Callers must validate the live offer rather than substitute a documentation price.

Use max_payment: "0.001" and approved_payment in local MCP, or maxPayment and approvedPayment in the SDK. Exact approved terms include network, scheme, amount (USDC base units), asset, payTo and extra: {name, version, verifyingContract}. The SDK rejects a changed fee, recipient, asset, network or signing domain before signing. Proof payment and any application transaction that relies on the proof require separate approvals.

Base and Base Sepolia use Dexter first and PayAI as a backup. --pay-with key and --pay-with cdp still choose the buyer's signing wallet; neither selects the server's facilitator. Provider failover reuses the identical EIP-3009 authorization, including its nonce, amount and recipient. Ethereum direct settlement keeps its own settlement route.

The server tries each configured facilitator at most once for connection failures, timeouts, HTTP 429/5xx or malformed responses. Payment rejections such as insufficient balance, invalid signatures and expired authorizations stop immediately. Before contacting the backup, the server checks the USDC authorization state on the selected chain. A pending settlement or an already consumed authorization is not submitted again. If that state cannot be established, the API reports settlement_unknown; known pending responses report settlement_pending, with a transaction hash when available. These outcomes require reconciliation, not a newly signed payment. This failover does not implement resumption of a proof request after its settlement response was lost. Final on-chain payment verification still runs before proof generation.

REST Endpoints

Endpoint

Method

Purpose

/health

GET

Health check + TEE status + payment mode

/api/v1/prove

POST

x402 single-step proof generation

/api/v1/guide/:circuit

GET

Dynamic proof generation guide (JSON)

/mcp

POST

StreamableHTTP MCP endpoint

/a2a

POST

A2A JSON-RPC endpoint

/.well-known/agent.json

GET

OASF Agent Card

/agent-card.json

GET

A2A Agent Card

/.well-known/mcp.json

GET

MCP discovery

/docs

GET

Swagger UI

/openapi.json

GET

OpenAPI spec

MCP Tools

Remote /mcp and the local npm MCP server have separate tool surfaces. Consult each actual tools/list response. The local package includes:

Tool

Purpose

generate_proof

All-in-one proof generation (x402 payment + E2E encryption auto-detect)

verify_proof

On-chain proof verification

get_supported_circuits

List available circuits

request_challenge

Request 402 challenge (step-by-step flow)

submit_proof

Submit proof inputs (step-by-step flow)

prepare_inputs

Prepare circuit inputs (step-by-step flow)

get_action_approval

Read the state of a human action approval

npm Packages

@zkproofport-ai/sdk   — TypeScript SDK for proof generation (ethers v6)
@zkproofport-ai/mcp   — Local MCP server for AI agents (stdio transport)

Install the MCP server for local AI agent usage:

npm install @zkproofport-ai/mcp@latest @zkproofport-ai/sdk@latest ethers
npx zkproofport-mcp    # Starts stdio MCP server

GIWA optional-action support requires SDK 0.2.14 or later and MCP 0.2.15 or later for the step-by-step input preparation path. MCP 0.2.14 has input-validation bugs in that path; its all-in-one tool delegates to the SDK. Install from npm and check the resolved version. Release Please manages package versions and the release workflow publishes them; repository source changes alone do not update @latest.

Guide System

GET /api/v1/guide/:circuit returns a comprehensive JSON guide for client AI agents to prepare all proof inputs. Includes:

  • Step-by-step instructions with code examples

  • Constants (attester keys, contract addresses, EAS schema UIDs)

  • Formulas (nullifier computation, signal hash, Merkle tree construction)

  • Input schema with types and descriptions

  • EAS GraphQL query templates

Circuits use aliases: coinbase_kyc → coinbase_attestation, coinbase_country → coinbase_country_attestation, oidc_domain → oidc_domain_attestation, human_passport → human_passport_score. giwa_attestation has no alias — it is named canonically or not at all.

A2A Protocol

A2A v0.3 JSON-RPC endpoint at POST /a2a:

Method

Purpose

message/send

Submit proof task (blocking)

message/stream

Submit proof task (SSE streaming)

tasks/get

Query task status

tasks/cancel

Cancel a running task

tasks/resubscribe

Resubscribe to task events

Agent Card at /.well-known/agent.json provides ERC-8004 on-chain identity and capability discovery.

TEE Integration (AWS Nitro Enclave)

Mode

Behavior

disabled

Standard Linux, no TEE, plaintext allowed

nitro

AWS Nitro Enclave, hardware attestation, E2E encryption enforced

The enclave runs aws/enclave-server.ts (compiled to dist/aws/enclave-server.js) which executes bb prove with --oracle_hash keccak (required for Solidity verifier compatibility). NSM attestation binds the proof hash and TEE public key to the enclave measurement (PCR0/PCR1/PCR2).

Attestation validation chain: AWS Nitro Root CA → Regional → Zonal → Instance → Leaf certificate, verified with COSE ES384 signature.

Supported Circuits

Coinbase KYC (coinbase_attestation)

Proves holder has passed Coinbase KYC verification.

  • Aliases: coinbase_kyc, coinbase_attestation

  • Public Inputs: address, scope

  • Nullifier: Yes (privacy, replay prevention)

Coinbase Country (coinbase_country_attestation)

Proves holder's KYC country matches attestation.

  • Aliases: coinbase_country, coinbase_country_attestation

  • Public Inputs: address, country, scope

  • Nullifier: Yes (privacy, replay prevention)

OIDC Domain (oidc_domain_attestation)

Proves holder owns an email address at a specific domain via OIDC JWT verification.

  • Aliases: oidc_domain, oidc_domain_attestation

  • Input type: OIDC JWT (id_token from Google, etc.)

  • Public Inputs: domain hash, scope

  • Nullifier: Yes (privacy, replay prevention)

Human Passport score (human_passport_score)

Proves the wallet holds an unexpired Human Passport score at or above a threshold, without revealing the wallet or the exact score.

  • Aliases: human_passport, human_passport_score

  • Client inputs: the wallet's signed request (or one EIP-712 action), min_score in Passport points and chain, the chain id the score is recorded on (Base, OP Mainnet, Arbitrum One, Linea, Scroll or zkSync Era); the server finds the wallet's score on that chain and refuses, before payment, a wallet with no score there, an expired one or one below the threshold

  • Public Inputs: signal hash / action, issuer root, scope, nullifier, threshold, scorer, time

  • Nullifier: Yes (wallet + circuit tag)

SDK/MCP 0.3.0 introduce a human wallet approval pause for requests containing a GIWA action. The AI service serves /approve/:id: a responsive request page with proof conditions, domain/network details, expandable typed action fields and wallet selection. Ordinary proofs without an action retain the existing flow. See the MCP human-approval instructions and SDK examples.

The service stores ten-minute approval sessions in Redis. Browser and requester capabilities are separate; approval is bound to the original action and consumed once before proof preparation/payment. Build the page with npm run build (included in the Docker image). A2A_BASE_URL must identify the externally reachable AI origin. Set WALLETCONNECT_PROJECT_ID to enable mobile-wallet pairing; browser extensions work without it. Deploy the compatible AI service before clients use the SDK/MCP 0.3.0 approval flow. The shared application SDK remains a separate dependency.

The approval UI ignores repeated, validated wallet state notifications while invalidating signatures on actual account/network changes or disconnects. Its WalletConnect 2.25.0 adapter consumes normalized chain events without echoing raw notifications back as switch commands, avoiding a request-before-provider-initialization race during pairing. Explicit network selection still uses the public provider API. Run the approval workspace tests, browser tests, and a real local wallet approval before deployment when changing this adapter. The modal uses the page's system font stack so AppKit does not preload unused remote font variants.

Contract Addresses

Base Sepolia (Testnet)

Contract

Address

KYC Verifier

0x0036B61dBFaB8f3CfEEF77dD5D45F7EFBFE2035c

Country Verifier

0xdEe363585926c3c28327Efd1eDd01cf4559738cf

ERC-8004 Identity

0x8004A818BFB912233c491871b3d84c89A494BD9e

ERC-8004 Reputation

0x8004B663056A597Dffe9eCcC1965A193B7388713

Base Mainnet (Production)

Contract

Address

ERC-8004 Identity

0x8004A169FB4a3325136EB29fA0ceB6D2e539a432

ERC-8004 Reputation

0x8004BAa17C55a88189AE136b182e5fdA19dE9b63

ERC-8004 Agent Identity

The agent auto-registers on-chain at startup via the ERC-8004 Identity contract. Reputation score increments after each successful proof generation.

Environment Variables

Required

Variable

Description

REDIS_URL

Redis connection string

BASE_RPC_URL

Base chain RPC endpoint

CHAIN_RPC_URL

RPC for proof verification

EAS_GRAPHQL_ENDPOINT

EAS GraphQL endpoint for attestation queries

PROVER_PRIVATE_KEY

Agent wallet private key (64 hex chars, optional 0x); also submits direct payment settlements

PAYMENT_MODE

disabled / testnet / mainnet

A2A_BASE_URL

Public-facing service URL (for Agent Card)

COINBASE_STATEMENT_KMS_KEY

Cloud KMS key version (projects/…/cryptoKeyVersions/N, EC_SIGN_P256_SHA256) that signs coinbase_attestation v2's revocation statement and oidc_domain_attestation's provider-key statement (the token's signing key is in the provider's published key list); both circuits pin its public key. The server refuses to start unless it can read the key. Credentials come from the runtime service account (Cloud Run) or GOOGLE_APPLICATION_CREDENTIALS (local; see docker-compose.kms.yml)

Optional

Variable

Default

Description

PORT

4002

Express server port

WALLETCONNECT_PROJECT_ID

Unset

Public WalletConnect project ID for human action approval; injected wallets remain available when unset

APPROVAL_TRUST_PROXY_HOPS

Unset (proxy trust disabled)

Integer 1–16 for the verified ingress proxy count; scoped to approval creation rate limits

NODE_ENV

development

Node environment

BB_PATH

bb

Barretenberg CLI path

CIRCUITS_DIR

/app/circuits

Circuit artifacts directory

CIRCUITS_REPO_URL

(GitHub raw URL)

Circuit artifacts download URL

TEE_MODE

disabled

disabled / local / nitro; GCP uses local without hardware attestation

ENCLAVE_CID

—

Nitro Enclave CID (required when TEE_MODE=nitro)

ENCLAVE_PORT

5000

Nitro Enclave port

TEE_ATTESTATION

false

Enable attestation verification

PAYMENT_PAY_TO

—

Payment recipient (required when payment enabled); must match the prover wallet when direct settlement is offered

PAYMENT_PROOF_PRICE

$0.10

Price per proof (USD)

X402_FACILITATOR_URL

https://x402.dexter.cash

Primary Base / Base Sepolia facilitator

X402_FALLBACK_FACILITATOR_URL

https://facilitator.payai.network

Backup for the same authorization; empty disables failover

X402_FACILITATOR_TIMEOUT_MS

15000

Per-provider deadline including response body, integer 1–60000 ms

GIWA_RPC_URL, GIWA_EXPLORER_URL

—

GIWA Sepolia input source and proof verification endpoints

ERC8004_IDENTITY_ADDRESS

—

ERC-8004 Identity contract

ERC8004_REPUTATION_ADDRESS

—

ERC-8004 Reputation contract

GEMINI_API_KEY

—

Gemini API key for chat

OPENAI_API_KEY

—

OpenAI API key for chat

PHOENIX_COLLECTOR_ENDPOINT

—

Phoenix OTLP endpoint for tracing

AGENT_VERSION

Server package version

Optional advertised agent version override

Human action approvals expire after ten minutes and retain an authenticated tombstone for five more minutes. Creation allows ten requests per client IP per minute. On Cloud Run, configure APPROVAL_TRUST_PROXY_HOPS only after verifying the ingress proxy count and ensuring requests cannot take a shorter path. With the setting unset, clients behind a proxy share its socket-IP bucket; arbitrary X-Forwarded-For headers are ignored. This setting does not change proxy trust for other service routes. Deployment workflows do not enable it automatically.

Direct payment settlement wallet

PROVER_PRIVATE_KEY is the single operator key for agent identity signing and direct x402 settlement. No separate PAYMENT_SETTLER_PRIVATE_KEY is read. When a configured payment network uses payee settlement, startup checks that the prover key is valid and its address matches PAYMENT_PAY_TO. A mismatch stops startup before the service offers payment. Fund this wallet for transaction gas on each directly settled network. Facilitator settlement does not use this wallet to submit each payment; payment-disabled operation skips this check.

For local paid-path tests, provide PROVER_PRIVATE_KEY and its public address as PAYMENT_PAY_TO in the shell, then run ./scripts/ai-dev.sh --payment. The script uses the same prover key in the server container. scripts/verify-payment.ts also uses this pair for direct settlement, plus a distinct PAYMENT_BUYER_KEY for the customer-side authorization; keep private keys out of shell history.

Deployment

The current deployment target is GCP Cloud Run, through the parent workspace's deploy-ai.yml workflow. Commit service changes to main, update the parent's pinned service commit, and dispatch that parent's main. Staging uses testnets; production uses mainnets. Cloud Run uses TEE_MODE=local, so it does not provide Nitro hardware attestation or the Nitro encrypted-payload endpoint.

The deployment gate verifies all configured ERC-8004 identities, all five circuit discovery entries, and every payment offer. Actual paid proof E2E is a separate check: use scripts/run-published-e2e.mjs with an explicit E2E_BASE_URL to install and exercise the versions in the package manifests. It verifies generated proofs on chain; a successful 402 response alone is not a paid proof test.

AWS Nitro reference

The retained AWS deployment supports hardware-attested proving and blue-green slot switching. It is not the current deployment target; use it only after an explicit change to that deployment decision.

Blue-Green Deployment

aws/deploy-blue-green.sh
  • Two slots: blue (ports 4002/3200) and green (ports 4003/3201)

  • Active slot tracked in /opt/proofport-ai/active-slot

  • Caddy reload (not restart) switches traffic

  • In-flight request drain before switching (up to 660s for proof generation)

  • Automatic rollback if new container health check fails

Infrastructure

  • Caddy — Reverse proxy with HTTPS (Cloudflare Full SSL)

  • systemd — Services: proofport-ai, proofport-ai-redis, proofport-ai-enclave, vsock-bridge

  • CloudWatch — Log driver awslogs, 30-day retention

  • GitHub Actions — deploy-ai-aws.yml workflow (NOT deploy.yml which is GCP)

Boot / Stop

aws/boot-active-slot.sh    # Start active slot containers
aws/stop-active-slot.sh    # Stop active slot containers

Testing

npm run test:unit       # Unit and integration tests
npm run test:e2e        # E2E against Docker stack
npm run test:watch      # Watch mode

Deployed approval HTTP smoke

After deploying the approval feature, explicitly opt in to its canonical staging or production origin. This check uses a public deterministic fixture signer, creates two short-lived approval sessions, and never calls proof, payment, or chain RPC endpoints:

node scripts/verify-approval-deployment.mjs \
  --allow-deployed --base-url https://stg-ai.zkproofport.app \
  --expected-version "$(node -p 'require("./package.json").version')" \
  --expected-assets-dir public/approval \
  --output "${TMPDIR:-/tmp}/proofport-approval-staging-smoke.json"

Use https://ai.zkproofport.app explicitly for production. The script rejects other hosts, non-HTTPS origins, URL credentials, paths, queries, fragments, and redirects. The existing local-container approval test remains localhost-only. --expected-assets-dir compares the deployed HTML and referenced JS/CSS bytes with the supplied build; --expected-index-sha256 can additionally pin an exact HTML digest. Output contains case results, service version, and public asset hashes, never capabilities, approval URLs, signatures, or response bodies.

Coverage includes capability separation, signature validation, altered-request rejection, atomic consumption, terminal rejection, public-status privacy, and fixed expiry without extension. Actual expiration is reported as untested in the quick run because the server TTL is ten minutes. Add --wait-for-expiry to create one more fixture and observe that transition; it takes about ten minutes. This is a deployed HTTP check with a public test EOA, not a real human-wallet or paid-proof end-to-end test.

Published SDK/MCP E2E

E2E_BASE_URL=https://stg-ai.zkproofport.app \
E2E_PAYMENT_NETWORK=base-sepolia \
npm run test:e2e:published

This installs the exact SDK/MCP versions from their package manifests into an isolated temporary directory. It also installs the SDK's optional wallet adapters: CDP and x402 extensions use the tested versions in the root lockfile. All adapter modules are imported from the isolated installation before any paid test begins. Missing or newly added optional peers fail this preflight instead of failing after a proof starts. It verifies those versions and puts the installation's binaries first on every test subprocess's PATH; the global installation is neither used nor changed. SDK imports and the MCP process use the installed registry artifacts, not workspace links. The installation is removed after testing. Use -- --sdk-version X.Y.Z --mcp-version X.Y.Z to validate a specific already published release.

The full run creates paid testnet proofs. Supply credentials in the untracked .env.test or process environment: ATTESTATION_KEY, GIWA_ATTESTATION_KEY, E2E_PAYER_WALLET_KEY, and E2E_OIDC_JWT (or an authenticated gcloud account). E2E_PAYMENT_NETWORK selects the proof suites' payment network. The separate payment matrix checks Base Sepolia and Ethereum Sepolia individually. Give it funded test wallets using explicit E2E_PAYER_KEY_BASE_SEPOLIA and E2E_PAYER_KEY_ETHEREUM_SEPOLIA overrides when the common payer cannot pay on those networks. The runner never derives a payer from the prover key or transfers funds automatically.

For an existing Base Sepolia or Ethereum Sepolia payer that lacks USDC, use the explicit faucet helper below. Put CDP_API_KEY_ID and CDP_API_KEY_SECRET in the untracked .env.test; no wallet secret or payer private key is needed for this request. Set E2E_PAYER_ADDRESS to the public address of the wallet already used by your test fixture, then run:

node --env-file=.env.test --import tsx scripts/request-testnet-usdc.ts \
  --network ethereum-sepolia --address "$E2E_PAYER_ADDRESS" --min-usdc 0.01
# Use --network base-sepolia for that testnet instead.

The helper checks the USDC balance first and requests faucet funds only below the minimum. It accepts only those two testnets and USDC, creates no wallet, and spends no real assets. requested includes the public transaction hash; wait for confirmation and rerun until the status is adequate before E2E. rate_limited, missing_credentials, balance_unavailable, or faucet_failed returns a failing exit status and a sanitized message, without automatic retry or printing provider errors. Funding is a separate explicit action; the E2E runner never invokes this helper automatically.

A free package/discovery check is:

E2E_BASE_URL=https://stg-ai.zkproofport.app \
npm run test:e2e:published -- -t 'should list all 5 circuits'

That check does not establish proof generation or settlement success.

A2A Testing (a2a-ui + Phoenix)

docker compose -f docker-compose.yml -f docker-compose.test.yml up --build -d

Service

URL

Purpose

proofport-ai

http://localhost:4002

Agent server

a2a-ui

http://localhost:3001

A2A web test UI

Phoenix

http://localhost:6006

Trace visualization

Version Locks

Tool

Version

bb (Barretenberg)

v1.0.0-nightly.20250723

nargo

1.0.0-beta.8

ethers

^6.13.0

@modelcontextprotocol/sdk

^1.0.0

Node.js

20 LTS

License

Apache 2.0

Available Tools

7 tools
generate_proofA

All-in-one ZK proof generation. Handles: prepare inputs, request challenge, and submit proof in a single call. Use this when you want the simplest path to a proof. For fine-grained control over each step, use prepare_inputs, request_challenge, and submit_proof individually.

CIRCUITS:

  • "coinbase_kyc": Proves the user passed Coinbase KYC verification, optionally binding the wallet's signature to ONE EIP-712 action (as giwa_attestation). Without action it signs the request signal hash.

  • "coinbase_country": Proves the user's country of residence is (or is not) in a given list, optionally binding the wallet's signature to ONE EIP-712 action (as coinbase_kyc). Requires country_list and is_included.

  • "oidc_domain": Proves the user authenticated via OIDC and their email belongs to a specific domain. Requires jwt and scope.

  • "human_passport": Proves the wallet holds an unexpired Human Passport score at or above min_score, without revealing the wallet or the exact score; optionally binds ONE EIP-712 action (as coinbase_kyc). Requires min_score and chain (the chain id the person recorded the score on).

  • "giwa_attestation": GIWA attestation, optionally binding the wallet's signature to ONE EIP-712 action. Without action it signs the request signal hash. With one, the proof carries that action's hash, so a contract can check WHICH instruction was authorised -- not merely that somebody eligible signed something. Uses a GIWA-attested wallet; verified on GIWA Sepolia (chain 91342).

WITH ACTION: Returns awaiting_approval with an approval URL for the HUMAN to review and sign in their wallet. Keep the request parameters unchanged, query get_action_approval, then repeat with approval_id when approved. ATTESTATION_KEY cannot authorize an action on the human's behalf. Ordinary proofs without action retain automatic signing.

RETURNS: awaiting_approval or the full ProofResult with proof bytes, public inputs, and timing information. Use verify_proof separately to verify on-chain.

NameRequiredDescriptionDefault
jwtNoOIDC JWT token (id_token) for oidc_domain circuit
chainNoRequired for human_passport: the chain id the Human Passport score is recorded on -- 8453 Base, 10 OP Mainnet, 42161 Arbitrum One, 59144 Linea, 534352 Scroll, 324 zkSync Era. Ask the user; there is no default.
scopeNoScope string for nullifier derivation. Defaults to "proofport" if omitted. For oidc_domain circuit, this is the domain scope string.
actionNoThe EIP-712 action to authorise. Optional for coinbase_kyc, coinbase_country, giwa_attestation and human_passport; rejected for other circuits. Any structure is provable: the circuit hashes it without reading it, so a deposit, a grant of authority or an agreement in prose all work. The wallet signs exactly these fields, and the proof carries their hash.
pay_onNoWhich chain to pay on: a CAIP-2 id ("eip155:84532") or a plain name ("base-sepolia", "ethereum-sepolia"). Call request_challenge to see what a service offers. Omitted takes the first chain offered. The payer signs an authorization and the service settles it, so no gas or native balance is needed on the paying chain -- only USDC.
circuitYesWhich circuit to use
pay_withNoWhich wallet pays, when the service charges. "key" signs with PAYMENT_PRIVATE_KEY. "cdp" uses a Coinbase CDP server wallet (CDP_API_KEY_ID, CDP_API_KEY_SECRET, CDP_WALLET_SECRET). Omit it and the single configured wallet is used; omit it with none configured against a paying service and the error names what to set. Wallet and chain are separate choices; both must support the actual offered signing domain.
providerNoOIDC provider. "google" (default) for Google Workspace, "microsoft" for Microsoft 365.
min_scoreNoRequired for human_passport: the Human Passport score threshold in points (e.g. 20; above 0, at most four decimals). The server finds the wallet's score on the chain named by `chain` and refuses, before payment, a wallet with none or below it.
approval_idNoResume the SAME original action request using the approval_id returned with awaiting_approval. Keep all original parameters unchanged.
is_includedNotrue = prove country IS in list, false = prove NOT in list. Required for coinbase_country circuit.
max_paymentNoMaximum USDC proof fee allowed by the user.
country_listNoISO 3166-1 alpha-2 country codes. Required for coinbase_country circuit.
approved_paymentNoExact user-approved terms. Set extra.verifyingContract to the offer asset (EIP-3009). Changed fee, recipient, token, chain or signing domain is rejected before signing.

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does most of it well: it discloses the awaiting_approval state machine (keep parameters unchanged, call get_action_approval, retry with approval_id), the signing-authority constraint that ATTESTATION_KEY cannot authorize for the human, and the auto-signing behavior for action-less proofs. It stops short of covering failure handling, idempotency, or whether payment is captured when the request parks in awaiting_approval.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The purpose and the sibling alternative are front-loaded before the long circuit catalogue, and headers (CIRCUITS, WITH ACTION, RETURNS) make the block skimmable. For a 14-parameter, five-circuit tool the length is mostly justified, though a few requirement sentences duplicate what the schema descriptions already state.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, and the description compensates by naming both possible returns (awaiting_approval or the full ProofResult with proof bytes, public inputs, and timing) and by pointing to verify_proof for on-chain verification. Combined with the per-circuit and approval-flow detail, an agent has everything needed to call this correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3; the description earns above that by supplying cross-parameter conditional requirements the flat schema cannot express — which circuit needs country_list/is_included, jwt/scope, or min_score/chain, and which circuits accept or reject action. It also explains that any EIP-712 structure is provable since the circuit only hashes it. Some circuit prerequisites are nonetheless restated in both description and schema, diluting the marginal gain.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb+resource ('All-in-one ZK proof generation') and immediately enumerates the three sub-steps it wraps (prepare inputs, request challenge, submit proof). It explicitly contrasts itself with the fine-grained siblings prepare_inputs, request_challenge, and submit_proof, so the agent can route without inspecting schemas.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives an explicit when-to-use ('simplest path to a proof') and when-to-use-something-else rule naming the three alternative tools for fine-grained control. The CIRCUITS block further tells the agent which parameters each circuit needs and where action is optional versus rejected, which is the main decision surface for this tool.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_action_approvalA

Read the status of a human wallet approval created by this MCP client. This operation never starts a proof or payment.

NameRequiredDescriptionDefault
approval_idYesThe approval_id returned by generate_proof or prepare_inputs

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations present, the description takes on the behavioral disclosure burden. It explicitly states the operation is read-only and has no side effects on proofs or payments, which is valuable for an agent deciding whether invocation is safe. It does not detail authorization requirements or possible returned statuses, but the core side-effect guarantee is clear.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences with no filler. The primary purpose is front-loaded, and the safety-relevant negation is placed second to reinforce the read-only nature. Every word contributes value.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a one-parameter read-only tool, this is largely complete: it identifies what the approval is, where its ID comes from, and that no proof or payment is initiated. It does not describe output fields, but no output schema exists and the tool's role as a status poller is adequately communicated through the sibling context.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the baseline is 3. The description reinforces that approval_id comes from generate_proof or prepare_inputs, but that same provenance detail also appears in the schema property description. No additional parameter semantics beyond the structured schema are provided.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific action and resource: 'Read the status of a human wallet approval created by this MCP client.' This clearly separates it from sibling proof/payment tools, and the second sentence reinforces that it is not a proof-starting or payment-triggering operation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear context for when to use the tool: after an approval has been created by this MCP client, to read its status. It also states a key exclusion ('never starts a proof or payment'), although it does not explicitly name alternative tools or define exact polling conditions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_supported_circuitsA

List all ZK circuits supported by ZKProofport, including verifier addresses and authorized signers. No parameters required. Call this first to discover available circuits before starting proof generation.

NameRequiredDescriptionDefault

No parameters

TDQS

A4.2/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations provided, so description must disclose behavior. It mentions no parameters required but does not state if it's read-only or any side effects. Minimal behavioral info, but acceptable for a simple listing tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, no wasted words. Efficiently conveys purpose, output contents, and usage order.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool has zero parameters and no output schema, the description adequately covers purpose and guidance. Could mention output format or safety of repeated calls, but it's mostly complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

No parameters defined; description adds value by explicitly stating 'No parameters required,' which reassures the agent. Baseline 4 for zero-parameter tools with coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Clearly states the tool lists all ZK circuits with specific details (verifier addresses and authorized signers). Distinguishes from siblings by being a discovery step before proof generation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly says 'Call this first to discover available circuits before starting proof generation,' which guides when to use it. Could be improved by specifying when not to use it or naming alternatives, but it's clear for a discovery tool.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

prepare_inputsA

Step 1 of the step-by-step flow. WITH ACTION: human wallet approval is required; returns awaiting_approval until resumed with approval_id. Approved action witnesses stay in private local storage; pass the returned prepared_inputs_id to submit_proof. WITHOUT ACTION: retains the existing credential-key signature and private witness result. Handle private witness inputs only in trusted local code, never expose them to the dApp, model or logs. Call this BEFORE request_challenge. For oidc_domain provide jwt and scope.

NameRequiredDescriptionDefault
jwtNoOIDC JWT token (id_token) for oidc_domain circuit
chainNoRequired for human_passport: the chain id the Human Passport score is recorded on -- 8453 Base, 10 OP Mainnet, 42161 Arbitrum One, 59144 Linea, 534352 Scroll, 324 zkSync Era. Ask the user; there is no default.
scopeNoScope string for nullifier derivation. Defaults to "proofport" if omitted. For oidc_domain circuit, this is the domain scope string.
actionNoThe EIP-712 action to authorise. Optional for coinbase_kyc, coinbase_country, giwa_attestation and human_passport; rejected for other circuits. Any structure is provable: the circuit hashes it without reading it, so a deposit, a grant of authority or an agreement in prose all work. The wallet signs exactly these fields, and the proof carries their hash.
circuitYesWhich circuit to use
providerNoOIDC provider. "google" (default) for Google Workspace, "microsoft" for Microsoft 365.
min_scoreNoRequired for human_passport: the Human Passport score threshold in points (e.g. 20; above 0, at most four decimals). The server finds the wallet's score on the chain named by `chain` and refuses, before payment, a wallet with none or below it.
approval_idNoResume the SAME original action request using the approval_id returned with awaiting_approval. Keep all original parameters unchanged.
is_includedNotrue = prove country IS in list, false = prove NOT in list. Required for coinbase_country circuit.
country_listNoISO 3166-1 alpha-2 country codes. Required for coinbase_country circuit.

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does substantial work: it discloses that human wallet approval is required for actions, that the call returns awaiting_approval until resumed with approval_id, that approved witnesses persist in private local storage, and that witness data must never reach the dApp, model, or logs. It stops short of stating whether the call itself performs work eagerly (e.g. wallet interaction timing) or any limits on repeated calls.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the flow position, then cleanly separated into WITH ACTION and WITHOUT ACTION blocks, each sentence carrying distinct information. The privacy warning is appended last rather than integrated, and several clauses are compressed into semicolon-chained sentences, but there is little waste.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 10-parameter tool with nested objects, no annotations, and no output schema, the description covers the state machine (approval, resume, handoff), the privacy constraint, and the ordering constraint. Adequate overall, though it does not explain how the returned prepared_inputs_id relates to circuits or what happens if the call is repeated without approval_id.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so per-parameter meaning, defaults, and enum semantics are already documented in the schema. The description adds only the oidc_domain pairing of jwt with scope, which the schema already specifies, so the baseline of 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description establishes the tool's role as step 1 of a flow and branches its behavior on WITH ACTION vs WITHOUT ACTION, returning prepared_inputs_id for submit_proof. It never states plainly what the tool produces in the no-action case beyond 'retains the existing credential-key signature', which leaves the purpose slightly implicit relative to its name.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit sequencing: 'Call this BEFORE request_challenge' and 'pass the returned prepared_inputs_id to submit_proof', plus the resume condition using approval_id rather than a fresh call. It does not name the get_action_approval sibling as the source of approval_id, so the routing to that tool is left implicit.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

request_challengeA

Step 2 of the step-by-step flow: Request a challenge from the server. Pass inputs: {} to discover the live payment offers, nonce and optional TEE key without transmitting private witness inputs. You MUST pass the returned "nonce" to submit_proof — without it the server just issues another challenge. MCP submit_proof does not sign payments or encrypt inputs; use generate_proof or the SDK for paid/encrypted orchestration.

NameRequiredDescriptionDefault
inputsYesUse {} to discover the nonce, payment offers and optional TEE key without transmitting private witness inputs. Also accepts a JSON string or object from trusted local code; any supplied witness is sent to the selected prover and must stay out of model context, dApp/UI and logs.
circuitYesWhich circuit to use

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the burden and does disclose the key behavioral traits: empty inputs avoid transmitting witness data, the returned nonce must be threaded into submit_proof or this tool is a no-op, and no signing/encryption happens here. It omits auth requirements, whether the challenge expires, and any rate limits.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the flow position and the main call pattern, and each sentence carries operational weight. It does partially restate the schema's inputs:{} guidance, which is minor redundancy in an otherwise tight description.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema and no annotations, the description still names what comes back (nonce, payment offers, optional TEE key) and how it feeds the next step. Enough to call it correctly and chain it without guessing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3. The description reinforces the discovery-mode use of inputs:{} but adds nothing about how to choose among the five circuit enum values, leaving the circuit parameter as opaque as the schema already does.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Request a challenge from the server') and pins its role as step 2 of a named multi-step flow. An agent can place it relative to submit_proof and generate_proof without opening schemas.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit call conditions ('Pass inputs: {} to discover the live payment offers, nonce and optional TEE key') and explicit exclusions ('use generate_proof or the SDK for paid/encrypted orchestration'; submit_proof doesn't sign or encrypt). It also warns that skipping the nonce hand-off causes the server to just re-issue another challenge.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

submit_proofA

Step 3 of the step-by-step flow: Submit prepared inputs to generate the ZK proof. The TEE server runs the Noir circuit and returns the UltraHonk proof. This step may take 30-90 seconds. The TEE server builds Prover.toml from these inputs.

You MUST pass the nonce returned by request_challenge. POST /api/v1/prove answers every request that arrives without that nonce with a fresh 402 challenge, so a submission that omits it can never produce a proof.

NameRequiredDescriptionDefault
nonceYesThe "nonce" field from the request_challenge response. Single-use and bound to the circuit it was issued for — request a new challenge for every submission and for every circuit.
inputsNoFull ProveInputs object from prepare_inputs. Accepts a JSON string or a structured object.
circuitYesWhich circuit to use
prepared_inputs_idNoPrivate local action witness handle returned by prepare_inputs. Use instead of inputs; consumed once.

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the behavioral burden and does well: it discloses that the TEE server runs the Noir circuit, returns an UltraHonk proof, builds Prover.toml, and that the call may take 30-90 seconds. It also explains the nonce failure mode with a fresh 402 challenge. It does not cover auth requirements, idempotency, or failure/retry behavior beyond the nonce case.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the step and purpose, and the nonce warning is placed prominently. It is appropriately sized for the complexity, though the 402 explanation is somewhat verbose and repeats the nonce requirement already stated. Every sentence is useful, but the second paragraph could be tighter.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a proof-submission tool with no output schema and no annotations, the description is substantially complete: it covers the flow position, required nonce, server-side proof generation, returned proof type, and latency. The remaining gap is response shape and error handling beyond the 402 case, but the agent has enough to invoke it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents all four parameters, including nonce, inputs, circuit enum, and prepared_inputs_id. The description adds context that the nonce must come from request_challenge and that inputs are submitted to the TEE server, but it does not add much beyond the schema. Baseline 3 is appropriate when the schema does the heavy lifting.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description gives a specific verb-action and resource: submit prepared inputs to generate a ZK proof. It clearly places the tool as step 3 in the flow and names related tools like request_challenge and prepare_inputs, though it does not explicitly distinguish itself from the sibling generate_proof. The core purpose is clear to an agent without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It states exactly when this tool is used: step 3 of the flow, after preparing inputs, and it requires the nonce from request_challenge. The 402 consequence for omitting the nonce is an explicit usage condition. It stops short of naming when to use generate_proof instead, so it is clear but not fully alternative-aware.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

verify_proofA

Step 4 (optional): Verify a ZK proof on-chain against ZKProofport's own pinned verifier contract for the circuit and chain. Pass the full generate_proof result object directly. The result's verifierAddress is only compared with the pinned one: a different address is refused, never called. Issuer anchors are checked too (OIDC provider key against Google/Microsoft's published keys; Coinbase/GIWA signer-list root). Returns { valid: true } if the proof is valid, otherwise { valid: false, error }.

NameRequiredDescriptionDefault
resultYesFull result object from generate_proof — pass it directly without extracting fields
min_scoreNohuman_passport: the threshold you asked for, in points. The proof's threshold must equal it; omit it and the threshold is not compared.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations present the description carries the full burden and does so well: it discloses that verifierAddress is only compared against the pinned one and a mismatch is refused, never called; that the rpcUrl in the result is ignored in favor of its own public RPC; and that issuer anchors (OIDC keys, Coinbase/GIWA signer-list root) are checked. It also states the return shape with both success and failure branches.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the step number, action, and target, then packs the security caveats and return contract into a tight block. Every sentence carries information, though the caveat cluster is dense enough to read as a run-on.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a nested-object verification tool with no output schema, the description covers input handling, the security model around verifier and issuer pinning, and the return contract in both success and failure cases. Nothing an agent needs to invoke it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description adds real meaning beyond the schema: it insists the whole result object be passed without extracting fields, and explains min_score's equality requirement (omit and no comparison happens).

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('Verify a ZK proof on-chain against ZKProofport's own pinned verifier contract') and adds the exact scope (circuit and chain). It is clearly distinguished from the sibling generate_proof by positioning itself as the downstream verification step.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Labels itself 'Step 4 (optional)' and tells the agent to pass the full generate_proof result object directly, which routes correctly between it and its predecessor. It does not spell out explicit exclusions such as when verification can be skipped, but the workflow context is unambiguous.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 2 tool updatesv0.2.50
    • Changedgenerate_proof2 fields changed
      • addedInput schema / properties / chain
        Added value: +{
        +  "description": "Required for human_passport: the chain id the Human Passport score is recorded on -- 8453 Base, 10 OP Mainnet, 42161 Arbitrum One, 59144 Linea, 534352 Scroll, 324 zkSync Era. Ask the user; there is no default.",
        +  "type": "number"
        +}
      • changedInput schema / properties / min_score / description
        Previous value: -"Required for human_passport: the Human Passport score threshold in points (e.g. 20; above 0, at most four decimals). The server finds the wallet's score on Base and refuses, before payment, a wallet with none or below it."New value: +"Required for human_passport: the Human Passport score threshold in points (e.g. 20; above 0, at most four decimals). The server finds the wallet's score on the chain named by `chain` and refuses, before payment, a wallet with none or below it."
    • Changedprepare_inputs2 fields changed
      • addedInput schema / properties / chain
        Added value: +{
        +  "description": "Required for human_passport: the chain id the Human Passport score is recorded on -- 8453 Base, 10 OP Mainnet, 42161 Arbitrum One, 59144 Linea, 534352 Scroll, 324 zkSync Era. Ask the user; there is no default.",
        +  "type": "number"
        +}
      • changedInput schema / properties / min_score / description
        Previous value: -"Required for human_passport: the Human Passport score threshold in points (e.g. 20; above 0, at most four decimals). The server finds the wallet's score on Base and refuses, before payment, a wallet with none or below it."New value: +"Required for human_passport: the Human Passport score threshold in points (e.g. 20; above 0, at most four decimals). The server finds the wallet's score on the chain named by `chain` and refuses, before payment, a wallet with none or below it."
  2. 5 tool updatesv0.2.49
    • Changedgenerate_proof3 fields changed
      • changedInput schema / properties / action / description
        Previous value: -"The EIP-712 action to authorise. Optional for coinbase_kyc, coinbase_country and giwa_attestation; rejected for other circuits. Any structure is provable: the circuit hashes it without reading it, so a deposit, a grant of authority or an agreement in prose all work. The wallet signs exactly these fields, and the proof carries their hash."New value: +"The EIP-712 action to authorise. Optional for coinbase_kyc, coinbase_country, giwa_attestation and human_passport; rejected for other circuits. Any structure is provable: the circuit hashes it without reading it, so a deposit, a grant of authority or an agreement in prose all work. The wallet signs exactly these fields, and the proof carries their hash."
      • changedInput schema / properties / circuit / enum
        Previous value: -[
        -  "coinbase_kyc",
        -  "coinbase_country",
        -  "oidc_domain",
        -  "giwa_attestation"
        -]New value: +[
        +  "coinbase_kyc",
        +  "coinbase_country",
        +  "oidc_domain",
        +  "giwa_attestation",
        +  "human_passport"
        +]
      • addedInput schema / properties / min_score
        Added value: +{
        +  "description": "Required for human_passport: the Human Passport score threshold in points (e.g. 20; above 0, at most four decimals). The server finds the wallet's score on Base and refuses, before payment, a wallet with none or below it.",
        +  "type": "number"
        +}
    • Changedprepare_inputs3 fields changed
      • changedInput schema / properties / action / description
        Previous value: -"The EIP-712 action to authorise. Optional for coinbase_kyc, coinbase_country and giwa_attestation; rejected for other circuits. Any structure is provable: the circuit hashes it without reading it, so a deposit, a grant of authority or an agreement in prose all work. The wallet signs exactly these fields, and the proof carries their hash."New value: +"The EIP-712 action to authorise. Optional for coinbase_kyc, coinbase_country, giwa_attestation and human_passport; rejected for other circuits. Any structure is provable: the circuit hashes it without reading it, so a deposit, a grant of authority or an agreement in prose all work. The wallet signs exactly these fields, and the proof carries their hash."
      • changedInput schema / properties / circuit / enum
        Previous value: -[
        -  "coinbase_kyc",
        -  "coinbase_country",
        -  "oidc_domain",
        -  "giwa_attestation"
        -]New value: +[
        +  "coinbase_kyc",
        +  "coinbase_country",
        +  "oidc_domain",
        +  "giwa_attestation",
        +  "human_passport"
        +]
      • addedInput schema / properties / min_score
        Added value: +{
        +  "description": "Required for human_passport: the Human Passport score threshold in points (e.g. 20; above 0, at most four decimals). The server finds the wallet's score on Base and refuses, before payment, a wallet with none or below it.",
        +  "type": "number"
        +}
    • Changedrequest_challenge1 field changed
      • changedInput schema / properties / circuit / enum
        Previous value: -[
        -  "coinbase_kyc",
        -  "coinbase_country",
        -  "oidc_domain",
        -  "giwa_attestation"
        -]New value: +[
        +  "coinbase_kyc",
        +  "coinbase_country",
        +  "oidc_domain",
        +  "giwa_attestation",
        +  "human_passport"
        +]
    • Changedsubmit_proof1 field changed
      • changedInput schema / properties / circuit / enum
        Previous value: -[
        -  "coinbase_kyc",
        -  "coinbase_country",
        -  "oidc_domain",
        -  "giwa_attestation"
        -]New value: +[
        +  "coinbase_kyc",
        +  "coinbase_country",
        +  "oidc_domain",
        +  "giwa_attestation",
        +  "human_passport"
        +]
    • Changedverify_proof1 field changed
      • addedInput schema / properties / min_score
        Added value: +{
        +  "description": "human_passport: the threshold you asked for, in points. The proof's threshold must equal it; omit it and the threshold is not compared.",
        +  "type": "number"
        +}
  3. 2 tool updatesv0.2.48
    • Changedgenerate_proof1 field changed
      • changedInput schema / properties / action / description
        Previous value: -"The EIP-712 action to authorise. Optional for giwa_attestation; rejected for other circuits. Any structure is provable: the circuit hashes it without reading it, so a deposit, a grant of authority or an agreement in prose all work. The wallet signs exactly these fields, and the proof carries their hash."New value: +"The EIP-712 action to authorise. Optional for coinbase_kyc, coinbase_country and giwa_attestation; rejected for other circuits. Any structure is provable: the circuit hashes it without reading it, so a deposit, a grant of authority or an agreement in prose all work. The wallet signs exactly these fields, and the proof carries their hash."
    • Changedprepare_inputs1 field changed
      • changedInput schema / properties / action / description
        Previous value: -"The EIP-712 action to authorise. Optional for giwa_attestation; rejected for other circuits. Any structure is provable: the circuit hashes it without reading it, so a deposit, a grant of authority or an agreement in prose all work. The wallet signs exactly these fields, and the proof carries their hash."New value: +"The EIP-712 action to authorise. Optional for coinbase_kyc, coinbase_country and giwa_attestation; rejected for other circuits. Any structure is provable: the circuit hashes it without reading it, so a deposit, a grant of authority or an agreement in prose all work. The wallet signs exactly these fields, and the proof carries their hash."
  4. 1 tool updatev0.2.47
    • Changedverify_proof4 fields changed
      • changedInput schema / properties / result / properties / verification / properties / chainId / description
        Previous value: -"Chain ID (e.g. 8453 for Base, 84532 for Base Sepolia)"New value: +"Chain the result names; selects the pinned verifier for the circuit on that chain"
      • changedInput schema / properties / result / properties / verification / properties / rpcUrl / description
        Previous value: -"RPC URL for the chain"New value: +"Ignored: verification uses its own public RPC for the chain, never one a result names"
      • changedInput schema / properties / result / properties / verification / properties / verifierAddress / description
        Previous value: -"Verifier contract address"New value: +"Verifier address the result names; compared with the pinned verifier, refused if different"
      • changedInput schema / properties / result / properties / verification / required
        Previous value: -[
        -  "verifierAddress",
        -  "chainId",
        -  "rpcUrl"
        -]New value: +[
        +  "verifierAddress",
        +  "chainId"
        +]
  5. 6 tool updatesv0.2.46
    • Removeddeposit_to_gateway
    • Removedgateway_balance
    • Changedgenerate_proof6 fields changed
      • changedInput schema / properties / action / description
        Previous value: -"The EIP-712 action to authorise. Optional for arc_eligibility and giwa_attestation; rejected for other circuits. Any structure is provable: the circuit hashes it without reading it, so a deposit, a grant of authority or an agreement in prose all work. The wallet signs exactly these fields, and the proof carries their hash."New value: +"The EIP-712 action to authorise. Optional for giwa_attestation; rejected for other circuits. Any structure is provable: the circuit hashes it without reading it, so a deposit, a grant of authority or an agreement in prose all work. The wallet signs exactly these fields, and the proof carries their hash."
      • changedInput schema / properties / approved_payment / description
        Previous value: -"Exact user-approved terms. For direct EIP-3009 set extra.verifyingContract to the offer asset; for Gateway copy its required extra.verifyingContract. Changed fee, recipient, token, chain or signing domain is rejected before signing."New value: +"Exact user-approved terms. Set extra.verifyingContract to the offer asset (EIP-3009). Changed fee, recipient, token, chain or signing domain is rejected before signing."
      • changedInput schema / properties / circuit / enum
        Previous value: -[
        -  "coinbase_kyc",
        -  "coinbase_country",
        -  "oidc_domain",
        -  "arc_eligibility",
        -  "giwa_attestation"
        -]New value: +[
        +  "coinbase_kyc",
        +  "coinbase_country",
        +  "oidc_domain",
        +  "giwa_attestation"
        +]
      • changedInput schema / properties / pay_on / description
        Previous value: -"Which chain to pay on: a CAIP-2 id (\"eip155:5042002\") or a plain name (\"arc-testnet\", \"arc-testnet-nano\", \"base-sepolia\"). Call request_challenge to see what a service offers. Omitted takes the first chain offered. The payer signs an authorization and the service settles it, so no gas or native balance is needed on the paying chain -- only USDC. \"arc-testnet-nano\" is Arc nanopayments: the authorization goes to Circle Gateway, which verifies it off chain in under a second and settles it later in a batch with thousands of others, so the gas per payment approaches zero. It requires a Gateway balance -- deposit first with the deposit_to_gateway tool -- and is the right choice for an agent buying many proofs. \"arc-testnet\" settles each payment on chain immediately and costs gas every time."New value: +"Which chain to pay on: a CAIP-2 id (\"eip155:84532\") or a plain name (\"base-sepolia\", \"ethereum-sepolia\"). Call request_challenge to see what a service offers. Omitted takes the first chain offered. The payer signs an authorization and the service settles it, so no gas or native balance is needed on the paying chain -- only USDC."
      • changedInput schema / properties / pay_with / description
        Previous value: -"Which wallet pays, when the service charges. \"arc\" is an Arc agent wallet — Circle holds it, it carries spending policies the agent cannot ignore, and Circle CLI signs with it (install: npm i -g @circle-fin/cli, then circle wallet login <email> --testnet). \"key\" signs with PAYMENT_PRIVATE_KEY. \"cdp\" uses a Coinbase CDP server wallet (CDP_API_KEY_ID, CDP_API_KEY_SECRET, CDP_WALLET_SECRET). \"circle\" uses a Circle developer-controlled wallet (CIRCLE_API_KEY, CIRCLE_ENTITY_SECRET, CIRCLE_WALLET_ID) when that wallet supports the selected offer. Omit it and the single configured wallet is used; omit it with none configured against a paying service and the error names what to set. Wallet and chain are separate choices; both must support the actual offered signing domain."New value: +"Which wallet pays, when the service charges. \"key\" signs with PAYMENT_PRIVATE_KEY. \"cdp\" uses a Coinbase CDP server wallet (CDP_API_KEY_ID, CDP_API_KEY_SECRET, CDP_WALLET_SECRET). Omit it and the single configured wallet is used; omit it with none configured against a paying service and the error names what to set. Wallet and chain are separate choices; both must support the actual offered signing domain."
      • changedInput schema / properties / pay_with / enum
        Previous value: -[
        -  "key",
        -  "cdp",
        -  "circle",
        -  "arc"
        -]New value: +[
        +  "key",
        +  "cdp"
        +]
    • Changedprepare_inputs2 fields changed
      • changedInput schema / properties / action / description
        Previous value: -"The EIP-712 action to authorise. Optional for arc_eligibility and giwa_attestation; rejected for other circuits. Any structure is provable: the circuit hashes it without reading it, so a deposit, a grant of authority or an agreement in prose all work. The wallet signs exactly these fields, and the proof carries their hash."New value: +"The EIP-712 action to authorise. Optional for giwa_attestation; rejected for other circuits. Any structure is provable: the circuit hashes it without reading it, so a deposit, a grant of authority or an agreement in prose all work. The wallet signs exactly these fields, and the proof carries their hash."
      • changedInput schema / properties / circuit / enum
        Previous value: -[
        -  "coinbase_kyc",
        -  "coinbase_country",
        -  "oidc_domain",
        -  "arc_eligibility",
        -  "giwa_attestation"
        -]New value: +[
        +  "coinbase_kyc",
        +  "coinbase_country",
        +  "oidc_domain",
        +  "giwa_attestation"
        +]
    • Changedrequest_challenge1 field changed
      • changedInput schema / properties / circuit / enum
        Previous value: -[
        -  "coinbase_kyc",
        -  "coinbase_country",
        -  "oidc_domain",
        -  "arc_eligibility",
        -  "giwa_attestation"
        -]New value: +[
        +  "coinbase_kyc",
        +  "coinbase_country",
        +  "oidc_domain",
        +  "giwa_attestation"
        +]
    • Changedsubmit_proof1 field changed
      • changedInput schema / properties / circuit / enum
        Previous value: -[
        -  "coinbase_kyc",
        -  "coinbase_country",
        -  "oidc_domain",
        -  "arc_eligibility",
        -  "giwa_attestation"
        -]New value: +[
        +  "coinbase_kyc",
        +  "coinbase_country",
        +  "oidc_domain",
        +  "giwa_attestation"
        +]
  6. 4 tool updatesv0.2.45
    • Changedgenerate_proof1 field changed
      • addedInput schema / properties / approval_id
        Added value: +{
        +  "description": "Resume the SAME original action request using the approval_id returned with awaiting_approval. Keep all original parameters unchanged.",
        +  "type": "string"
        +}
    • Addedget_action_approval
    • Changedprepare_inputs1 field changed
      • addedInput schema / properties / approval_id
        Added value: +{
        +  "description": "Resume the SAME original action request using the approval_id returned with awaiting_approval. Keep all original parameters unchanged.",
        +  "type": "string"
        +}
    • Changedsubmit_proof2 fields changed
      • addedInput schema / properties / prepared_inputs_id
        Added value: +{
        +  "description": "Private local action witness handle returned by prepare_inputs. Use instead of inputs; consumed once.",
        +  "type": "string"
        +}
      • changedInput schema / required
        Previous value: -[
        -  "circuit",
        -  "inputs",
        -  "nonce"
        -]New value: +[
        +  "circuit",
        +  "nonce"
        +]
  7. 4 tool updatesv0.2.44
    • Changedgenerate_proof3 fields changed
      • changedInput schema / properties / action / description
        Previous value: -"The EIP-712 action to authorise. Required for arc_eligibility and rejected for every other circuit. Any structure is provable: the circuit hashes it without reading it, so a deposit, a grant of authority or an agreement in prose all work. The wallet signs exactly these fields, and the proof carries their hash."New value: +"The EIP-712 action to authorise. Optional for arc_eligibility and giwa_attestation; rejected for other circuits. Any structure is provable: the circuit hashes it without reading it, so a deposit, a grant of authority or an agreement in prose all work. The wallet signs exactly these fields, and the proof carries their hash."
      • changedInput schema / properties / approved_payment / description
        Previous value: -"Exact user-approved terms. The SDK rejects any changed fee, recipient, token, chain or Gateway signing domain before signing the actual challenge."New value: +"Exact user-approved terms. For direct EIP-3009 set extra.verifyingContract to the offer asset; for Gateway copy its required extra.verifyingContract. Changed fee, recipient, token, chain or signing domain is rejected before signing."
      • changedInput schema / properties / circuit / enum
        Previous value: -[
        -  "coinbase_kyc",
        -  "coinbase_country",
        -  "oidc_domain",
        -  "arc_eligibility"
        -]New value: +[
        +  "coinbase_kyc",
        +  "coinbase_country",
        +  "oidc_domain",
        +  "arc_eligibility",
        +  "giwa_attestation"
        +]
    • Changedprepare_inputs2 fields changed
      • changedInput schema / properties / action / description
        Previous value: -"The EIP-712 action to authorise. Required for arc_eligibility and rejected for every other circuit. Any structure is provable: the circuit hashes it without reading it, so a deposit, a grant of authority or an agreement in prose all work. The wallet signs exactly these fields, and the proof carries their hash."New value: +"The EIP-712 action to authorise. Optional for arc_eligibility and giwa_attestation; rejected for other circuits. Any structure is provable: the circuit hashes it without reading it, so a deposit, a grant of authority or an agreement in prose all work. The wallet signs exactly these fields, and the proof carries their hash."
      • changedInput schema / properties / circuit / enum
        Previous value: -[
        -  "coinbase_kyc",
        -  "coinbase_country",
        -  "oidc_domain",
        -  "arc_eligibility"
        -]New value: +[
        +  "coinbase_kyc",
        +  "coinbase_country",
        +  "oidc_domain",
        +  "arc_eligibility",
        +  "giwa_attestation"
        +]
    • Changedrequest_challenge1 field changed
      • changedInput schema / properties / circuit / enum
        Previous value: -[
        -  "coinbase_kyc",
        -  "coinbase_country",
        -  "oidc_domain",
        -  "arc_eligibility"
        -]New value: +[
        +  "coinbase_kyc",
        +  "coinbase_country",
        +  "oidc_domain",
        +  "arc_eligibility",
        +  "giwa_attestation"
        +]
    • Changedsubmit_proof1 field changed
      • changedInput schema / properties / circuit / enum
        Previous value: -[
        -  "coinbase_kyc",
        -  "coinbase_country",
        -  "oidc_domain",
        -  "arc_eligibility"
        -]New value: +[
        +  "coinbase_kyc",
        +  "coinbase_country",
        +  "oidc_domain",
        +  "arc_eligibility",
        +  "giwa_attestation"
        +]
  8. 6 tool updatesv0.2.43
    • Addeddeposit_to_gateway
    • Addedgateway_balance
    • Changedgenerate_proof6 fields changed
      • addedInput schema / properties / action
        Added value: +{
        +  "additionalProperties": false,
        +  "description": "The EIP-712 action to authorise. Required for arc_eligibility and rejected for every other circuit. Any structure is provable: the circuit hashes it without reading it, so a deposit, a grant of authority or an agreement in prose all work. The wallet signs exactly these fields, and the proof carries their hash.",
        +  "properties": {
        +    "domain": {
        +      "additionalProperties": false,
        +      "properties": {
        +        "chainId": {
        +          "type": "number"
        +        },
        +        "name": {
        +          "type": "string"
        +        },
        +        "verifyingContract": {
        +          "type": "string"
        +        },
        +        "version": {
        +          "type": "string"
        +        }
        +      },
        +      "required": [
        +        "name",
        +        "version",
        +        "chainId",
        +        "verifyingContract"
        +      ],
        +      "type": "object"
        +    },
        +    "message": {
        +      "additionalProperties": {},
        +      "type": "object"
        +    },
        +    "primaryType": {
        +      "type": "string"
        +    },
        +    "types": {
        +      "additionalProperties": {
        +        "items": {
        +          "additionalProperties": false,
        +          "properties": {
        +            "name": {
        +              "type": "string"
        +            },
        +            "type": {
        +              "type": "string"
        +            }
        +          },
        +          "required": [
        +            "name",
        +            "type"
        +          ],
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "type": "object"
        +    }
        +  },
        +  "required": [
        +    "domain",
        +    "types",
        +    "primaryType",
        +    "message"
        +  ],
        +  "type": "object"
        +}
      • addedInput schema / properties / approved_payment
        Added value: +{
        +  "additionalProperties": false,
        +  "description": "Exact user-approved terms. The SDK rejects any changed fee, recipient, token, chain or Gateway signing domain before signing the actual challenge.",
        +  "properties": {
        +    "amount": {
        +      "pattern": "^\\d+$",
        +      "type": "string"
        +    },
        +    "asset": {
        +      "type": "string"
        +    },
        +    "extra": {
        +      "additionalProperties": false,
        +      "properties": {
        +        "name": {
        +          "type": "string"
        +        },
        +        "verifyingContract": {
        +          "type": "string"
        +        },
        +        "version": {
        +          "type": "string"
        +        }
        +      },
        +      "required": [
        +        "name",
        +        "version",
        +        "verifyingContract"
        +      ],
        +      "type": "object"
        +    },
        +    "network": {
        +      "type": "string"
        +    },
        +    "payTo": {
        +      "type": "string"
        +    },
        +    "scheme": {
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "network",
        +    "scheme",
        +    "amount",
        +    "asset",
        +    "payTo",
        +    "extra"
        +  ],
        +  "type": "object"
        +}
      • changedInput schema / properties / circuit / enum
        Previous value: -[
        -  "coinbase_kyc",
        -  "coinbase_country",
        -  "oidc_domain"
        -]New value: +[
        +  "coinbase_kyc",
        +  "coinbase_country",
        +  "oidc_domain",
        +  "arc_eligibility"
        +]
      • addedInput schema / properties / max_payment
        Added value: +{
        +  "description": "Maximum USDC proof fee allowed by the user.",
        +  "pattern": "^\\d+(\\.\\d{1,6})?$",
        +  "type": "string"
        +}
      • addedInput schema / properties / pay_on
        Added value: +{
        +  "description": "Which chain to pay on: a CAIP-2 id (\"eip155:5042002\") or a plain name (\"arc-testnet\", \"arc-testnet-nano\", \"base-sepolia\"). Call request_challenge to see what a service offers. Omitted takes the first chain offered. The payer signs an authorization and the service settles it, so no gas or native balance is needed on the paying chain -- only USDC. \"arc-testnet-nano\" is Arc nanopayments: the authorization goes to Circle Gateway, which verifies it off chain in under a second and settles it later in a batch with thousands of others, so the gas per payment approaches zero. It requires a Gateway balance -- deposit first with the deposit_to_gateway tool -- and is the right choice for an agent buying many proofs. \"arc-testnet\" settles each payment on chain immediately and costs gas every time.",
        +  "type": "string"
        +}
      • addedInput schema / properties / pay_with
        Added value: +{
        +  "description": "Which wallet pays, when the service charges. \"arc\" is an Arc agent wallet — Circle holds it, it carries spending policies the agent cannot ignore, and Circle CLI signs with it (install: npm i -g @circle-fin/cli, then circle wallet login <email> --testnet). \"key\" signs with PAYMENT_PRIVATE_KEY. \"cdp\" uses a Coinbase CDP server wallet (CDP_API_KEY_ID, CDP_API_KEY_SECRET, CDP_WALLET_SECRET). \"circle\" uses a Circle developer-controlled wallet (CIRCLE_API_KEY, CIRCLE_ENTITY_SECRET, CIRCLE_WALLET_ID) when that wallet supports the selected offer. Omit it and the single configured wallet is used; omit it with none configured against a paying service and the error names what to set. Wallet and chain are separate choices; both must support the actual offered signing domain.",
        +  "enum": [
        +    "key",
        +    "cdp",
        +    "circle",
        +    "arc"
        +  ],
        +  "type": "string"
        +}
    • Changedprepare_inputs2 fields changed
      • addedInput schema / properties / action
        Added value: +{
        +  "additionalProperties": false,
        +  "description": "The EIP-712 action to authorise. Required for arc_eligibility and rejected for every other circuit. Any structure is provable: the circuit hashes it without reading it, so a deposit, a grant of authority or an agreement in prose all work. The wallet signs exactly these fields, and the proof carries their hash.",
        +  "properties": {
        +    "domain": {
        +      "additionalProperties": false,
        +      "properties": {
        +        "chainId": {
        +          "type": "number"
        +        },
        +        "name": {
        +          "type": "string"
        +        },
        +        "verifyingContract": {
        +          "type": "string"
        +        },
        +        "version": {
        +          "type": "string"
        +        }
        +      },
        +      "required": [
        +        "name",
        +        "version",
        +        "chainId",
        +        "verifyingContract"
        +      ],
        +      "type": "object"
        +    },
        +    "message": {
        +      "additionalProperties": {},
        +      "type": "object"
        +    },
        +    "primaryType": {
        +      "type": "string"
        +    },
        +    "types": {
        +      "additionalProperties": {
        +        "items": {
        +          "additionalProperties": false,
        +          "properties": {
        +            "name": {
        +              "type": "string"
        +            },
        +            "type": {
        +              "type": "string"
        +            }
        +          },
        +          "required": [
        +            "name",
        +            "type"
        +          ],
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "type": "object"
        +    }
        +  },
        +  "required": [
        +    "domain",
        +    "types",
        +    "primaryType",
        +    "message"
        +  ],
        +  "type": "object"
        +}
      • changedInput schema / properties / circuit / enum
        Previous value: -[
        -  "coinbase_kyc",
        -  "coinbase_country",
        -  "oidc_domain"
        -]New value: +[
        +  "coinbase_kyc",
        +  "coinbase_country",
        +  "oidc_domain",
        +  "arc_eligibility"
        +]
    • Changedrequest_challenge2 fields changed
      • changedInput schema / properties / circuit / enum
        Previous value: -[
        -  "coinbase_kyc",
        -  "coinbase_country",
        -  "oidc_domain"
        -]New value: +[
        +  "coinbase_kyc",
        +  "coinbase_country",
        +  "oidc_domain",
        +  "arc_eligibility"
        +]
      • changedInput schema / properties / inputs / description
        Previous value: -"Full ProveInputs object from prepare_inputs. Accepts a JSON string or a structured object."New value: +"Use {} to discover the nonce, payment offers and optional TEE key without transmitting private witness inputs. Also accepts a JSON string or object from trusted local code; any supplied witness is sent to the selected prover and must stay out of model context, dApp/UI and logs."
    • Changedsubmit_proof3 fields changed
      • changedInput schema / properties / circuit / enum
        Previous value: -[
        -  "coinbase_kyc",
        -  "coinbase_country",
        -  "oidc_domain"
        -]New value: +[
        +  "coinbase_kyc",
        +  "coinbase_country",
        +  "oidc_domain",
        +  "arc_eligibility"
        +]
      • addedInput schema / properties / nonce
        Added value: +{
        +  "description": "The \"nonce\" field from the request_challenge response. Single-use and bound to the circuit it was issued for — request a new challenge for every submission and for every circuit.",
        +  "type": "string"
        +}
      • changedInput schema / required
        Previous value: -[
        -  "circuit",
        -  "inputs"
        -]New value: +[
        +  "circuit",
        +  "inputs",
        +  "nonce"
        +]

TDQS

A4.2/5.0

Scored across 7 tools

Disambiguation4/5

Each tool maps to a distinct step (prepare, challenge, submit, verify) plus discovery, approval polling, and an all-in-one shortcut. The only real overlap is generate_proof versus the three-step pipeline, but the description explicitly frames generate_proof as the simplified path, so an agent can choose confidently.

Naming Consistency5/5

All seven tools follow a clean snake_case verb_noun pattern (get_action_approval, prepare_inputs, request_challenge, submit_proof, verify_proof, get_supported_circuits, generate_proof). No mixed conventions or vague one-word names.

Tool Count5/5

Seven tools is well within the sweet spot and each one earns its place: discovery, three granular pipeline steps, an orchestrated shortcut, on-chain verification, and async approval polling. Nothing feels padded or missing at the count level.

Completeness4/5

The surface covers the full proof lifecycle from circuit discovery through challenge, proof submission, and on-chain verification, including the human-approval resumption loop. Minor gaps exist around payment orchestration (explicitly deferred to the SDK) and approval management (no list/cancel), but agents can work around these.

Maintenance

ActivityActive
ResponsivenessResponsive

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    A
    maintenance
    MCP server for wallet auth: read wallet state on-chain, evaluate against conditions, return an ECDSA-signed boolean with a post-quantum companion signature. Condition-based access across 37 chains (EVM, Solana, XRPL, Bitcoin, Tron, Stellar, Sui). No balances, no identity, no shared secrets; verifiable offline via JWKS. 27 tools: wallet attestation, trust profiles, payment verification.
    27
    499 npm
    2
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    An MCP server for agentic commerce, enabling AI agents to discover services, make x402 payments with USDC across multiple chains, and manage crypto wallets and token swaps.
    324 npm
    1
    MIT