Getting Started

Read Agent Data

Last updated July 8, 2026

Read and verify agent identity after registration — directly on-chain with the SDK, or through the indexed DAS API.

Summary

Agent identity is read on-chain with the Agent Registry SDK or from indexed fields via the DAS API.

  • On-chain (SDK) — check registration, inspect the AgentIdentity plugin, fetch the ERC-8004 document, derive the Asset Signer PDA
  • Indexed (DAS) — read is_agent, asset_signer, and agent_token from getAsset; discover agents with searchAssets
  • Same wallet addressfindAssetSignerPda and DAS asset_signer return the same PDA

Quick Start

This page covers SDK registration checks, registration documents, wallet PDAs, and DAS-indexed agent fields.

Jump to: Check Registration · Registration Document · Agent Wallet · Read via DAS

  1. One agent, full detail — use safeFetchAgentIdentityV1 and fetchAsset (SDK sections below)
  2. One agent, indexed fields — call getAsset with the Core asset address (DAS section below)
  3. Discover agents — call searchAssets with isAgent: true or filter by agentToken / assetSigner

Check Registration

The safe fetch method returns null instead of throwing if the identity doesn't exist, which is useful for checking whether an asset has been registered:

1import {
2 safeFetchAgentIdentityV1,
3 findAgentIdentityV1Pda,
4 mplAgentIdentity,
5} from '@metaplex-foundation/mpl-agent-registry'
6import { createUmi } from '@metaplex-foundation/umi-bundle-defaults'
7import { publicKey } from '@metaplex-foundation/umi'
8
9const umi = createUmi('https://api.mainnet-beta.solana.com').use(mplAgentIdentity())
10const assetPublicKey = publicKey('AGENT_CORE_ASSET_ADDRESS')
11
12const pda = findAgentIdentityV1Pda(umi, { asset: assetPublicKey })
13const identity = await safeFetchAgentIdentityV1(umi, pda)
14
15console.log('Registered:', identity !== null)
16
17// Registered: true

Fetch from Seeds

You can also fetch the identity directly from the asset's public key without manually deriving the PDA:

1import {
2 fetchAgentIdentityV1FromSeeds,
3 mplAgentIdentity,
4} from '@metaplex-foundation/mpl-agent-registry'
5import { createUmi } from '@metaplex-foundation/umi-bundle-defaults'
6import { publicKey } from '@metaplex-foundation/umi'
7
8const umi = createUmi('https://api.mainnet-beta.solana.com').use(mplAgentIdentity())
9const assetPublicKey = publicKey('AGENT_CORE_ASSET_ADDRESS')
10
11// Throws if the identity account does not exist — use safeFetchAgentIdentityV1 for unregistered assets.
12const identity = await fetchAgentIdentityV1FromSeeds(umi, {
13 asset: assetPublicKey,
14})
15
16console.log('Identity:', identity)
17
18// Identity: { ... }

Verify the AgentIdentity Plugin

Registration attaches an AgentIdentity plugin to the Core asset. You can read it directly off the fetched asset to inspect the registration URI and lifecycle hooks:

1import { fetchAsset, mplCore } from '@metaplex-foundation/mpl-core'
2import { createUmi } from '@metaplex-foundation/umi-bundle-defaults'
3import { publicKey } from '@metaplex-foundation/umi'
4
5const umi = createUmi('https://api.mainnet-beta.solana.com').use(mplCore())
6const assetPublicKey = publicKey('AGENT_CORE_ASSET_ADDRESS')
7
8const assetData = await fetchAsset(umi, assetPublicKey)
9const agentIdentity = assetData.agentIdentities?.[0]
10
11console.log(agentIdentity?.uri)
12console.log(agentIdentity?.lifecycleChecks?.transfer)
13console.log(agentIdentity?.lifecycleChecks?.update)
14console.log(agentIdentity?.lifecycleChecks?.execute)
15
16// https://example.com/agent-registration.json
17// { __kind: 'Listen' }
18// { __kind: 'Listen' }
19// { __kind: 'Listen' }

Read the Registration Document

The uri on the AgentIdentity plugin points to an off-chain JSON document with the agent's full profile — name, description, service endpoints, and more. Fetch it like any other URI:

