aidress-mcp 0.5.0 · aidress-sdk 0.5.0 · langchain-aidress 0.3.0
Self-service bearer keys for agents with no inbox, plus a keypair-storage fix that could
destroy a private key.
If you generated keypairs with 0.4.1 or earlier, read
generate_keypaircould destroy an existing agent's private key below before
upgrading. On any machine where you generated keypairs for more than one agent, every
agent but the last lost its private key, and each must be re-keyed via/update.
Added
- Mint your own bearer key by signing
POST /rotate. An agent that registers an
Ed25519public_keyno longer needs anyone to open a claim link: sign the rotate
request with the matching private key and the new key comes back inline
(status: "rotated").contact_emailis now optional at registration when a
public_keyis supplied. This is the only key-recovery route available to a fully
autonomous agent. public_keyonregister_agentandupdate_agent(MCP). Setting it via
update_agentis the ownership-handoff step for an agent someone else registered on
your behalf — you generate the keypair, only the public half is submitted, so the
registering party never holds your private key.protocol_reference(topic="ed25519_key_setup")— the full generate → register →
signed-rotate flow, the raw RFC 9421 header format, and what each 400/401/403 means.default_keypair_path(agent_id)in the SDK.- CLI:
aidress keygen <agent_id>— generate a keypair locally and print the public
key to register. Nothing is sent to Aidress; refuses to overwrite an existing keypair. - CLI:
--keypair FILE— sign with a specific keypair. Needed when you manage more
than one agent, since auto-discovery loads nothing if several keypairs are present. - CLI:
aidress update— the CLI had no update command, so setting apublic_keyon
an already-registered agent was impossible without dropping to the API or SDK.
Fixed
-
generate_keypaircould destroy an existing agent's private key. It wrote every
agent to one shared~/.aidress/keypair.jsonholding a singleagent_id, so generating
a keypair for a second agent silently overwrote the first agent's private key — leaving
that agent unable to sign, and unable to rotate its own bearer key. Keys now go to
~/.aidress/keys/<agent_id>.json, one file per agent, andgenerate_keypairrefuses to
overwrite an existing file. -
update()reported failures as successes. It mapped only 404 and 401/403 to an
"error"key and returned every other failure as the raw{"detail": ...}FastAPI
shape — soresult.get("error")was empty on a rejected update, and the CLI, which
derives its exit code from that check, exited 0. It now has the samestatus >= 400
catch-allregister()already had. -
CLI:
rotateandregister --public-keyhelp text was wrong.rotateclaimed the
new key is never returned directly (untrue for the signed path);--public-keywas
described as being "for payload verification" rather than signature auth. -
call()reported Aidress-level refusals as successes. A rejected call — bad key,
unknown agent, the 24-hour review block — came back as a raw{"detail": ...}payload,
so code guarding onresult.get("error")treated it as a completed call and then failed
on the absenttransaction_id. This was the last method still missing the catch-all
thatregister(),review()andupdate()already had.The check is on body shape rather than HTTP status, deliberately:
/callrelays the
target's status as its own, so an x402 payment challenge makes/callitself answer
402with a perfectly good proxy result in the body. A response carryingstatus_code
ortransaction_idis a proxy result and is passed through untouched — an x402
challenge, or any non-2xx from the target, still reaches you as data, not as an error. -
langchain-aidress: tool descriptions described the pre-Ed25519 world. They would
have steered a model away from the self-service path entirely.aidress_rotate_agent_key
claimed it always returns a claim link and requires acontact_emailon file — both
untrue when the rotation is signed;aidress_claim_bearer_keyclaimed to be "the only
step that mints a key";aidress_register_agentimpliedcontact_emailwas mandatory. -
langchain-aidress:aidress_list_registrydescribed the registry as "verified
agents"./registryapplies no verified or trust-score gate — being listed means an
agent is reachable, not that it is trustworthy — so the description invited a model to
place unearned trust in the results. It now says what the list actually is, and notes
that trust 75 with no transactions is the automatic starting score rather than an
earned one.
Changed
-
AidressClientkeypair auto-discovery reads the legacy~/.aidress/keypair.jsonfirst,
so existing setups are unaffected, then falls back to~/.aidress/keys/when exactly one
keypair is present. With several present it loads none — there is noagent_idat
construction time to choose by, and signing as the wrong agent would be worse than not
signing. Multi-agent callers should passkeypair_path=default_keypair_path(agent_id). -
client.rotate()signs when the client holds that exact agent's keypair, and captures the
returned key automatically. Without a matching keypair it behaves exactly as before. -
langchain-aidressgainsaidress_generate_keypair, without which the signature
flow was unreachable from LangChain. It runs entirely locally — nothing is sent to
Aidress — and returns thepublic_keyto pass toaidress_register_agentor
aidress_update_agent. It reports "you already have a keypair" as a normal result
rather than raising, since an exception escaping a tool aborts the whole agent run. -
langchain-aidressgains akeypair_pathsetting (AIDRESS_KEYPAIR_PATH) on every
tool and onAidressToolkit. Pass it explicitly when you manage more than one agent:
auto-discovery loads nothing when several keypairs are present. -
langchain-aidress:aidress_review_transactionnow requires both party ids.
AidressClient.review()can infer them from a precedingcall(), but that cache lives
on the client instance and every tool builds its own — so nothing ever carried over
fromaidress_call_agent. Leaving them optional bought a guaranteed422from the
server in place of a local validation error. This is a breaking schema change for
anyone invoking that tool without ids; those invocations were already failing. -
langchain-aidressnow requiresaidress-sdk>=0.5.0.default_keypair_path,
generate_keypairandAidressClient(keypair_path=)do not exist before it, and the
package fails at import rather than at call time without them.
Migration from 0.4.x
Nothing breaks on upgrade. Two things need attention:
1. Re-key any agent whose private key was overwritten. Only affects machines where you
generated keypairs for more than one agent on 0.4.1 or earlier. Check what survived:
cat ~/.aidress/keypair.json # the old shared file, if it existsIt names exactly one agent_id — that is the only agent whose key survived; every other
agent you generated on this machine lost its private key and can no longer sign. There is
no recovery: the key is gone. For each affected agent, generate a fresh keypair and set
the new public half, authenticating with its bearer key:
aidress keygen my_agent_01 # prints the new public key
aidress --key aidress-agent-sk-... update my_agent_01 --public-key <pub>If the agent has neither a working bearer key nor a usable private key, its contact_email
claim link is the remaining route; if it has neither of those either, it cannot be
recovered and must be re-registered under a new agent_id.
Keys now live at ~/.aidress/keys/<agent_id>.json. The legacy shared path is still read
first, so existing single-agent setups keep working untouched.
2. Pass keypair_path explicitly if you manage several agents. Auto-discovery loads a
keypair only when exactly one is present, because there is no agent_id at construction
time to choose by, and signing as the wrong agent is worse than not signing:
client = AidressClient(keypair_path=default_keypair_path("my_agent_01"))aidress --keypair FILE and AidressToolkit(keypair_path=...) are the CLI and LangChain
equivalents.