Skip to main content
Glama

move_party

Move your RPG party between connected locations, check travel status, or review movement history within the ChatRPG game environment.

Instructions

Move the party between connected locations. Operations: move (travel to connected location), status (show current location and exits), history (show travel history). Validates connections, handles locked/hidden passages, one-way paths, and tracks travel history.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
operationNo
toLocationIdNo
toLocationNameNo
forceNo
unlockedNo
discoveredNo
showHiddenNo

Implementation Reference

  • Core handler function for move_party tool. Parses input with Zod schema, routes to operation-specific handlers (handleMove for movement logic, handlePartyStatus for current location/exits, handlePartyHistory for travel log), handles errors, and returns formatted MCP CallToolResult with ASCII art output.
    export async function moveParty(input: unknown): Promise<{ content: { type: 'text'; text: string }[] }> {
      try {
        const parsed = movePartySchema.parse(input);
    
        let result: string;
    
        // Determine operation type
        const op = (parsed as any).operation || 'move';
    
        switch (op) {
          case 'move':
            result = handleMove(parsed as z.infer<typeof moveOperationSchema>);
            break;
          case 'status':
            result = handlePartyStatus(parsed as z.infer<typeof statusOperationSchema>);
            break;
          case 'history':
            result = handlePartyHistory();
            break;
          default:
            result = createBox('ERROR', ['Unknown operation'], DISPLAY_WIDTH);
        }
    
        return { content: [{ type: 'text' as const, text: result }] };
      } catch (error) {
        const lines: string[] = [];
    
        if (error instanceof z.ZodError) {
          for (const issue of error.issues) {
            lines.push(`${issue.path.join('.')}: ${issue.message}`);
          }
        } else if (error instanceof Error) {
          lines.push(error.message);
        } else {
          lines.push('An unknown error occurred');
        }
    
        return { content: [{ type: 'text' as const, text: createBox('ERROR', lines, DISPLAY_WIDTH) }] };
      }
    }
  • Zod input schema for move_party tool. Discriminated by operation: 'move' (toLocationId/name, force/unlock/discover flags), 'status' (show hidden exits), 'history' (travel log). Supports fuzzy enums.
    const MovePartyOperationSchema = fuzzyEnum(['move', 'status', 'history'] as const);
    
    /** Move operation schema */
    const moveOperationSchema = z.object({
      operation: z.literal('move').optional().default('move'),
      toLocationId: z.string().optional(),
      toLocationName: z.string().optional(),
      force: z.boolean().optional().default(false),
      unlocked: z.boolean().optional().default(false),
      discovered: z.boolean().optional().default(false),
    });
    
    /** Status operation schema */
    const statusOperationSchema = z.object({
      operation: z.literal('status'),
      showHidden: z.boolean().optional().default(false),
    });
    
    /** History operation schema */
    const historyOperationSchema = z.object({
      operation: z.literal('history'),
    });
    
    /** Combined schema for move_party */
    export const movePartySchema = z.union([
      moveOperationSchema,
      statusOperationSchema,
      historyOperationSchema,
    ]);
  • Tool registration entry in central registry. Converts Zod schema to JSON Schema for MCP, provides thin wrapper handler that calls the actual moveParty implementation, includes tool description.
    move_party: {
      name: 'move_party',
      description: 'Move the party between connected locations. Operations: move (travel to connected location), status (show current location and exits), history (show travel history). Validates connections, handles locked/hidden passages, one-way paths, and tracks travel history.',
      inputSchema: toJsonSchema(movePartySchema),
      handler: async (args) => {
        try {
          const result = await moveParty(args);
          return result;
        } catch (err) {
          if (err instanceof z.ZodError) {
            const messages = err.errors.map(e => `${e.path.join('.')}: ${e.message}`).join(', ');
            return error(`Validation failed: ${messages}`);
          }
          const message = err instanceof Error ? err.message : String(err);
          return error(message);
        }
      },
    },
  • Primary helper implementing 'move' operation logic: finds target, validates edge traversal (one-way, locked DC, hidden discovery), updates party location state and history, renders arrival scene with exits.
    function handleMove(input: z.infer<typeof moveOperationSchema>): string {
      // Validate input
      if (!input.toLocationId && !input.toLocationName) {
        return createBox('ERROR', ['Either toLocationId or toLocationName is required'], DISPLAY_WIDTH);
      }
    
      // Find target location
      const target = findLocation(input.toLocationId || input.toLocationName || '');
      if (!target) {
        return createBox('ERROR', [`Location not found: ${input.toLocationId || input.toLocationName}`], DISPLAY_WIDTH);
      }
    
      // Check if already at target
      if (partyState.currentLocationId === target.id) {
        return createBox('ALREADY HERE', [`The party is already at ${target.name}.`], DISPLAY_WIDTH);
      }
    
      // Get current location
      const current = partyState.currentLocationId ? locationStore.get(partyState.currentLocationId) : null;
    
      // If no current location or force, just place the party
      if (!current || input.force) {
        partyState.currentLocationId = target.id;
        partyState.history.push({ locationId: target.id, timestamp: Date.now() });
    
        const lines: string[] = [];
        lines.push(`Location: ${target.name}`);
        if (target.locationType) {
          lines.push(`Type: ${target.locationType}`);
        }
        if (target.lighting) {
          lines.push(`Lighting: ${target.lighting}`);
        }
        if (target.description) {
          lines.push('');
          lines.push(target.description);
        }
    
        // Show exits
        const exits = getExitsForLocation(target.id, false);
        if (exits.length > 0) {
          lines.push('');
          lines.push('Exits:');
          for (const exit of exits) {
            lines.push(`  ${ARROW} ${exit.locationName} (${exit.connectionType})`);
          }
        }
    
        return createBox('PARTY ARRIVED', lines, DISPLAY_WIDTH);
      }
    
      // Check if connected
      const edge = getEdgeBetween(current.id, target.id);
      if (!edge) {
        return createBox('CANNOT TRAVEL', [`${target.name} is not connected to ${current.name}.`], DISPLAY_WIDTH);
      }
    
      // Check one-way
      if (!isEdgeTraversable(edge, current.id)) {
        return createBox('ONE-WAY PATH', [`Cannot travel back through this one-way passage.`], DISPLAY_WIDTH);
      }
    
      // Check locked
      if (edge.locked && !input.unlocked) {
        const lines: string[] = [];
        lines.push(`The ${edge.connectionType} to ${target.name} is locked.`);
        if (edge.lockDC) {
          lines.push(`Lock DC: ${edge.lockDC}`);
        }
        lines.push('');
        lines.push('Use unlocked: true to bypass the lock.');
        return createBox('LOCKED', lines, DISPLAY_WIDTH);
      }
    
      // Check hidden
      if (edge.hidden && !input.discovered && !partyState.discoveredHiddenEdges.has(edge.id)) {
        return createBox('CANNOT TRAVEL', [`No visible path to ${target.name} from here.`], DISPLAY_WIDTH);
      }
    
      // Mark hidden edge as discovered if using discovered flag
      if (edge.hidden && input.discovered) {
        partyState.discoveredHiddenEdges.add(edge.id);
      }
    
      // Perform the move
      const previousLocation = current.name;
      partyState.currentLocationId = target.id;
      partyState.history.push({ locationId: target.id, timestamp: Date.now() });
    
      // Build output
      const lines: string[] = [];
      lines.push(`From: ${previousLocation}`);
      lines.push(`To: ${target.name}`);
      lines.push(`Via: ${edge.connectionType}`);
    
      if (target.locationType) {
        lines.push(`Type: ${target.locationType}`);
      }
      if (target.lighting) {
        lines.push(`Lighting: ${target.lighting}`);
      }
      if (target.description) {
        lines.push('');
        lines.push(target.description);
      }
    
      // Show exits
      const exits = getExitsForLocation(target.id, false);
      if (exits.length > 0) {
        lines.push('');
        lines.push('Exits:');
        for (const exit of exits) {
          lines.push(`  ${ARROW} ${exit.locationName} (${exit.connectionType})`);
        }
      }
    
      return createBox('PARTY MOVED', lines, DISPLAY_WIDTH);
    }
  • Global in-memory state tracking party's current location ID, travel history stack, and discovered hidden connections. Essential for movement validation and status reporting.
    let partyState: PartyLocationState = {
      currentLocationId: null,
      history: [],
      discoveredHiddenEdges: new Set(),
    };

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/Mnehmos/ChatRPG'

If you have feedback or need assistance with the MCP directory API, please join our Discord server