Skip to main content
Glama
leo4life2

Minecraft MCP Server

by leo4life2

attackSomeone

Initiate combat, defend, or eliminate targets in Minecraft using this tool. Specify entity type (player, mob, animal), optional name, duration, and kill count for precise actions. Works with MCP Server for game control.

Instructions

Attack, kill, defend against, or initiate combat with someone

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
countNoOptional: Number of kills to achieve (default: 1)
durationNoOptional: Duration in seconds to attack (default: 20, max: 120)
targetNameNoOptional: The specific name of the entity to attack
targetTypeYesThe type of target: 'player', 'mob', or 'animal'

Implementation Reference

  • The main exported handler function for the 'attackSomeone' MCP tool. It validates the input parameters and delegates execution to the core 'attack' helper function.
    export const attackSomeone = async (
      bot: Bot,
      params: ISkillParams,
      serviceParams: ISkillServiceParams,
    ): Promise<boolean> => {
      const skillName = 'attackSomeone';
      const requiredParams = ['targetType'];
      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;
      }
    
      return attack(bot, {
        targetType: params.targetType ?? null,
        targetName: params.targetName ?? '',
        duration: params.duration ?? 20,
        killNumber: params.count ?? 1,
        signal: serviceParams.signal,
        getStatsData: serviceParams.getStatsData,
        setStatsData: serviceParams.setStatsData,
        resetTimeout: serviceParams.resetTimeout,
      });
    };
  • Core helper function implementing the attack logic: finds targets, equips sword, attacks, handles multiple kills, collects loot by navigating to death position, manages timeouts and cancellations.
    export const attack = async (
      bot: Bot,
      options: IAttackOptions,
    ): Promise<boolean> => {
      const defaultOptions = {
        targetType: '',
        targetName: '',
        duration: 20,
        killNumber: 1,
      };
      let {
        targetType,
        targetName,
        duration,
        killNumber,
        signal,
        setStatsData,
        getStatsData,
        resetTimeout,
      } = {...defaultOptions, ...options};
      const ENTITY_RADIUS = bot.nearbyEntityRadius;
      const WAIT_TIME = 10; // 10 milliseconds
      const MAX_DURATION = 60; // 60 seconds
      const MAX_KILL_NUMBER = 5; // Maximum number of entities to kill
    
      // Stop attacking anyone before attacking someone else
      bot.pvp.forceStop();
    
      let kills = 0;
      targetName = targetName ?? '';
    
      const targetStr = targetName ? targetName : targetType;
      targetName = targetName.replace(/\s/g, '_'); // Replace spaces in name with _
    
      duration = Math.min(duration, MAX_DURATION); // Set max duration to 60 seconds.
      killNumber = Math.min(killNumber, MAX_KILL_NUMBER); // Set max duration to 60 seconds.
    
      // filter for the target using the entity type
      let target = findTarget(bot, {targetType, targetName});
    
      if (!target) {
        return bot.emit(
          'alteraBotEndObservation',
          `Mistake: You chose to attack ${targetName} but you couldn't find anyone with that name.`,
        );
      }
    
      if (
        target.position.distanceTo(bot.entity.position) > ENTITY_RADIUS &&
        (targetType === 'mob' || targetType === 'animal')
      ) {
        return bot.emit(
          'alteraBotEndObservation',
          `There's no ${targetStr} close enough for you to attack.`,
        );
      }
    
      autoEquipSword(bot);
    
      const startTime = Date.now();
    
      let endMessage = null;
    
      try {
        // Event handler to collect loot after killing the target
        const handleDeath = async (entity: Entity) => {
          // console.log(entity === target)
          if (entity === target) {
            bot.pvp.forceStop();
    
            kills++;
            resetTimeout(); // reset the skill timeout on the bot to make sure the bot doesn't stop the skill while it's still attacking
            if (kills < killNumber)
              bot.emit(
                'alteraBotTextObservation',
                `You have killed ${kills} of ${killNumber} ${targetStr}.`,
              );
    
            // move to the target's last known position to (hopefully) collect loot
            const navigateFunc = async function () {
              return navigateToLocation(bot, {
                x: target.position.x,
                y: target.position.y,
                z: target.position.z,
                range: 0.5,
              });
            };
            await asyncwrap({func: navigateFunc, setStatsData, getStatsData});
    
            // Check if we're done killing
            await bot.waitForTicks(2);
    
            if (isSignalAborted(signal)) {
              stopAttack();
              endMessage = `You decided to do something else after you killed ${kills} ${targetStr}.`;
              return;
            }
    
            // check signal for cancellation
            if (kills >= killNumber) {
              stopAttack();
              endMessage = `You finished killing ${kills} ${targetStr}.`;
              return;
            }
    
            // Select a new target, since there are more to kill
            let newTarget = findTarget(bot, {targetType, targetName});
    
            // make sure the target is the entity we just killed and that we have a new target
            // find target may still find the same target for a brief window
            let findTargetLimit = 40; // emergency limit to prevent infinite loop // this is in ticks
            while (newTarget == target && findTargetLimit >= 0) {
              newTarget = findTarget(bot, {targetType, targetName});
              await bot.waitForTicks(1);
              findTargetLimit--;
            }
    
            if (findTargetLimit <= 0) {
              stopAttack();
              endMessage = `ERROR: couldn't find a new ${targetStr} to kill.`;
              return;
            }
    
            target = newTarget;
    
            if (
              !target ||
              (target.position.distanceTo(bot.entity.position) > ENTITY_RADIUS &&
                (targetType === 'mob' || targetType === 'animal'))
            ) {
              stopAttack();
              endMessage = `You killed ${kills} ${targetStr} and there are no more ${targetStr} nearby.`;
              return;
            }
    
            console.log(` attacking the next ${targetStr}.`);
    
            // re-equip a sword (in case old one broke)
            autoEquipSword(bot);
            bot.pathfinder.stop(); // Stop pathfinding
    
            // Reset the loot trigger and start attacking the new target
            bot.waitForTicks(2);
    
            bot.pvp.attack(target);
          }
          return;
        };
    
        bot.on('entityDead', handleDeath);
    
        // await asyncwrap(async function(){return bot.pvp.attack(target)});
        bot.pvp.attack(target);
    
        let cleanUpTimeout;
        let stoppedAttacking = false;
    
        const stopAttack = () => {
          if (!stoppedAttacking) {
            bot.removeListener('entityDead', handleDeath);
            bot.pvp.forceStop();
            stoppedAttacking = true;
            attacking = false;
          }
        };
    
        let attackTime = 0;
        let attacking = true;
        const totalDuration = duration * 1000;
        while (attacking && attackTime < totalDuration) {
          // check signal for cancellation
          // this check may be redundant, but it's here just in case
          if (isSignalAborted(signal)) {
            stopAttack();
            if (!endMessage)
              endMessage = `You decided to do something else instead of attacking ${targetStr}.`;
            return bot.emit('alteraBotEndObservation', endMessage);
          }
    
          // wait for 10 milliseconds
          await new Promise((resolve) => setTimeout(resolve, WAIT_TIME));
    
          attackTime += WAIT_TIME;
        }
    
        console.log(` stopped attacking after ${duration} seconds.`);
    
        stopAttack();
    
        if (!endMessage)
          endMessage = `You stopped attacking ${targetStr} after ${duration} seconds.`;
    
        return bot.emit('alteraBotEndObservation', endMessage);
      } catch (err) {
        const error = err as Error;
        return bot.emit(
          'alteraBotEndObservation',
          `You couldn't attack ${targetStr} because: ${error.message}`,
        );
      }
    };
  • Input schema and metadata definition for the 'attackSomeone' tool, including parameters, descriptions, and required fields.
    attackSomeone: {
        description: "Attack, kill, defend against, or initiate combat with someone",
        params: {
            targetType: { type: "string", description: "The type of target: 'player', 'mob', or 'animal'" },
            targetName: { type: "string", description: "Optional: The specific name of the entity to attack" },
            duration: { type: "number", description: "Optional: Duration in seconds to attack (default: 20, max: 120)" },
            count: { type: "number", description: "Optional: Number of kills to achieve (default: 1)" }
        },
        required: ["targetType"]
    },
  • Dynamic registration of all skills, including 'attackSomeone', by iterating over SKILL_METADATA and creating SkillDefinition objects with schema and executor.
    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