Blockchain ödemelerini doğrular ve ajanların dolandırıcılık içeren veya hatalı işlemleri imzalamasını önlemek için satıcı metinlerini tarar.
Ayrıca bilinen adı runningoffcode/agent-wormhole, wormhole-x402
- Yıldızlar
- 6
- Araçlar
- —
- İndirmeler, 30 gün
- —
- En son sürüm
- 0.8.0
- Son commit
- 10 Kas 2026
- Lisans
- Apache-2.0
Agent Wormhole MCP nedir?
Agent Wormhole bir MCP sunucusudur. Blockchain ödemelerini doğrular ve ajanların dolandırıcılık içeren veya hatalı işlemleri imzalamasını önlemek için satıcı metinlerini tarar.
Özet, projenin README dosyasından oluşturuldu
Agent Wormhole MCP sunucusu hakkında
Agent Wormhole, blockchain işlemleri gerçekleştiren otonom ajanlar için bir güvenlik katmanı sağlar. Bir ajanın teknik olarak geçerli olan ancak hedeflenen satıcı veya tutarla eşleşmeyen bir işlemi imzalaması gibi spesifik bir güvenlik açığını giderir. Sunucu, ödeme içeriğinin sağlanan bir teklifle (quote) mükemmel şekilde eşleşmesini sağlamak için bir kontrol noktası görevi görerek saldırganların fonları başka yöne aktarmasını veya maliyetleri şişirmesini engeller.
Geliştiriciler bunu stdio üzerinden yerel bir MCP tool server olarak kullanabilir veya bir WORMHOLE_API_KEY kullanarak barındırılan bir doğrulayıcıya bağlanabilirler. Sistem hem Solana hem de EVM ağlarını destekler. İki ana araç sunar: bir ağ teklifini işlem içeriğiyle karşılaştıran verify_payment ve bir yapay zeka modeli metni işlemeden önce satıcı açıklamalarını kötü niyetli talimatlara karşı inceleyen scan_text. Gelişmiş güvenlik için kullanıcılar, barındırılan kararların bilinen bir genel anahtara (public key) karşı kriptografik olarak doğrulanmasını sağlamak amacıyla WORMHOLE_VERIFY_PUBKEY yapılandırabilirler.
Neler yapabilirsiniz
- 1Sahte ödeme hedeflerini önlemeBir yapay zeka ajanı, işlemin teklif edilen satıcı yerine bir saldırgana gönderilip gönderilmediğini kontrol etmelidir.
- 2Şişirilmiş işlem tutarlarını tespit etmeAjanın imzalamak üzere olduğu tutarın, satıcı teklifinde belirtilen tutarla tam olarak eşleştiğini doğrulayın.
- 3Satıcı açıklamalarını temizlemeModelin davranışını manipüle edebilecek enjekte edilmiş talimatlara karşı satıcı metinlerini ve ajan kartlarını tarayın.
- 4Headless ajan iş akışlarını güvenli hale getirmeİşlemleri onaylamak için insan müdahalesine (human in the loop) sahip olmayan ajanlar için bir güvenlik kontrol noktası sağlayın.
Projenin README dosyasından alınmıştır. Her kullanım durumu, oradaki bir alıntı ile kontrol edilir.
Agent Wormhole MCP nasıl yüklenir
Biçimler 10 Kas 2026 tarihinde doğrulandıCursor'a ekleGoose'a ekleAgent Wormhole MCP'yi Claude Code içine yükleyin
$ claude mcp add --env 'WORMHOLE_API_KEY=<YOUR_WORMHOLE_API_KEY>' wormhole-x402 -- npx -y wormhole-x402Agent Wormhole MCP'yi Cursor içine yükleyin
~/.cursor/mcp.json
{
"mcpServers": {
"wormhole-x402": {
"command": "npx",
"args": [
"-y",
"wormhole-x402"
],
"env": {
"WORMHOLE_API_KEY": "<YOUR_WORMHOLE_API_KEY>"
}
}
}
}Agent Wormhole MCP'yi VS Code içine yükleyin
.vscode/mcp.json
{
"servers": {
"wormhole-x402": {
"type": "stdio",
"command": "npx",
"args": [
"-y",
"wormhole-x402"
],
"env": {
"WORMHOLE_API_KEY": "<YOUR_WORMHOLE_API_KEY>"
}
}
}
}Agent Wormhole MCP'yi VS Code CLI içine yükleyin
$ code --add-mcp '{"name":"wormhole-x402","type":"stdio","command":"npx","args":["-y","wormhole-x402"],"env":{"WORMHOLE_API_KEY":"<YOUR_WORMHOLE_API_KEY>"}}'Agent Wormhole MCP'yi Claude Desktop içine yükleyin
claude_desktop_config.json
{
"mcpServers": {
"wormhole-x402": {
"command": "npx",
"args": [
"-y",
"wormhole-x402"
],
"env": {
"WORMHOLE_API_KEY": "<YOUR_WORMHOLE_API_KEY>"
}
}
}
}Agent Wormhole MCP'yi Codex içine yükleyin
$ codex mcp add wormhole-x402 --env 'WORMHOLE_API_KEY=<YOUR_WORMHOLE_API_KEY>' -- npx -y wormhole-x402Agent Wormhole MCP'yi Codex config.toml içine yükleyin
~/.codex/config.toml
[mcp_servers.wormhole-x402] command = "npx" args = ["-y", "wormhole-x402"] [mcp_servers.wormhole-x402.env] WORMHOLE_API_KEY = "<YOUR_WORMHOLE_API_KEY>"
Agent Wormhole MCP'yi Gemini CLI içine yükleyin
$ gemini mcp add -s user -e 'WORMHOLE_API_KEY=<YOUR_WORMHOLE_API_KEY>' wormhole-x402 npx -- -y wormhole-x402Agent Wormhole MCP'yi Gemini settings.json içine yükleyin
~/.gemini/settings.json
{
"mcpServers": {
"wormhole-x402": {
"command": "npx",
"args": [
"-y",
"wormhole-x402"
],
"env": {
"WORMHOLE_API_KEY": "<YOUR_WORMHOLE_API_KEY>"
}
}
}
}Yapılandırma
WORMHOLE_API_KEYGizliOptional. Hosted-mode key from dashboard.agentwormhole.com: adds URL checks with change history, and the operator's spend policy (budgets, approvals, kill switch) on payments.
WORMHOLE_ADDRESS_LEDGEROptional. Path to the address-provenance ledger written by wormhole-guard's readguard hook (default ~/.wormhole/addresses.jsonl).
WORMHOLE_VERIFY_URLOptional. Override the hosted verifier endpoint (default https://dashboard.agentwormhole.com/api/v1/verify).
| Ad | Açıklama | Sunucu |
|---|---|---|
| WORMHOLE_API_KEY | Optional. Hosted-mode key from dashboard.agentwormhole.com: adds URL checks with change history, and the operator's spend policy (budgets, approvals, kill switch) on payments. | Gizli |
| WORMHOLE_ADDRESS_LEDGER | Optional. Path to the address-provenance ledger written by wormhole-guard's readguard hook (default ~/.wormhole/addresses.jsonl). | |
| WORMHOLE_VERIFY_URL | Optional. Override the hosted verifier endpoint (default https://dashboard.agentwormhole.com/api/v1/verify). |
Otomatik kontroller
Çalıştırıldı 13 Kas 2026Tam rapor →Otomatik kontrollerimizden geçti. Bu bir güvenlik denetimi değildir: kodu okuyun ve sunucuya ihtiyaç duyduğu en dar erişimi verin. Kontroller nasıl çalışır
- Kaynak deposu bağlantılı ve erişilebilirGeçti
- Açık kaynak lisansı (OSI)Geçti
- Son bir yıl içinde commit veya sürüm mevcutGeçti
- Paket adı popüler bir pakete yakın değilGeçti
- Uzak uç nokta HTTPS kullanıyorKontrol edilmedi
- Yıkıcı araçlar etiketlenmişKontrol edilmedi
- Modele yönelik gizli talimat yokGeçti
- Pakette veya bağımlılıklarında kritik uyarı yokGeçti
wormhole-x402
Integration guide: payment safety, policy, confirmed top-ups and launch attestations.
Your agent is about to sign a payment. Is it the one it was quoted?
ALLOW pays the quoted merchant, quoted amount
REFUSE pays an ATTACKER instead
[X402-001] payment destination is not the account derived from the quote
REFUSE pays the merchant but 900x the amount
[X402-002] payment amount does not match the quoted amount
REFUSE pays correctly + silently approves a delegate
[X402-006] Approve — delegates spending authority over the account
ABSTAIN garbage bytes
could not deserialize — refusing to report it as safe
5 transactions checked in 5ms — no RPC, no network
The gap
Every transaction-security product answers the same question: what will this transaction do? Simulation, asset diffs, address reputation. All useful.
None of it helps an agent, because a payment to an attacker's address simulates perfectly. Correct balances. No revert. Clean verdict. The transaction is entirely valid — it is simply not the one that was asked for.
Nobody answers is this the transaction that was asked for?
In the leading provider's API that question is not merely unimplemented, it is
not expressible. Their Solana scan request carries origin — "DApp domain
proposing these transactions" — and has no field for the agent's instructions
at all. The stack is shaped around a human approving a website's request. A
headless agent has neither a website nor a human.
How it decides
One call, either chain
verify() takes a quote and the payment about to be signed, picks the rail from
the network string, and returns one verdict. It runs the quote-text scan first —
an injected instruction in a merchant's description is refused before its numbers
are ever treated as authoritative — then compares destination, asset and amount.
import { verify } from "wormhole-x402/verify";
const result = await verify(
{
network: "eip155:8453", // or "solana"
quote, // what the merchant's 402 said
payload, // what the agent is about to sign
},
{ quoteProvenance: "caller_asserted", issuedAt: new Date().toISOString() },
);
if (result.decision !== "allow") {
// refuse AND abstain both mean do not sign. "We could not check it" is
// never "it is fine" — that conflation is the bug this library exists for.
throw new Error(result.findings.map((f) => f.code).join(","));
}
Time is an input rather than read from the clock, so a verdict is a pure function of its request and replays identically later.
The other entry points
| Import | What it is |
|---|---|
wormhole-x402/verify |
verify() — the unified check, both rails |
wormhole-x402/client |
guardedPay() / guardedFetch() — one line in front of sign() |
wormhole-x402/receipt |
verifyReceipt() / replayMatches() — check a receipt offline |
wormhole-x402/server |
createVerifyHandler() — host it yourself |
wormhole-x402/metering |
usage accounting and cross-agent correlation |
wormhole-x402/mcp |
the verifier as an MCP tool server — npx wormhole-x402-mcp |
wormhole-x402/provenance |
X402-301 — was this payee introduced by anything legitimate? |
wormhole-x402/delivery |
X402-4xx — did the paid response deliver the quoted resource? |
wormhole-x402/tx |
X402-7xx — is this transaction the one the agent meant to send? |
guardedPay takes the transport as an argument rather than a URL, so the same
call runs against the local verifier or a remote one and the two cannot drift.
A verdict off a socket is a claim, not an answer
guardedPay and guardedFetch require an integrity option. It has no
default, because every default here is either a silent downgrade of your
security or a surprise change to your behaviour:
import { guardedPay } from "wormhole-x402/client";
import { publicKeyFromSpkiBase64 } from "wormhole-x402/receipt";
// The verifier publishes its key at GET <base>/v1/key
const publicKey = publicKeyFromSpkiBase64(publishedKeyBase64);
const res = await guardedPay({
network, quote, payload, transport,
integrity: { mode: "required", publicKey },
});
if (res.allow) await sign(payload);
Under mode: "required" a decisive verdict clears only if a receipt is present,
its signature verifies against your key, the receipt is bound by digest to the
request you actually sent, and the receipt's own decision agrees with the
envelope's. Anything else becomes an abstain — never an allow, and never a
refuse — with integrityFailure naming which check failed. res.verified tells
you whether the cryptography actually ran.
For an in-process transport that never crosses a network, say so explicitly:
integrity: { mode: "trusted_transport", reason: "in-process verify(), no socket" }
verified is then false, because nothing was checked. A verifier running
without a signing key produces abstains under required, which is the honest
answer: an unsigned verdict is one nobody can check.
The MCP server applies the same rule to hosted verdicts. Set
WORMHOLE_VERIFY_PUBKEY to the published key; without it a hosted allow is
downgraded to abstain unless you explicitly accept an unverifiable one with
WORMHOLE_ALLOW_UNSIGNED_HOSTED=1.
Receipts
A decisive verdict carries a receipt: the decision, the rule codes, a coarse amount band and a SHA-256 digest of the request — never the quote text, never the payment bytes. Signed, it is checkable by someone who does not trust you:
import { verifyReceipt, replayMatches } from "wormhole-x402/receipt";
verifyReceipt(receipt, signature, publicKey); // did we really say this?
replayMatches(receipt, request); // is it this exact request?
Neither call touches the network. That is the point of a receipt — an attestation you have to phone someone to check is just their word with extra steps.
Install
Every chain dependency is an optional peer, so you install only the one you
use — and you must install it. The entry point for each chain imports its own SDK
at the top level, so wormhole-x402 alone imports nothing useful:
# Solana
npm install wormhole-x402 @solana/web3.js @solana/spl-token
# EVM
npm install wormhole-x402 viem
# Text scanning only — no chain SDK needed
npm install wormhole-x402
Each entry point is independent. wormhole-x402/evm and
wormhole-x402/quotetext work with no Solana packages present, and
wormhole-x402 works with no viem. Importing an entry point whose SDK is not
installed is a module-resolution error, not a silent no-op.
As an MCP tool server
Agents that cannot be rewired — Claude Code, Cursor, any MCP host — get the
same checkpoint as a tool. Zero extra dependencies: the server is
newline-delimited JSON-RPC over stdio, spoken with Node's own readline.
# full install — verifies payments on both rails
claude mcp add x402-guard -- npx -y -p wormhole-x402 -p @solana/web3.js -p @solana/spl-token -p viem wormhole-x402-mcp
# lightest form — text scanning only; verify_payment abstains with install
# instructions until the chain SDKs for your rail are present
claude mcp add x402-guard -- npx -y wormhole-x402
Two tools:
verify_payment— network, quote, payload (and optionallyexpectedPayer) in;allow/refuse/abstainwith findings out. Anything that is notallowmeans do-not-sign.scan_text— a 402 body, a merchant listing, an agent card, a memo; scanned for injection shapes before the model reads it.
The server always starts and scan_text always works — the verify core
loads lazily, so a missing chain SDK is a per-call abstain naming the install
command, never a startup crash.
Set WORMHOLE_API_KEY and verification runs against the hosted verifier
instead, returning its answer verbatim — including any spend-policy decision
the operator's account enforces there. An unreachable hosted verifier abstains
rather than silently falling back to the local core: the operator configured
hosted mode to get their policy applied, kill switch included. Verdicts carry caller_asserted provenance — the server cannot see
where the quote came from, so its receipts say so rather than implying an
attestation nobody made.
import { guardSigner } from "wormhole-x402";
// `quote` is the PaymentRequirements from the server's HTTP 402 response.
const wallet = guardSigner(myWallet, () => currentQuote);
// Signing now throws unless the transaction matches the quote.
await wallet.signTransaction(tx);
On EVM the payment is a detached EIP-3009 authorization rather than a
transaction, so it has its own wrapper — same guarantee, async because domain
verification can read the chain:
import { guardEvmSigner } from "wormhole-x402/evm";
const signer = guardEvmSigner(myWalletClient, () => currentQuote);
// viem sends this single object; ethers sends the same parts positionally —
// signTypedData(domain, types, value) — and the wrapper recognises both. This
// is the call that CREATES the signature, so there is nothing to recover from
// yet. The wrapper checks the domain against the trusted table for (chainId,
// asset), requires the TransferWithAuthorization struct exactly as verified,
// and compares to, value, the validity window and the nonce to the quote.
await signer.signTypedData({ domain, types, primaryType, message });
The typed-data request is what the wallet signs, so it is the one checked, read where the signer reads it: viem's one request object, the first argument, or ethers' domain, types and value, the first three. A call that could be read either way, or that carries an already-signed payment beside a typed-data request, is refused, with the typed request's own findings when it has any: which one a wallet would sign is the wallet's choice, and one cannot be checked for the other.
Both wrappers are default-deny. Every function property is wrapped, not a
named subset: the ones the wrapper knows how to check are checked, and
everything else is refused rather than handed back. Object properties that
expose signing methods — viem's account, a wallet adapter's inner provider —
are wrapped too, because handing back the raw object is the same hole one level
down.
That means an unmodelled method is unusable rather than unchecked, which is the
trade worth making: "we did not recognise the call so we allowed it" is how
every bypass is written up afterwards. If a method cannot move funds, name it in
allow — an escape hatch with a name on it. Dotted paths work for nested
members (allow: ["account.sign"]).
No quote is a refusal, not a pass. Every optional security parameter with a permissive default ends up unset in production, and then the guard reports green on all traffic and nobody notices.
Or inspect without wrapping:
import { inspectPayment } from "wormhole-x402";
const verdict = inspectPayment(serializedTx, {
payTo: "merchant address from the 402 response",
asset: "token mint",
amount: "1000000", // base units, exact
});
// → { decision: "allow" | "refuse" | "abstain", findings: [...] }
The facilitator flow
Most agents never submit a transaction themselves — they build and partially
sign one (the facilitator pays the fee, which is what makes it feel gasless)
and ship it base64 inside the X-PAYMENT header. The client's key still
touches the bytes exactly once. These are those bytes:
import { inspectPaymentPayload, quoteFromRequirements } from "wormhole-x402";
// `accepts[0]` from the server's 402 response — never model-authored
const quote = quoteFromRequirements(paymentRequired.accepts[0]);
// the X-PAYMENT payload the client is about to sign/ship
const verdict = inspectPaymentPayload(xPaymentHeader, quote);
if (verdict.decision !== "allow") throw new Error(verdict.reason);
EVM (EIP-3009)
On EVM the agent does not sign a transaction — it signs an EIP-712 typed message authorizing the transfer, which a facilitator later submits. The same question applies to those bytes: does the authorization about to be signed match the quote? The EVM verifier lives at a separate entry point so a Solana-only install never pulls an EVM crypto library.
import { inspectAuthorization } from "wormhole-x402/evm";
// quote: { network: "eip155:8453", asset, payTo, amount } from the 402 response
// payload: { signature, authorization: { from, to, value, validAfter, validBefore, nonce } }
const verdict = await inspectAuthorization(quote, payload); // offline, no RPC
if (verdict.decision !== "allow") throw new Error(verdict.reason);
inspectAuthorization recovers the signer from the signature and confirms it is
the stated payer, then compares recipient, amount, token, and chain against the
quote. The EIP-712 domain is built from a curated (chainId, contract) table
of on-chain-verified values — never from the quote's extra, which is
attacker-influenceable. An unknown chain or token abstains rather than guesses.
It refuses standing-authority primitives — an Approve, an EIP-2612
Permit, a Permit2 allowance — that grant a spender ongoing access rather than
making a one-shot payment. This matters on EVM specifically: USDC on Base
implements EIP-2612, so a malicious unbounded Permit validates against the
same domain as a legitimate transfer; the only offline discriminator is the
EIP-712 type. viem is an optional peer dependency (npm install wormhole-x402 viem).
The validity window gets the same treatment as a standing authority, because a
long one is one: an authorization still valid next week can be collected next
week. Before signing (inspectTypedDataRequest, and so guardEvmSigner), the
window may run no longer than the quote's maxTimeoutSeconds plus ten minutes
of clock allowance, and never longer than a day; a quote that names no timeout
gets the day, and one whose timeout cannot be read gets no verdict. Past that,
X402-105 refuses. On a signed payment (inspectAuthorization, verify()), a
window over a day is reported as a medium X402-105 instead: the signature
already exists, and the payer's guard is the place to refuse it. The caller's
clockSkewSeconds widens the other window checks, never these caps.
evmQuoteFromRequirements carries the 402 entry's timeout as a whole number of
seconds, and leaves out any other value, so a converted quote's request digest
is what it was without it.
The one design constraint
Intent must never be something the agent states.
If intent is a field the model fills in, a compromised model fills in both sides of the comparison and validates its own forgery. That is worse than no check at all, because it manufactures confidence at the exact moment funds move irreversibly.
x402 is the case where this works cleanly. The recipient, amount and mint arrive as structured JSON in the server's HTTP 402 response — before the transaction exists, on a channel entirely separate from the model's context. That is a genuinely independent second input.
And the comparison is pure arithmetic: the destination token account derives
deterministically from (recipient, mint). No RPC required.
Agent Wormhole MCP soruları
Agent Wormhole MCP'yi Claude Code'a nasıl eklerim?
Terminalinizde claude mcp add --env 'WORMHOLE_API_KEY=<YOUR_WORMHOLE_API_KEY>' wormhole-x402 -- npx -y wormhole-x402 komutunu çalıştırın. Her projede kullanılabilir olması için --scope user ekleyin.
Agent Wormhole MCP'yi Cursor'a nasıl eklerim?
~/.cursor/mcp.json dosyasını açın ve yukarıdaki yükleme bölümünde gösterilen Cursor yapılandırmasını kullanarak sunucuyu mcpServers altına ekleyin.
Bunu satıcı açıklamalarını taramak için kullanabilir miyim?
Evet, scan_text aracı, model metni okumadan önce 402 gövdelerini, satıcı listelerini veya ajan kartlarını injection biçimlerine karşı tarar.
Sunucu, işlemleri doğrulamak için bir ağ bağlantısına ihtiyaç duyar mı?
Hayır, RPC veya ağ çağrıları yapmadan çevrimdışı kararlar verebilir.
MCP server barındırılan kararları nasıl yönetir?
Yerel kararlarla aynı kuralları uygular; eğer WORMHOLE_VERIFY_PUBKEY ayarlanmamışsa, barındırılan bir izin (allow), açıkça izin verilmediği sürece çekimser (abstain) durumuna düşürülür.