Belong.net Logo
Crypto

Starknet NFT Minting Guide for MCP

End-to-end NFT minting on Starknet using MCP tools.

Overview

This document describes the complete process of minting NFTs on the Starknet blockchain using MCP (Model Context Protocol) tools. The process involves several steps that must be executed in a specific order to successfully create and mint NFTs.

📋 Prerequisites: Before using these tools, make sure you have set up MCP integration with your API key.

Account deployment note: Starknet wallet addresses are account contracts. The creator_address and each items[].receiver must be deployed on the target network, otherwise you may see errors like Requested contract address ... is not deployed.

The same operations are available as REST API endpoints (see starknet.hono.ts): POST /deploy, POST /complete-deploy, POST /mint, POST /complete-mint. REST routes require auth and accept the same JSON bodies as the data payloads described below.

All four operations are now network-aware. Pass the same network value through the full lifecycle (deploy -> complete-deploy -> mint -> complete-mint). Supported values are "SN_MAIN" and "SN_SEPOLIA", and the connected wallet must be on the same network.

Process Flow

sequenceDiagram participant MCP as MCP Client participant Tools as MCP Tools participant API as Backend API participant Frontend as Frontend participant Blockchain as Starknet

Note over MCP,Blockchain: Deploy Collection
MCP->>Tools: starknet-deploy-collection
Tools-->>MCP: calls[]
MCP->>Frontend: pass calls[]
Frontend->>Blockchain: account.execute(calls)
Blockchain-->>Frontend: receipt (transaction_hash)

Note over MCP,Blockchain: Complete Deployment
MCP->>Tools: starknet-complete-deploy
Tools-->>MCP: collection data

Note over MCP,Blockchain: Approve Token Before Mint
Frontend->>Blockchain: approve(collection_address, total_amount)
Blockchain-->>Frontend: approve receipt

Note over MCP,Blockchain: Mint NFT
MCP->>Tools: starknet-mint-nft
Tools-->>MCP: calls[]
MCP->>Frontend: pass calls[]
Frontend->>Blockchain: account.execute(calls)
Blockchain-->>Frontend: receipt (transaction_hash)

Note over MCP,Blockchain: Complete Mint
MCP->>Tools: starknet-complete-mint
Tools-->>MCP: NFT records

MCP Tools

All tools accept input under a data key: pass { data: { ...fields } } when calling a tool. The schemas below describe the contents of data.

1. Deploy Collection

Tool: starknet-deploy-collection

Description: Deploy a collection. As a result of executing this command, you will receive a transaction that needs to be signed and sent to the blockchain.

Input data:

{
  name: string,                    // Collection name (required, min 1 char, cannot be empty/whitespace)
  symbol: string,                   // Collection symbol (required, min 1 char, cannot contain spaces)
  description?: string,             // Optional description
  feeNumerator: number,             // Royalty numerator in percentage (0-8, e.g., 8 = 8%)
  transferable: boolean,            // Whether NFT can be transferred
  maxTotalSupply: number,           // Maximum NFT count
  mintPrice: number,                // Base price per mint (human amount, e.g., 2, 0.5)
  whitelistMintPrice: number,       // Discounted price for whitelisted minters (human amount)
  paymentToken: "STRK"|"ETH"|"USDC", // Payment token
  creator: string,                  // Creator wallet address (Starknet address format)
  externalUrl?: string | null,      // Optional external website/app link
  referralCode?: string,            // Optional referral code
  network: "SN_MAIN"|"SN_SEPOLIA" // Target Starknet network
}

Note: The backend automatically calculates total royalty (platform fee + creator fee) and validates it doesn't exceed 80%.

Output data:

{
  calls: [
    {
      contractAddress: string,      // Factory contract address
      entrypoint: "produce",       // Entrypoint name
      calldata: any[]               // Compiled calldata
    }
  ]
}

Note: Returns an object { calls: [...] } (or { error: string } on failure). After executing the transaction, use the transaction hash with starknet-complete-deploy and payload under data to finalize collection creation in the database.

2. Complete Deployment

Tool: starknet-complete-deploy

Description: Validates the deployment transaction receipt and creates or refreshes the collection record in the database. When activityId or hubId is provided, the linked entity is published with passStrategy: STATIC to enable QR pass flow.

Input: Pass as { data: { ... } }:

