Skip to main content
Glama
leo4life2

Minecraft MCP Server

by leo4life2

runAway

Escape threats in Minecraft by specifying the threat type, name, and run distance. Integrates with the MCP Server to enable AI-controlled character movement for survival scenarios.

Instructions

Run away from a threat

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
runDistanceNoDistance to run away (default: 20)
targetNameNoOptional: Specific name of the threat
targetTypeYesType of threat: 'player', 'mob', or 'animal'

Implementation Reference

  • The core handler function implementing the 'runAway' tool logic. Detects nearby hostile mobs or specified targets, computes a weighted escape vector, and uses pathfinder to move to a safe distance.
    export const runAway = async (
      bot: Bot,
      params: ISkillParams,
      serviceParams: ISkillServiceParams,
    ): Promise<boolean> => {
      const skillName = 'runAway';
      const requiredParams: string[] = [];
      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 = {
        targetType: params.targetType ?? 'mob',
        targetName: params.targetName ?? '',
        runDistance: params.runDistance ?? 10,
        signal: serviceParams.signal,
      };
      let { targetType, targetName, runDistance, signal } = unpackedParams;
      // Define the radius within which you want to detect mobs
      const NEARBY_ENTITY_RADIUS = bot.nearbyEntityRadius;
      const MIN_DISTANCE = 0.01; // Minimum distance to avoid extremely small values
    
      targetName = targetName ?? '';
    
      const targetStr = targetName ? targetName : targetType;
      targetName = targetName.replace(/\s/g, '_'); // Replace spaces in name with _
    
      if (targetType == 'mob') {
        targetType = 'hostile';
      }
    
      // Check if entities are available
      if (!bot.entities) return;
    
      const allEntities = Object.values(bot.entities);
    
      // Filter function to identify mobs within the specified radius
      const isNearbyEntity = (entity: Entity) => {
        return (
          entity.position.distanceTo(bot.entity.position) < NEARBY_ENTITY_RADIUS
        );
      };
    
      // Filter for nearby hostile mobs
      const hostileMobs = allEntities.filter((entity) => {
        const version = parseInt(bot.version.split('.')[1]);
        const NBT_HEALTH =
          version < 10 ? 6 : version < 14 ? 7 : version < 17 ? 8 : 9;
        if (targetName) {
          if (targetType === 'player') {
            const closestPlayer = findClosestPlayerByName(bot, { name: targetName });
            return (
              isNearbyEntity(entity) &&
              entity.username !== bot.entity.username &&
              entity.username == closestPlayer.username
            );
          } else {
            return (
              isNearbyEntity(entity) &&
              entity.name.toLowerCase() === targetName.toLowerCase()
            );
          }
        }
        return (
          isNearbyEntity(entity) &&
          entity.type === targetType &&
          entity.metadata[NBT_HEALTH] &&
          entity.username !== bot.entity.username
        );
      });
    
      // Check if there are no hostile mobs
      if (hostileMobs.length === 0) {
        return bot.emit(
          'alteraBotEndObservation',
          `There are no ${targetType}s to run away from.`,
        );
      }
    
      // Calculate the weighted vector direction to run away
      const runVector = { x: 0, y: 0, z: 0 };
      hostileMobs.forEach((mob) => {
        const vector = {
          x: bot.entity.position.x - mob.position.x,
          y: bot.entity.position.y - mob.position.y,
          z: bot.entity.position.z - mob.position.z,
        };
    
        const distance = Math.sqrt(vector.x ** 2 + vector.y ** 2 + vector.z ** 2);
        const weight = 1 / Math.max(distance, MIN_DISTANCE); // Avoid division by extremely small values
    
        runVector.x += vector.x * weight;
        runVector.y += vector.y * weight;
        runVector.z += vector.z * weight;
      });
    
      // Normalize the resulting vector
      const vectorLength = Math.sqrt(
        runVector.x ** 2 + runVector.y ** 2 + runVector.z ** 2,
      );
      if (vectorLength > 0) {
        runVector.x /= vectorLength;
        runVector.y /= vectorLength;
        runVector.z /= vectorLength;
      }
    
      // Determine the destination position
      const runDestination = new Vec3(
        bot.entity.position.x + runVector.x * runDistance,
        bot.entity.position.y + runVector.y * runDistance,
        bot.entity.position.z + runVector.z * runDistance,
      );
    
      if (bot.pathfinder.isMoving()) await bot.pathfinder.stop();
    
      await bot.waitForTicks(1); // give the pathfinder some time to stop
    
      // Make the bot move to the destination position
      const goal = new GoalXZ(runDestination.x, runDestination.z);
    
      // execute a cancelable move to the destination
      const result = await cancelableMove(bot, { goal, signal });
    
      // check signal 1st
      if (isSignalAborted(signal)) {
        return bot.emit(
          'alteraBotEndObservation',
          `You decided to do something else and stop running away.`,
        );
      }
    
      if (result.error) {
        return bot.emit(
          'alteraBotEndObservation',
          `You couldn't finish running away, but did your best.`,
        );
      }
    
      // Print out the list of all nearby hostile mobs
      // const hostileMobNames = hostileMobs.map(entity => entity.name);
      // const uniqueHostileMobTypes = [...new Set(hostileMobNames)];
      // console.log(`Nearby hostile mobs: ${hostileMobNames.join(', ')}`);
      return bot.emit('alteraBotEndObservation', `You have finished running away!`);
    };
  • Input schema and metadata definition for the 'runAway' tool used during registration, specifying parameters like targetType (required), targetName, and runDistance.
    runAway: {
        description: "Run away from a threat",
        params: {
            targetType: { type: "string", description: "Type of threat: 'player', 'mob', or 'animal'" },
            targetName: { type: "string", description: "Optional: Specific name of the threat" },
            runDistance: { type: "number", description: "Distance to run away (default: 20)" }
        },
        required: ["targetType"]
    },
  • Generic registration logic in loadSkills() that registers all skills including 'runAway' from SKILL_METADATA by creating SkillDefinition objects with schema and dynamic executor.
        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?

With no annotations provided, the description carries full burden but offers minimal behavioral insight. It implies a movement action to evade danger but doesn't disclose critical traits like whether this consumes stamina, has cooldowns, requires line-of-sight to the threat, or what happens if no threat exists. For a safety-related tool with zero annotation coverage, this 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.

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 ('run away') and immediately specifies the purpose ('from a threat'), making it easy for an agent to parse quickly.

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 tool with 3 parameters, no annotations, and no output schema, the description is incomplete. It lacks details on behavioral outcomes (e.g., success/failure conditions, side effects), doesn't explain the relationship between parameters (e.g., if targetName overrides targetType), and provides no error handling context. Given the complexity and safety implications, more guidance 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?

Schema description coverage is 100%, so the schema fully documents all three parameters (runDistance, targetName, targetType) with descriptions and types. The description adds no parameter-specific information beyond what's in the schema, such as clarifying threat prioritization or distance units. Baseline 3 is appropriate when the schema does the heavy lifting.

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 ('run away') and the target ('from a threat'), which is a specific verb+resource combination. However, it doesn't explicitly differentiate from sibling tools like 'swimToLand' or 'goToKnownLocation' which might also be used for evasion, though the threat-specific context provides some distinction.

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 doesn't mention prerequisites (e.g., needing a threat present), exclusions (e.g., not usable indoors), or compare to siblings like 'swimToLand' for water threats or 'goToKnownLocation' for general movement. The agent must infer usage from context 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