Lucent
This server analyzes Ethereum transactions and ERC-7730 clear-signing descriptors to assess how safely a contract call can be presented to a signer.
Preflight a transaction — bind chain, sender, destination, calldata, and value to a descriptor; get a
safe_to_present,review, orblockdecision plus audit, comprehension, danger, and assurance details.Check a descriptor — authoring-time review of an ERC-7730 descriptor with audit grade, comprehension risk, and danger-primitive scan.
Explain a signature — generate a plain-language actor→action→object consequence sentence and risk tier for one function's confirmation copy.
Scan a contract — fetch a verified ABI from Sourcify and flag dangerous capabilities such as arbitrary calls, delegatecall, self-destruct, upgrade-and-execute, unbounded delegation, authority transfer, and value sweeps.
Allows AI agents to pre-flight Ethereum transactions by checking ERC-7730 clear signing descriptors, explaining contract call semantics, and danger-scanning deployed contracts for unsafe primitives.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@LucentCheck the ERC-7730 descriptor for the USDC contract"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Lucent
Tooling to author, verify, and attest ERC-7730 Clear Signing descriptors for the public registry that compatible wallets read from.
A descriptor is a JSON file that tells a wallet how to render a contract call in plain language, so users see what they are signing instead of raw hex. Lucent covers the full path: find contracts that lack a descriptor, write and harden one, check it beyond schema validity, prove it against real transactions, and produce an ERC-8176 attestation.
Hosted preflight API
Lucent's primary product surface is a call-scoped HTTP API with a stateless analysis core and bounded access/payment ledgers. It binds one unsigned EVM call (including sender) to one descriptor deployment, resolves the exact calldata selector, decodes the arguments, and runs the audit, comprehension, and danger checks only for that selected function:
make setup
make api
curl http://127.0.0.1:8780/health
open http://127.0.0.1:8780/docsPOST /v1/preflight returns call and assessment fingerprints with a
safe_to_present, review, or block decision. A blocked call is a successful
assessment and therefore returns HTTP 200; malformed, unbound, ambiguous, or
undecodable input returns a stable application/problem+json error.
The words are intentional: safe_to_present never means safe to execute.
Version 1 uses a deliberately narrow scalar presentation profile. Local mode
can analyze caller-supplied ABI data; protected deployments can instead require
a finalized runtime-bytecode match and Sourcify ABI before a verdict is
returned. Hosted V1 rejects proxy-backed deployments until dispatch and
upgrade-state semantics can be proven, including custom delegatecall
dispatchers without EIP-1967 slots. Neither mode simulates state, detects
economic exploits, or judges the counterparty. Those limits ride in every
response. Full contract and deployment modes:
docs/HOSTED-API.md.
Protected access and Base-USDC payments
The API and container start disabled. make api opts into loopback-only local
development (open, verified source off, x402 off). Production modes are
configured explicitly at startup and fail closed when their dependencies are
incoherent:
api_key— hashed tenant keys, per-tenant token buckets, and five-minute idempotent result replay;x402— official x402 v2 challenge/signature/receipt headers and exact USDC settlement on Base mainnet;api_key_or_x402— subscription/quota access for integrations, with USDC pay-per-request fallback.
Any mode that accepts x402 requires verified-source mode. Payment proofs are verified before Lucent uses RPC/Sourcify capacity, settled only after a complete result exists. Exact retries replay the retained receipt, while a separate authorization ledger prevents the same signed EIP-3009 transfer from being rewrapped under a new idempotency key. Paid outcomes are not evicted while unexpired, and authorizations must expire within the server-owned five-minute window. The container runs one worker by default; scale-out requires a shared quota/idempotency/authorization-claim backend.
Related MCP server: web3agent
For signing agents: the MCP server
An AI agent about to sign a transaction faces exactly the question Lucent's
checks answer — is this call clear enough to present, and does the screen a
human would see actually describe what it does? scripts/mcp_server.py exposes
that as an MCP server (JSON-RPC over stdio) so an agent can pre-flight a signature:
preflight_transaction— the primary transaction-time gate. It bindschain_id,from,to,data, andvalueto a matching descriptor deployment, decodes one unique selector, analyzes only that function, and fingerprints the complete request.check_descriptor— an authoring-time report over an ERC-7730 descriptor: the audit grade (screen shows the right fields), the comprehension grade (a plain-language consequence sentence + risk tier per function), and the danger scan (structural primitives a clear screen can't make safe). It is not bound to a pending call and must never authorize one.explain_signature— an unbound actor→action→object sentence + risk tier for descriptor-authoring and UX-copy review, never transaction approval.scan_contract— danger-scan a deployed contract by address (fetches the verified ABI from Sourcify), so an agent can assess a contract before any transaction is built.
make mcp # or: .venv/bin/python scripts/mcp_server.pyRegister it as a stdio MCP server pointing at scripts/mcp_server.py from the
repo root (see mcp.json). Same transport shape as the sibling Groundcheck and
Seiche servers.
For every pending call, use preflight_transaction. Its model-facing output
hashes arbitrary string calldata, and its server-owned consequence sentence
never incorporates descriptor-authored prose.
Install
make setup # creates .venv and installs requirements (Python 3.12+)Most stages that read on-chain data need a free Etherscan API key:
export ETHERSCAN_API_KEY=...Pipeline
Stage | Script | Purpose |
Discover |
| Classify candidates: verified, signable, and uncovered |
Fetch ABI |
| Verified ABI from Sourcify (a registry requirement) |
Resolve proxy |
| Cache an implementation ABI under a proxy address |
Generate |
| Bootstrap a draft descriptor |
Lint |
| Schema, selectors, device limits, ABI consistency |
Audit |
| Grade the descriptor on screen trustworthiness |
Comprehend |
| Grade the descriptor on human comprehension risk |
Danger |
| Flag structural danger primitives a clear screen can't make safe |
Verify |
| Check the screen against real on-chain movements |
Prove |
| Render the screen and build real test vectors |
Package |
| Registry-form output under |
Attest |
| ERC-8176 attestation over the descriptor hash |
Watch |
| Monitor merged descriptors for drift |
Review |
| All checks composed into one publishable report |
A common.py module holds the shared Sourcify and Etherscan clients and ABI
utilities. lucent/preflight.py is the shared call-scoped decision core used by
both HTTP and MCP, so transports cannot drift on verdict policy.
Audit
erc7730 lint checks that a descriptor is well-formed. audit.py checks whether
the on-device screen would mislead a user, which lint does not:
CRITICAL: a payable function that never shows
@.value, or atokenAmountwith no known token.HIGH: a signable function with no intent or no visible field, or an address shown as raw hex.
MEDIUM/LOW: labels or intents past the device character limits, missing interpolated summaries.
It reports a letter grade. to_submission.py refuses to package below grade B.
A raw generated draft of the ENS controller scores F; the hardened descriptors
score A.
Comprehension risk
Lint checks that a descriptor is well-formed; audit.py checks that the screen
shows the right fields. Neither asks the question that
"What I Sign Is Not What I See" shows is the
real failure: users mis-understand a technically-correct screen. Its studies
found people fixate on the amount and recipient and miss scope, delegation, and
unlimited allowances — and that a bare field list, even a complete one, leaves
comprehension at chance on the dangerous cases. Its Signature Semantic Decoder
cut false approvals on unlimited-allowance and phishing transactions by 73% and
46% by rendering an actor→action→object sentence and a risk tier with a reason.
comprehend.py brings that to the descriptor. For each signable function it
emits:
a consequence sentence — who acts on what, plus conditions, built from the ABI and the descriptor's own labels so it renders what the wallet will show: "You let {Operator} transfer ANY of your tokens in this contract, at any time, until you revoke it."
a risk tier with the clause that earned it — the paper's users rejected bare labels and demanded the why. Patterns scored are the ones the study found people miss: operator grants (
setApprovalForAll), ERC-20 allowances (flagged distinctly from ERC-721 token-id approvals, sinceapprove(address,uint256)reads identically but means different things), permits (off-chain, invisible in history), admin/upgrade authority, and raw-hex recipients (the address-poisoning surface).
An unrecognised function with no on-screen intent is reported as an unexplained
screen (a caution), never silently cleared — an unexplained screen invites blind
approval, which is the failure the paper measures. Run it with make comprehend DESC=…; NameWrapper's setApprovalForAll and the controller's
transferOwnership both surface as CRITICAL comprehension risks that lint and
audit pass.
Danger surface
Audit asks whether the screen shows the right fields; comprehend asks whether the
human understands them. danger.py asks the third question: can this function,
by construction, do something a clear screen still can't make safe? A descriptor
can render a perfectly honest sentence for execute(address target, bytes data) —
"Call {target} with {data}" — and that call can still drain the wallet, because
the primitive itself is unbounded.
Runtime systems catch this by instrumenting transaction-trace properties
(arXiv:2408.14621: arbitrary
CALL/DELEGATECALL/SELFDESTRUCT in the trace). danger.py lifts the same
property set to static ABI analysis, so the danger is named before anyone
signs:
CRITICAL — arbitrary external call (a call-family name, or a target-address
calldata-blob signature),
delegatecall(foreign code in this contract's context), self-destruct, and upgrade-and-execute.
HIGH — unbounded delegation (
setApprovalForAll), authority transfer (ownership / admin / role).MEDIUM — value sweep to a caller-supplied address.
Precision is the whole game: a danger scan that cries wolf on safeTransferFrom
is worse than none. The detector distinguishes calldata from data-as-content by
parameter name (target+data, not any address-plus-bytes), excludes to
(a recipient, not a callee), and whitelists the standard ERC receiver hooks — so
the shipped ENS bundle raises zero false arbitrary-call flags while a real
execute(target,data) drainer is still caught. --strict exits non-zero on any
CRITICAL.
Semantic verification
Lint proves a descriptor is well-formed, not that its summary is honest. A descriptor can pass every schema check and still render a benign screen for a call that sends assets elsewhere.
For each test vector, semverify.py fetches the mined receipt (the record of
what actually moved), extracts the asset movements and approvals (ETH, ERC-20,
ERC-1155, ApprovalForAll), and checks the screen against them: every real
recipient and operator is shown, ETH spent is shown, and the field labelled as
the recipient matches the address that received the asset.
Worked example, a safeTransferFrom descriptor with the To and From labels
swapped:
Check | Result |
| pass (schema-valid, both fields shown) |
| grade A (structurally correct) |
| divergence (labels the sender as recipient) |
The receipt is exact for mined transactions. The recipient check is heuristic on field labels; it catches recipient hiding and label spoofing, not every possible mismatch.
Unmined calls — fork replay. A brand-new descriptor for a call that has never
been mined (a fresh contract, a rarely-used function) has no receipt to check
against. forkreplay.py closes that gap: given a call spec
{signer, function, args, value} it forks mainnet at HEAD into a local anvil,
impersonates the signer, executes the call against real on-chain state, and reads
back the standard eth receipt. That (tx, receipt) pair is handed to
semverify.verify_one unchanged — so a label swap or hidden recipient on an
unmined call is caught by the identical, tested code path, not a second
implementation. Run it with make semverify DESC=… SIMULATE=1 on a test file
whose vectors carry a call object instead of a txHash. It needs anvil +
cast (foundryup) and an RPC URL (ETH_RPC_URL); without them the call vector
is skipped with a reason, never silently passed.
Reviewing a registry PR
The clear-signing governance model asks security reviewers to check descriptor
PRs "for correctness, clarity, and adversarial edge cases, then publish your
findings clearly." review.py is that role as one command: it composes lint,
the screen audit, the comprehension grade, the danger scan, and (when test
vectors and an ETHERSCAN_API_KEY are available) semantic verification into a
single markdown report ready to post on the pull request:
make review DESC=path/to/calldata-Contract.json OUT=review.mdreview.py and check_descriptor are authoring reports over the full
descriptor. They intentionally do not replace the call-scoped
preflight_transaction gate: only preflight binds sender, destination,
calldata, value, and one selected function. Checks that cannot run are reported
as explicit skips with the reason, never silently passed. To review a descriptor
from a registry PR, fetch its ABI first
(make fetch CHAIN=<id> ADDR=<address>) so the audit runs against the verified
on-chain ABI.
Post-quantum co-signing
A descriptor hash is keccak256, which is quantum-safe. The ECDSA signature over
it is not, and attestations are long-lived. attest.py --pq adds a post-quantum
signature over the same hash so the attestation stays verifiable if the
signature scheme is broken. The hash is unchanged; only the signature scheme is
added.
Scheme | Standard | Signature size |
| FIPS 204 | ~3.3 KB |
| FIPS 204 | ~2.4 / ~4.6 KB |
| FIPS 206 draft | ~0.65 KB (float and side-channel risk) |
| FIPS 205 | ~7.9 KB (hash-based) |
The signature binds the exact descriptor hash. Keys are read from LUCENT_PQ_*
env vars or a gitignored .attester-keys/ directory, written owner-only. No
cryptographically-relevant quantum computer exists yet and there is no standard
for post-quantum attestations, so this is forward positioning, not a current
requirement.
Attestation and fork replay are offline operator tools. They are deliberately absent from the hosted API container: the current scripts accept RPC/process or key-bearing inputs that belong in isolated workers with strict egress, resource, and signing-policy controls.
Current state
Three ENS descriptors, each grade A and lint clean against the on-chain ABI,
packaged under dist/registry-pr/ens/:
Descriptor | Functions | Test vectors |
ETHRegistrarController ( | 7 | 8 |
NameWrapper ( | 26 | 6 |
BulkRenewal | 1 | 3 |
Test vectors are real historical transactions, built with
fetch_tx.py <chain> <address> <descriptor>.
A registry PR should be submitted by or on behalf of the contract's owner. The remaining step for the ENS descriptors is that authorization, not code.
Attester registration
attest.py --profile writes an auditor profile
(auditors/eip155-1-<address>/profile.json) for a registry PR. Signing an EAS
offchain attestation needs the ERC-8176 schema UID (published on clearsigning.org)
and an attester key. Without them, attest.py writes an unsigned evidence
bundle so the pipeline can run end to end first.
Available Tools
4 toolscheck_descriptorA
PURPOSE: Authoring-time review of an ERC-7730 Clear Signing descriptor. Combines three lenses — audit (does the wallet screen show the right fields, grade A-F), comprehension (a plain-language consequence sentence + risk tier per function), and danger (structural attack primitives). Returns {verdict: {gate, reason}, audit, comprehension, danger}. GUIDELINES: Use this while writing or reviewing a descriptor. Never use it to approve a pending transaction because it does not bind chain, address, calldata, or value; use preflight_transaction for every pending call. LIMITATIONS: Static full-descriptor analysis with transaction_bound=false. It does NOT simulate the transaction against live chain state, detect economic exploits (price manipulation, MEV), or judge whether the counterparty is honest. It reports authoring defects; its verdict is not a pending-call decision. EXAMPLE: check_descriptor({"descriptor": {"context": {...}, "display": {"formats": {...}}}}) -> {"verdict": {"gate": "block", "reason": "1 CRITICAL danger primitive…"}, …}
| Name | Required | Description | Default |
|---|---|---|---|
| descriptor | Yes | The full ERC-7730 descriptor JSON, inline: an object with context.contract.abi and display.formats. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden. It discloses limitations: static analysis, no simulation against live chain state, no economic exploit detection, and explicitly states its verdict is not a pending-call decision. This is rich and honest transparency.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is structured into PURPOSE, GUIDELINES, LIMITATIONS, and EXAMPLE sections. Each segment is purposeful and front-loaded; nothing is redundant or wasteful, making it highly concise for its complexity.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Even without an output schema, the description fully covers the tool's purpose, usage boundaries, limitations, and example invocation. It leaves no critical gap for an agent to understand when and how to use it.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the descriptor parameter is already documented. The description adds an example call but largely reaffirms the schema's structure. Baseline 3 applies because the description does not significantly augment parameter understanding beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb ('Authoring-time review') and names the resource (ERC-7730 Clear Signing descriptor). It clearly distinguishes from sibling tools by focusing on descriptor analysis rather than transaction preflight or contract scanning.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit 'Use this while writing or reviewing a descriptor' and 'Never use it to approve a pending transaction... use preflight_transaction' provides clear when-to-use and when-not-to-use guidance, directly naming the alternative tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
explain_signatureA
PURPOSE: Review UX copy for ONE function of an ERC-7730 descriptor — an unbound actor->action->object consequence sentence ('You let {spender} move up to {amount} of your tokens…'), a risk tier (CRITICAL/HIGH/MEDIUM/LOW), and the specific reason it earned that tier. Returns {found, function, sentence, tier, reason}. GUIDELINES: Use this only while authoring or reviewing confirmation copy. It is not bound to chain, sender, destination, calldata, or value and MUST NOT approve a pending signature. Use preflight_transaction for every pending call. LIMITATIONS: Explains a single function's intent and comprehension risk; it does not run the danger-primitive scan (use check_descriptor / scan_contract for that) and does not simulate on-chain effects. Returns found=false with the available function names if the name is not in the descriptor. EXAMPLE: explain_signature({"descriptor": {…}, "function": "approve"}) -> {"found": true, "tier": "HIGH", "sentence": "You let … spend up to …", "reason": "an ERC-20 allowance lets the spender pull tokens…"}
| Name | Required | Description | Default |
|---|---|---|---|
| function | No | Exact function NAME to explain (not the full signature), e.g. 'approve' or 'setApprovalForAll'. | |
| signature | No | Preferred canonical signature, e.g. 'approve(address,uint256)'; required for overloads. | |
| descriptor | Yes | The ERC-7730 descriptor JSON. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden. It discloses limitations: does not run danger-primitive scan, does not simulate on-chain effects, and returns found=false with available function names when the name is missing. It also warns 'MUST NOT approve a pending signature', which is a critical behavioral constraint.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-organized into PURPOSE, GUIDELINES, LIMITATIONS, and EXAMPLE sections. It front-loads the core purpose and each section is concise without filler. The length is justified by the tool's complexity and the need to differentiate from siblings.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the description explicitly defines the return object: {found, function, sentence, tier, reason}. It also covers the failure case (found=false) and provides a concrete example. This makes the tool's behavior fully understandable without requiring additional context.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% with all parameters already well-described. The description adds an example invocation and clarifies 'function' vs 'signature' usage, but this is largely redundant with the schema. No significant new parameter semantics are provided, so baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's purpose: 'Review UX copy for ONE function of an ERC-7730 descriptor'. It specifies the resource (ERC-7730 descriptor), the action (review/explain), and the output. It also explicitly differentiates from siblings by noting it is not bound to chain/sender/calldata and does not approve signatures, distinguishing it from preflight_transaction, check_descriptor, and scan_contract.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives explicit when-to-use guidance: 'Use this only while authoring or reviewing confirmation copy'. It also names alternatives: 'Use preflight_transaction for every pending call' and 'use check_descriptor / scan_contract for that' for danger-primitive scan. This fully covers when and when not to use the tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
preflight_transactionA
PURPOSE: Analyze one exact unsigned EVM call before it is presented to a signer. Binds chain_id, sender, destination, calldata selector, decoded arguments, ETH value, and an inline ERC-7730 descriptor into one fingerprinted result. Only the selected function is assessed. Returns present/review/block plus audit, comprehension, danger, assurance, and explicit limitations. GUIDELINES: Use this as the PRIMARY transaction-time gate. block means the screen is missing essential information or the selected ABI function has a CRITICAL known danger pattern. review means a human must inspect the named risk. safe_to_present means only that the call is clear enough to show; it does not mean execution is safe. LIMITATIONS: Caller-supplied descriptor and ABI, static analysis only. No bytecode verification, proxy resolution, runtime simulation, MEV analysis, or counterparty judgment.
| Name | Required | Description | Default |
|---|---|---|---|
| descriptor | Yes | ||
| transaction | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden, and it handles this well. It discloses that analysis is static-only, lists omitted capabilities (bytecode verification, proxy resolution, runtime simulation, MEV analysis, counterparty judgment), and explicitly states that 'safe_to_present' does not mean execution is safe. It also clarifies that the descriptor and ABI are caller-supplied, which is a key dependency.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured into PURPOSE, GUIDELINES, and LIMITATIONS sections. Every sentence provides substantive information, and the purpose statement is front-loaded. No redundant or fluff content exists; it is concise yet comprehensive for a complex tool.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity (nested objects, no annotations, no output schema), the description covers key aspects: what it does, how to use it, and its limitations. It also names the return categories (present/review/block plus audit, comprehension, danger, assurance, limitations). However, it does not describe the exact output schema or error behavior, leaving minor gaps. Overall, it is nearly complete for a preflight analysis tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so the description must compensate. It mentions binding 'chain_id, sender, destination, calldata selector, decoded arguments, ETH value, and an inline ERC-7730 descriptor,' giving high-level meaning to transaction fields and the descriptor. However, it does not detail the expected structure or format of the descriptor object, nor does it explain the exact interpretation of 'safe_to_present' beyond a one-line caveat. It adds semantic value but leaves some param-level ambiguity.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's purpose: 'Analyze one exact unsigned EVM call before it is presented to a signer.' It specifies the resource (unsigned EVM call), the verb (analyze), and the scope ('only the selected function is assessed'). It distinguishes from siblings by framing itself as 'PRIMARY transaction-time gate' and listing specific outputs (present/review/block) that differ from likely descriptor validation or contract scanning.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit guidance is given: 'Use this as the PRIMARY transaction-time gate.' The meanings of block, review, and safe_to_present are explained, clarifying when to rely on the tool. However, it does not explicitly mention when to use alternatives (e.g., scan_contract, explain_signature, check_descriptor), so it lacks a full when-not comparison.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
scan_contractA
PURPOSE: Assess a deployed EVM contract for structural danger primitives by ADDRESS — no descriptor needed. Fetches the contract's verified ABI from Sourcify and flags every signable function that is a 'loaded gun': arbitrary external call, delegatecall, self-destruct, upgrade-and-execute, unbounded delegation (setApprovalForAll), authority transfer, or value sweep. Returns {matched, danger_findings: [{severity, function, primitive, why}], critical, worst_severity}. GUIDELINES: Call this to vet a contract an agent is about to interact with BEFORE any transaction is even built — the earliest possible safety check. Treat any CRITICAL finding as a strong signal not to interact without human review. Once a pending call is built, use preflight_transaction; neither this discovery scan nor check_descriptor is a signing gate. LIMITATIONS: Flags DANGEROUS CAPABILITIES the contract exposes, not proof of malicious intent — many legitimate contracts expose upgrade or admin functions. Requires a verified ABI on Sourcify; returns matched=false with a reason when the ABI is unavailable or the fetch fails. Does not analyze bytecode, proxy implementations beyond the fetched ABI, or runtime behavior. EXAMPLE: scan_contract({"chain_id": 1, "address": "0x00000000006c3852cbEf3e08E8dF289169EdE581"})
| Name | Required | Description | Default |
|---|---|---|---|
| address | Yes | 0x-prefixed 40-hex-char contract address. | |
| chain_id | No | EVM chain id: 1=Ethereum mainnet, 8453=Base, 10=Optimism, 42161=Arbitrum, 137=Polygon. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden of behavioral disclosure. It honestly states limitations: 'Requires a verified ABI on Sourcify; returns matched=false with a reason when the ABI is unavailable or the fetch fails. Does not analyze bytecode, proxy implementations beyond the fetched ABI, or runtime behavior.' It also clarifies the interpretation of findings: 'Flags DANGEROUS CAPABILITIES... not proof of malicious intent.' The return shape is disclosed, providing a complete picture.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured with clear headers (PURPOSE, GUIDELINES, LIMITATIONS, EXAMPLE), making it easy to scan and front-loaded with the purpose. It is slightly longer than needed, but every section contains valuable information. The format is appropriate for the tool's complexity.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given no output schema and no annotations, the description is remarkably complete. It explains the return structure, failure modes, limitations, and usage context in detail. It also provides an example, making it fully actionable for an agent. The description covers all necessary aspects for correct invocation and interpretation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
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 adds an example call with both parameters, which is helpful, but it does not add semantic meaning beyond the schema descriptions (address format, chain_id values). The example is a minor bonus but not a significant enhancement.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's purpose: 'Assess a deployed EVM contract for structural danger primitives by ADDRESS — no descriptor needed.' It elaborates with specific actions ('Fetches the contract's verified ABI from Sourcify and flags every signable function that is a 'loaded gun'') and lists the specific primitives detected. It distinguishes from siblings by noting 'no descriptor needed' and explicitly stating it is not a signing gate, unlike preflight_transaction.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit when-to-use guidance: 'Call this to vet a contract an agent is about to interact with BEFORE any transaction is even built — the earliest possible safety check.' It also gives alternative tool guidance: 'Once a pending call is built, use preflight_transaction; neither this discovery scan nor check_descriptor is a signing gate.' This clearly explains when to use this tool versus alternatives.
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. Dates show when Glama detected each change.
3 tool updates
v0.2.1- Changed
check_descriptor1 field changed- changed
Input schema / properties / descriptor / descriptionPrevious value: -"The full ERC-7730 descriptor JSON, inline: an object with context.contract (abi or deployments) and display.formats."New value: +"The full ERC-7730 descriptor JSON, inline: an object with context.contract.abi and display.formats."
- Changed
explain_signature3 fields changed- added
Input schema / anyOfAdded value: +[ + { + "required": [ + "signature" + ] + }, + { + "required": [ + "function" + ] + } +] - added
Input schema / properties / signatureAdded value: +{ + "description": "Preferred canonical signature, e.g. 'approve(address,uint256)'; required for overloads.", + "type": "string" +} - changed
Input schema / requiredPrevious value: -[ - "descriptor", - "function" -]New value: +[ + "descriptor" +]
- Added
preflight_transaction
3 tool updates
v0.1.0- First observed
check_descriptor - First observed
explain_signature - First observed
scan_contract
TDQS
Each tool occupies a distinct niche: check_descriptor is a holistic pre-sign gate, explain_signature drills into a single function's comprehension risk, and scan_contract assesses a deployed contract by address. While check_descriptor and scan_contract both detect danger primitives, they operate on different inputs (descriptor vs. address) and serve different stages of the workflow.
All tool names follow a consistent verb_noun snake_case pattern (check, explain, scan). No mixed conventions or vague verbs.
Three tools is a tight, purposeful set for a specialized security server. Each tool addresses a distinct phase, and none feel redundant.
The tool set covers the core workflow: vet a contract before interaction (scan_contract), gate a descriptor before signing (check_descriptor), and render a human-readable risk explanation for one function (explain_signature). No dead ends, though on-chain simulation or economic exploit detection are not provided — but those are explicitly listed as limitations, not omitted features.
Maintenance
Related MCP Connectors
Email safety MCP server. Detects phishing, prompt injection, CEO fraud for AI agents.
Security firewall for AI agents — scans MCP calls for injection, secrets, and risks.
Pre-execution safety layer for autonomous agent wallets via MCP and x402.
Crypto transaction firewall and risk tools for MCP agents.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenancePre-execution safety layer for autonomous agent wallets. Risk scoring, transaction simulation, and policy enforcement via MCP.MIT
- AlicenseCqualityAmaintenanceWeb3 MCP proxy server for AI agents: EVM execution, DeFi swaps, bridges, advanced orders, market data, wallet management, and confirmation-gated writes.1001601MIT

@vorionsys/mcp-serverofficial
AlicenseAqualityBmaintenanceMCP server for AI-agent governance using trust scoring, behavioral signals, and pre-flight action checks.10241Apache 2.0- AlicenseNot gradedqualityBmaintenanceMCP server for a pre-interaction risk check on any EVM contract/token, enabling agents to verify contracts before approving, swapping, or trusting an address.1MIT
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/beepboop2025/lucent'
If you have feedback or need assistance with the MCP directory API, please join our Discord server