1import { fetchAsset, mplCore } from '@metaplex-foundation/mpl-core'
2import { createUmi } from '@metaplex-foundation/umi-bundle-defaults'
3import { publicKey } from '@metaplex-foundation/umi'
4
5const umi = createUmi('https://api.mainnet-beta.solana.com').use(mplCore())
6const assetPublicKey = publicKey('AGENT_CORE_ASSET_ADDRESS')
7
8const assetData = await fetchAsset(umi, assetPublicKey)
9const agentIdentity = assetData.agentIdentities?.[0]
10
11if (agentIdentity?.uri) {
12 const response = await fetch(agentIdentity.uri)
13 if (!response.ok) {
14 throw new Error(`Registration document fetch failed: HTTP ${response.status}`)
15 }
16 const registration = await response.json()
17
18 console.log(registration.name)
19 console.log(registration.description)
20 console.log(registration.active)
21
22 for (const service of registration.services ?? []) {
23 console.log(service.name)
24 console.log(service.endpoint)
25 console.log(service.version)
26 }
27}
28
29// Plexpert
30// An informational agent...
31// true
32// web
33// https://metaplex.com/agent/<ASSET_PUBKEY>
34// undefined

The document follows the ERC-8004 agent registration standard. A typical one looks like this:

{
"type": "https://eips.ethereum.org/EIPS/eip-8004#registration-v1",
"name": "An informational agent providing help related to Metaplex protocols and tools.",
"description": "An autonomous agent that executes DeFi strategies on Solana.",
"image": "https://arweave.net/agent-avatar-tx-hash",
"services": [
{
"name": "web",
"endpoint": "https://metaplex.com/agent/<ASSET_PUBKEY>"
},
{
"name": "A2A",
"endpoint": "https://metaplex.com/agent/<ASSET_PUBKEY>/agent-card.json",
"version": "0.3.0"
}
],
"active": true,
"registrations": [
{
"agentId": "<MINT_ADDRESS>",
"agentRegistry": "solana:101:metaplex"
}
],
"supportedTrust": ["reputation", "crypto-economic"]
}

See Register an Agent for the full field reference.

Fetch the Agent's Wallet

Every Core asset has a built-in wallet called the Asset Signer — a PDA derived from the asset's public key. No private key exists, so it can't be stolen. The wallet can hold SOL, tokens, or any other asset. Derive the address with findAssetSignerPda:

1import { findAssetSignerPda, mplCore } from '@metaplex-foundation/mpl-core'
2import { createUmi } from '@metaplex-foundation/umi-bundle-defaults'
3import { publicKey } from '@metaplex-foundation/umi'
4
5const umi = createUmi('https://api.mainnet-beta.solana.com').use(mplCore())
6const assetPublicKey = publicKey('AGENT_CORE_ASSET_ADDRESS')
7
8const assetSignerPda = findAssetSignerPda(umi, { asset: assetPublicKey })
9const balance = await umi.rpc.getBalance(assetSignerPda)
10
11console.log('Agent wallet:', assetSignerPda)
12console.log('Balance:', balance.basisPoints.toString(), 'lamports')
13
14// Agent wallet: 6ttUwc5VVmHeVKTddB6XM5vQgBMfw62DThuoiVEufVZq
15// Balance: 1000000 lamports

The address is deterministic, so anyone can derive it from the asset's public key to send funds or check balances. Only the asset itself can sign for this wallet, through Core's Execute instruction via a delegated executive.

See the MPL Agent Registry smart contract docs for account layouts, PDA derivation details, and error codes.

Read Agent Data via DAS API

The DAS API indexes agent fields on MPL Core assets — registration status, wallet PDA, and canonical token mint — so you can read them without parsing Core accounts yourself.

Prerequisites: a DAS-enabled RPC endpoint and @metaplex-foundation/digital-asset-standard-api on a Umi instance.

DAS Agent Response Fields

DAS derives agent metadata from two on-chain sources and surfaces them as top-level response fields.

FieldTypePresent onSource
is_agentbooleanMplCoreAssettrue when the asset has an AgentIdentity external plugin
asset_signerstring (pubkey)MplCoreAsset onlySame PDA as findAssetSignerPda above
agent_tokenstring (pubkey)MplCoreAsset when setAgentIdentityV2 PDA mint, written by setAgentTokenV1

