back to posts
#24 Part 4 2025-09-15 10 min

Building Interactive NFT Creation Workflows with MCP Servers

How we solved the approval problem for AI-generated NFTs in a stateless protocol

Part 4 of the Journey: Advanced Topics & Deep Dives Previous: The Chain Info Breakthrough | Next: The Bloomberg Terminal Rescue

Building Interactive NFT Creation Workflows with MCP Servers

How we solved the approval problem for AI-generated NFTs in a stateless protocol

Date: September 15, 2025 Author: Myron Koch & Claude Code Category: MCP Architecture Patterns

The Problem

We built an NFT Pipeline MCP server that could generate AI images, upload to IPFS, and create metadata - all the pre-blockchain steps for NFT creation. But there was a UX problem:

Users couldn’t approve or modify the generated image before minting.

In a traditional web app, you’d show a preview, let the user regenerate or edit, then proceed. But MCP servers are stateless - each tool call is independent. How do you create an interactive, multi-step workflow with approval points?

The Insight

MCP tools can return structured data that acts as a “continuation token” for the next step. By breaking the workflow into multiple tools that pass data between them, we can create approval checkpoints.

The Solution: Multi-Tool Workflow Pattern

Instead of one monolithic create_nft tool, we created five sequential tools:

1. generate_nft_images    → Returns multiple options with IDs
2. approve_nft_image      → User picks one, can modify
3. create_nft_metadata    → Returns draft for review
4. approve_nft_metadata   → User approves/edits, uploads to IPFS
5. mint_nft_final        → Executes on blockchain

How It Works

Each tool returns:

The user (or AI assistant) orchestrates the flow, maintaining control at each step.

Implementation Example

Here’s how the image generation step works:

export async function handleNftGenerateImageOptions(args: {
  prompt: string;
  variations?: number;
}) {
  const images = [];
  const variationCount = args.variations ?? 3;  // Default to 3 variations

  // Generate multiple variations
  for (let i = 0; i < variationCount; i++) {
    const imageUrl = await generateImage(args.prompt, i);
    images.push({
      id: `temp_${Date.now()}_${i}`,
      url: imageUrl,
      prompt: args.prompt
    });
  }

  return {
    content: [{
      type: 'text',
      text: JSON.stringify({
        images: images,
        instructions: 'Review images and call approve_nft_image with chosen ID',
        nextStep: 'approve_nft_image'
      })
    }]
  };
}

The User Experience

This pattern transforms the interaction from a black box into a collaborative process:

User: "Create an NFT of a robot chef"

AI: Generated 3 image variations:
    1. [Preview URL] - Robot in kitchen
    2. [Preview URL] - Robot with chef hat
    3. [Preview URL] - Futuristic cooking robot

    Which would you like to use?

User: "Number 2, but make it more colorful"

AI: Image approved with modifications.
    Here's your metadata draft:
    {
      "name": "RoboChef #001",
      "description": "A culinary automaton",
      "attributes": [...]
    }

    Would you like to modify anything?

User: "Add trait 'Rarity: Legendary' and mint it"

AI: NFT minted successfully!
    Transaction: 0x123...
    OpenSea: https://opensea.io/...

Key Architectural Insights

1. State Through Return Values

MCP’s stateless nature becomes a strength - each step explicitly returns its state as data, making the workflow debuggable and resumable.

2. User as Orchestrator

Instead of hiding the process, we expose each step, giving users fine-grained control. The AI assistant helps orchestrate but doesn’t hide the mechanics.

3. Progressive Enhancement

Start with basic single-tool implementation, then split into multiple tools as you identify approval points. Not every operation needs this pattern.

4. Temporary Storage Pattern

Use timestamp-based IDs for temporary assets. In production, you’d want Redis or similar for actual temp storage, but IDs in return values work for prototypes.

Alternative Approach: Stage-Based Single Tool

For simpler workflows, you can use one tool with explicit stages:

async function handleNftWorkflow(args: {
  stage: 'generate' | 'approve_image' | 'metadata' | 'mint';
  sessionId?: string;
  // stage-specific params...
}) {
  switch(args.stage) {
    case 'generate':
      return { images, nextStage: 'approve_image', sessionId };
    case 'approve_image':
      return { approved, nextStage: 'metadata', sessionId };
    // etc...
  }
}

This keeps everything in one tool while maintaining the approval workflow.

Broader Applications

This pattern works for any multi-step process needing user approval:

Lessons Learned

  1. Don’t fight the protocol - Work with MCP’s stateless nature, not against it
  2. Explicit is better - Show users what’s happening at each step
  3. Return rich data - Include preview URLs, formatted displays, and clear instructions
  4. Design for interruption - Users should be able to stop and restart at any step
  5. Progressive disclosure - Start simple, add approval steps based on user feedback

What’s Next

We’re implementing this pattern across our blockchain MCP servers. Each NFT-capable chain will get these approval workflows, giving users unprecedented control over the NFT creation process.

The bigger insight? MCP’s constraints force us to build more transparent, user-controlled workflows. What seemed like a limitation became a feature.

Code References


This is part of our ongoing series documenting architectural patterns and insights from building the Blockchain MCP Server Ecosystem - 17 blockchain integrations and counting.


Prerequisites

Next Steps

Deep Dives