Skip to main content
Glama

get_sip009_token_info

Retrieve comprehensive SIP-009 NFT details including ownership, metadata URI, and content for specific token IDs on the Stacks blockchain network.

Instructions

Get complete information about a specific SIP-009 NFT including owner, metadata URI, and actual metadata content.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
contractAddressYesThe contract address
contractNameYesThe contract name of the SIP-009 NFT collection
networkYesThe Stacks network
tokenIdYesThe NFT token ID

Implementation Reference

  • The main execution handler for the 'get_sip009_token_info' tool. Fetches NFT owner and token URI using parallel Hiro API read-only contract calls, parses results, fetches and displays metadata, and returns formatted information.
    export const getSIP009TokenInfoTool: Tool<undefined, typeof SIP009TokenInfoScheme> = { name: "get_sip009_token_info", description: "Get complete information about a specific SIP-009 NFT including owner, metadata URI, and actual metadata content.", parameters: SIP009TokenInfoScheme, execute: async (args, context) => { try { await recordTelemetry({ action: "get_sip009_token_info" }, context); // Get NFT information in parallel const [ownerResult, uriResult] = await Promise.all([ callReadOnlyFunction( args.contractAddress, args.contractName, "get-owner", [`0x${args.tokenId.toString(16).padStart(32, '0')}`], args.network ), callReadOnlyFunction( args.contractAddress, args.contractName, "get-token-uri", [`0x${args.tokenId.toString(16).padStart(32, '0')}`], args.network ), ]); // Parse results const owner = ownerResult.okay && ownerResult.result !== 'none' ? ownerResult.result.replace(/[()]/g, '').replace('some ', '') : 'No owner (token may not exist)'; const metadataUri = uriResult.okay && uriResult.result !== 'none' ? uriResult.result.replace(/[()]/g, '').replace('some ', '').replace(/"/g, '') : null; let metadata = null; if (metadataUri) { metadata = await fetchMetadata(metadataUri); } return `# SIP-009 NFT Information **Contract**: ${args.contractAddress}.${args.contractName} **Token ID**: ${args.tokenId} **Network**: ${args.network} ## Ownership - **Current Owner**: ${owner} ## Metadata - **URI**: ${metadataUri || 'No metadata URI'} ${metadata ? ` ## Metadata Content - **Name**: ${metadata.name || 'N/A'} - **Description**: ${metadata.description || 'N/A'} - **Image**: ${metadata.image || 'N/A'} - **External URL**: ${metadata.external_url || 'N/A'} ${metadata.attributes ? ` ### Attributes ${metadata.attributes.map((attr: any) => `- **${attr.trait_type}**: ${attr.value}`).join('\n')} ` : ''} ` : metadata === null && metadataUri ? ` ⚠️ **Metadata fetch failed** - URI may be inaccessible ` : ''} ## Contract Verification ✅ This contract implements the SIP-009 NFT standard trait. ## Transfer Notes - Post-conditions are REQUIRED for all transfers - Only the current owner can initiate transfers - Use native Stacks post-conditions for security`; } catch (error) { return `❌ Failed to get SIP-009 NFT info: ${error}`; } }, };
  • Input schema (Zod) defining required parameters: contractAddress, contractName, tokenId, and network (mainnet/testnet/devnet).
    const SIP009TokenInfoScheme = z.object({ contractAddress: z.string().describe("The contract address"), contractName: z.string().describe("The contract name of the SIP-009 NFT collection"), tokenId: z.number().describe("The NFT token ID"), network: NetworkScheme.describe("The Stacks network"), });
  • Registers the getSIP009TokenInfoTool with the FastMCP server instance.
    server.addTool(getSIP009TokenInfoTool);
  • Helper function to perform read-only contract function calls via Hiro API (stacks-blockchain explorer). Used to fetch 'get-owner' and 'get-token-uri'.
    async function callReadOnlyFunction( contractAddress: string, contractName: string, functionName: string, functionArgs: any[], network: string ): Promise<any> { const apiUrl = network === "mainnet" ? "https://api.hiro.so" : "https://api.testnet.hiro.so"; try { const response = await fetch( `${apiUrl}/v2/contracts/call-read/${contractAddress}/${contractName}/${functionName}`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ sender: contractAddress, arguments: functionArgs, }), } ); if (!response.ok) { const data: any = await response.json(); throw new Error(data.error || `HTTP ${response.status}`); } return await response.json(); } catch (error) { throw new Error(`Failed to call ${functionName}: ${error}`); } }
  • Helper function to fetch and parse NFT metadata JSON from the token URI, with IPFS support and 5-second timeout.
    async function fetchMetadata(uri: string): Promise<any> { try { // Handle IPFS URIs if (uri.startsWith('ipfs://')) { uri = uri.replace('ipfs://', 'https://ipfs.io/ipfs/'); } const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), 5000); const response = await fetch(uri, { signal: controller.signal }); clearTimeout(timeoutId); if (!response.ok) { throw new Error(`HTTP ${response.status}`); } return await response.json(); } catch (error) { return null; } }

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/exponentlabshq/stacks-clarity-mcp'

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