Skip to main content
Glama
bmurdock

Scryfall MCP Server

by bmurdock

suggest_mana_base

Generate optimal mana base compositions and land recommendations for Magic: The Gathering decks based on color requirements, deck size, strategy, budget, and special needs.

Instructions

Suggest optimal mana base composition and land recommendations for a deck

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
average_cmcNoAverage converted mana cost of non-land cards
budgetNoBudget constraint for land recommendationsmoderate
color_intensityNoColor intensity requirements (1-10 scale)
color_requirementsYesColor requirements (e.g., "WU", "RBG", "WUBRG")
deck_sizeNoTotal deck size
formatNoFormat to suggest lands for
special_requirementsNoSpecial mana base requirements
strategyNoDeck strategy archetypemidrange

Implementation Reference

  • Main handler function that orchestrates validation, calculations, recommendation generation, and response formatting for the suggest_mana_base tool.
    async execute(args: unknown) {
      try {
        const params = this.validateParams(args);
        
        // Calculate land count
        const landCount = this.calculateLandCount(params);
        
        // Calculate color distribution
        const colorDistribution = this.calculateColorDistribution(params, landCount);
        
        // Generate land recommendations
        const landRecommendations = await this.generateLandRecommendations(params, colorDistribution);
        
        // Format response
        const responseText = this.formatManaBaseResponse(params, landCount, colorDistribution, landRecommendations);
        
        return {
          content: [{
            type: 'text',
            text: responseText
          }]
        };
    
      } catch (error) {
        if (error instanceof ValidationError) {
          return {
            content: [{
              type: 'text',
              text: `Validation error: ${error.message}`
            }],
            isError: true
          };
        }
    
        return {
          content: [{
            type: 'text',
            text: `Unexpected error: ${error instanceof Error ? error.message : 'Unknown error occurred'}`
          }],
          isError: true
        };
      }
    }
  • Input schema defining the parameters for the suggest_mana_base tool, including color requirements, deck size, format, strategy, and more.
    readonly inputSchema = {
      type: 'object' as const,
      properties: {
        color_requirements: {
          type: 'string',
          description: 'Color requirements (e.g., "WU", "RBG", "WUBRG")'
        },
        deck_size: {
          type: 'number',
          default: 60,
          minimum: 40,
          maximum: 250,
          description: 'Total deck size'
        },
        format: {
          type: 'string',
          enum: ['standard', 'modern', 'legacy', 'vintage', 'commander', 'pioneer', 'brawl', 'standardbrawl'],
          description: 'Format to suggest lands for'
        },
        strategy: {
          type: 'string',
          enum: ['aggro', 'midrange', 'control', 'combo', 'ramp'],
          default: 'midrange',
          description: 'Deck strategy archetype'
        },
        average_cmc: {
          type: 'number',
          minimum: 0,
          maximum: 10,
          description: 'Average converted mana cost of non-land cards'
        },
        budget: {
          type: 'string',
          enum: ['budget', 'moderate', 'expensive', 'no_limit'],
          default: 'moderate',
          description: 'Budget constraint for land recommendations'
        },
        color_intensity: {
          type: 'object',
          properties: {
            W: { type: 'number', minimum: 0, maximum: 10 },
            U: { type: 'number', minimum: 0, maximum: 10 },
            B: { type: 'number', minimum: 0, maximum: 10 },
            R: { type: 'number', minimum: 0, maximum: 10 },
            G: { type: 'number', minimum: 0, maximum: 10 }
          },
          description: 'Color intensity requirements (1-10 scale)'
        },
        special_requirements: {
          type: 'array',
          items: {
            type: 'string',
            enum: ['enters_untapped', 'basic_types', 'nonbasic_hate_protection', 'utility_lands', 'combo_lands']
          },
          description: 'Special mana base requirements'
        }
      },
      required: ['color_requirements']
    };
  • src/server.ts:79-79 (registration)
    Registration of the SuggestManaBaseTool instance in the MCP server's tools map under the name 'suggest_mana_base'.
    this.tools.set("suggest_mana_base", new SuggestManaBaseTool(this.scryfallClient));
  • Helper function to calculate the optimal number of lands based on deck size, strategy, average CMC, and format.
    private calculateLandCount(params: any): number {
      const { deck_size, strategy, average_cmc } = params;
      
      // Base land count ratios by strategy
      const baseRatios = {
        aggro: 0.35,    // 35% lands
        midrange: 0.40, // 40% lands  
        control: 0.42,  // 42% lands
        combo: 0.38,    // 38% lands
        ramp: 0.45      // 45% lands
      };
      
      let baseCount = Math.round(deck_size * baseRatios[strategy as keyof typeof baseRatios]);
      
      // Adjust for average CMC
      if (average_cmc !== undefined) {
        if (average_cmc > 4) {
          baseCount += Math.round((average_cmc - 4) * 2);
        } else if (average_cmc < 2.5) {
          baseCount -= Math.round((2.5 - average_cmc) * 2);
        }
      }
      
      // Format-specific adjustments
      if (params.format === 'commander') {
        baseCount = Math.max(36, Math.min(40, baseCount));
      } else if (params.format === 'brawl') {
        baseCount = Math.max(22, Math.min(26, baseCount));
      }
      
      return Math.max(Math.round(deck_size * 0.30), Math.min(Math.round(deck_size * 0.50), baseCount));
    }
  • Helper function to format the final mana base suggestion response in a readable markdown format.
    private formatManaBaseResponse(params: any, landCount: number, colorDistribution: Record<string, number>, recommendations: any): string {
      let response = `**Mana Base Suggestion**\n\n`;
      
      // Overview
      response += `🎯 **Overview:**\n`;
      response += `β€’ Colors: ${params.color_requirements}\n`;
      response += `β€’ Strategy: ${params.strategy}\n`;
      response += `β€’ Total Lands: ${landCount}/${params.deck_size}\n`;
      if (params.format) {
        response += `β€’ Format: ${params.format}\n`;
      }
      response += `β€’ Budget: ${params.budget}\n\n`;
      
      // Land count breakdown
      response += `πŸ“Š **Land Distribution:**\n`;
      for (const [color, count] of Object.entries(colorDistribution)) {
        if (count > 0 && color !== 'dual' && color !== 'utility') {
          const colorName = { W: 'White', U: 'Blue', B: 'Black', R: 'Red', G: 'Green' }[color as keyof typeof colorDistribution] || color;
          response += `β€’ ${colorName}: ${count} lands\n`;
        }
      }
      if (colorDistribution.dual) {
        response += `β€’ Dual/Fixing: ${colorDistribution.dual} lands\n`;
      }
      if (colorDistribution.utility) {
        response += `β€’ Utility: ${colorDistribution.utility} lands\n`;
      }
      response += '\n';
      
      // Basic lands
      if (recommendations.basics.length > 0) {
        response += `πŸ”οΈ **Basic Lands:**\n`;
        for (const basic of recommendations.basics) {
          response += `β€’ ${basic.count}x ${basic.name}\n`;
        }
        response += '\n';
      }
      
      // Dual lands
      if (recommendations.duals.length > 0) {
        response += `🌈 **Dual Lands:**\n`;
        for (const dual of recommendations.duals) {
          response += `β€’ ${dual.count}x ${dual.name}\n`;
          response += `  πŸ’‘ *${dual.reason}*\n`;
          if (dual.example) {
            response += `  πŸ“ Example: ${dual.example}\n`;
          }
        }
        response += '\n';
      }
      
      // Utility lands
      if (recommendations.utility.length > 0) {
        response += `πŸ› οΈ **Utility Lands:**\n`;
        for (const utility of recommendations.utility) {
          response += `β€’ ${utility.count}x ${utility.name}\n`;
          response += `  πŸ’‘ *${utility.reason}*\n`;
          if (utility.example) {
            response += `  πŸ“ Example: ${utility.example}\n`;
          }
        }
        response += '\n';
      }
      
      // Budget alternatives
      if (recommendations.budget_alternatives.length > 0) {
        response += `πŸ’° **Budget Alternatives:**\n`;
        for (const alt of recommendations.budget_alternatives) {
          response += `β€’ ${alt.count}x ${alt.name}\n`;
          response += `  πŸ’‘ *${alt.reason}*\n`;
          if (alt.example) {
            response += `  πŸ“ Example: ${alt.example}\n`;
          }
        }
        response += '\n';
      }
      
      // Additional recommendations
      response += `πŸ’‘ **Additional Tips:**\n`;
      
      if (params.strategy === 'aggro') {
        response += `β€’ Prioritize lands that enter untapped\n`;
        response += `β€’ Consider fewer utility lands for speed\n`;
      } else if (params.strategy === 'control') {
        response += `β€’ Include more utility lands for late game\n`;
        response += `β€’ Consider lands with card selection\n`;
      } else if (params.strategy === 'combo') {
        response += `β€’ Focus on consistency over speed\n`;
        response += `β€’ Include tutoring lands if available\n`;
      }
      
      if (params.color_requirements.length > 2) {
        response += `β€’ Three+ color decks need excellent mana fixing\n`;
        response += `β€’ Consider green ramp spells for color fixing\n`;
      }
      
      return response;
    }

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/bmurdock/scryfall-mcp'

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