Skip to main content
Glama
blockscout

Blockscout MCP Server

Official

nft_tokens_by_address

Retrieve NFT tokens owned by a specific address, grouped by collection, with details on token IDs, metadata, and collection information. Supports pagination for large datasets.

Instructions

Retrieve NFT tokens (ERC-721, ERC-404, ERC-1155) owned by an address, grouped by collection. Provides collection details (type, address, name, symbol, total supply, holder count) and individual token instance data (ID, name, description, external URL, metadata attributes). Essential for a detailed overview of an address's digital collectibles and their associated collection data. **SUPPORTS PAGINATION**: If response includes 'pagination' field, use the provided next_call to get additional pages.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
addressYesNFT owner address
chain_idYesThe ID of the blockchain
cursorNoThe pagination cursor from a previous response to get the next page of results.

Implementation Reference

  • Primary handler function implementing the nft_tokens_by_address tool: fetches NFT collections from Blockscout API, processes data, handles pagination, and returns structured ToolResponse.
    @log_tool_invocation async def nft_tokens_by_address( chain_id: Annotated[str, Field(description="The ID of the blockchain")], address: Annotated[str, Field(description="NFT owner address")], ctx: Context, cursor: Annotated[ str | None, Field(description="The pagination cursor from a previous response to get the next page of results."), ] = None, ) -> ToolResponse[list[NftCollectionHolding]]: """ Retrieve NFT tokens (ERC-721, ERC-404, ERC-1155) owned by an address, grouped by collection. Provides collection details (type, address, name, symbol, total supply, holder count) and individual token instance data (ID, name, description, external URL, metadata attributes). Essential for a detailed overview of an address's digital collectibles and their associated collection data. **SUPPORTS PAGINATION**: If response includes 'pagination' field, use the provided next_call to get additional pages. """ # noqa: E501 api_path = f"/api/v2/addresses/{address}/nft/collections" params = {"type": "ERC-721,ERC-404,ERC-1155"} apply_cursor_to_params(cursor, params) await report_and_log_progress( ctx, progress=0.0, total=2.0, message=f"Starting to fetch NFT tokens for {address} on chain {chain_id}..." ) base_url = await get_blockscout_base_url(chain_id) await report_and_log_progress( ctx, progress=1.0, total=2.0, message="Resolved Blockscout instance URL. Fetching NFT data..." ) response_data = await make_blockscout_request(base_url=base_url, api_path=api_path, params=params) await report_and_log_progress(ctx, progress=2.0, total=2.0, message="Successfully fetched NFT data.") # Process all items first to prepare for pagination original_items = response_data.get("items", []) processed_items = [] for item in original_items: token = item.get("token", {}) token_instances = [] for instance in item.get("token_instances", []): # To preserve the LLM context, only specific fields for NFT instances are # added to the response metadata = instance.get("metadata", {}) or {} token_instances.append( { "id": instance.get("id", ""), "name": metadata.get("name"), "description": metadata.get("description"), "image_url": metadata.get("image_url"), "external_app_url": metadata.get("external_url"), "metadata_attributes": metadata.get("attributes"), } ) # To preserve the LLM context, only specific fields for NFT collections are # added to the response collection_info = { "type": token.get("type", ""), "address": token.get("address_hash", ""), "name": token.get("name"), "symbol": token.get("symbol"), "holders_count": token.get("holders_count") or 0, "total_supply": token.get("total_supply") or 0, } processed_item = { "token": token, # Keep original token info for cursor extraction "amount": item.get("amount", ""), "token_instances": token_instances, "collection_info": collection_info, } processed_items.append(processed_item) # Use create_items_pagination helper to handle slicing and pagination sliced_items, pagination = create_items_pagination( items=processed_items, page_size=config.nft_page_size, tool_name="nft_tokens_by_address", next_call_base_params={ "chain_id": chain_id, "address": address, }, cursor_extractor=extract_nft_cursor_params, force_pagination=False, ) # Convert sliced items to NftCollectionHolding objects nft_holdings: list[NftCollectionHolding] = [] for item in sliced_items: collection_info = NftCollectionInfo(**item["collection_info"]) token_instances = [NftTokenInstance(**instance) for instance in item["token_instances"]] nft_holdings.append( NftCollectionHolding( collection=collection_info, amount=item["amount"], token_instances=token_instances, ) ) return build_tool_response(data=nft_holdings, pagination=pagination)
  • MCP tool registration for nft_tokens_by_address with FastMCP instance, setting title and annotations.
    mcp.tool( structured_output=False, annotations=create_tool_annotations("Get NFT Tokens by Address"), )(nft_tokens_by_address)
  • Pydantic schema models defining the structure for nft_tokens_by_address response data: NftTokenInstance, NftCollectionInfo, NftCollectionHolding.
    # --- Model for nft_tokens_by_address Data Payload --- class NftTokenInstance(BaseModel): """Represents a single NFT instance with its metadata.""" id: str = Field(description="The unique identifier of the NFT token instance.") name: str | None = Field(None, description="The name of the NFT, extracted from its metadata.") description: str | None = Field(None, description="The description of the NFT, extracted from its metadata.") image_url: str | None = Field(None, description="A URL for the NFT's image, from its metadata.") external_app_url: str | None = Field( None, description="A URL to an external site or application related to the NFT.", # noqa: E501 ) metadata_attributes: list | dict | None = Field( None, description="The metadata attributes (traits) associated with the NFT.", ) # --- Model for nft_tokens_by_address Data Payload --- class NftCollectionInfo(BaseModel): """Represents the metadata for an NFT collection.""" type: str = Field(description="The token standard of the collection.") address: str = Field(description="The smart contract address of the NFT collection.") name: str | None = Field(None, description="The name of the collection.") symbol: str | None = Field(None, description="The symbol of the collection.") holders_count: int = Field(description="The number of unique addresses that hold a token from this collection.") total_supply: int = Field(description="The total number of tokens in the collection.") # --- Model for nft_tokens_by_address Data Payload --- class NftCollectionHolding(BaseModel): """Represents an address's holding in a single NFT collection.""" collection: NftCollectionInfo = Field(description="The details of the NFT collection.") amount: str = Field(description="The number of tokens from this collection owned by the address.") token_instances: list[NftTokenInstance] = Field( description="A list of the specific NFT instances owned by the address." )
  • Helper function to extract pagination cursor parameters from NFT collection items.
    def extract_nft_cursor_params(item: dict) -> dict: """Extract cursor parameters from an NFT collection item for pagination continuation. This function determines which fields from the last item should be used as cursor parameters for the next page request. The returned dictionary is encoded and used in the `cursor` parameter for pagination. """ token_info = item.get("token", {}) return { "token_contract_address_hash": token_info.get("address_hash"), "token_type": token_info.get("type"), "items_count": 50, }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/blockscout/mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server