Skip to main content
Glama
leo4life2

Minecraft MCP Server

by leo4life2

useItemOnBlockOrEntity

Execute item interactions on specific blocks or entities in Minecraft. Define the item, target, and optional count to perform precise in-game actions.

Instructions

Use an item on a block or entity

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
countNoOptional: Number of times to use (default: 1)
itemYesName of the item to use
targetYesTarget block or entity

Implementation Reference

  • Main handler function for the 'useItemOnBlockOrEntity' tool. Validates input, equips the specified item, determines if the target is a block or entity using fuzzy matching on minecraft-data, navigates if needed, and performs the use action.
    export const useItemOnBlockOrEntity = async (
      bot: Bot,
      params: ISkillParams,
      serviceParams: ISkillServiceParams,
    ): Promise<boolean> => {
      const mcData = minecraftData(bot.version);
      const skillName = 'useItemOnBlockOrEntity';
      const requiredParams = ['item', 'target'];
      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 = {
        item: params.item,
        target: params.target,
        count: params.count ?? 1,
      };
    
      let itemName;
      if (!unpackedParams.item || unpackedParams.item === '') {
        itemName = 'hands';
      } else {
        // First check if the item is valid
        itemName = findClosestItemName(bot, {name: unpackedParams.item});
        if (!itemName) {
          // if the item is not in the list, return an error message
          return bot.emit(
            'alteraBotEndObservation',
            `Mistake: The item ${unpackedParams.item} does not exist in Minecraft, so you can't use it on ${unpackedParams.target}.`,
          );
        }
    
        // Equip the item
        const inventoryItem = bot.inventory.findInventoryItem(
          itemName as any,
          null,
          false,
        );
        if (!inventoryItem) {
          return bot.emit(
            'alteraBotEndObservation',
            `Mistake: You don't have any ${itemName} in your inventory to use on ${unpackedParams.target}.`,
          );
        } else {
          console.log(
            `Equipping ${inventoryItem.name} to use on ${unpackedParams.target}.`,
          );
          await bot.equip(inventoryItem, 'hand');
        }
      }
    
      // Then check if the target is an entity or a block
      let targetIsEntity = false;
      let targetIsBlock = false;
    
      // Special case for boat, if boat is a substring of the target, map the target to boat
      if (unpackedParams.target.includes('boat')) {
        unpackedParams.target = 'boat';
      }
    
      // find a matching entity entry in mcData based on the name
      const entityName = closest(
        unpackedParams.target.toLowerCase(),
        Object.keys(mcData.entitiesByName),
      );
      const distanceToEntity = distance(
        unpackedParams.target.toLowerCase(),
        entityName,
      );
      if (distanceToEntity < 4) {
        targetIsEntity = true;
        console.log(`targetIsEntity is true, found ${entityName}`);
      }
    
      const blockName = closest(
        unpackedParams.target.toLowerCase(),
        Object.keys(mcData.blocksByName),
      );
      const distanceToBlock = distance(
        unpackedParams.target.toLowerCase(),
        blockName,
      );
      if (distanceToBlock < 4) {
        targetIsBlock = true;
        console.log(`targetIsBlock is true, found ${blockName}`);
      }
    
      if (!targetIsEntity && !targetIsBlock) {
        return bot.emit(
          'alteraBotEndObservation',
          `Mistake: The target ${unpackedParams.target} does not exist in Minecraft. Do you mean ${entityName} or ${blockName}?`,
        );
      }
    
      if (targetIsEntity && targetIsBlock) {
        if (distanceToBlock < distanceToEntity) {
          targetIsEntity = false;
        } else {
          targetIsBlock = false;
        }
      }
    
      if (targetIsEntity) {
        return useItemOnEntity(bot, {
          itemName,
          entityName,
          count: unpackedParams.count,
        });
      } else {
        return useItemOnBlock(bot, {
          itemName,
          blockName,
          count: unpackedParams.count,
        });
      }
    };
  • Helper function called by handler to use the item on up to 'count' nearest matching entities. Handles navigation, looking, and useOn.
    export const useItemOnEntity = async (
      bot: Bot,
      options: IUseItemOnEntityOptions,
    ): Promise<boolean> => {
      const defaultOptions = {
        count: 1,
      };
      const {itemName, entityName, count} = {...defaultOptions, ...options};
    
      const nearbyEntityList = Object.values(bot.entities).filter(
        (entity) =>
          entity.name === entityName &&
          bot.entity.position.distanceTo(entity.position) <= bot.nearbyEntityRadius,
      );
    
      let entityList = [];
    
      if (nearbyEntityList.length > 0) {
        // sort the list by distance
        nearbyEntityList.sort(
          (a, b) =>
            a.position.distanceTo(bot.entity.position) -
            b.position.distanceTo(bot.entity.position),
        );
        entityList = nearbyEntityList.slice(0, count);
      } else {
        return bot.emit(
          'alteraBotEndObservation',
          `You couldn't find any ${entityName} nearby. `,
        );
      }
    
      console.log(
        `Found ${entityList.length} ${entityName} nearby to use ${itemName} on.`,
      );
    
      let successCount = 0;
      // use the item on the entity
      for (const activeEntity of entityList) {
        const heldItem = bot.inventory.slots[36];
    
        if (itemName !== 'hands' && (heldItem === null || heldItem === undefined)) {
          return bot.emit(
            'alteraBotEndObservation',
            `You lost or wore out the ${itemName}.`,
          );
        }
    
        if (!bot.entities[activeEntity.id]) {
          console.log(
            `UseItemOnEntity: The entity ${activeEntity.name} is no longer valid, skipping.`,
          );
          continue; // Skip if the entity is no longer valid
        }
    
        if (activeEntity.position.distanceTo(bot.entity.position) > 2) {
          console.log(`Navigating to ${activeEntity.name}.`);
          await navigateToLocation(bot, {
            x: activeEntity.position.x,
            y: activeEntity.position.y,
            z: activeEntity.position.z,
            range: 2,
          });
        }
    
        console.log(`looking at ${activeEntity.name}.`);
        bot.lookAt(activeEntity.position);
    
        console.log(`Using ${itemName} on ${activeEntity.name}.`);
    
        try {
          bot.useOn(activeEntity);
    
          bot.waitForTicks(5);
    
          // We don't really know what's the best way to check if the item was used on the entity
          successCount++;
          // Wait for a short period before moving to the next entity
        } catch (err) {
          const error = err as Error;
          console.error(
            `Error using ${itemName} on ${activeEntity.name}: ${error.message}`,
          );
        }
      }
    
      return bot.emit(
        'alteraBotEndObservation',
        `You have successfuly finished using ${itemName} on ${entityName}.`,
      );
    };
  • Helper function called by handler to use the item on up to 'count' nearby matching blocks. Uses low-level client writes to simulate item use on block.
    export const useItemOnBlock = async (
      bot: Bot,
      options: IUseItemOnBlockOptions,
    ): Promise<boolean> => {
      const mcData = minecraftData(bot.version);
      const defaultOptions = {
        count: 1,
      };
      const {itemName, blockName, count} = {...defaultOptions, ...options};
      const blockPositions = bot.findBlocks({
        matching: mcData.blocksByName[blockName].id,
        maxDistance: bot.nearbyBlockXZRange,
        count: count, // ignore count, find all blocks, filter later
      });
    
      if (blockPositions.length === 0) {
        return bot.emit(
          'alteraBotEndObservation',
          `You couldn't find any ${blockName} nearby.`,
        );
      }
    
      console.log(
        `Found ${blockPositions.length} ${blockName} nearby to use ${itemName} on.`,
      );
    
      let successCount = 0;
      // use the item on the block
      for (const blockPosition of blockPositions) {
        const heldItem = bot.inventory.slots[36];
        if (itemName !== 'hands' && (heldItem === null || heldItem === undefined)) {
          return bot.emit(
            'alteraBotEndObservation',
            `You lost or wore out the ${itemName}.`,
          );
        }
        const block = bot.blockAt(blockPosition);
        if (blockPosition.distanceTo(bot.entity.position) > 2) {
          console.log(`Navigating to ${block.name}.`);
          await navigateToLocation(bot, {
            x: block.position.x,
            y: block.position.y,
            z: block.position.z,
            range: 2,
          });
        }
        console.log(`looking at ${block.name} at ${block.position}.`);
        await bot.lookAt(block.position.offset(0.5, 0.5, 0.5), true);
        console.log(`Using ${itemName} on ${block.name}.`);
    
        try {
          bot._client.write('use_item', {hand: 0}); // 0 for main hand
          bot._client.write('block_place', {
            location: block.position,
            direction: 1, // 1 for the top face of the block
            hand: 0,
            cursorX: 0.5,
            cursorY: 0.5,
            cursorZ: 0.5,
            insideBlock: false,
          });
    
          await bot.waitForTicks(5);
    
          // We don't really know what's the best way to check if the item was used on the block
          successCount++;
          // Wait for a short period before moving to the next block
        } catch (err) {
          const error = err as Error;
          console.error(
            `Error using ${itemName} on ${block.name}: ${error.message}`,
          );
        }
      }
    
      return bot.emit(
        'alteraBotEndObservation',
        `You have successfuly finished using ${itemName} on ${blockName}.`,
      );
    };
  • Schema definition in SKILL_METADATA used to generate inputSchema for the tool during registration.
    useItemOnBlockOrEntity: {
        description: "Use an item on a block or entity",
        params: {
            item: { type: "string", description: "Name of the item to use" },
            target: { type: "string", description: "Target block or entity" },
            count: { type: "number", description: "Optional: Number of times to use (default: 1)" }
        },
        required: ["item", "target"]
    },
  • Registration function that iterates over SKILL_METADATA (including useItemOnBlockOrEntity) to create SkillDefinition objects with schema and dynamic executor that imports the handler file.
    export async function loadSkills(): Promise<SkillDefinition[]> {
        const skills: SkillDefinition[] = [];
    
        for (const [skillName, metadata] of Object.entries(SKILL_METADATA)) {
            skills.push({
                name: skillName,
                description: metadata.description,
                inputSchema: {
                    type: "object",
                    properties: metadata.params,
                    required: metadata.required
                },
                execute: createSkillExecutor(skillName)
            });
        }
    
        return skills;
    }
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 ('use') but does not explain what happens during use (e.g., item consumption, block interaction effects, entity reactions, permissions needed, or error conditions). For a tool with no annotations and potential mutative effects, this lack of detail is a significant gap.

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

