Honeypot and rug-pull check API for AI agents
One call before your agent buys a token: a sell simulation, the taxes, liquidity
depth, pair age and same-ticker impersonation, rolled into low, medium,
high or unknown with every signal behind it. Remote MCP server and plain
HTTP. Free, no account, no API key.
Connect over MCP
Streamable HTTP at https://vetagent.dev/mcp. Any MCP client that accepts a remote
server URL works; for one that reads a JSON config:
{
"mcpServers": {
"vetagent": { "type": "http", "url": "https://vetagent.dev/mcp" }
}
}
Three tools: assess_token_risk (the verdict), get_token_liquidity
(price and depth only) and find_new_hot_pools (discovery, never an endorsement).
Or call it over HTTP
# the address in the body, which keeps it out of URLs and logs along the way
curl -X POST https://vetagent.dev/assess \
-H 'content-type: application/json' \
-d '{"address": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", "chain_hint": "base"}'
# convenient, but the address travels in the URL
curl "https://vetagent.dev/assess/0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913?chain_hint=base"
What comes back
A shortened real answer for USDC on Base (evidence trimmed):
{
"risk_level": "low",
"risk_score": 0,
"confidence": "high",
"driver": null,
"signals": [
{"severity": "ok", "name": "Liquidity is adequate", "category": "liquidity"},
{"severity": "ok", "name": "Buys and sells normally", "category": "honeypot"}
],
"recommendation": "Low risk: sellable and liquid when checked, no fatal signal. ...",
"checked_at": "2026-09-15T05:17:23Z",
"evidence_max_age_seconds": 0
}
| Field | How an agent should read it |
|---|---|
risk_level | low means no fatal signal in the checks that
ran — the exit was open when we looked, not that nobody can close it. medium:
real signals, none fatal; surface them. high: do not proceed unreviewed.
unknown: a critical check could not run — never a green
light. |
driver | The one signal that decided the verdict, by name and
category. null when nothing above ok fired. |
confidence | How complete the input data was, not how safe the token
is. An answer that leaned on cached data is at most medium. |
unknown_kind, next_action | Only on
unknown: whether to retry (our upstream failed) or abstain (nothing can see the
token). |
checked_at, evidence_max_age_seconds | When the answer was made, and how old its oldest evidence is. |
What it checks, and where
| Check | Chains |
|---|---|
| Buy/sell simulation (honeypot), buy/sell/transfer tax | Ethereum, BSC, Base |
| Mint and freeze authority, top-10 holder concentration | Solana |
Liquidity depth — counted only for reserves held in independently priced assets,
so a pool priced in its creator's own token cannot buy a low | Ethereum, BSC, Base, Arbitrum, Optimism, Polygon, Avalanche, Solana; elsewhere the depth a pool states is used as stated |
| Pair age, 24h turnover across the token's pools | Every chain |
| Same-ticker impersonation, within one chain | Every chain |
| Owner powers in the bytecode (blacklist, tax change, pause, mint) — disclosed, never scored | Ethereum, BSC, Base |
On a chain the sell simulator does not cover, the answer says so and comes back
unknown rather than pretending the check ran. Pass chain_hint
(ethereum, bsc, base, arbitrum,
polygon, optimism, avalanche, solana): the same
address can exist on several chains, and without a hint an answer covers the one holding the most
depth and names it.
Limits
About 60 tool calls a minute per caller, then HTTP 429 with Retry-After. At most 10
messages in one JSON-RPC batch. The token address you look up is not logged. How accurate it is,
including the numbers that make it look worst, is on the method page.