Skip to main content
Glama
leo4life2

Minecraft MCP Server

by leo4life2

harvestMatureCrops

Automatically collect mature crops within a specified radius on Minecraft MCP Server, streamlining farming tasks for efficient gameplay.

Instructions

Harvest mature crops from nearby farmland

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
numberNoNumber of crops to harvest
radiusNoSearch radius (default: 30)

Implementation Reference

  • Main handler function that validates parameters, finds mature crops nearby, and harvests them by navigating to each position and digging.
    export const harvestMatureCrops = async (
      bot: Bot,
      params: ISkillParams,
      serviceParams: ISkillServiceParams,
    ): Promise<boolean> => {
      const skillName = 'harvestMatureCrops';
      const requiredParams: string[] = [];
      const isParamsValid = validateSkillParams(
        params,
        requiredParams,
        skillName,
      );
      if (!isParamsValid) {
        serviceParams.cancelExecution?.();
        bot.emit(
          'alteraBotEndObservation',
          `Mistake: You didn't provide all of the required parameters ${requiredParams.join(', ')} for the ${skillName} skill.`,
        );
        return false;
      }
    
      const unpackedParams = {
        number: params.number ?? 1000,
        radius: params.radius ?? 16,
      };
    
      const { number, radius } = unpackedParams;
      const { signal, getStatsData, setStatsData } = serviceParams;
    
      // Define crop types and their mature stage block state
      const cropsInfo = [
        { name: 'wheat', matureState: 7 },
        { name: 'carrots', matureState: 7 },
        { name: 'potatoes', matureState: 7 },
        { name: 'beetroots', matureState: 3 }, // Note: Beetroots mature at state 3
      ];
    
      const matureCrops = await findMatureCrops(bot, { cropsInfo, number, radius });
    
      // console.log("Mature crops found: ", matureCrops.length)
      if (matureCrops.length === 0) {
        return bot.emit(
          'alteraBotEndObservation',
          'You tried to harvest crops but there are no mature crops found nearby.',
        );
      }
    
      await harvestCrops(bot, { matureCrops, signal, getStatsData, setStatsData });
      bot.emit('alteraBotEndObservation', 'You have finished harvesting crops');
    };
  • Helper function to find positions of mature wheat, carrots, potatoes, and beetroots within the specified radius using bot.findBlocks.
    const findMatureCrops = async (
      bot: Bot,
      options: IFindMatureCropsOptions,
    ): Promise<Array<{ x: number; y: number; z: number }>> => {
      const { cropsInfo, number, radius } = options;
      const matureCrops = [];
      for (const cropInfo of cropsInfo) {
        const cropBlockId = bot.registry.blocksByName[cropInfo.name]?.id;
        if (!cropBlockId) continue; // Skip if crop type is not found in registry
    
        const positions = bot.findBlocks({
          point: bot.entity.position,
          matching: (block) =>
            block.type === cropBlockId && block.metadata === cropInfo.matureState,
          maxDistance: radius,
          count: number,
        });
    
        matureCrops.push(...positions);
      }
      return matureCrops;
    };
  • Helper function that iterates over mature crop positions, moves the bot to each using pathfinder, digs the block, emits observations, and handles errors and cancellation.
    const harvestCrops = async (
      bot: Bot,
      options: IHarvestCrops,
    ): Promise<boolean> => {
      const { matureCrops, signal, getStatsData, setStatsData } = options;
    
      for (const pos of matureCrops) {
        try {
          const block = bot.blockAt(new Vec3(pos.x, pos.y, pos.z));
          if (block) {
            const goal = new GoalNear(pos.x, pos.y, pos.z, 1);
            const result = cancelableMove(bot, { goal, signal });
            // check for cancelation signal
            if (isSignalAborted(signal)) {
              return bot.emit(
                'alteraBotEndObservation',
                `You decided to do something else and stopped harvesting.`,
              );
            }
    
            const digFn = async function () {
              return bot.dig(block);
            };
            await asyncwrap({ func: digFn, getStatsData, setStatsData });
    
            bot.emit(
              'alteraBotTextObservation',
              `Harvested ${block.name} at (${pos.x}, ${pos.y}, ${pos.z})`,
            );
    
            // Wait for items to drop
            const waitFn = async function () {
              return new Promise((resolve) => setTimeout(resolve, 1000));
            };
            await asyncwrap({ func: waitFn, setStatsData, getStatsData }); // Wait for 1 second
          }
        } catch (error) {
          console.error(
            `Failed to harvest at (${pos.x}, ${pos.y}, ${pos.z}): ${error}`,
          );
          bot.emit(
            'alteraBotEndObservation',
            `Failed to harvest at (${pos.x}, ${pos.y}, ${pos.z}): ${error}`,
          );
        }
      }
    };
  • Schema definition for the harvestMatureCrops tool including input parameters (number and radius) and description.
    harvestMatureCrops: {
        description: "Harvest mature crops from nearby farmland",
        params: {
            number: { type: "number", description: "Number of crops to harvest" },
            radius: { type: "number", description: "Search radius (default: 30)" }
        },
        required: []
    },
  • Generic registration code in loadSkills that adds all skills from SKILL_METADATA to the skills array, dynamically loading the handler via createSkillExecutor.
        skills.push({
            name: skillName,
            description: metadata.description,
            inputSchema: {
                type: "object",
                properties: metadata.params,
                required: metadata.required
            },
            execute: createSkillExecutor(skillName)
        });
    }
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden of behavioral disclosure. It states the action ('harvest') but doesn't clarify if this is destructive (removes crops), has side effects (e.g., yields items, affects farmland), requires specific conditions (e.g., tools, permissions), or details response behavior. For a mutation tool with zero annotation coverage, this leaves significant gaps.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, efficient sentence with zero wasted words. It front-loads the core action and target, making it immediately understandable without unnecessary elaboration.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given this is a mutation tool (implied by 'harvest') with no annotations and no output schema, the description is incomplete. It lacks details on what happens after harvesting (e.g., items gained, effects on crops/farmland), error conditions, or behavioral traits. The schema covers parameters well, but overall context for safe and effective use is insufficient.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, with clear parameter descriptions in the schema ('number of crops to harvest', 'search radius'). The description adds no additional parameter semantics beyond implying 'nearby farmland' relates to radius, but doesn't explain units, defaults, or constraints. Baseline 3 is appropriate as the schema handles most documentation.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action ('harvest') and target resource ('mature crops from nearby farmland'), which is specific and actionable. However, it doesn't explicitly differentiate from potential sibling tools like 'pickupItem' or 'retrieveItemsFromNearbyFurnace', which might involve similar collection actions in different contexts.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides no guidance on when to use this tool versus alternatives. It doesn't mention prerequisites (e.g., needing mature crops available), exclusions (e.g., not for immature crops), or comparisons to siblings like 'pickupItem' for general item collection. The context is implied but not explicit.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Related Tools

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/leo4life2/minecraft-mcp-http'

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