Conciseness4/5

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

The description is a single, straightforward sentence with no wasted words, making it efficient and front-loaded. However, it is overly concise to the point of under-specification, lacking necessary details for a tool with potential complex interactions. While structurally sound, it could benefit from more informative content.

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 no annotations, no output schema, and a tool that likely involves mutative actions (using items), the description is incomplete. It does not cover behavioral aspects, return values, or error handling, leaving gaps in understanding how the tool operates. For a 3-parameter tool in a context-rich environment with many siblings, more context is needed.

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?

The input schema has 100% description coverage, with clear parameter definitions (e.g., 'item' as name of item, 'target' as block or entity, 'count' as optional number of uses). The description adds no additional meaning beyond the schema, such as examples or constraints. With high schema coverage, the baseline score of 3 is appropriate as the schema handles parameter documentation adequately.

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

Purpose3/5

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

The description 'Use an item on a block or entity' states a verb ('use') and resources ('item', 'block or entity'), which provides a basic purpose. However, it is vague about what 'use' entails (e.g., applying, interacting, consuming) and does not differentiate from siblings like 'placeItemNearYou' or 'giveItemToSomeone', which involve similar actions with items and targets. The purpose is clear but lacks specificity.

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 does not mention prerequisites, exclusions, or context for choosing this over siblings such as 'placeItemNearYou' (for placing items) or 'giveItemToSomeone' (for giving items to entities). Without any usage instructions, the agent must infer based on the tool name alone.

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