Skip to main content
Glama

getNFTInfo

Retrieve ERC-721 NFT holdings and tokenURIs for a wallet address from a specific smart contract on EVM chains like Ethereum, Polygon, and Arbitrum.

Instructions

특정 컨트랙트에서 지갑 주소가 보유한 ERC-721 NFT 목록과 tokenURI를 조회합니다

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
addressYes조회할 지갑 주소 (0x...)
chainNoEVM 체인ethereum
contractAddressNo특정 NFT 컨트랙트 주소 (미지정 시 오류 반환)

Implementation Reference

  • The handler function implements the logic for fetching NFT information by checking balance, token IDs via enumeration, and tokenURIs via RPC.
    async function handler(args: z.infer<typeof inputSchema>): Promise<ToolResult<NFTInfoData>> {
      const { address, chain, contractAddress } = args;
    
      // contractAddress 없이는 인덱서 없이 NFT 열거 불가
      if (!contractAddress) {
        return makeError(
          "contractAddress is required. Enumerating all NFTs without an indexer is not supported.",
          "INVALID_INPUT",
        );
      }
    
      const cacheKey = `nftinfo:${chain}:${contractAddress.toLowerCase()}:${address.toLowerCase()}`;
      const cached = cache.get<NFTInfoData>(cacheKey);
      if (cached.hit) return makeSuccess(chain, cached.data, true);
    
      try {
        const client = getClient(chain);
        const ownerAddr = address as `0x${string}`;
        const contractAddr = contractAddress as `0x${string}`;
    
        // 1단계: balanceOf로 보유 수량 확인
        const balance = await client.readContract({
          address: contractAddr,
          abi: ERC721_ABI,
          functionName: "balanceOf",
          args: [ownerAddr],
        }) as bigint;
    
        const tokenCount = Number(balance);
    
        // 보유 토큰 없으면 빈 배열 반환
        if (tokenCount === 0) {
          const data: NFTInfoData = {
            owner: address,
            contractAddress,
            totalOwned: 0,
            tokens: [],
          };
          cache.set(cacheKey, data, NFT_INFO_CACHE_TTL);
          return makeSuccess(chain, data, false);
        }
    
        // 최대 MAX_TOKENS개까지만 조회
        const fetchCount = Math.min(tokenCount, MAX_TOKENS);
    
        // 2단계: tokenOfOwnerByIndex로 각 인덱스의 tokenId 조회
        const tokenIdResults = await Promise.allSettled(
          Array.from({ length: fetchCount }, (_, i) =>
            client.readContract({
              address: contractAddr,
              abi: ERC721_ABI,
              functionName: "tokenOfOwnerByIndex",
              args: [ownerAddr, BigInt(i)],
            }),
          ),
        );
    
        // 성공한 tokenId 목록 수집
        const tokenIds: bigint[] = [];
        for (const result of tokenIdResults) {
          if (result.status === "fulfilled") {
            tokenIds.push(result.value as bigint);
          }
        }
    
        // 3단계: 각 tokenId에 대해 tokenURI 조회
        const tokenURIResults = await Promise.allSettled(
          tokenIds.map((tokenId) =>
            client.readContract({
              address: contractAddr,
              abi: ERC721_ABI,
              functionName: "tokenURI",
              args: [tokenId],
            }),
          ),
        );
    
        // NFTItem 배열 구성
        const tokens: NFTItem[] = tokenIds.map((tokenId, i) => {
          const uriResult = tokenURIResults[i];
          return {
            tokenId: tokenId.toString(),
            tokenURI: uriResult.status === "fulfilled" ? (uriResult.value as string) : "",
            contractAddress,
          };
        });
    
        const data: NFTInfoData = {
          owner: address,
          contractAddress,
          totalOwned: tokenCount,
          tokens,
        };
    
        cache.set(cacheKey, data, NFT_INFO_CACHE_TTL);
        return makeSuccess(chain, data, false);
      } catch (err) {
        const message = sanitizeError(err);
        return makeError(`Failed to fetch NFT info: ${message}`, "RPC_ERROR");
      }
    }
  • Zod schema definition for validating the input arguments to the getNFTInfo tool.
    const inputSchema = z.object({
      address: z.string().describe("조회할 지갑 주소 (0x...)"),
      chain: z.enum(SUPPORTED_CHAINS).default("ethereum").describe("EVM 체인"),
      contractAddress: z.string().optional().describe("특정 NFT 컨트랙트 주소 (미지정 시 오류 반환)"),
    });
  • The register function adds the getNFTInfo tool to the MCP server.
    export function register(server: McpServer) {
      server.tool(
        "getNFTInfo",
        "특정 컨트랙트에서 지갑 주소가 보유한 ERC-721 NFT 목록과 tokenURI를 조회합니다",
        inputSchema.shape,
        async (args) => {
          const result = await handler(args as z.infer<typeof inputSchema>);
          return { content: [{ type: "text" as const, text: JSON.stringify(result, null, 2) }] };
        },
      );
    }

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/calintzy/evmscope'

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