manage_aura
Create, track, and apply D&D 5e aura effects like Spirit Guardians to targets within range, handling damage, healing, conditions, and saving throws.
Instructions
Manage D&D 5e aura effects (Spirit Guardians, Aura of Protection, etc.). Operations: create (new aura), list (active auras), process (apply effects to targets in range), remove (end aura). Supports damage, healing, conditions, and saving throws.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| operation | No | ||
| ownerId | No | ||
| spellName | No | ||
| radius | No | ||
| duration | No | ||
| damage | No | ||
| damageType | No | ||
| healing | No | ||
| effect | No | ||
| condition | No | ||
| saveDC | No | ||
| saveAbility | No | ||
| halfOnSave | No | ||
| affectsEnemies | No | ||
| affectsAllies | No | ||
| auraId | No | ||
| reason | No | ||
| targets | No | ||
| decrementDuration | No | ||
| manualDamageRolls | No | ||
| manualHealingRolls | No | ||
| manualSaveRolls | No |
Implementation Reference
- src/modules/magic.ts:633-647 (handler)Main handler function for the manage_aura tool. Dispatches to operation-specific handlers: create, list, remove, process.export function manageAura(input: ManageAuraInput): string { switch (input.operation) { case 'create': return handleCreateAura(input); case 'list': return handleListAuras(input); case 'remove': return handleRemoveAura(input); case 'process': return handleProcessAura(input); default: const _exhaustive: never = input; throw new Error(`Unknown operation: ${(_exhaustive as { operation: string }).operation}`); } }
- src/modules/magic.ts:592-599 (schema)Zod schema for manage_aura input validation. Union of schemas for create, list, remove, process operations.export const manageAuraSchema = z.union([ createAuraSchema, listAuraSchema, removeAuraSchema, processAuraSchema, ]); export type ManageAuraInput = z.infer<typeof manageAuraSchema>;
- src/registry.ts:980-998 (registration)Tool registration in the MCP registry. Defines name, description, input schema, and handler wrapper that validates args and calls manageAura.manage_aura: { name: 'manage_aura', description: 'Manage D&D 5e aura effects (Spirit Guardians, Aura of Protection, etc.). Operations: create (new aura), list (active auras), process (apply effects to targets in range), remove (end aura). Supports damage, healing, conditions, and saving throws.', inputSchema: toJsonSchema(manageAuraSchema), handler: async (args) => { try { const validated = manageAuraSchema.parse(args); const result = manageAura(validated); return success(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); } }, },
- src/modules/magic.ts:653-724 (helper)Helper: Creates a new aura with generated ID and stores it in auraStore. Formats ASCII output with aura details.function handleCreateAura(input: z.infer<typeof createAuraSchema>): string { const id = `aura-${randomUUID().slice(0, 8)}`; const content: string[] = []; const aura: ExtendedAuraState = { id, ownerId: input.ownerId, spellName: input.spellName, radius: input.radius, duration: input.duration, damage: input.damage, damageType: input.damageType, healing: input.healing, effect: input.effect, condition: input.condition, saveDC: input.saveDC, saveAbility: input.saveAbility, halfOnSave: input.halfOnSave, affectsEnemies: input.affectsEnemies, affectsAllies: input.affectsAllies, }; auraStore.set(id, aura); content.push(centerText('AURA CREATED', DISPLAY_WIDTH)); content.push(''); content.push(`ID: ${id}`); content.push(`Spell: ${input.spellName}`); content.push(`Owner: ${input.ownerId}`); content.push(`Radius: ${input.radius} ft`); if (input.duration !== undefined) { content.push(`Duration: ${input.duration} rounds`); } content.push(''); content.push(BOX.LIGHT.H.repeat(DISPLAY_WIDTH)); if (input.damage) { content.push(''); content.push(`Damage: ${input.damage} ${input.damageType || ''}`); if (input.saveDC && input.saveAbility) { content.push(`Save: DC ${input.saveDC} ${input.saveAbility.toUpperCase()}`); if (input.halfOnSave) { content.push('Half damage on save'); } } } if (input.healing) { content.push(''); content.push(`Healing: ${input.healing}`); } if (input.condition) { content.push(''); content.push(`Applies: ${input.condition}`); } if (input.affectsEnemies !== undefined || input.affectsAllies !== undefined) { content.push(''); const targets: string[] = []; if (input.affectsEnemies) targets.push('enemies'); if (input.affectsAllies) targets.push('allies'); if (targets.length === 0) { targets.push(input.affectsEnemies === false ? 'allies only' : 'all'); } content.push(`Affects: ${targets.join(', ')}`); } return createBox('AURA CREATED', content); }
- src/modules/magic.ts:536-647 (helper)In-memory storage for auras, used by manage_aura operations.const auraStore = new Map<string, ExtendedAuraState>(); // ============================================================ // AURA SCHEMAS // ============================================================ const auraTargetSchema = z.object({ targetId: z.string(), distance: z.number(), saveModifier: z.number().optional(), }); const manualSaveRollSchema = z.object({ targetId: z.string(), roll: z.number().min(1).max(20), }); const createAuraSchema = z.object({ operation: z.literal('create'), ownerId: z.string(), spellName: z.string(), radius: z.number().min(1), duration: z.number().optional(), damage: z.string().optional(), damageType: DamageTypeSchema.optional(), healing: z.string().optional(), effect: z.string().optional(), condition: ConditionSchema.optional(), saveDC: z.number().optional(), saveAbility: AbilitySchema.optional(), halfOnSave: z.boolean().optional(), affectsEnemies: z.boolean().optional(), affectsAllies: z.boolean().optional(), }); const listAuraSchema = z.object({ operation: z.literal('list'), ownerId: z.string().optional(), }); const removeAuraSchema = z.object({ operation: z.literal('remove'), auraId: z.string(), reason: z.string().optional(), }); const processAuraSchema = z.object({ operation: z.literal('process'), auraId: z.string(), targets: z.array(auraTargetSchema), decrementDuration: z.boolean().optional(), manualDamageRolls: z.array(z.number()).optional(), manualHealingRolls: z.array(z.number()).optional(), manualSaveRolls: z.array(manualSaveRollSchema).optional(), }); export const manageAuraSchema = z.union([ createAuraSchema, listAuraSchema, removeAuraSchema, processAuraSchema, ]); export type ManageAuraInput = z.infer<typeof manageAuraSchema>; // ============================================================ // AURA PUBLIC API // ============================================================ /** * Get an aura by ID. */ export function getAura(auraId: string): ExtendedAuraState | undefined { return auraStore.get(auraId); } /** * Get all auras for an owner. */ export function getAurasForOwner(ownerId: string): ExtendedAuraState[] { return Array.from(auraStore.values()).filter(a => a.ownerId === ownerId); } /** * Clear all auras (for testing). */ export function clearAllAuras(): void { auraStore.clear(); } // ============================================================ // AURA HANDLER // ============================================================ /** * Main handler for the manage_aura tool. */ export function manageAura(input: ManageAuraInput): string { switch (input.operation) { case 'create': return handleCreateAura(input); case 'list': return handleListAuras(input); case 'remove': return handleRemoveAura(input); case 'process': return handleProcessAura(input); default: const _exhaustive: never = input; throw new Error(`Unknown operation: ${(_exhaustive as { operation: string }).operation}`); } }