Only MplCoreAsset rows can be agents (is_agent: true). Collections and groups may include is_agent: false in DAS responses, but agent registration applies to individual Core assets only. Non-Core assets (Token Metadata NFTs, compressed NFTs, fungible tokens) omit all three fields.

A registered agent without a linked token returns is_agent: true and asset_signer, but omits agent_token:

getAsset response (registered, no token)
{
"interface": "MplCoreAsset",
"id": "84jw9dw7hMRJXFvzJXrBzVQpmVWaGUtYT7R6QhNU9qt3",
"is_agent": true,
"asset_signer": "6ttUwc5VVmHeVKTddB6XM5vQgBMfw62DThuoiVEufVZq",
"external_plugins": [
{
"type": "AgentIdentity",
"adapter_config": { "uri": "https://example.com/agent-registration.json" }
}
]
}

After setAgentTokenV1, DAS includes agent_token:

getAsset response (registered with token)
{
"interface": "MplCoreAsset",
"id": "84jw9dw7hMRJXFvzJXrBzVQpmVWaGUtYT7R6QhNU9qt3",
"is_agent": true,
"agent_token": "FakeToken11111111111111111111111111111111111",
"asset_signer": "6ttUwc5VVmHeVKTddB6XM5vQgBMfw62DThuoiVEufVZq"
}

JSON-RPC responses use snake_case (is_agent, agent_token, asset_signer). searchAssets request parameters use camelCase (isAgent, agentToken, assetSigner); snake_case aliases are also accepted.

Get One Agent via DAS

Use getAsset when you know the Core asset address.

1import { dasApi } from '@metaplex-foundation/digital-asset-standard-api'
2import { createUmi } from '@metaplex-foundation/umi-bundle-defaults'
3import { publicKey } from '@metaplex-foundation/umi'
4
5const umi = createUmi('<DAS_ENDPOINT>').use(dasApi())
6
7const asset = await umi.rpc.getAsset(publicKey('AGENT_CORE_ASSET_ADDRESS'))
8
9if (asset.is_agent) {
10 console.log('Agent wallet (asset_signer):', asset.asset_signer)
11 console.log('Canonical token mint:', asset.agent_token ?? 'not set')
12} else {
13 console.log('Core asset is not a registered agent')
14}
15
16// Agent wallet (asset_signer): 6ttUwc5VVmHeVKTddB6XM5vQgBMfw62DThuoiVEufVZq
17// Canonical token mint: not set

Search Registered Agents

Use searchAssets with isAgent: true to list registered agents. Combine with interface: "MplCoreAsset" to exclude collections and groups.

1import { dasApi } from '@metaplex-foundation/digital-asset-standard-api'
2import { createUmi } from '@metaplex-foundation/umi-bundle-defaults'
3
4const umi = createUmi('<DAS_ENDPOINT>').use(dasApi())
5
6const results = await umi.rpc.searchAssets({
7 isAgent: true,
8 interface: 'MplCoreAsset',
9 limit: 100,
10})
11
12for (const agent of results.items) {
13 console.log(agent.id, agent.asset_signer, agent.agent_token ?? 'no token')
14}
15
16// 1RUC5FMQherGNoLF9wDBxa1oznbq1mTieWLZ8gU8S31 DwgDrVVwcuXGU2MjHcZEcNtG2cGF6cLXCS35gPiUsU6p no token

Lookup Agent by Token Mint

After an agent links its canonical token, filter by agentToken to resolve the agent Core asset from the mint address. Each agent can have at most one token — the binding is permanent.

1curl -X POST <DAS_ENDPOINT> \
2 -H "Content-Type: application/json" \
3 -d '{
4 "jsonrpc": "2.0",
5 "id": 1,
6 "method": "searchAssets",
7 "params": {
8 "agentToken": "TOKEN_MINT_ADDRESS",
9 "interface": "MplCoreAsset",
10 "limit": 1
11 }
12 }'

Lookup Agent by Asset Signer

The assetSigner filter finds the Core asset whose execute PDA matches a given address. Use this when you know the agent wallet but not the asset pubkey.

