DEV Community

Edison Flores
Edison Flores

Posted on

ATC is now real: Ed25519-signed agent trust cards with working verify + revoke

Yesterday I wrote about 8 security layers for my MCP marketplace. Today I'm shipping the 9th: Agent Trust Cards (ATC) — and this time the cryptography is real, not a mock.

What is ATC?

ATC = SSL certificates for AI agents. MarketNow acts as the Certificate Authority (CA). Every agent gets a cryptographically signed trust card that other agents can verify.

Agent A wants to call Agent B's tools
→ Agent A fetches Agent B's ATC: GET /api/atc?action=verify&card_id=X
→ Verifies the Ed25519 signature with the CA public key
→ Checks: not expired, not revoked, sentinel_score > threshold
→ If valid: trusts Agent B and proceeds
→ If invalid: refuses to interact
Enter fullscreen mode Exit fullscreen mode

This is exactly how SSL works for websites, but for agents.

What's real now (vs what was mock before)

Component Before (mock) Now (real)
CA keypair 'marketnow-ca-public-key-placeholder' Ed25519 generated with crypto.generateKeyPairSync
Signature 'signed_by_marketnow_ca' (literal string) crypto.sign(null, data, privateKey) → 128 hex chars
Verify Always returned valid: true Fetches record from GitHub, verifies signature with crypto.verify, checks expiry + revocation
Revoke Returned "revoked" but didn't persist Updates the persisted record; future verify returns valid: false, reason: 'revoked'
Persistence None (1 hardcoded card) GitHub Contents API → _data/atc/{card_id}.json (public ledger)
Sentinel score Hardcoded 10 Fetched from real Sentinel certificate in _data/sentinel_certificates/

How it works

1. The CA keypair

const { publicKey, privateKey } = crypto.generateKeyPairSync('ed25519');
// Private key → Vercel env var MARKETNOW_ATC_CA_PRIVATE_KEY
// Public key → committed to _data/atc/ca-public-key.json
Enter fullscreen mode Exit fullscreen mode

Anyone can fetch the CA public key:

GET https://marketnow.site/api/atc?action=ca-key
Enter fullscreen mode Exit fullscreen mode

2. Issuing an ATC

POST https://marketnow.site/api/atc
Content-Type: application/json

{
  "action": "issue",
  "agent_id": "agent.example.myagent",
  "public_key": "<Ed25519 public key>",
  "capabilities": ["search", "recommend"],
  "protocol_language": "mcp",
  "skill_id": "mn-mcp-filesystem"
}
Enter fullscreen mode Exit fullscreen mode

Response:

{
  "status": "issued",
  "card_id": "ATC-2026-1115271",
  "agent_id": "agent.example.myagent",
  "trust": {
    "sentinel_score": 4,
    "risk_level": "high",
    "certificate_id": "MN-SC-2026-8393995"
  },
  "signature": {
    "algorithm": "Ed25519 (RFC 8032)",
    "value": "bc79ee606339460a382f3ecc324c629e...",
    "signed_by": "MarketNow Sentinel CA"
  }
}
Enter fullscreen mode Exit fullscreen mode

The signature is over the canonical JSON of the payload:

JSON.stringify(payload, Object.keys(payload).sort())
Enter fullscreen mode Exit fullscreen mode

3. Verifying (independently)

Anyone can verify an ATC without trusting MarketNow's API:

import crypto from 'crypto';

// 1. Fetch the CA public key
const caKeyRes = await fetch('https://marketnow.site/api/atc?action=ca-key');
const { public_key_pem } = await caKeyRes.json();
const publicKey = crypto.createPublicKey(public_key_pem);

// 2. Fetch the ATC record
const atcRes = await fetch('https://marketnow.site/api/atc?action=verify&card_id=ATC-2026-1115271');
const atc = await atcRes.json();

// 3. Verify the signature yourself
const data = Buffer.from(JSON.stringify(atc.payload, Object.keys(atc.payload).sort()));
const signature = Buffer.from(atc.signature.value, 'hex');
const valid = crypto.verify(null, data, publicKey, signature);
// → true
Enter fullscreen mode Exit fullscreen mode

4. Revoking

POST https://marketnow.site/api/atc
{
  "action": "revoke",
  "card_id": "ATC-2026-1115271",
  "reason": "Key compromised"
}
Enter fullscreen mode Exit fullscreen mode

The persisted record is updated: status: 'revoked'. Future verify calls return:

{
  "valid": false,
  "reason": "revoked",
  "revoked_at": "2026-07-16T02:58:57.604Z",
  "revocation_reason": "Key compromised"
}
Enter fullscreen mode Exit fullscreen mode

5. Framework translation (bonus)

ATC also translates between agent frameworks:

POST https://marketnow.site/api/atc
{
  "action": "translate",
  "from": "langchain",
  "to": "mcp",
  "message": {
    "name": "search",
    "description": "Search skills",
    "args_schema": { "type": "object", "properties": { "q": {"type":"string"} } }
  }
}
Enter fullscreen mode Exit fullscreen mode

Returns the MCP-formatted tool schema (inputSchema instead of args_schema). Real schema mapping, not passthrough.

The public ledger

Every ATC is persisted to _data/atc/ in the public GitHub repo. Anyone can:

  • Audit the full ledger: GET /api/atc
  • Verify any card: GET /api/atc?action=verify&card_id=X
  • Check the CA key: GET /api/atc?action=ca-key
  • Clone the repo and verify signatures offline

No database, no proprietary backend. Just signed JSON files in a git repo. That's the transparency layer.

Why this matters

Agents are starting to call each other autonomously. A2A (Google) and MCP (Anthropic) handle the communication. But nobody handles trust.

Without trust:

  • Agent A can't know if Agent B is malicious
  • Agent A can't know if Agent B's tools have been audited
  • Agent A can't know if Agent B has been revoked (key compromised, ToS violation, etc.)

ATC fills that gap. It's the SSL layer for agent commerce.

Try it

# Get the CA public key
curl https://marketnow.site/api/atc?action=ca-key

# Issue a trust card for your agent
curl -X POST https://marketnow.site/api/atc \
  -H "Content-Type: application/json" \
  -d '{"action":"issue","agent_id":"your.agent","public_key":"your-ed25519-pubkey"}'

# Verify it
curl "https://marketnow.site/api/atc?action=verify&card_id=YOUR_CARD_ID"
Enter fullscreen mode Exit fullscreen mode

Edison Flores, AliceLabs LLC — marketnow.site

Top comments (0)