listTrades
Retrieve available trades from villagers within a specified range using natural language commands for efficient inventory management in Minecraft via MCP Minecraft Remote.
Instructions
List available trades from a nearby villager
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| range | No | Range to search for villagers | |
| villagerName | No | Name or identifier of the villager (optional) |
Implementation Reference
- src/tools/trading.ts:26-125 (handler)The handler function for the listTrades tool. Finds nearby villagers matching the optional name within the given range, selects the closest, opens the trading window, extracts non-null slots as trades (name, displayName, count), formats a numbered list response, handles errors and window closing.async ({ villagerName, range }) => { if (!botState.isConnected || !botState.bot) { return createNotConnectedResponse() } try { // Find villagers in range const villagers = Object.values(botState.bot.entities).filter( (entity) => { if (!entity || !entity.position || !botState.bot) return false const distance = entity.position.distanceTo( botState.bot.entity.position ) return ( distance <= range && String(entity.type) === 'villager' && (!villagerName || (entity.name && entity.name .toLowerCase() .includes(villagerName.toLowerCase()))) ) } ) if (villagers.length === 0) { return createSuccessResponse( villagerName ? `No villager named "${villagerName}" found nearby.` : 'No villagers found nearby.' ) } // Choose the closest villager if multiple are found const villager = villagers.reduce((closest, current) => { if (!closest.position || !current.position || !botState.bot) return current const distClosest = closest.position.distanceTo( botState.bot.entity.position ) const distCurrent = current.position.distanceTo( botState.bot.entity.position ) return distCurrent < distClosest ? current : closest }) // We need to use the real Villager class // First step is to use openVillager method const villagerEntity = await botState.bot.openVillager(villager as any) await botState.bot.trade(villagerEntity, 1, 1) // Just to open the window, numbers don't matter // Check if window is open before accessing properties if (!botState.bot.currentWindow) { return createSuccessResponse( `Could not open trading window with villager.` ) } const trades = botState.bot.currentWindow.slots .filter((item) => item !== null && item !== undefined) .map((item) => { if (!item) return null // Try to extract trade details return { name: item.name, displayName: item.displayName || item.name, count: item.count || 1, // Add more properties as needed } }) .filter((trade) => trade !== null) // Close the trading window if open if (botState.bot.currentWindow) { await botState.bot.closeWindow(botState.bot.currentWindow) } if (trades.length === 0) { return createSuccessResponse( `Villager found, but no trades are available.` ) } // Format the response let response = `Available trades from villager ${ villager.name || 'Unknown' } (${villager.position .distanceTo(botState.bot.entity.position) .toFixed(1)} blocks away):\n\n` trades.forEach((trade, index) => { response += `${index + 1}. ${trade.displayName} (x${trade.count})\n` }) return createSuccessResponse(response) } catch (error) { return createErrorResponse(error) } }
- src/tools/trading.ts:15-25 (schema)Zod input schema for listTrades: villagerName (optional string, villager identifier), range (optional number default 4, search range).{ villagerName: z .string() .optional() .describe('Name or identifier of the villager (optional)'), range: z .number() .optional() .default(4) .describe('Range to search for villagers'), },
- src/tools/trading.ts:13-126 (registration)server.tool registration for 'listTrades', including description 'List available trades from a nearby villager', schema, and handler function.'listTrades', 'List available trades from a nearby villager', { villagerName: z .string() .optional() .describe('Name or identifier of the villager (optional)'), range: z .number() .optional() .default(4) .describe('Range to search for villagers'), }, async ({ villagerName, range }) => { if (!botState.isConnected || !botState.bot) { return createNotConnectedResponse() } try { // Find villagers in range const villagers = Object.values(botState.bot.entities).filter( (entity) => { if (!entity || !entity.position || !botState.bot) return false const distance = entity.position.distanceTo( botState.bot.entity.position ) return ( distance <= range && String(entity.type) === 'villager' && (!villagerName || (entity.name && entity.name .toLowerCase() .includes(villagerName.toLowerCase()))) ) } ) if (villagers.length === 0) { return createSuccessResponse( villagerName ? `No villager named "${villagerName}" found nearby.` : 'No villagers found nearby.' ) } // Choose the closest villager if multiple are found const villager = villagers.reduce((closest, current) => { if (!closest.position || !current.position || !botState.bot) return current const distClosest = closest.position.distanceTo( botState.bot.entity.position ) const distCurrent = current.position.distanceTo( botState.bot.entity.position ) return distCurrent < distClosest ? current : closest }) // We need to use the real Villager class // First step is to use openVillager method const villagerEntity = await botState.bot.openVillager(villager as any) await botState.bot.trade(villagerEntity, 1, 1) // Just to open the window, numbers don't matter // Check if window is open before accessing properties if (!botState.bot.currentWindow) { return createSuccessResponse( `Could not open trading window with villager.` ) } const trades = botState.bot.currentWindow.slots .filter((item) => item !== null && item !== undefined) .map((item) => { if (!item) return null // Try to extract trade details return { name: item.name, displayName: item.displayName || item.name, count: item.count || 1, // Add more properties as needed } }) .filter((trade) => trade !== null) // Close the trading window if open if (botState.bot.currentWindow) { await botState.bot.closeWindow(botState.bot.currentWindow) } if (trades.length === 0) { return createSuccessResponse( `Villager found, but no trades are available.` ) } // Format the response let response = `Available trades from villager ${ villager.name || 'Unknown' } (${villager.position .distanceTo(botState.bot.entity.position) .toFixed(1)} blocks away):\n\n` trades.forEach((trade, index) => { response += `${index + 1}. ${trade.displayName} (x${trade.count})\n` }) return createSuccessResponse(response) } catch (error) { return createErrorResponse(error) } } )
- src/tools/index.ts:40-40 (registration)Invocation of registerTradingTools() within registerAllTools(), which registers the listTrades tool.registerTradingTools()
- src/index.ts:7-7 (registration)Invocation of registerAllTools() which ultimately registers the listTrades tool.registerAllTools()