{
  hash: string,                    // Transaction hash from deploy step (required, non-zero)
  gasless?: boolean,               // Enable gasless transactions (optional)
  hubId?: string | null,           // Optional hub ID for whitelisting
  activityId?: string | null,      // Optional activity ID
  whitelist_hubIDs?: string[],     // Array of hub IDs for whitelist (optional)
  whitelist_userIDs?: string[],    // Array of user IDs for whitelist (optional)
  attributes?: [                   // Default attributes for NFTs (optional)
    {
      trait_type: string,
      display_type?: "string" | "number" | "date" | "boost_number" | "boost_percentage", // Optional, defaults to "string"
      value: string
    }
  ],
  network: "SN_MAIN"|"SN_SEPOLIA" // Same network used during deploy
}

Output data:

{
  // NftCollection object with all collection data
  id: string,
  contractAddress: string,
  // ... other collection fields
}

3. Approve Payment Token (Required before Mint)

⚠️ Important: Before minting NFTs, you must approve the collection contract to spend the required amount of payment tokens on your behalf.

Important units: ERC20 approve(amount) expects the base-units amount (u256), not a human decimal string. If your items[].price values are human amounts, convert them to base units using token decimals before summing and approving.

Token addresses depend on the selected Starknet network:

const STARKNET_TOKEN_ADDRESSES = {
  SN_MAIN: {
    STRK: "0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d",
    ETH: "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7",
    USDC: "0x033068f6539f8e6e6b131e6b2b814e6c34a5224bc66947c47dab9dfee93b35fb",
  },
  SN_SEPOLIA: {
    STRK: "0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d",
    ETH: "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7",
    USDC: "0x0512feac6339ff7889822cb5aa2a86c848e9d392bb0e3e237c008674feed8343",
  },
};

Implementation:

// Example: approve 1 token (18 decimals) => 1e18 base units
const approveCall = {
  contractAddress: STARKNET_TOKEN_ADDRESSES[network].STRK,
  entrypoint: "approve",
  calldata: [
    collection_address, // spender
    "1000000000000000000", // amount
    "0", // high part
  ],
};

await account.execute([approveCall]);

4. Mint NFT

Tool: starknet-mint-nft

Description: Mint an NFT. As a result of executing this command, you will receive a transaction that needs to be signed and sent to the blockchain.

Input data:

{
  collection_address: string,      // Created collection address
  items: [
    {
      receiver: string,            // NFT receiver address
      name: string,                // NFT name
      description: string,         // NFT description
      price: string,               // Human amount string (e.g. "0.2") - backend converts to u256 base-units by token decimals
      quantity: number,            // Number of copies
      image?: string,              // NFT image URL
      externalUrl?: string,        // External link
      animation_url?: string,      // Animation URL
      attributes?: [               // NFT attributes
        {
          trait_type: string,
          value: string
        }
      ]
    }
  ],
  network: "SN_MAIN"|"SN_SEPOLIA" // Same network used during deploy
}

Output data:

{
  calls: [
    {
      contractAddress: string,
      entrypoint: string,
      calldata: any[]
    }
  ]
}

Note: Returns an object { calls: [...] }. After executing the transaction, use the transaction hash with starknet-complete-mint MCP tool to parse the receipt and create NFT records in the database.

5. Complete Mint

Tool: starknet-complete-mint

Description: Parses the mint transaction receipt, extracts minted NFT information (token IDs, receivers), fetches metadata from tokenUri, calculates minted_price, and creates NFT records in the database. It also returns the minter Starknet wallet in cryptoAddress response field without persisting Starknet wallet addresses in crypto_addresses. Requires MCP auth (API key / user context).

Input: Pass as { data: { hash, network } }:

{
  hash: string,                    // Transaction hash from mint step (required)
  network: "SN_MAIN"|"SN_SEPOLIA" // Same network used during mint
}

Output data:

[
  {
    id: string,
    name: string,
    hash: string,
    address: string,
    block_number: string | null,
    token_id: string,
    token_uri: string | null,
    image: string | null,
    userId: string,
    minted_price: number | null,
    attributes: [
      {
        trait_type: string,
        display_type?: "string" | "number" | "date" | "boost_number" | "boost_percentage",
        value: string
      }
    ] | null,
    cryptoAddress: {
      address: string
    },
    receiver: string | null,
    serialNumber?: string
  }
]

Note:

  • Automatically parses Transfer events from the transaction receipt to identify minted NFTs and the actual NFT contract
  • Fetches and parses metadata from tokenUri (supports JSON strings, HTTP/HTTPS URLs, and Data URIs)
  • Creates NFT records in DB during complete-mint; repeat calls for the same transaction are not intended as the primary flow
  • complete-deploy and complete-mint must be called with the same network value that was used for the original transaction
  • Extracts metadata fields: name, image, description, external_url, animation_url, and attributes
  • If the collection is linked to an activityId or hubId, QR passes are created during NFT persistence and QR emails use Voyager links for Starknet