1curl -X POST <DAS_ENDPOINT> \
2 -H "Content-Type: application/json" \
3 -d '{
4 "jsonrpc": "2.0",
5 "id": 1,
6 "method": "searchAssets",
7 "params": {
8 "assetSigner": "ASSET_SIGNER_PDA_ADDRESS",
9 "limit": 1
10 }
11 }'

How DAS Indexing Works

DAS populates agent fields from two on-chain sources during ingestion. MPL Core asset account updates set is_agent (when an AgentIdentity plugin is present) and derive asset_signer for MplCoreAsset rows. Agent Registry PDA updates set agent_token on existing MplCoreAsset rows when an AgentIdentityV2 mint is present.

EventField updatedNotes
Core asset created or updatedis_agent, asset_signerApplies to MplCoreAsset rows only; is_agent reflects the AgentIdentity external plugin; asset_signer is derived for every indexed Core asset
AgentIdentityV2 PDA updatedagent_tokenWritten by the Agent Registry transformer; only updates existing, non-burnt MplCoreAsset rows
Asset burntSubsequent Agent Registry updates are ignored
Stale-slot PDA replayUpdates with a lower slot than slot_updated_agent_registry are skipped

Notes

  • The Asset Signer is a PDA — no private key exists for it. It can receive funds from any source, but only the asset itself can sign outgoing transactions through Core's Execute instruction.
  • safeFetchAgentIdentityV1 returns null for unregistered assets rather than throwing, making it safe for existence checks without try/catch.
  • findAssetSignerPda and DAS asset_signer return the same deterministic address on every network.
  • agent_token is permanent once set via setAgentTokenV1 — there is no instruction to clear or reassign it.
  • DAS asset_signer is returned on MplCoreAsset rows, not only registered agents; use is_agent to distinguish agents from plain Core NFTs.
  • Registered agents without a linked token omit agent_token — expected before createAndRegisterLaunch or manual setAgentTokenV1.
  • Agent Registry updates never create new asset rows; the Core asset must be indexed first.
  • Provider support varies — confirm your DAS provider runs an indexer with agent registry support.

Quick Reference

This table lists agent-related DAS filters, response fields, and program IDs.

ItemValue
Agent Registry program1DREGFgysWYxLnRnKQnwrxnJQeSMk2HmGaC6whw2B2p
MPL Core programCoREENxT6tW1HoK8ypY1SxRMZTcVPm7R94rH4PZNhX7d
Asset Signer seeds['mpl-core-execute', <core_asset_pubkey>]
DAS isAgent filtersearchAssets param isAgent: true | false
DAS agentToken filtersearchAssets param agentToken: <mint_pubkey>
DAS assetSigner filtersearchAssets param assetSigner: <pda_pubkey>
DAS response methodsgetAsset, getAssets, searchAssets

FAQ

When does agentToken appear in a DAS response?

agent_token is present only when the agent's AgentIdentityV2 PDA has a token mint set via setAgentTokenV1. Registered agents without a linked token omit the field. AgentIdentityV1 PDAs do not carry a token mint and never populate agent_token.

Is assetSigner the same as the agent wallet?

Yes. DAS asset_signer is the Core Asset Signer PDA — the same address as findAssetSignerPda. It is returned on MplCoreAsset rows; for registered agents it acts as the on-chain wallet.

Can I filter non-Core assets with isAgent?

No. is_agent, agent_token, and asset_signer apply only to MplCoreAsset. Token Metadata NFTs and other asset types omit these fields.

Do all DAS providers support agent token fields?

Agent token indexing ships with the Metaplex DAS indexer. Third-party providers must run a compatible indexer version with the agent registry transformer and database migration.

Glossary

These terms appear in agent DAS responses and the SDK read paths above.

TermDefinition
AgentIdentity pluginExternal plugin on a Core asset set during registration; carries the off-chain registration URI
is_agentDAS boolean indicating the Core asset has an AgentIdentity external plugin
agent_tokenCanonical token mint pubkey indexed from the AgentIdentityV2 PDA; set once via setAgentTokenV1
asset_signerCore execute PDA that acts as the agent's onchain wallet; derived from ['mpl-core-execute', <asset>]
AgentIdentityV2Agent Registry PDA that stores the linked token mint; updated independently of the Core asset account
Agent Registry transformerDAS ingestion handler that writes agent_token from Agent Registry PDA updates onto existing Core asset rows