Previous wiki_recipe only returned the page thumbnail, so "send me the
recipe image" delivered a picture of the item, not the recipe itself.
minecraft.wiki renders recipes as live HTML grids, not standalone PNGs,
so we now generate the image ourselves.
mcp/lib/minecraft-wiki-tools.ts:
- parseCraftingGrid(html): pulls the 3×3 input grid + result item URL
from <span class="mcui mcui-Crafting_Table">. Each <span class="invslot">
is either empty (chunk starts with </span>) or has an <img src="/images/
Invicon_X.png?h">. Reading-order chunks → grid; first non-null after
the 9th input slot → result.
- composeRecipePng(grid, result): fetches each unique sprite, resizes
to 64×64 via sharp (nearest-neighbour to keep pixel art crisp),
composites onto a #8b8b8b inventory-style background with #6f6f6f
slot squares + dark borders, places an SVG-rendered "→" arrow,
then the result cell next to it. PNG buffer returned.
- New tool wiki_recipe_image(title, chat, caption?) that runs the
pipeline end-to-end and uploads via tg.sendPhotoBytes — one tool
call, image already in the chat when it returns.
mcp/lib/types.ts:
- TgClient gains sendPhotoBytes({ chat_id, bytes, filename?, caption?,
parse_mode?, reply_to_message_id? }). Multipart/form-data POST to
sendPhoto, since Telegram's URL-mode can only fetch public URLs and
the composited PNG only lives in memory. 30s timeout (vs the 20s on
the JSON call) because uploads are bigger.
mcp/package.json + bot/package.json: add sharp ^0.33.5. mcp/ pulls it
in too so /mc/mcp/lib resolves it at the bot's runtime (the bot's
node_modules is at /app while the lib files live at /mc/mcp/lib).
Persona prompt: wiki_recipe_image is now the FIRST call for any
"recipe" / "send me the recipe image" request. Single tool turn ends
with the photo already in the chat. wiki_recipe stays as a fallback
when the page has no 3×3 crafting widget (smelting / brewing / smithing
use different mcui classes).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Drops two new capabilities on top of the existing Telegram bot + Minecraft
stack, both built around a shared toolkit so there's one source of truth
for the actions either side can take.
mcp/ — a Bun-native MCP server exposing 38 tools to MCP clients (Claude
Code, etc.): server lifecycle, rcon, backup, player/db CRUD, plus 23
Telegram Bot API methods (messaging, reactions, polls, dice, photos,
stickers, pins, forum topics, chat config). Runs over stdio.
mcp/lib/telegram-tools.ts — the Telegram tool catalog as Zod-typed
handlers. Imported by both mcp/server.ts (registers each as an MCP tool)
and bot/bot.ts (exposes each as a Gemini function declaration), so adding
a tool in one place lights it up everywhere.
bot/bot.ts — replaces the silent-on-unknown-text behaviour with Redstone,
an in-bot persona driven by gemini-2.5-flash-lite with native function
calling. In DMs it always responds; in groups only when @-mentioned or
replied to. The tool-use loop (max 4 rounds) lets it decide to send a
poll, react with an emoji, roll dice, etc. via the shared handlers rather
than just text. Thinking budget zeroed and system prompt locked down so
the model doesn't leak its reasoning into replies.
docker-compose.yml — adds google_key as a docker secret and passes
GEMINI_API_KEY_FILE + GEMINI_MODEL to the bot.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>