Usage

// 1. Deploy collection using MCP tool
const collectionData = {
  name: "My NFT Collection",
  symbol: "MNFT",
  description: "A unique collection",
  feeNumerator: 5, // 5% royalty
  transferable: true,
  maxTotalSupply: 10000,
  mintPrice: 2,
  whitelistMintPrice: 1,
  paymentToken: "USDC",
  creator: "0x...", // Your Starknet wallet address
  externalUrl: "https://example.com",
  referralCode: "0", // Optional
};

const deployResult = await mcp.callTool("starknet-deploy-collection", {
  data: collectionData,
});

const calls = JSON.parse(deployResult.content[0].text); // Extract calls array from MCP response

// On frontend: Execute transaction
const receipt = await account.execute(calls);
const transactionHash = receipt.transaction_hash;

// 2. Complete deployment (create collection in database)
// After transaction is confirmed, call complete-deploy MCP tool with payload under data
const completeResult = await mcp.callTool("starknet-complete-deploy", {
  data: {
    hash: transactionHash,
    gasless: false, // Optional
    hubId: null, // Optional
    activityId: null, // Optional
    whitelist_hubIDs: [], // Optional
    whitelist_userIDs: [], // Optional
    attributes: [
      // Optional
      {
        trait_type: "Color",
        display_type: "string",
        value: "Blue",
      },
    ],
  },
});

const collection = JSON.parse(completeResult.content[0].text); // Extract collection data from MCP response
const collectionAddress = collection.contractAddress; // Get collection address from response

// 3. Before minting: Approve payment token
import { parseUnits } from "viem";

const tokenDecimals = 18; // STRK/ETH are 18; USDC is 6 (see token address section below)
const totalAmount = mintData.items
  .reduce((sum, item) => {
    const itemBaseUnits = parseUnits(item.price, tokenDecimals);
    return sum + itemBaseUnits * BigInt(item.quantity);
  }, 0n)
  .toString();

const tokenAddress = {
  STRK: "0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d",
  ETH: "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7",
  // USDC addresses differ by network. Prefer the addresses used by the backend configuration:
  // - Sepolia (native USDC): 0x0512feAc6339Ff7889822cb5aA2a86C848e9D392bB0E3E237C008674feeD8343
  // - Mainnet (native USDC): 0x033068F6539f8e6e6b131e6B2B814e6c34A5224bC66947c47DaB9dFeE93b35fb
  USDC: "0x0512feAc6339Ff7889822cb5aA2a86C848e9D392bB0E3E237C008674feeD8343",
}[paymentToken]; // Use the same payment token as in collection

const approveCall = {
  contractAddress: tokenAddress,
  entrypoint: "approve",
  calldata: [collection_address, totalAmount, "0"],
};

// Execute approve transaction
await account.execute([approveCall]);

// 4. Mint NFT using MCP tool
const mintData = {
  collection_address: collectionAddress, // From complete-deploy response
  items: [
    {
      receiver: "0x...", // Receiver wallet address
      name: "NFT One",
      description: "Description of the NFT",
      price: "0.2", // Human amount string
      quantity: 1,
      image: "https://example.com/image.png", // Optional
      externalUrl: "https://example.com/external-link.html", // Optional
      animation_url: "https://example.com/animation.mp4", // Optional
      attributes: [
        // Optional
        {
          trait_type: "Rarity",
          value: "Common",
        },
      ],
    },
  ],
};

const mintResult = await mcp.callTool("starknet-mint-nft", {
  data: mintData,
});

const { calls } = JSON.parse(mintResult.content[0].text); // Extract calls from MCP response

// On frontend: Execute mint transaction
const mintReceipt = await account.execute(calls);
const mintTransactionHash = mintReceipt.transaction_hash;

// 5. Complete mint (parse receipt and create NFT records in database)
// After transaction is confirmed, call complete-mint MCP tool
const completeMintResult = await mcp.callTool("starknet-complete-mint", {
  data: {
    hash: mintTransactionHash,
  },
});

const nfts = JSON.parse(completeMintResult.content[0].text); // Extract NFT records from MCP response
console.log(`Successfully created ${nfts.length} NFT records`);

Errors

MCP tools return errors in the standard MCP error format when operations fail.

Copyright © 2026