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