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; }

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