Skip to main content
Glama

compare_monsters

Compare 2-3 D&D 5e monsters side by side, displaying AC, HP, ability scores, speeds, resistances, immunities, actions, and special abilities 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

  • Main function that registers the 'compare_monsters' tool handler. It accepts 2-3 monster names, fetches them from the DB, builds a side-by-side comparison table (AC, HP, ability scores, speeds, resistances, actions, traits, etc.), and returns the result as markdown text.
    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') }],
          };
        },
      );
    }
  • Input schema for the compare_monsters tool: an array of 2-3 monster names (z.array(z.string()).min(2).max(3)).
    {
      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'),
      },
    },
  • src/server.ts:56-57 (registration)
    Registration call in the server setup: registerCompareMonsters(server, db) invoked during server creation.
    registerCompareMonsters(server, db);
    registerAnalyzeLoadout(server, db);
  • Helper function abilityMod() used to compute ability score modifier from a stat value.
    function abilityMod(score: number): string {
      const mod = Math.floor((score - 10) / 2);
      return mod >= 0 ? `+${mod}` : `${mod}`;
    }
  • Helper function safeParseJson() for safely parsing JSON fields (traits, actions, speed, etc.).
    function safeParseJson<T>(value: string | null): T | null {
      if (!value) return null;
      try {
        return JSON.parse(value) as T;
      } catch {
        return null;
      }
    }
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations present, so description carries burden. It discloses that the tool shows specific monster attributes, implying read-only behavior with no side effects. However, it lacks details on authentication, rate limits, or performance implications. Still, it is reasonably transparent for a read-only comparison tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences effectively convey the purpose and output. Front-loaded with the action (compare) and resource (monsters), then lists displayed fields. No unnecessary words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given no output schema, the description compensates by listing output attributes. It covers the key comparison aspects for a monster tool. However, it omits potential return format, ordering, or error handling. Still, sufficient for its simplicity.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema has 100% coverage with a parameter description. The description adds value by explaining the tool's output (AC, HP, etc.) beyond the schema, enhancing understanding of what the parameter drives. However, it does not provide additional constraints or format details.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool compares 2-3 D&D 5e monsters side by side, listing specific attributes shown (AC, HP, etc.). It distinguishes itself from siblings like search_monsters (which likely finds monsters) by focusing on comparison.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage when a side-by-side comparison is needed, but it does not explicitly state when to avoid this tool versus alternatives (e.g., search_monsters for single monster details or build_encounter for encounter building). No exclusions or when-not guidance provided.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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