xrpl-did-mcp
This MCP server lets an agent work with did:xrpl identities and XLS-70 credentials on the XRP Ledger, with read-only tools by default and opt-in ledger-writing tools.
Derive a
did:xrplDID from an XRP address without registration or fees.Resolve a
did:xrplDID to its DID Document by reading the XRP Ledger.Check whether an agent is authorized to act, with auditable allow/deny reasons.
Apply an operator trust policy on top of caller-supplied rules, including required, denied, and banned credentials/agents.
Look up an account's balance, object count, and sequence.
Look up a transaction's result, ledger index, and validation status.
Read one credential's state: existence, acceptance, URI, and expiration.
List credentials held by or issued by an account.
Publish or revoke an account's DID Document when writes are enabled.
Issue, accept, or revoke credentials when writes are enabled.
Keep write tools disabled unless started with
--allow-writes.Use the OS keychain for signing seeds by default; inline seeds are refused unless explicitly enabled.
Target testnet by default or mainnet explicitly.
Provides tools for deriving and resolving did:xrpl W3C-compatible decentralized identifiers on the XRP Ledger, checking agent authorization, looking up ledger account and transaction data, and optionally publishing DID Documents to the ledger.
Click on "Deploy 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., "@xrpl-did-mcp give me a DID for rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"
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.
xrpl-did-mcp
An MCP server for did:xrpl — W3C-compatible decentralized identifiers for AI agents on the XRP Ledger.
Point any MCP client at it and your agent can derive, resolve, and authorize identities natively.
# not on PyPI yet -- install from GitHub, pinned to the release tag
pip install "xrpl-did-mcp @ git+https://github.com/DuNorth595/xrpl_did_mcp.git@v0.6.0"That one command pulls in xrpl-agent-id and xrpl-py as well. Both are
pinned to release tags, so an install cannot silently change underneath
you.
What it gives an MCP client
Tool | What it does | Writes to the ledger? |
| Turn an XRP address into a | No |
| Read a DID Document for a | No |
| Decide whether an agent may act, with reasons | No |
| Read an account's balance and on-ledger state | No |
| Read a transaction's result and inclusion status | No |
| Read a credential's state — exists, accepted, URI, expiry | No |
| List the credentials on an account, held and issued | No |
| Create a credential for a subject | Yes — spends XRP |
| Accept a credential issued to the signing account | Yes — spends XRP |
| Publish an agent's DID Document | Yes — spends XRP |
| Delete an account's DID Document | Yes — spends XRP |
| Withdraw one credential | Yes — spends XRP |
Seven of the twelve tools are read-only. The five that write:
Refuse by default. Each returns
WRITES_DISABLEDunless the server was started with--allow-writes.Take no seed argument. The signing seed comes from the OS keychain, which the server reads itself, so the seed never passes through the agent's context.
Revocation
revoke_did submits a DIDDelete, so the DID no longer resolves.
DIDDelete always targets the signer's own DID, so the tool refuses with
ADDRESS_MISMATCH if the address is not the one the seed controls —
before anything is submitted.
revoke_credential submits a CredentialDelete, withdrawing one
credential. A credential is identified by the triple (issuer, subject,
credential_type); the subject may be an address or a did:xrpl.
Deleting a DID does not delete the account's credentials. A DID and a
credential are separate ledger objects — a DID is keyed by its owner
account, a credential by (issuer, subject, credential_type). rippled's
DIDDelete erases only the DID. To withdraw an authorization, revoke the
credential too.
The credential lifecycle
A credential is identified by the triple (issuer, subject, credential_type), and it takes two signatures before it is valid for the subject:
Step | Tool | Who signs |
1. Create |
| the issuer |
2. Accept |
| the subject |
3. Read one |
| nobody — it is a read |
4. List all |
| nobody — it is a read |
5. Withdraw |
| the issuer |
issue_credential submits a CredentialCreate. The credential exists on
the ledger at that point, but XLS-70 only sets the accepted flag when the
subject signs — so until accept_credential runs, the credential does not
count as held. get_credential reports the two states separately, because
existence is not acceptance.
The subject and issuer may each be an address or a did:xrpl; a
did:xrpl is reduced to its address before the transaction is built.
Finding credentials without knowing which
get_credential needs all three identifiers: issuer, subject, and
credential type. When you know the account but not the credential,
list_credentials enumerates instead:
{
"account": "rSubjectAddress",
"held_count": 2,
"issued_count": 0,
"held": [
{
"issuer": "did:xrpl:2:rIssuer",
"subject": "did:xrpl:2:rSubject",
"credential_type": "KYC",
"accepted": false,
"uri": null,
"expiration": null,
"role": "subject"
}
]
}held is what the account holds as a subject; issued is what it has
issued to others. Each entry carries the issuer, the subject, the
credential type, the URI, the expiry, and whether the subject has
accepted it — the same fields get_credential returns, so the two tools
answer the same shape of question at different scopes.
Pass include_issued=False to skip the issued side when you only care
about what the account holds.
Related MCP server: xrpl-identity-mcp
Connect it
Claude Desktop / Claude Code
{
"mcpServers": {
"xrpl-did": {
"command": "xrpl-did-mcp",
"env": { "XRPL_MCP_NETWORK": "testnet" }
}
}
}Any other MCP client (stdio)
xrpl-did-mcp # stdio, testnet, read-only
xrpl-did-mcp --network mainnet # stdio, mainnet, read-only
xrpl-did-mcp --allow-writes # enable the write tools
xrpl-did-mcp --http 8080 # streamable-httpEnabling the write tools
The write tools — publish_did_set, revoke_did, revoke_credential,
issue_credential and accept_credential — need two things: the server
started with --allow-writes, and a signing seed in the OS keychain.
# Store a seed (macOS). The server reads it; the agent never sees it.
security add-generic-password -a "$USER" -s xrpl-did-mcp -w '<your seed>'The keychain service defaults to xrpl-did-mcp; set
XRPL_MCP_KEYCHAIN_SERVICE to change it.
If the keychain has no entry, the tool returns NO_SEED with the setup
instructions. It never falls back to something weaker.
For throwaway testnet use where a seed in the conversation is harmless,
--allow-inline-seed permits passing one directly as the tool's seed
argument. It is off by default, because a seed in the agent's context is a
seed the agent can read.
Without that flag the seed argument is refused: the tool returns
INLINE_SEED_REFUSED and falls back to the keychain. The keychain is
always tried first, even when an inline seed is supplied.
Operator trust policy
The caller of a tool is not necessarily the operator of the server. An agent that chooses its own trust policy can always choose a permissive one, so the server keeps its own policy on disk and applies it on top of whatever the caller passes.
Put a trust_policy.json in the server's working directory, or point
XRPL_MCP_POLICY at one:
{
"require": {
"issuers": ["rTrustedIssuer..."],
"credential_type": "agent-authorization"
},
"deny": {
"issuers": ["rRevokedIssuer..."],
"credential_type": "agent-authorization"
},
"ban": {
"agents": ["did:xrpl:1:rBanned...", "rBannedPlain..."]
}
}Every section is optional.
require— the agent must hold this credential.deny— holding this credential is grounds for refusal, whatever else it holds.ban— the agent is refused outright.
The operator's rules cannot be waived by the caller. A missing policy file means the operator has not expressed an opinion — it does not mean allow everything; it means no operator rules are added to the caller's.
A policy file that exists but cannot be parsed is surfaced as
POLICY_INVALID rather than ignored, because silently dropping the
operator's deny rules would quietly remove the property the file exists to
provide.
What it looks like in a conversation
Agent: Give me a DID for
rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh.
Tool
derive_did:did:xrpl:1:rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh— derived from the address. No registration, no fee, no database row.
Agent: Resolve it.
Tool
resolve_did: reads theDIDSetfrom the ledger and returns the DID Document. Anyone can do this — there is no server of ours in the path.
Agent: Can this agent act?
Tool
check_authorization:ALLOW— orDENYwith the list of missing credentials and the deny rules that fired.
Why a DID and not just an address
An XRP address says who holds a key. It does not say what that key is allowed to do, who vouches for it, or whether it was revoked.
did:xrpl adds a resolvable DID Document, so an agent's identity can
carry credentials — and the authorization decision becomes a ledger read
rather than a trust-me.
Built on xrpl_agent_id,
which implements the XLS-40d DID model and XLS-70d credentials.
Networks
Testnet by default. Mainnet is the same code with network="mainnet".
xrpl_agent_id has been validated on XRPL mainnet — all six authorization
roles, verified against the public ledger. See the
mainnet decision record.
Development
git clone https://github.com/DuNorth595/xrpl_did_mcp
cd xrpl_did_mcp
pip install -e ".[dev]"
pytestThe default suite is fully offline. Two ledger-backed tests are skipped unless
XRPL_MCP_LIVE=1 is set.
Documentation
Document | What it covers |
Reporting a vulnerability, and the security-relevant design decisions | |
How to contribute, and how to add a tool | |
Release history |
License
MIT — see LICENSE.
Available Tools
12 toolsaccept_credentialAccept a credential issued to this account (writes to the ledger)A
Accept a credential that was issued to this account, making it valid for the subject. THIS WRITES TO THE LEDGER and spends XRP.
A credential created with issue_credential is not valid for the subject until the subject signs it. This tool is the subject's side of that: it submits the CredentialAccept.
The signing seed comes from the OS keychain, which the server reads itself, so the agent never sees the seed. This tool is only available if the server was started with --allow-writes.
An optional seed argument exists for throwaway testnet use. It is refused unless the server was started with --allow-inline-seed.
To read a credential's state without changing anything, use get_credential. To withdraw a credential, use revoke_credential.
Inputs: issuer (required), credential_type (required), seed, network. Returns: object
check_authorizationDecide whether an agent is authorized to actA
Evaluate an agent against a trust policy and return an allow/deny decision with the reasons. The result reports which required credentials are missing and which deny rules matched, so the decision is auditable rather than a bare boolean.
The caller's policy is combined with the server operator's policy file, if one is configured. The operator's deny and ban rules are applied on top of the caller's and cannot be waived by them.
Inputs: agent_did (required), credential_type (required), trusted_issuers (required), network, +2 more. Returns: object
derive_didDerive a did:xrpl from an XRP addressA
Derive the W3C-compatible decentralized identifier for an account on the XRP Ledger. Format: did:xrpl::. This is a pure derivation -- no transaction, no registration, no fee.
Inputs: address (required), network. Returns: object
get_credentialRead a credential's state on the ledgerA
Read one credential's state from the XRP Ledger: whether it exists, whether the subject has accepted it, its URI, and its expiration.
This is a pure read. It submits no transaction, spends nothing, and does not need --allow-writes.
Existence is not acceptance: a credential issued with issue_credential does not become valid for the subject until the subject accepts it. This tool reports which of those is true.
For an account's balance and other state, use lookup_account. To accept a credential, use accept_credential.
Inputs: issuer (required), subject (required), credential_type (required), network. Returns: object
issue_credentialIssue a credential to a subject (writes to the ledger)A
Create a credential on the XRP Ledger, so a subject can be authorised to act. THIS WRITES TO THE LEDGER and spends XRP.
The signing seed comes from the OS keychain, which the server reads itself, so the agent never sees the seed. This tool is only available if the server was started with --allow-writes.
An optional seed argument exists for throwaway testnet use. It is refused unless the server was started with --allow-inline-seed, because a seed in the agent's context is a seed the agent can read.
The credential is created but not yet valid for the subject until the subject accepts it with accept_credential. To withdraw a credential, use revoke_credential instead. To read a credential's state without changing anything, use get_credential.
Inputs: subject (required), credential_type (required), uri, seed, +2 more. Returns: object
list_credentialsList the credentials on an accountA
List every credential on the XRP Ledger that involves an account -- the ones it holds as a subject, and the ones it issued to others.
This is a pure read. It submits no transaction, spends nothing, and does not need --allow-writes.
Use this when you know WHO but not WHICH credential: it answers 'what credentials does this account have?' without needing the issuer, subject and type up front. For one known credential's state, use get_credential instead.
Results carry the issuer, the subject, the credential type, and whether the subject has accepted each one. Credentials that exist but were never accepted are marked accepted=false, because XLS-70 only sets that flag when the subject signs.
Inputs: account (required), network, include_issued. Returns: object
lookup_accountLook up an account's balance and state on the ledgerA
Read an XRP Ledger account's on-ledger state: its balance in drops, the number of objects it owns, and its next transaction sequence.
For an account's DID Document, use resolve_did instead -- that tool returns the document itself, not the account's other state.
Inputs: address (required), network. Returns: object
lookup_transactionLook up a transaction's result on the ledgerA
Read a transaction's outcome from the XRP Ledger by its hash: the result code (for example tesSUCCESS for a successful transaction, or tecUNFUNDED_PAYMENT for one that failed), the ledger index it was included in, and whether it has been validated.
For the account that sent or received it, use lookup_account.
Inputs: tx_hash (required), network. Returns: object
publish_did_setPublish an agent's DID Document (writes to the ledger)A
Submit a DIDSet transaction so the agent's DID resolves to a DID Document. THIS WRITES TO THE LEDGER and spends XRP.
The signing seed comes from the OS keychain, which the server reads itself, so the agent never sees the seed. This tool is only available if the server was started with --allow-writes.
An optional seed argument exists for throwaway testnet use. It is refused unless the server was started with --allow-inline-seed, because a seed in the agent's context is a seed the agent can read.
Defaults to testnet; pass network='mainnet' explicitly to use mainnet.
Inputs: address (required), seed, network, document_uri. Returns: object
resolve_didResolve a did:xrpl to its DID DocumentA
Resolve a did:xrpl into its DID Document by reading the XRP Ledger. The document is fetched from the ledger itself, so the result is verifiable by anyone and does not depend on this server.
This is the only tool that returns a DID Document. For an account's balance and other on-ledger state, use lookup_account.
Inputs: did (required), network. Returns: object
revoke_credentialRevoke a credential (writes to the ledger)A
Submit a CredentialDelete transaction, withdrawing one credential so it no longer counts as held. THIS WRITES TO THE LEDGER and spends XRP.
A credential is identified by the triple (issuer, subject, credential_type). The issuer or the subject may sign the delete.
This tool is only available if the server was started with --allow-writes. The signing seed comes from the OS keychain, which the server reads itself, so the seed never passes through the agent's context.
Inputs: subject (required), credential_type (required), seed, network. Returns: object
revoke_didDelete an account's DID Document (writes to the ledger)A
Submit a DIDDelete transaction, removing the account's DID Document from the ledger so the DID no longer resolves. THIS WRITES TO THE LEDGER and spends XRP.
DIDDelete takes only common fields -- it always deletes the signer's own DID, so the address must match the account the seed controls.
This does NOT delete the account's credentials. A DID and a credential are separate ledger objects, and rippled's DIDDelete erases only the DID. To withdraw an authorization, revoke the credential too.
This tool is only available if the server was started with --allow-writes. The signing seed comes from the OS keychain, which the server reads itself, so the seed never passes through the agent's context.
Inputs: address (required), seed, network. Returns: object
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 12 tools
Each tool targets a distinct ledger action or read: derive/resolve/publish/revoke for DIDs, issue/accept/revoke/get/list for credentials, plus account and transaction reads. Descriptions explicitly disambiguate the closest pairs (derive_did vs resolve_did, get_credential vs list_credentials, lookup_account vs lookup_transaction) with explicit 'use X instead' pointers.
Nearly all names follow verb_noun (derive_did, issue_credential, revoke_credential, lookup_account). The exceptions are publish_did_set, which is named after the ledger transaction type rather than a verb_noun, and the split between get_/list_/lookup_/resolve_ for read operations, which is readable but not perfectly uniform.
Twelve tools is well within a comfortable range and each one maps to a concrete step in the DID or credential lifecycle. Nothing appears redundant or padded; the read-only/write split also justifies separate tools.
Coverage is strong: DIDs have derive, publish (also usable to update the document), resolve, and revoke; credentials have issue, accept, read, list, and revoke; policy evaluation and account/transaction reads round it out. The main gap is transaction discovery — lookup_transaction requires a known hash and there is no way to list an account's transactions, so agents must obtain hashes elsewhere.
Maintenance
Related MCP Connectors
Discover MCP servers and A2A agents; verify, message, post, follow, react, and receive webhooks.
Neutral W3C DID/VC identity and reputation oracle for AI agents (did:key/did:web, eddsa-jcs-2022).
Verifiable agent DIDs + capability discovery — the passport & directory of the A2A economy.
Public MCP for agent verification, work discovery and governed interoperability.
Related MCP Servers
- FlicenseAqualityBmaintenanceMock identity-management MCP server for decentralized identity that allows minting DIDs, issuing signed Verifiable Credentials, and verifying them.8-
- AlicenseAqualityDmaintenanceAn MCP server for XRP Ledger identity features including DIDs, credentials, multisig, and safe transaction workflows.1279 npm1MIT

vantic-mcpofficial
AlicenseNot gradedqualityDmaintenanceEnables MCP hosts to verify agent spending mandates and receipts, providing stateless tools for authorization, chain verification, credential verification, and DID resolution.Apache 2.0
Proofable MCPofficial
AlicenseAqualityBmaintenanceEnables AI agents to manage identity, permissions, secrets, and verifiable proofs through a hosted MCP server, letting clients sign in and check what an agent may do before it acts.15286 npmApache 2.0