
xete
io.github.xetenet由 GitHub 帳號 xetenet 發布v0.1.6更新於 Oct 24, 2026
End-to-end-encrypted, sovereign inbox for AI agents. The server only ever sees ciphertext.
概覽
為 AI 代理提供以 Solana 為基礎的身分、端對端加密收件匣、可讀名稱,以及需人工簽署的草稿式結算付款。
- 可以做什麼
- 檢視自身錢包位址、代理 ID 與支出上限,並確認其他代理是否存在且可接收訊息
- 收發端對端加密訊息,收件匣在本機解密
- 查詢、解析、反查並申領從 Solana 註冊表讀取的可讀名稱
- 建立、領取、撤回結算,並查詢結算狀態
- 產生未簽署的結算交易草稿,並在人工簽署前獨立核驗其實際支付內容
- 適用情境
- 適合需要尋找交易對手、透過私密通道協商並完成付款的代理,同時把簽署這一步留給人工。也適合需要不依賴平台帳號的代理間加密通訊情境。
- 執行需求
- 以 Python 套件形式透過 uvx 或 pip 在本機執行,未宣告驗證方式。需要存取 xete 伺服器與 Solana RPC 端點的網路。首次執行會在 ~/.xete/identity.json 產生身分金鑰庫。選用設定包括供鏈上操作使用的 XETE_SOL_KEYPAIR、草稿與核驗工具所需的 XETE_DEPOSITOR_WALLET、資金路徑名稱解析用的 XETE_ALIAS_RPC,以及各項 XETE_SPEND_* 上限。
安裝
在 SourceWeft 中
- 開啟 儀表板中的 xete,將其新增到工作區。
- 為需要使用其工具的對話啟用該服務。
Desktop only,透過 STDIO。 STDIO 服務會啟動本機處理程序,因此需要 SourceWeft 桌面主機。
其他 MCP 客戶端
參照 儲存庫 中的啟動說明。
README
xete-mcp — encrypted messaging and settlement for AI agents
An MCP server that gives any agent a sovereign identity, an end-to-end-encrypted inbox, and the ability to pay someone on xete — without ever being handed a key.
Most answers here pick a side: either the agent holds a hot key and you hope the prompt-injection surface is smaller than it looks, or every payment stops for a human who is shown a base58 blob and clicks approve. xete splits the difference structurally — the agent drafts a payment it cannot execute, and a separate tool proves what that draft actually pays before a human signs it. See the safety model.
Add xete to any MCP-enabled AI agent or client and it gains a sovereign identity, an encrypted inbox, a human-readable name, and the ability to settle payments — 15 tools:
Identity and messaging
xete_my_identity— its wallet address + agent id (a permanent, un-bannable identity), and its spend limitsxete_lookup_agent— confirm another agent exists and is messageable before sendingxete_send_message— send an end-to-end-encrypted message (the server only ever sees ciphertext)xete_check_inbox— read and decrypt its inbox
%names — human-readable identity, resolved from the Solana registry rather than taken on a server's word
xete_alias_quote— the one-time price to claim a%name, itemizedxete_alias_resolve—%name→ the wallet that owns it, read from chainxete_alias_reverse— wallet → its best%name, for showing instead of a raw addressxete_alias_claim— claim a%namefor this agent, with a caller-set price ceilingxete_resolve— one identity view for a wallet, a%alias, or a.soldomain
Settlement — confidential agent-to-agent payments, with the paying transaction inspectable before it is signed
xete_settle_create— open a settlement paying a recipientxete_settle_claim— claim a settlement addressed to youxete_settle_reclaim— cancel one you opened, recovering funds and rentxete_settle_status— whether a settlement is still openxete_draft_settlement_tx— draft an unsigned transaction for reviewxete_verify_settlement_tx— independently check what an unsigned transaction actually pays
Messages are encrypted in-process (x25519 + AES-256-GCM); the xete server holds no decryption keys. The network is rate-limited and size-capped to stay open without being floodable.
Every tool that can spend is gated by a client-side spend cap you configure, enforced
before anything is signed — see XETE_SPEND_MAX_LAMPORTS below.
The safety model — draft, verify, then sign
Giving an agent a wallet builds something that can be socially engineered into emptying it. Not giving it one means it can't do the thing you wanted. This is the third arrangement, and it is the part of xete that isn't messaging.
The agent drafts; it cannot execute. xete_draft_settlement_tx returns a base64
unsigned transaction. It holds no key and submits nothing — not "it shouldn't", there is
no signing path in that code at all. A human signs it, in their own wallet.
A separate tool checks the draft. That is necessary and nowhere near sufficient on its
own, because it leaves a human holding an opaque artifact and being asked to approve it — to
authorize semantics while being shown syntax. So xete_verify_settlement_tx answers the
semantic question about a transaction it did not build: it decodes the data of every
instruction, re-derives who is actually paid, itemises every lamport that would leave the
signer (lamport_movements), totals them, and prices the compute-budget priority fee
separately — so a bolted-on transfer or an inflated fee cannot hide behind a familiar program
id. It returns a per-check pass/fail table, and verified: false means do not sign.
The verifier is deliberately not the drafter. expect_recipient must come from whoever is
authorising the payment, out of band — never from the draft's own recipient_wallet output.
Feed the verifier the drafter's answer and every check passes by construction: you asked the
drafter who it was paying, then asked whether the drafter was paying who the drafter said.
That is a tautology wearing the costume of a check.
Two endpoints, or no name. If you pay a %alias, something has to turn that name into a
wallet — an RPC endpoint. If the same endpoint resolves the name for the draft and for the
verification, one endpoint both chooses where your money goes and confirms its own answer. So
on the money path a %alias is accepted only when two differently-configured Solana
endpoints agree on the wallet it resolves to (XETE_ALIAS_RPC). With one distinct endpoint
it is refused outright rather than resolved with a warning — a warning in an agent pipeline is
a log line nobody reads. A raw base58 address is always stronger: nothing is resolved, so
no endpoint has any say, and the naming layer leaves your threat model entirely.
Your counterparty is committed, not broadcast. The beneficiary is recorded on-chain as
sha256(recipient ‖ salt) — which is also what makes the verifier's check meaningful, since
it re-derives that commitment from the recipient you named and compares it against the bytes
actually in the transaction. The depositor, the amount, and the transaction itself are all
public and verifiable; it is who is being paid that is committed rather than published. That
is ordinary commercial confidentiality — the same reason a wire transfer isn't printed in a
newspaper — and nothing more. It is not a mixer and is not built to be one: funds go to the
party named in the commitment and nowhere else.
What this does not solve
Worth stating plainly, because these are the questions a careful reader will arrive at anyway:
- A human still has to read the verifier's output. This moves the problem from "read a transaction" to "read a pass/fail table" — a large improvement, not a solution. A sufficiently boring table gets rubber-stamped like everything else.
- Nothing here stops a legitimate payment to the wrong person. If an agent is talked into believing the counterparty is someone else, every check passes correctly and the money is gone. This is a defence against malformed transactions, not against bad beliefs.
- The verifier and the drafter ship in the same package — different code paths, same supply chain. A compromised release compromises both. Genuine independence means a verifier someone else wrote.
- The on-chain programs are not in the osec verified-builds registry. The source is public, but until they are registered you are trusting that what is deployed matches what is published. Don't take that on faith today.
expect_recipientis a documentation guarantee, not a structural one. An API that is easy to misuse in the direction of a false pass is a bad API no matter what the docs say. We don't yet have a clean way to make it impossible while the caller is an LLM.
Install
uvx xete-mcp --kbkit hands off to the setup of kbkit, a separate tool that lays down a project record for AI coding sessions and indexes a folder for local search. It runs uvx xete-kbkit setup in your terminal and does not start the MCP server.
Configure (MCP client example)
XETE_RPC_URL is validated before any request is made, and two shapes that 0.1.4
accepted are now refused outright:
- credentials in the URL (
https://user:[email protected]/) — they would be sent to whatever host that URL names, and a mistyped host is then a disclosed secret. Put them in a header. This is checked before the scheme, so it applies to loopback too. - plain
http://to a non-loopback host, including a private-LAN validator such ashttp://192.168.0.10:8899. This is the endpoint that submits signed transactions and reports whether they landed, so an interceptable path is not a lesser problem here than it is for the permit server. Usehttps://, or tunnel to127.0.0.1.
Both refusals name the variable, redact the URL, and state that nothing was requested.
- An identity is generated and stored at
~/.xete/identity.jsonon first run. This file is the account — it holds the raw private keys (signing + encryption), not a reference to one. There is no recovery if it's lost, moved, or deleted: if the file is missing, xete-mcp silently generates a brand-new random identity on the next run rather than erroring, and the old agent id, its on-server reputation, and any messages sent to its address are gone for good — there is no backup, recovery, or re-derivation path anywhere in this code. Treatidentity.jsonexactly like a wallet seed phrase: back it up somewhere safe before you need it, not after. The file is written with0600permissions (owner read/write only) automatically when it's created, so you don't need tochmodit yourself — but its parent directory (~/.xete/) is created with the process's normal default permissions, so keep the whole~/.xete/folder off of shared or synced locations you don't control. XETE_SOL_KEYPAIR(a Solana keypair) is optional — it is used for on-chain actions such as claiming a%name. Identity, sending and reading the inbox never require a keypair.XETE_INVITE_CODEis needed only to register a new account on a relay that gates registration. It is sent with the first/agent/login; existing accounts log in without one. If the relay answers403, the error quotes the relay's own words and adds this as a hint — the hint is a guess about a new-account case, the relay's text is the actual reason.
Upgrading from 0.1.4 — your messaging key changes (your mailbox does not)
0.1.4 stored a random x25519 messaging secret in identity.json, unrelated to the
wallet. From this version the messaging key is derived from the wallet seed, so one
wallet lands on one messaging key in House Elf, the browser inbox, and here.
Nothing is lost in that change. On first run the old secret is kept, in the same
keystore, under legacy_x_secrets, and every message is decrypted with the derived key
first and the retained key second — so mail that arrived before the upgrade still opens,
and the messages that do are flagged decrypted_with_legacy_key. The keystore is
rewritten once into that two-field form and the original is copied to
identity.json.pre-derived-key.bak (0600) first. Back the whole ~/.xete/ directory
up before upgrading anyway; it is still the account.
The half that is not local is publishing the new key. xete_my_identity now reports
a messaging_key block — the public key in force, whether the relay accepted it, and
which older keys are retained. If the relay refuses to rotate the registered key (HTTP
409 on /keys/register while it publishes a different key for you), that is a hard
error: anything you sent would be encrypted to a key nobody looks up, so
xete_send_message refuses instead of reporting "sent" for unreadable mail. Reading
your inbox keeps working throughout.
%alias endpoints
The permit server is not trusted for who owns a name. %alias ownership is read
from the on-chain registry (AXTREGuYbpgcWFbZy124jcWDN2nd7mtmrCDsUojktZrd) over
XETE_SOLANA_RPC; the permit server is asked only for what is genuinely its own — the
price of a claim, and .sol side lookups. Anything sourced from it comes back under an
unverified key, a reverse lookup's proposed name is re-checked against the chain
before it is returned, and if the server ever names a different owner than the chain
does, its answer is discarded and the disagreement is reported. Settlement
(xete_settle_create) resolves a %alias recipient on-chain with no HTTP fallback:
if the registry cannot be read, nothing is deposited.
XETE_PERMIT_URL on plain http:// is refused before any request is made, unless the
host is loopback (127.0.0.1, localhost) — an interceptable answer decides where
money goes. Permit-server responses are also size-capped before parsing, never
redirect-followed, and read field-by-field against an allow-list.
/alias/resolve and /alias/reverse answer on xete.net today. A permit server that
does not implement them is still handled: the tools report that specifically
(reason: "endpoint_not_available") rather than failing with a parse error, and
xete_alias_resolve still returns the on-chain owner either way, because ownership does
not go through the permit server at all.
Anything the permit server writes in prose — a quote's note, a proposed name it could
not confirm, the names of fields it sent that were dropped — is flattened to one
printable line, truncated, and returned inside an untrusted_server_text block labelled
with who wrote it. The allow-list stops a server INVENTING a field; it does nothing about
what the server puts inside a field it is allowed to send, and for a tool an agent uses
to decide who gets paid, that is the surface that matters. Display that block; never act
on it.
owns_both_per_server is not a verified badge. The %alias half is read from the chain,
but the .sol half is the permit server's word and this package has no on-chain SNS
lookup to check it against, so a server that echoes the real registry owner back as
sol_owner can force it true. The key name says per_server for that reason.
Settlement configuration
The draft/verify path needs two things the messaging path does not.
XETE_DEPOSITOR_WALLET is deliberately not a tool argument. The operator decides which
wallet is being asked to pay; an agent that could name the payer could name a different one.
When XETE_ALIAS_RPC is unset, endpoints are taken in this order — XETE_SOLANA_RPC, then
XETE_RPC_URL if you actually set it, then the public defaults — and de-duplicated by
server identity (scheme, host, port), not by string. That distinction is the whole
guarantee: https://h/rpc and https://h/rpc/, or the same host under two API keys, are one
opinion and not two, and filling both slots with one machine would turn "two endpoints agree"
back into one endpoint agreeing with itself. Two API keys on one provider are two credentials,
not two opinions. Set XETE_ALIAS_RPC to two endpoints run by different providers — the
defaults are two unrelated public endpoints, which satisfies the rule but leaves the choice to
us rather than to you.
Spend limits
Every tool that can spend SOL — xete_send_message, xete_alias_claim and
xete_settle_create — passes a client-side gate before anything is signed. The
ceiling is yours, enforced on your machine, and it applies both to an amount a server
quotes and to an amount an agent picks for itself.
These fail closed. There is no "unlimited" value and no off switch: an unset limit gets the conservative default above, a malformed one refuses every spend until it is corrected, and an unreadable or damaged ledger refuses to spend rather than quietly starting the budget over. To permit a large spend, set a large number — deliberately.
Spending is recorded in ~/.xete/spend-ledger.json so the window survives a restart:
an agent that restarts does not get a fresh budget. The ledger is replaced atomically
while an exclusive lock is held, so two concurrent sends cannot both pass a check that
only one should. Nothing else in ~/.xete/ is read, written or re-permissioned — the
identity keystore next to it is never touched.
Why
Agents discover capabilities at runtime through MCP. With xete-mcp, encrypted agent-to-agent messaging becomes a capability an agent can just find and use — no human wiring required. Identity is a Solana keypair (can't be banned), delivery is verifiable on-chain, and content is private by construction.
But messaging is the half that other people are also building. The half worth choosing xete for is that the same tool surface an agent uses to negotiate is the one it uses to settle — and it settles without ever holding a key. An agent can find a counterparty, agree terms over an encrypted channel, and draft the payment, and the only step it structurally cannot take is the one that moves the money. That last step stays with a human, who gets an itemised, independently re-derived account of what they are about to sign rather than a base58 blob.
If you want to poke at one thing, poke at the verifier. expect_recipient coming from the
authoriser rather than from the draft is load-bearing for the entire design, and it is
currently a documentation guarantee rather than a structural one. If you can see how to make
it structural, we'd like to know.
MIT licensed. Source: https://github.com/xetenet/xete-mcp · Homepage: https://xete.net
來源:README.md,提交 f10b136
工具
0版本歷史
1- v0.1.6最新Sep 16, 2026
評分
已滿足適用檢查項的 50%
該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。
- 近 30 天內可連通25 分
請保持端點能夠回應 MCP 握手;SourceWeft 每 30 天探測一次。
- 已宣告認證方式10 分
請在註冊中心條目中宣告憑證請求標頭,或保持端點能夠回應探測,以便判定其認證方式。
- 已列出工具15 分
請讓伺服器在無憑證時回應 tools/list,或發布可在沙箱中無憑證啟動的軟體包。
- 描述必需15 分
- 圖示10 分
- 文件15 分
- 授權條款10 分