buy_item
Purchase items from the Habitica shop by providing the item key and optionally specifying quantity.
Instructions
Buy an item from a shop.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| itemKey | Yes | ||
| quantity | No |
Implementation Reference
- index.js:320-331 (schema)Tool definition and input schema for 'buy_item'. Declares itemKey (required string) and quantity (optional number, default 1).
{ name: "buy_item", description: "Buy an item from a shop.", inputSchema: { type: "object", properties: { itemKey: { type: "string" }, quantity: { type: "number", default: 1 }, }, required: ["itemKey"], }, }, - index.js:451-454 (handler)Handler function for 'buy_item'. Calls POST /user/buy/:itemKey with quantity, returns confirmation message with gold remaining.
buy_item: async ({ itemKey, quantity = 1 }) => { const r = (await api("POST", `/user/buy/${encodeURIComponent(itemKey)}`, { quantity })).data; return ok(`Bought ${itemKey} x${quantity}. gp: ${r?.gp ?? "?"}`); }, - index.js:58-367 (registration)The 'tools' array contains all tool definitions including 'buy_item' (line 320-331). This array is returned by the ListToolsRequestHandler (line 480).
const tools = [ { name: "get_user_profile", description: "Get the authenticated user's full profile (stats, prefs, items, party, etc).", inputSchema: { type: "object", properties: {} }, }, { name: "get_stats", description: "Get user stats only (HP, MP, XP, level, gold, class).", inputSchema: { type: "object", properties: {} }, }, { name: "get_tasks", description: "List tasks. Optionally filter by type.", inputSchema: { type: "object", properties: { type: { type: "string", enum: ["habits", "dailys", "todos", "rewards", "completedTodos"], description: "Optional task-type filter.", }, }, }, }, { name: "get_task", description: "Get a single task by id.", inputSchema: { type: "object", properties: { taskId: { type: "string" } }, required: ["taskId"], }, }, { name: "create_task", description: "Create a habit, daily, todo, or reward.", inputSchema: { type: "object", properties: { type: { type: "string", enum: ["habit", "daily", "todo", "reward"] }, text: { type: "string", description: "Title." }, notes: { type: "string", description: "Notes / description." }, difficulty: { type: "number", enum: [0.1, 1, 1.5, 2], description: "0.1=trivial, 1=easy, 1.5=medium, 2=hard.", }, priority: { type: "number", enum: [0.1, 1, 1.5, 2], description: "0.1=low, 1=med, 1.5=high, 2=urgent.", }, date: { type: "string", description: "Due date for todos (ISO)." }, value: { type: "number", description: "Cost in gold for rewards." }, checklist: { type: "array", items: { type: "object", properties: { text: { type: "string" }, completed: { type: "boolean", default: false }, }, required: ["text"], }, }, }, required: ["type", "text"], }, }, { name: "update_task", description: "Update fields on a task (text, notes, difficulty, priority, etc).", inputSchema: { type: "object", properties: { taskId: { type: "string" }, text: { type: "string" }, notes: { type: "string" }, difficulty: { type: "number", enum: [0.1, 1, 1.5, 2] }, priority: { type: "number", enum: [0.1, 1, 1.5, 2] }, date: { type: "string" }, }, required: ["taskId"], }, }, { name: "score_task", description: "Score a task. direction='up' completes a todo/daily or marks a + habit; 'down' is for negative habits.", inputSchema: { type: "object", properties: { taskId: { type: "string" }, direction: { type: "string", enum: ["up", "down"], default: "up" }, }, required: ["taskId"], }, }, { name: "delete_task", description: "Delete a task by id.", inputSchema: { type: "object", properties: { taskId: { type: "string" } }, required: ["taskId"], }, }, // Checklist { name: "get_task_checklist", description: "Get checklist items for a task.", inputSchema: { type: "object", properties: { taskId: { type: "string" } }, required: ["taskId"], }, }, { name: "add_checklist_item", description: "Add a checklist item to a task.", inputSchema: { type: "object", properties: { taskId: { type: "string" }, text: { type: "string" }, }, required: ["taskId", "text"], }, }, { name: "update_checklist_item", description: "Update text/completed on a checklist item.", inputSchema: { type: "object", properties: { taskId: { type: "string" }, itemId: { type: "string" }, text: { type: "string" }, completed: { type: "boolean" }, }, required: ["taskId", "itemId"], }, }, { name: "score_checklist_item", description: "Toggle a checklist item complete/incomplete.", inputSchema: { type: "object", properties: { taskId: { type: "string" }, itemId: { type: "string" }, }, required: ["taskId", "itemId"], }, }, { name: "delete_checklist_item", description: "Delete a checklist item.", inputSchema: { type: "object", properties: { taskId: { type: "string" }, itemId: { type: "string" }, }, required: ["taskId", "itemId"], }, }, // Tags { name: "get_tags", description: "Get all tags.", inputSchema: { type: "object", properties: {} }, }, { name: "create_tag", description: "Create a tag.", inputSchema: { type: "object", properties: { name: { type: "string" } }, required: ["name"], }, }, // Inventory / pets / mounts / equip { name: "get_inventory", description: "Get full inventory (items, eggs, food, hatching potions, special).", inputSchema: { type: "object", properties: {} }, }, { name: "get_pets", description: "Get owned pets map.", inputSchema: { type: "object", properties: {} }, }, { name: "get_mounts", description: "Get owned mounts map.", inputSchema: { type: "object", properties: {} }, }, { name: "feed_pet", description: "Feed a pet a piece of food.", inputSchema: { type: "object", properties: { pet: { type: "string", description: "Pet key, e.g. Wolf-Base." }, food: { type: "string", description: "Food key, e.g. Meat." }, }, required: ["pet", "food"], }, }, { name: "hatch_pet", description: "Hatch a pet from an egg + hatching potion.", inputSchema: { type: "object", properties: { egg: { type: "string" }, hatchingPotion: { type: "string" }, }, required: ["egg", "hatchingPotion"], }, }, { name: "equip_item", description: "Equip a pet, mount, costume piece, or battle gear.", inputSchema: { type: "object", properties: { type: { type: "string", enum: ["pet", "mount", "costume", "equipped"] }, key: { type: "string" }, }, required: ["type", "key"], }, }, // Rewards / shop / spells { name: "buy_reward", description: "Buy a custom reward by key.", inputSchema: { type: "object", properties: { key: { type: "string" } }, required: ["key"], }, }, { name: "get_shop", description: "Get items in a shop (default: market).", inputSchema: { type: "object", properties: { shopType: { type: "string", enum: ["market", "questShop", "timeTravelersShop", "seasonalShop"], default: "market", }, }, }, }, { name: "buy_item", description: "Buy an item from a shop.", inputSchema: { type: "object", properties: { itemKey: { type: "string" }, quantity: { type: "number", default: 1 }, }, required: ["itemKey"], }, }, { name: "cast_spell", description: "Cast a class spell, optionally on a target task or party member.", inputSchema: { type: "object", properties: { spellId: { type: "string" }, targetId: { type: "string" }, }, required: ["spellId"], }, }, // Notifications { name: "get_notifications", description: "Get unread notifications.", inputSchema: { type: "object", properties: {} }, }, { name: "read_notification", description: "Mark a notification as read.", inputSchema: { type: "object", properties: { notificationId: { type: "string" } }, required: ["notificationId"], }, }, // Cron { name: "run_cron", description: "Run the daily cron (advance day, apply damage from missed dailies). Normally auto-runs on first action of the day.", inputSchema: { type: "object", properties: {} }, }, ]; - index.js:371-471 (registration)The 'handlers' object maps tool names to async handler functions. buy_item is at line 451-454.
const handlers = { get_user_profile: async () => json((await api("GET", "/user")).data), get_stats: async () => json((await api("GET", "/user")).data?.stats), get_tasks: async ({ type } = {}) => { const path = type ? `/tasks/user?type=${encodeURIComponent(type)}` : "/tasks/user"; return json((await api("GET", path)).data); }, get_task: async ({ taskId }) => json((await api("GET", `/tasks/${taskId}`)).data), create_task: async (args) => { const t = (await api("POST", "/tasks/user", args)).data; return ok(`Created ${t.type}: "${t.text}" (id: ${t.id})`); }, update_task: async ({ taskId, ...updates }) => { const t = (await api("PUT", `/tasks/${taskId}`, updates)).data; return ok(`Updated task: "${t.text}"`); }, score_task: async ({ taskId, direction = "up" }) => { const r = (await api("POST", `/tasks/${taskId}/score/${direction}`)).data; const parts = [`Scored task ${direction}.`]; if (r?.exp != null) parts.push(`exp Δ ${r.delta?.toFixed?.(2) ?? ""} → ${r.exp}`); if (r?.gp != null) parts.push(`gp ${r.gp.toFixed(2)}`); if (r?.lvl != null) parts.push(`level ${r.lvl}`); return ok(parts.join(" · ")); }, delete_task: async ({ taskId }) => { await api("DELETE", `/tasks/${taskId}`); return ok(`Deleted task ${taskId}.`); }, get_task_checklist: async ({ taskId }) => { const t = (await api("GET", `/tasks/${taskId}`)).data; const list = t?.checklist ?? []; if (list.length === 0) return ok(`Task "${t.text}" has no checklist items.`); return ok( `Task: ${t.text}\n` + list.map((i) => `${i.completed ? "✓" : "○"} ${i.text} (${i.id})`).join("\n"), ); }, add_checklist_item: async ({ taskId, text }) => { await api("POST", `/tasks/${taskId}/checklist`, { text }); return ok(`Added checklist item to ${taskId}: "${text}"`); }, update_checklist_item: async ({ taskId, itemId, ...updates }) => { await api("PUT", `/tasks/${taskId}/checklist/${itemId}`, updates); return ok(`Updated checklist item ${itemId}.`); }, score_checklist_item: async ({ taskId, itemId }) => { await api("POST", `/tasks/${taskId}/checklist/${itemId}/score`); return ok(`Toggled checklist item ${itemId}.`); }, delete_checklist_item: async ({ taskId, itemId }) => { await api("DELETE", `/tasks/${taskId}/checklist/${itemId}`); return ok(`Deleted checklist item ${itemId}.`); }, get_tags: async () => json((await api("GET", "/tags")).data), create_tag: async ({ name }) => { const t = (await api("POST", "/tags", { name })).data; return ok(`Created tag "${t.name}" (id: ${t.id})`); }, get_inventory: async () => json((await api("GET", "/user")).data?.items), get_pets: async () => json((await api("GET", "/user")).data?.items?.pets), get_mounts: async () => json((await api("GET", "/user")).data?.items?.mounts), feed_pet: async ({ pet, food }) => { await api("POST", `/user/feed/${encodeURIComponent(pet)}/${encodeURIComponent(food)}`); return ok(`Fed ${food} to ${pet}.`); }, hatch_pet: async ({ egg, hatchingPotion }) => { await api("POST", `/user/hatch/${encodeURIComponent(egg)}/${encodeURIComponent(hatchingPotion)}`); return ok(`Hatched ${egg}-${hatchingPotion}.`); }, equip_item: async ({ type, key }) => { await api("POST", `/user/equip/${type}/${encodeURIComponent(key)}`); return ok(`Equipped ${type}: ${key}`); }, buy_reward: async ({ key }) => { const r = (await api("POST", `/user/buy/${encodeURIComponent(key)}`)).data; return ok(`Bought reward "${key}". gp: ${r?.gp ?? "?"}`); }, get_shop: async ({ shopType = "market" } = {}) => json((await api("GET", `/shops/${shopType}`)).data), buy_item: async ({ itemKey, quantity = 1 }) => { const r = (await api("POST", `/user/buy/${encodeURIComponent(itemKey)}`, { quantity })).data; return ok(`Bought ${itemKey} x${quantity}. gp: ${r?.gp ?? "?"}`); }, cast_spell: async ({ spellId, targetId }) => { const path = targetId ? `/user/class/cast/${spellId}?targetId=${encodeURIComponent(targetId)}` : `/user/class/cast/${spellId}`; await api("POST", path); return ok(`Cast ${spellId}${targetId ? ` on ${targetId}` : ""}.`); }, get_notifications: async () => json((await api("GET", "/notifications")).data), read_notification: async ({ notificationId }) => { await api("POST", `/notifications/${notificationId}/read`); return ok(`Marked notification ${notificationId} read.`); }, run_cron: async () => { await api("POST", "/cron"); return ok("Cron run."); }, }; - index.js:482-492 (registration)The CallToolRequestHandler looks up the tool name in the handlers object and invokes the matching function.
server.setRequestHandler(CallToolRequestSchema, async (req) => { const { name, arguments: args = {} } = req.params; const fn = handlers[name]; if (!fn) throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`); try { return await fn(args); } catch (err) { if (err instanceof McpError) throw err; throw new McpError(ErrorCode.InternalError, err?.message ?? String(err)); } });