Skip to main content
Glama

compare_monsters

Compare D&D 5e monsters side by side to analyze AC, HP, abilities, resistances, immunities, and special actions for encounter planning.

Instructions

Compare 2-3 D&D 5e monsters side by side. Shows AC, HP, ability scores, speeds, resistances, immunities, actions, and special abilities.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
monster_namesYesNames of 2-3 monsters to compare

Implementation Reference

  • The async handler function for the 'compare_monsters' tool, which processes input monster names, retrieves data from the database, formats the comparison table in Markdown, and returns it.
      async ({ monster_names }) => {
        const monsters: MonsterRow[] = [];
        const notFound: string[] = [];
    
        for (const name of monster_names) {
          const monster = getMonsterByName(db, name);
          if (monster) {
            monsters.push(monster);
          } else {
            notFound.push(name);
          }
        }
    
        if (notFound.length > 0) {
          return {
            content: [
              {
                type: 'text' as const,
                text: `Monster(s) not found: ${notFound.join(', ')}. Use the search_monsters tool first to find the exact name.`,
              },
            ],
            isError: true,
          };
        }
    
        const lines: string[] = [];
        lines.push('# Monster Comparison');
        lines.push('');
    
        // Separator helper for table
        const sep = monsters.map(() => '---').join(' | ');
        const header = monsters.map((m) => `**${m.name}**`).join(' | ');
    
        lines.push(`| Stat | ${header} |`);
        lines.push(`|------|${sep}|`);
    
        // Basic info
        lines.push(`| Size | ${monsters.map((m) => m.size).join(' | ')} |`);
        lines.push(`| Type | ${monsters.map((m) => {
          const sub = m.subtype ? ` (${m.subtype})` : '';
          return `${m.type}${sub}`;
        }).join(' | ')} |`);
        lines.push(`| Alignment | ${monsters.map((m) => m.alignment).join(' | ')} |`);
    
        // Combat stats
        lines.push(`| AC | ${monsters.map((m) => {
          return m.ac_type ? `${m.ac} (${m.ac_type})` : `${m.ac}`;
        }).join(' | ')} |`);
        lines.push(`| HP | ${monsters.map((m) => `${m.hp} (${m.hit_dice})`).join(' | ')} |`);
        lines.push(`| Speed | ${monsters.map((m) => formatSpeed(m.speed)).join(' | ')} |`);
        lines.push(`| CR | ${monsters.map((m) => {
          const xp = m.xp || getXpForCr(m.cr);
          return `${m.cr} (${xp.toLocaleString()} XP)`;
        }).join(' | ')} |`);
        lines.push(`| Prof. Bonus | ${monsters.map((m) => m.proficiency_bonus ? `+${m.proficiency_bonus}` : '—').join(' | ')} |`);
    
        // Ability scores
        lines.push(`| STR | ${monsters.map((m) => formatScore(m.str)).join(' | ')} |`);
        lines.push(`| DEX | ${monsters.map((m) => formatScore(m.dex)).join(' | ')} |`);
        lines.push(`| CON | ${monsters.map((m) => formatScore(m.con)).join(' | ')} |`);
        lines.push(`| INT | ${monsters.map((m) => formatScore(m.int)).join(' | ')} |`);
        lines.push(`| WIS | ${monsters.map((m) => formatScore(m.wis)).join(' | ')} |`);
        lines.push(`| CHA | ${monsters.map((m) => formatScore(m.cha)).join(' | ')} |`);
    
        // Defenses
        lines.push(`| Resistances | ${monsters.map((m) => m.resistances ?? '—').join(' | ')} |`);
        lines.push(`| Immunities | ${monsters.map((m) => m.immunities ?? '—').join(' | ')} |`);
        lines.push(`| Vulnerabilities | ${monsters.map((m) => m.vulnerabilities ?? '—').join(' | ')} |`);
        lines.push(`| Condition Immunities | ${monsters.map((m) => m.condition_immunities ?? '—').join(' | ')} |`);
    
        // Senses & languages
        lines.push(`| Senses | ${monsters.map((m) => m.senses ?? '—').join(' | ')} |`);
        lines.push(`| Languages | ${monsters.map((m) => m.languages ?? '—').join(' | ')} |`);
        lines.push('');
    
        // Detailed sections
        const traitSection = formatAbilitiesSection('Traits', monsters, 'traits');
        if (traitSection) lines.push(traitSection);
    
        const actionSection = formatAbilitiesSection('Actions', monsters, 'actions');
        if (actionSection) lines.push(actionSection);
    
        const reactionSection = formatAbilitiesSection('Reactions', monsters, 'reactions');
        if (reactionSection) lines.push(reactionSection);
    
        const legendarySection = formatAbilitiesSection('Legendary Actions', monsters, 'legendary_actions');
        if (legendarySection) lines.push(legendarySection);
    
        return {
          content: [{ type: 'text' as const, text: lines.join('\n') }],
        };
      },
    );
  • The definition and input schema (zod validation) for the 'compare_monsters' tool.
    server.registerTool(
      'compare_monsters',
      {
        description:
          'Compare 2-3 D&D 5e monsters side by side. Shows AC, HP, ability scores, speeds, resistances, immunities, actions, and special abilities.',
        inputSchema: {
          monster_names: z
            .array(z.string())
            .min(2)
            .max(3)
            .describe('Names of 2-3 monsters to compare'),
        },
      },
  • Function used to register the 'compare_monsters' tool with the McpServer.
    export function registerCompareMonsters(
      server: McpServer,
      db: Database.Database,
    ): void {
      server.registerTool(
        'compare_monsters',
        {
          description:
            'Compare 2-3 D&D 5e monsters side by side. Shows AC, HP, ability scores, speeds, resistances, immunities, actions, and special abilities.',
          inputSchema: {
            monster_names: z
              .array(z.string())
              .min(2)
              .max(3)
              .describe('Names of 2-3 monsters to compare'),
          },
        },
        async ({ monster_names }) => {
          const monsters: MonsterRow[] = [];
          const notFound: string[] = [];
    
          for (const name of monster_names) {
            const monster = getMonsterByName(db, name);
            if (monster) {
              monsters.push(monster);
            } else {
              notFound.push(name);
            }
          }
    
          if (notFound.length > 0) {
            return {
              content: [
                {
                  type: 'text' as const,
                  text: `Monster(s) not found: ${notFound.join(', ')}. Use the search_monsters tool first to find the exact name.`,
                },
              ],
              isError: true,
            };
          }
    
          const lines: string[] = [];
          lines.push('# Monster Comparison');
          lines.push('');
    
          // Separator helper for table
          const sep = monsters.map(() => '---').join(' | ');
          const header = monsters.map((m) => `**${m.name}**`).join(' | ');
    
          lines.push(`| Stat | ${header} |`);
          lines.push(`|------|${sep}|`);
    
          // Basic info
          lines.push(`| Size | ${monsters.map((m) => m.size).join(' | ')} |`);
          lines.push(`| Type | ${monsters.map((m) => {
            const sub = m.subtype ? ` (${m.subtype})` : '';
            return `${m.type}${sub}`;
          }).join(' | ')} |`);
          lines.push(`| Alignment | ${monsters.map((m) => m.alignment).join(' | ')} |`);
    
          // Combat stats
          lines.push(`| AC | ${monsters.map((m) => {
            return m.ac_type ? `${m.ac} (${m.ac_type})` : `${m.ac}`;
          }).join(' | ')} |`);
          lines.push(`| HP | ${monsters.map((m) => `${m.hp} (${m.hit_dice})`).join(' | ')} |`);
          lines.push(`| Speed | ${monsters.map((m) => formatSpeed(m.speed)).join(' | ')} |`);
          lines.push(`| CR | ${monsters.map((m) => {
            const xp = m.xp || getXpForCr(m.cr);
            return `${m.cr} (${xp.toLocaleString()} XP)`;
          }).join(' | ')} |`);
          lines.push(`| Prof. Bonus | ${monsters.map((m) => m.proficiency_bonus ? `+${m.proficiency_bonus}` : '—').join(' | ')} |`);
    
          // Ability scores
          lines.push(`| STR | ${monsters.map((m) => formatScore(m.str)).join(' | ')} |`);
          lines.push(`| DEX | ${monsters.map((m) => formatScore(m.dex)).join(' | ')} |`);
          lines.push(`| CON | ${monsters.map((m) => formatScore(m.con)).join(' | ')} |`);
          lines.push(`| INT | ${monsters.map((m) => formatScore(m.int)).join(' | ')} |`);
          lines.push(`| WIS | ${monsters.map((m) => formatScore(m.wis)).join(' | ')} |`);
          lines.push(`| CHA | ${monsters.map((m) => formatScore(m.cha)).join(' | ')} |`);
    
          // Defenses
          lines.push(`| Resistances | ${monsters.map((m) => m.resistances ?? '—').join(' | ')} |`);
          lines.push(`| Immunities | ${monsters.map((m) => m.immunities ?? '—').join(' | ')} |`);
          lines.push(`| Vulnerabilities | ${monsters.map((m) => m.vulnerabilities ?? '—').join(' | ')} |`);
          lines.push(`| Condition Immunities | ${monsters.map((m) => m.condition_immunities ?? '—').join(' | ')} |`);
    
          // Senses & languages
          lines.push(`| Senses | ${monsters.map((m) => m.senses ?? '—').join(' | ')} |`);
          lines.push(`| Languages | ${monsters.map((m) => m.languages ?? '—').join(' | ')} |`);
          lines.push('');
    
          // Detailed sections
          const traitSection = formatAbilitiesSection('Traits', monsters, 'traits');
          if (traitSection) lines.push(traitSection);
    
          const actionSection = formatAbilitiesSection('Actions', monsters, 'actions');
          if (actionSection) lines.push(actionSection);
    
          const reactionSection = formatAbilitiesSection('Reactions', monsters, 'reactions');
          if (reactionSection) lines.push(reactionSection);
    
          const legendarySection = formatAbilitiesSection('Legendary Actions', monsters, 'legendary_actions');
          if (legendarySection) lines.push(legendarySection);
    
          return {
            content: [{ type: 'text' as const, text: lines.join('\n') }],
          };
        },
      );
    }

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/gregario/dnd-oracle'

If you have feedback or need assistance with the MCP directory API, please join our Discord server