Skip to main content
Glama
leo4life2

Minecraft MCP Server

by leo4life2

pickupItem

Pick up specific items from the ground in Minecraft using a designated item name. This tool integrates with the MCP server to enable AI agents to automate item collection tasks efficiently within the game.

Instructions

Pick up items from the ground

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
itemNameYesName of the item to pick up

Implementation Reference

  • The core handler function for the 'pickupItem' MCP tool. It validates parameters, finds the nearest dropped item by name using bot.nearestEntity, navigates to it with pathfinder GoalFollow, waits nearby until picked up, compares inventory snapshots to confirm pickup, emits observations, and falls back to mining the block if no dropped item is found.
    export const pickupItem = async (
      bot: Bot,
      params: ISkillParams,
      serviceParams: ISkillServiceParams,
    ): Promise<boolean> => {
      const skillName = 'pickupItem';
      const requiredParams = ['itemName'];
      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 = {
        signal: serviceParams?.signal,
        itemName: params.itemName,
        getStatsData: serviceParams.getStatsData,
        setStatsData: serviceParams.setStatsData,
        resetTimeout: serviceParams.resetTimeout,
      };
      const { signal, itemName, getStatsData, setStatsData, resetTimeout } =
        unpackedParams;
      const mcData = minecraftData(bot.version);
      const SEARCH_DISTANCE = bot.nearbyEntityRadius;
    
      if (typeof itemName !== 'string') {
        return bot.emit('alteraBotEndObservation', 'itemName must be a string');
      }
    
      const closestItemName = findClosestItemName(bot, { name: itemName });
      if (!closestItemName) {
        return bot.emit(
          'alteraBotEndObservation',
          `There is no item named ${itemName} in Minecraft.`,
        );
      }
    
      const version = parseInt(bot.version.split('.')[1]);
      let target = null;
      if (version < 10) {
        // 1.8
        target = bot.nearestEntity(
          (entity) =>
            entity?.name?.toLowerCase() === 'item' &&
            (entity.metadata[10] as any)?.blockId == mcData.itemsByName[closestItemName].id,
        );
      } else {
        target = bot.nearestEntity(
          (entity) =>
            entity?.name?.toLowerCase() === 'item' &&
            (entity.metadata[8] as any)?.itemId == mcData.itemsByName[closestItemName].id,
        );
      }
    
      if (target == null || !target.isValid) {
        // If the bot can't find the item on the ground, check to see if its a block
        const closestBlockName = closest(
          (itemName || '').toLowerCase(),
          Object.keys(mcData.blocksByName),
        );
        const blockName = mcData.itemsByName[closestBlockName]?.name;
        if (blockName && distance(closestBlockName, itemName.toLowerCase()) < 3) {
          console.log(
            `No ${itemName} found on the ground nearby. Trying to mine it...`,
          );
          return await mineBlock(bot, {
            name: itemName,
            count: 1,
            signal: signal,
            getStatsData,
            setStatsData,
            resetTimeout,
          });
        } else {
          return bot.emit(
            'alteraBotEndObservation',
            `You were trying to pick up ${itemName}, but there aren't any ${itemName} on the ground nearby for you to pick up!`,
          );
        }
      }
    
      if (target.position.distanceTo(bot.entity.position) > SEARCH_DISTANCE) {
        return bot.emit(
          'alteraBotEndObservation',
          `You were trying to pick up ${itemName}, but there aren't any ${itemName} on the ground nearby for you to pick up!`,
        );
      }
    
      try {
        // var pickedUpTarget = false;
        // Collect the item, assuming the bot is close enough to collect it
        const inventory = getInventorySnapshot(bot);
    
        bot.pathfinder.goto(new GoalFollow(target, 0));
    
        while (
          target.isValid &&
          target.position.distanceTo(bot.entity.position) < 1.5
        ) {
          // Make sure the item gets registered in the inventory
          const waitFn = async function () {
            return new Promise((r) => setTimeout(r, 50));
          };
          await asyncwrap({ func: waitFn, setStatsData, getStatsData });
    
          // check signal for cancellation
          if (isSignalAborted(signal)) {
            return bot.emit(
              'alteraBotEndObservation',
              `You decided to do something else and stopped picking up ${itemName}.`,
            );
          }
        }
    
        // Wait for 10 ticks to make sure the item is registered in the inventory
        await bot.waitForTicks(10);
    
        const differences = compareInventories(
          inventory,
          getInventorySnapshot(bot),
        );
    
        return bot.emit(
          'alteraBotEndObservation',
          `You picked up ${getCollapsedItemCounts(differences)}`,
        );
      } catch (error) {
        console.log(
          `An error occurred while trying to go and collect ${itemName}: ${error}`,
        );
        return bot.emit(
          'alteraBotEndObservation',
          `You weren't able to collect any ${itemName} because ${error}`,
        );
      }
    };
  • Defines the input schema and metadata for the 'pickupItem' tool, used during registration. Specifies the required 'itemName' string parameter.
    pickupItem: {
        description: "Pick up items from the ground",
        params: {
            itemName: { type: "string", description: "Name of the item to pick up" }
        },
        required: ["itemName"]
  • The loadSkills function registers all skills including 'pickupItem' by iterating over SKILL_METADATA, creating SkillDefinition objects with schema and dynamic executor that imports the handler module.
    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;
    }
  • Helper function to capture a snapshot of the bot's inventory before attempting pickup, used for comparison after to confirm item collection.
    const getInventorySnapshot = (bot: Bot): IInventoryItem[] => {
      return bot.inventory.items().map((item) => ({
        name: item.name,
        count: item.count,
      }));
    };
  • Helper function to compare pre- and post-pickup inventory snapshots and identify newly acquired items.
    const compareInventories = (
      oldInv: IInventoryItem[],
      newInv: IInventoryItem[],
    ): IInventoryItem[] => {
      const oldMap = new Map(oldInv.map((item) => [item.name, item.count]));
      const newMap = new Map(newInv.map((item) => [item.name, item.count]));
    
      const differences: IInventoryItem[] = [];
    
      newMap.forEach((newCount, name) => {
        const oldCount = oldMap.get(name) || 0;
        if (newCount > oldCount) {
          differences.push({ name, count: newCount - oldCount });
        }
      });
    
      return differences;
    };
Behavior2/5

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

With no annotations provided, the description carries the full burden of behavioral disclosure. It implies a mutation (picking up changes item ownership/location) but doesn't specify permissions needed, whether it's reversible, rate limits, or what happens on failure (e.g., if item isn't nearby). This leaves significant gaps for a tool that likely modifies game state.

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's front-loaded with the core action and context, 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?

For a mutation tool with no annotations and no output schema, the description is incomplete. It lacks details on behavioral traits (e.g., success conditions, error cases), output format, or integration with sibling tools. Given the complexity of game interactions, more context is needed for effective use.

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 the single parameter 'itemName' documented in the schema. The description adds no additional parameter semantics beyond implying the item must be on the ground, which is already covered by the tool's purpose. This meets the baseline for high schema coverage.

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 ('pick up') and target ('items from the ground'), providing a specific verb+resource combination. However, it doesn't differentiate from sibling tools like 'retrieveItemsFromNearbyFurnace' or 'openNearbyChest', which might involve similar item acquisition 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 offers no guidance on when to use this tool versus alternatives. It doesn't mention prerequisites (e.g., needing to be near items), exclusions (e.g., not working on equipped items), or comparisons to siblings like 'retrieveItemsFromNearbyFurnace' for furnace-specific retrieval.

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