Skip to main content
Glama

synthesize_spell

Create custom spell effects in RPG sessions by proposing spell parameters, rolling Arcana checks with DC based on spell level and modifiers, and generating temporary magical outcomes or mishaps.

Instructions

Arcane Synthesis for improvised magic. Caster proposes a custom spell effect; Arcana check DC = 10 + (level × 2) + modifiers. Success creates temporary spell effect, failure may cause mishaps. Supports circumstance modifiers (ley lines, desperation, material components).

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
encounterIdNo
casterIdYes
intentYes
proposedSpellYes
arcanaBonusNo
rollModeNo
manualRollNo
manualRollsNo
nearLeyLineNo
desperationBonusNo
materialComponentValueNo

Implementation Reference

  • Main handler function for the synthesize_spell tool. Performs Arcana check with DC calculation based on spell level and modifiers, resolves roll with advantage/disadvantage support, determines success/mishap/critical outcomes, and returns formatted ASCII output describing the improvised spell creation result.
    export function synthesizeSpell(input: SynthesizeSpellInput): string { const content: string[] = []; const { encounterId, casterId, intent, proposedSpell, arcanaBonus = 0, rollMode = 'normal', manualRoll, manualRolls, nearLeyLine, desperationBonus, materialComponentValue, } = input; // Calculate DC using helper function const { dc, modifiers: dcModifiers } = calculateSynthesisDC( proposedSpell.level, nearLeyLine, materialComponentValue ); // Build header content.push(centerText('ARCANE SYNTHESIS', DISPLAY_WIDTH)); content.push(''); content.push(`Caster: ${casterId}`); if (encounterId) { content.push(`Encounter: ${encounterId}`); } content.push(''); content.push(`Intent: "${intent}"`); content.push(''); content.push(BOX.LIGHT.H.repeat(DISPLAY_WIDTH)); content.push(''); // Show proposed spell content.push(centerText('PROPOSED SPELL', DISPLAY_WIDTH)); content.push(''); content.push(`Name: ${proposedSpell.name}`); content.push(`Level: ${proposedSpell.level}`); content.push(`School: ${proposedSpell.school}`); content.push(`Range: ${proposedSpell.range} ft`); // Effect details content.push(''); content.push(`Effect Type: ${proposedSpell.effect.type}`); if (proposedSpell.effect.damage) { content.push(`Damage: ${proposedSpell.effect.damage} ${proposedSpell.effect.damageType || ''}`); } if (proposedSpell.effect.healing) { content.push(`Healing: ${proposedSpell.effect.healing}`); } if (proposedSpell.effect.condition) { content.push(`Condition: ${proposedSpell.effect.condition}`); } // Area of effect if (proposedSpell.area) { content.push(`Area: ${proposedSpell.area.size} ft ${proposedSpell.area.shape}`); } // Saving throw if (proposedSpell.savingThrow) { content.push(`Save: DC ${proposedSpell.savingThrow.dc} ${proposedSpell.savingThrow.ability.toUpperCase()}`); } // Concentration and duration if (proposedSpell.concentration) { content.push(`Concentration: Yes`); } if (proposedSpell.duration) { content.push(`Duration: ${proposedSpell.duration}`); } content.push(''); content.push(BOX.LIGHT.H.repeat(DISPLAY_WIDTH)); content.push(''); // Show DC calculation content.push(centerText('ARCANA CHECK', DISPLAY_WIDTH)); content.push(''); content.push(`Base DC: 10 + (${proposedSpell.level} × 2) = ${10 + proposedSpell.level * 2}`); if (dcModifiers.length > 0) { content.push(`Modifiers: ${dcModifiers.join(', ')}`); } content.push(`Final DC: DC ${dc}`); content.push(''); // Show circumstance bonuses if (nearLeyLine) { content.push('Near ley line: DC reduced'); } if (desperationBonus) { content.push(`Desperation: +${DESPERATION_ROLL_BONUS} to roll (mishap on failure)`); } if (materialComponentValue !== undefined) { content.push(`Material components: ${materialComponentValue}gp`); } // Roll the check const { finalRoll, rollDisplay } = resolveArcanaRoll(rollMode, manualRoll, manualRolls); // Apply desperation bonus to roll let rollBonus = arcanaBonus; if (desperationBonus) { rollBonus += DESPERATION_ROLL_BONUS; } const total = finalRoll + rollBonus; const isNat1 = finalRoll === 1; const isNat20 = finalRoll === 20; content.push(''); content.push(`Roll: ${rollDisplay}`); if (rollBonus !== 0) { content.push(`Modifier: ${formatModifier(rollBonus)}`); content.push(`Total: ${finalRoll} ${formatModifier(rollBonus)} = ${total}`); } else { content.push(`Total: ${total}`); } content.push(''); content.push(BOX.LIGHT.H.repeat(DISPLAY_WIDTH)); content.push(''); // Determine outcome const success = total >= dc && !isNat1; const marginOfSuccess = total - dc; const enhancedSuccess = success && marginOfSuccess >= ENHANCED_MASTERY_THRESHOLD; const criticalSuccess = success && isNat20; const mishap = isNat1 || (desperationBonus && !success); // Display result if (criticalSuccess) { content.push(centerText('CRITICAL SUCCESS!', DISPLAY_WIDTH)); content.push(''); content.push('The magic flows flawlessly!'); content.push('The spell manifests with perfect clarity.'); content.push(''); content.push(`${proposedSpell.name} created successfully!`); if (proposedSpell.effect.damage) { content.push(`Deals maximum damage: ${proposedSpell.effect.damage}`); } } else if (enhancedSuccess) { content.push(centerText('ENHANCED SUCCESS!', DISPLAY_WIDTH)); content.push(''); content.push('Exceptional mastery of the arcane!'); content.push(`Beat DC by ${marginOfSuccess} - enhanced effect`); content.push(''); content.push(`${proposedSpell.name} created with bonus!`); } else if (success) { content.push(centerText('SUCCESS', DISPLAY_WIDTH)); content.push(''); content.push('The improvised magic takes form!'); content.push(''); content.push(`${proposedSpell.name} created successfully!`); if (proposedSpell.effect.damage) { content.push(`Damage: ${proposedSpell.effect.damage} ${proposedSpell.effect.damageType || ''}`); } if (proposedSpell.effect.healing) { content.push(`Healing: ${proposedSpell.effect.healing}`); } } else if (mishap) { if (isNat1) { content.push(centerText('MISHAP!', DISPLAY_WIDTH)); content.push(''); content.push('The magic surges wildly!'); content.push('A critical failure causes a magical backfire!'); } else { content.push(centerText('SEVERE MISHAP!', DISPLAY_WIDTH)); content.push(''); content.push('Desperation magic gone wrong!'); content.push('The risky casting has backfired terribly!'); } content.push(''); content.push('The DM should determine the mishap effect:'); content.push('- Wild magic surge'); content.push('- Damage to caster'); content.push('- Unintended effect'); } else { content.push(centerText('FAILED', DISPLAY_WIDTH)); content.push(''); content.push('The magic fails to coalesce.'); content.push('The spell fizzles without taking form.'); content.push(''); content.push(`Missed DC by ${dc - total}`); } const title = mishap ? 'SPELL MISHAP' : success ? 'SPELL SYNTHESIZED' : 'SYNTHESIS FAILED'; return createBox(title, content); }
  • Zod schema defining input validation for synthesize_spell, including proposed spell details, caster info, intent, and various modifiers for the Arcana check.
    export const synthesizeSpellSchema = z.object({ encounterId: z.string().optional(), casterId: z.string(), intent: z.string(), proposedSpell: ProposedSpellSchema, // Arcana check modifiers arcanaBonus: z.number().optional(), rollMode: RollModeSchema.optional(), manualRoll: z.number().min(1).max(20).optional(), manualRolls: z.array(z.number().min(1).max(20)).length(2).optional(), // Circumstance modifiers nearLeyLine: z.boolean().optional(), desperationBonus: z.boolean().optional(), materialComponentValue: z.number().optional(), });
  • Tool registration in the central registry, including name, description, input schema conversion, and wrapper handler that validates input and delegates to the synthesizeSpell function.
    synthesize_spell: { name: 'synthesize_spell', description: 'Arcane Synthesis for improvised magic. Caster proposes a custom spell effect; Arcana check DC = 10 + (level × 2) + modifiers. Success creates temporary spell effect, failure may cause mishaps. Supports circumstance modifiers (ley lines, desperation, material components).', inputSchema: toJsonSchema(synthesizeSpellSchema), handler: async (args) => { try { const validated = synthesizeSpellSchema.parse(args); const result = synthesizeSpell(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); } }, },
  • Helper function to calculate the Arcana check DC for spell synthesis based on spell level, ley line proximity, and material component value.
    function calculateSynthesisDC( level: number, nearLeyLine?: boolean, materialComponentValue?: number ): { dc: number; modifiers: string[] } { let dc = 10 + (level * 2); const modifiers: string[] = []; if (nearLeyLine) { dc -= 2; modifiers.push('Near ley line: -2'); } if (materialComponentValue && materialComponentValue >= 100) { const reduction = Math.floor(materialComponentValue / 100); dc -= reduction; modifiers.push(`Components (${materialComponentValue}gp): -${reduction}`); } return { dc, modifiers }; }

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