Skip to main content
Glama
leo4life2

Minecraft MCP Server

by leo4life2

goToSomeone

Navigate to a specific player in Minecraft, allowing you to maintain a set distance and optionally follow them using the MCP Server's client library.

Instructions

Navigate to another player

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
distanceNoDistance to maintain from the player (default: 3)
keepFollowingNoContinue following the player (default: false)
userNameYesUsername of the player to go to

Implementation Reference

  • The primary handler function for the 'goToSomeone' tool. It validates the input parameters (requiring 'userName'), sets defaults, and delegates the navigation logic to the 'goToPerson' helper.
    export const goToSomeone = async (
      bot: Bot,
      params: ISkillParams,
      serviceParams: ISkillServiceParams,
    ): Promise<boolean> => {
      const skillName = 'goToSomeone';
      const requiredParams = ['userName'];
      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 defaultParams = {
        keepFollowing: true,
        distance: 3,
      };
    
      return goToPerson(bot, {
        name: params.userName,
        distance: params.distance ?? defaultParams.distance,
        keepFollowing:
          params.keepFollowing ?? defaultParams.keepFollowing,
        signal: serviceParams.signal,
      });
    };
  • Input schema definition for the 'goToSomeone' tool, specifying parameters, their types, descriptions, and required fields. Used to create the SkillDefinition.inputSchema.
    goToSomeone: {
        description: "Navigate to another player",
        params: {
            userName: { type: "string", description: "Username of the player to go to" },
            distance: { type: "number", description: "Distance to maintain from the player (default: 3)" },
            keepFollowing: { type: "boolean", description: "Continue following the player (default: false)" }
        },
        required: ["userName"]
    },
  • Registration metadata for the 'goToSomeone' tool in SKILL_METADATA, which is used by loadSkills() to register the skill with its schema and dynamic executor.
    goToSomeone: {
        description: "Navigate to another player",
        params: {
            userName: { type: "string", description: "Username of the player to go to" },
            distance: { type: "number", description: "Distance to maintain from the player (default: 3)" },
            keepFollowing: { type: "boolean", description: "Continue following the player (default: false)" }
        },
        required: ["userName"]
    },
  • Core helper function implementing the pathfinding logic to go to a player by name, using mineflayer-pathfinder's GoalFollow, with features like distance monitoring, following, teleport fallback, and observation emissions.
    export const goToPerson = async (
      bot: Bot,
      params: IGoToPersonParams,
    ): Promise<boolean> => {
      const { distance: distanceParam, name, keepFollowing, signal } = params;
      const distance = Math.max(1, distanceParam); // Ensure distance is at least 1
    
      const TELEPORT_TOLERANCE_THRESHOLD = 30; // in blocks, if the entity is this far away, try to teleport to them
      const EMIT_UPDATE_RATE = 2000; // in milliseconds - 2 seconds, how often to emit a message while following
      const MAX_FOLLOW_TIME = 300000; // in milliseconds - 5 minutes, how long to follow before stopping, this is an emergency time - out
      const PROCESS_UPDATE_FREQUENCY = 50; // how often to check if the bot is still following the entity in milliseconds, ~20 times per second
      const HASNT_MOVED_THRESHOLD = 10000; // in milliseconds - 3 seconds, how long to wait before assuming the entity has stopped moving
    
      const entity = findClosestPlayerByName(bot, { name });
    
      if (!entity) {
        // bot.chat(`Entity ${name} not found.`);
        return bot.emit(
          'alteraBotEndObservation',
          `Mistake: You couldn't find anyone with the name ${name} to go to.`,
        );
        // return;
      }
    
      if (bot.pathfinder.isMoving()) {
        await bot.pathfinder.stop();
      }
    
      await bot.waitForTicks(2); // give time for pathfinder to stop
    
      if (isSignalAborted(signal)) {
        return;
      }
    
      // define a dynamic goal to follow the entity
      const followGoal = new GoalFollow(entity, distance);
      bot.pathfinder.setGoal(followGoal, true); // The second argument true makes the goal dynamic
    
      await bot.waitForTicks(2);
    
      let curDistance = -9999;
    
      let messageCounter = 0;
    
      let followTargetPosition = new Vec3(
        entity.position.x,
        entity.position.y,
        entity.position.z,
      );
    
      let hasntMovedCount = 0;
      // bot.emit('alteraBotTextObservation', `You started following ${ entity.username }`);
      for (let n = 0; n < MAX_FOLLOW_TIME; n += PROCESS_UPDATE_FREQUENCY) {
        if (followTargetPosition.equals(entity.position)) {
          hasntMovedCount += PROCESS_UPDATE_FREQUENCY;
          if (hasntMovedCount > HASNT_MOVED_THRESHOLD) {
            bot.emit('alteraBotTextObservation', `${name} has stopped moving.`);
            break;
          }
        } else {
          // reset hasn't moved count
          followTargetPosition = new Vec3(
            entity.position.x,
            entity.position.y,
            entity.position.z,
          );
          // console.log(`new target position: ${ JSON.stringify(bot.followTargetPosition)}`);
          hasntMovedCount = 0;
        }
    
        if (!isBotFollowing(bot, { entity })) {
          break;
        }
    
        if (isSignalAborted(signal)) {
          break;
        }
    
        curDistance = bot.entity.position.distanceTo(entity.position);
    
        // check to see if we are too far away and cheats are enabled
        if (bot.cheatsAllowed === undefined)
          // if cheats have never been set, set them to true, assume they're enabled
          bot.cheatsAllowed = true;
    
        if (curDistance > TELEPORT_TOLERANCE_THRESHOLD && bot.cheatsAllowed) {
          console.log(
            ` attempting to telport to ${entity.username} because they are too far away.`,
          );
          bot.chat(`/tp ${entity.username}`); // this assumes cheats are enabled
          // check to see if the we got a failure message when teleporting if cheats are not enabled
          await bot.waitForTicks(2); // give time for teleport to complete
          curDistance = bot.entity.position.distanceTo(entity.position);
    
          // check to see if we are still too far away (with a small buffer)
          if (curDistance > TELEPORT_TOLERANCE_THRESHOLD - 2) {
            console.log(
              ` failed to teleport to ${entity.username} because cheats are not enabled.  Turning off cheats.`,
            );
            bot.cheatsAllowed = false;
          }
        }
    
        if (curDistance <= distance && !keepFollowing) {
          return bot.emit(
            'alteraBotEndObservation',
            `You finished going to ${name}.`,
          );
        }
    
        messageCounter += PROCESS_UPDATE_FREQUENCY;
    
        if (keepFollowing && messageCounter >= EMIT_UPDATE_RATE) {
          bot.emit('alteraBotTextObservation', `You are still following ${name}.`);
          messageCounter = 0;
        }
    
        await new Promise((resolve) =>
          setTimeout(resolve, PROCESS_UPDATE_FREQUENCY),
        ); // wait for a little bit
      }
    
      await bot.pathfinder.stop();
      bot.pathfinder.setGoal(null);
    
      bot.waitForTicks(2);
    
      return bot.emit(
        'alteraBotEndObservation',
        `You have stopped following ${name}.`,
      );
    };

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