foundry-vtt
Connect a Foundry VTT world to Claude, ChatGPT, Codex, Cursor, Gemini or any MCP client.
Что умеет
- Actor Create: Create a new actor from scratch (custom NPCs, characters, creatures). type must be valid for the world's game system — dnd5e: character, npc, vehicle, group; pf2e: character, npc, hazard
- Actor Create From Compendium: Import an actor (monster, NPC) from a compendium pack into the world. Pass either uuid — the "Compendium.<scope>.<pack>.Actor.<id>" value returned by dnd5e-compendium-fil
- Actor Delete: Delete an actor from the world. This action cannot be undone!
Какие данные видит
Нужен ли аккаунт
Не нужен: сервер работает без входа
Connect a Foundry VTT world to Claude, ChatGPT, Codex, Cursor, Gemini or any MCP client. 121 tools: actors and inventory, dice and combat, journals and roll tables, scenes and tokens, compendium search and import; D&D 5e and Pathfinder 2e aware. Sign in with Patreon (OAuth), no API key to paste; free to start, paid tiers unlock journals, scenes, tokens, combat and compendiums.
Setup: install the "Foundry API Bridge" module in Foundry VTT, get a key from the module settings, then add this server to your client and sign in. Code mode for Claude Code and Codex: https://foundry-mcp.com/code
Website: https://foundry-mcp.com Docs: https://github.com/alexivenkov/foundry-api-bridge-module Privacy: https://foundry-mcp.com/privacy
Как подключить
Как подключить foundry-vtt к Claude
Адрес сервера, который нужно вставить в настройках Claude:
https://foundry-vtt--ai-nitromoon.run.tools
- Откройте Claude (сайт claude.ai или приложение для компьютера).
- Перейдите в Настройки → Коннекторы (в английском интерфейсе: Settings → Connectors).
- Нажмите Добавить пользовательский коннектор (Add custom connector).
- Вставьте адрес сервера, скопированный ниже, в поле URL удалённого MCP-сервера и нажмите Добавить.
- В чате нажмите + → Коннекторы и включите новый коннектор.
Пользовательские коннекторы доступны на тарифах Free, Pro, Max, Team и Enterprise. На Free можно добавить только один. В Team и Enterprise коннектор сначала добавляет владелец организации в Настройки организации → Коннекторы.
Авторизация
После нажатия Добавить откроется окно входа в сервис. Войдите под своим аккаунтом и подтвердите доступ. Пароль Claude не видит.
Как подключить foundry-vtt к ChatGPT
Адрес сервера, который нужно вставить в настройках ChatGPT:
https://foundry-vtt--ai-nitromoon.run.tools
- Откройте ChatGPT в браузере (chatgpt.com). Нужен тариф Plus, Pro, Business, Enterprise или Edu.
- Один раз включите режим разработчика: Настройки → Приложения → Дополнительные настройки → Режим разработчика (Settings → Apps → Advanced settings → Developer mode).
- Откройте Настройки → Коннекторы и нажмите Создать (Create).
- Заполните форму: Название (любое), Описание (одна фраза, что делает сервис), URL MCP-сервера (скопируйте ниже).
- В поле Аутентификация выберите OAuth, если сервис требует вход, иначе Нет. Нажмите Создать.
- В новом чате откройте + → Приложения/Коннекторы и включите коннектор.
Название раздела у OpenAI менялось (Connectors → Apps/Plugins). Если пункт называется иначе, ищите «режим разработчика» в настройках. В рабочих пространствах Business/Enterprise администратор должен разрешить пользовательские коннекторы.
Авторизация
При первом использовании ChatGPT откроет окно входа в сервис. Войдите и подтвердите доступ.
Как подключить foundry-vtt к Cursor
Адрес сервера, который нужно вставить в настройках Cursor:
https://foundry-vtt--ai-nitromoon.run.tools
Быстрый способ: нажмите кнопку Открыть в Cursor ниже, Cursor сам предложит добавить сервер.
Вручную:
- В Cursor откройте Settings → Cursor Settings → MCP и нажмите Add new global MCP server.
- Вставьте JSON, скопированный ниже, в открывшийся файл
~/.cursor/mcp.json(для одного проекта:.cursor/mcp.jsonв корне проекта). - Сохраните файл. Сервер появится в списке MCP; при необходимости пройдите авторизацию по кнопке рядом с ним.
Авторизация
Если сервис требует вход, рядом с сервером в списке MCP появится кнопка авторизации.
Список инструментов сервера (60)
Технические названия из tools/list. Нужны только разработчикам.
| actor-create | Create a new actor from scratch (custom NPCs, characters, creatures). type must be valid for the world's game system — dnd5e: character, npc, vehicle, group; pf2e: character, npc, hazard, loot, familiar, party, vehicle, army. To import a monster from a compendium use actor-create-from-compendium. system is deep-merged over the system defaults. |
| actor-create-from-compendium | Import an actor (monster, NPC) from a compendium pack into the world. Pass either uuid — the "Compendium.<scope>.<pack>.Actor.<id>" value returned by dnd5e-compendium-filter-actors, pf2e-compendium-filter-actors and compendium-search — or packId + actorId from compendium-browse. |
| actor-delete | Delete an actor from the world. This action cannot be undone! |
| actor-get | Get full actor details: HP, AC, abilities, skills, speed, proficiency, inventory with item IDs. Use actor-list or actor-filter FIRST to find actorId. Item IDs from here are needed for dnd5e-roll-attack, dnd5e-roll-damage, dnd5e-item-use. The statblock layout follows the dnd5e data model; in other systems sections such as skills or currency stay empty — use uuid-resolve with "Actor.<id>" for the raw document. |
| actor-list | List actors in the world (name, type, ID), at most 200 rows. For anything beyond a plain listing — by name, CR, creature type, size, folder, HP, AC — use actor-filter, which also paginates. Actor IDs are needed for rolls, combat, items, and effects. |
| actor-filter | Search WORLD actors with D&D 5e structured filters (dnd5e worlds only). Returns paginated {id, name} entries; call actor-get for full stats. Filters combine with AND, values inside one array with OR. Use for "undead with CR 1-5", "PCs in the party", "dragons with AC 18+", "NPCs in folder Chapter 7". For every actor unfiltered use actor-list; compendiums are NOT searched (use dnd5e-compendium-filter-actors). CRITICAL DATA FORMATS - CR is a NUMBER from the exact set 0, 0.125, 0.25, 0.5, 1..30 ("1/4" -> 0.25; 0.7 is rejected). - Sizes are SHORT codes: tiny, sm, med, lg, huge, grg ("small" is rejected). - creatureType: the 14 lowercase SRD types only; subtypes ("demon") are rejected, use the base type ("fiend"). - Ranges are {min?, max?}, inclusive; min = max for an exact match. Actors lacking a filtered field are silently excluded (PCs have no CR, vehicles no abilities, root-level actors no folder). - Pagination: limit 1..200 (default 50), offset; the response has total and hasMore. EXAMPLES { "cr": { "min": 0.25, "max": 0.25 }, "type": ["npc"] } { "creatureType": ["undead"], "folder": { "name": "Chapter 3", "recursive": true } } |
| actor-update | Update an actor's name, image, folder, or system data (HP, XP, abilities...). system is DEEP-MERGED into the existing data: pass only the paths you change, e.g. {"attributes": {"hp": {"value": 25}}} sets current HP and leaves everything else intact; arrays are replaced whole. Common dnd5e paths: attributes.hp.value, details.xp.value. |
| chat-clear | Delete ALL chat messages. This action is IRREVERSIBLE. Use ONLY when the user explicitly asks to clear the entire chat log. |
| chat-delete | Delete a specific chat message by ID. Use to remove erroneous messages or clean up chat. Use chat-list FIRST to find the message ID. |
| chat-export | Export the full chat log as text or JSON. Use for session summaries, recapping what happened, or saving chat history. Text format: "[Speaker] Content" per line. JSON format: array of message objects with id, timestamp, author, speaker, content, flavor, isRoll. |
| chat-list | Read recent chat messages from Foundry VTT. Use to see what players are discussing, check roll results, or review combat narration. Returns plain text (HTML stripped). Use since param with a message ID to poll for new messages since last check. Filters: authorId, actorId, type (ic/ooc/emote/roll), search text. Messages are returned in chronological order (oldest first). |
| chat-send | Send a message to the Foundry VTT chat log. Use for narration, NPC dialogue, combat descriptions, and out-of-character communication with the player. Supports HTML formatting. Pass actorId to speak as an NPC (shows their portrait). Use flavor for context subtitles like "Narration", "The Tavern", "Combat". Players watching Foundry only see what is posted here. You can insert document links in content using @UUID[Actor.actorId]{Name}, @UUID[Item.itemId]{Sword}, @UUID[JournalEntry.journalId]{Quest} — Foundry renders them as clickable links. |
| chat-update | Edit content or flavor of an existing chat message. Use to fix typos in DM narration or update descriptions. Use chat-list FIRST to find the message ID. At least one of content or flavor must be provided. |
| combat-add-combatant | Add actor to combat. Use actor-list or actor-filter FIRST to find actorId. After adding all combatants, use combat-roll-all-initiative before combat-start. |
| combat-create | Create new combat encounter. First step in combat workflow. After creating: use combat-add-combatant to add actors, then combat-roll-all-initiative, then combat-start. |
| combat-delete | Delete combat encounter immediately without confirmation. Use when combat is over or cancelled. |
| combat-get | Get combat state: combatants, round, turn, whose turn it is. Call FIRST to check if combat exists before other combat operations. Returns combatant IDs needed for combat-roll-initiative, combat-set-combatant-defeated, etc. combatId selects a specific encounter; omit it for the active combat. |
| combat-next-turn | Advance to next combatant's turn. Auto-advances round when all have acted. includeContext (default true) appends the tactical context: current combatant position, nearby enemies with distances and line of sight, ASCII map; set false on routine turns to save context. |
| combat-previous-turn | Go back to previous combatant's turn. Use to undo an accidental combat-next-turn. |
| combat-remove-combatant | Remove combatant from combat. Use combat-get to find combatantId (not same as actorId). Use when creature flees or is removed from encounter. |
| combat-roll-all-initiative | Roll initiative for all combatants at once. Call AFTER combat-add-combatant, BEFORE combat-start. Use npcsOnly=true to let players roll their own. |
| combat-roll-initiative | Roll initiative for specific combatants. Use combat-get to find combatantIds. For rolling all at once, use combat-roll-all-initiative instead. |
| combat-set-combatant-defeated | Mark combatant as defeated (shows skull icon, skips their turn). Use when creature reaches 0 HP or is otherwise eliminated. |
| combat-set-initiative | Manually set initiative value. Use for readied actions, special circumstances, or fixing rolls. |
| combat-set-turn | Jump directly to a specific combatant's turn in combat. Does NOT cycle through intermediate turns or increment the round. Use this instead of repeated combat-next-turn calls to avoid triggering round-based effects (Rage expiry, concentration checks, condition durations). Get combatant IDs from combat-get. includeContext (default true) appends the tactical context for the new current combatant. |
| combat-start | Begin combat (round 1, turn 0). Call AFTER adding combatants and rolling initiative. Returns the combat state; includeContext (default true) appends the tactical context: current combatant position, nearby enemies with distances and line of sight, ASCII map. |
| combat-toggle-combatant-visibility | Set or toggle a combatant's visibility to players (hidden enemies, invisible creatures, surprise). Pass hidden to set the state explicitly; omit it to flip the current state. |
| compendium-browse | Browse the contents of a compendium pack. Lists documents (monsters, items, spells, etc.) in the compendium. Use compendium-list first to find the packId. Use types to select only given subtypes (e.g. ["spell"]), and ids to BATCH-fetch specific documents in one call — e.g. every item a class grants, taken from uuid-resolve output — instead of N compendium-document-get calls. types+ids combine with AND. On bridge module 8.11.0+ the selection happens inside Foundry; on older modules the full pack is fetched and the same selection is applied gateway-side. Paginate with limit (default 50, max 200) and offset. For structured stat filters (CR, level, rarity, traits, price...) prefer dnd5e-compendium-filter-* / pf2e-compendium-filter-* instead. |
| compendium-document-get | Get a compendium document as a readable summary: actors come back as a statblock (HP, AC, abilities, attacks), other types as core fields plus system data. For the complete raw JSON use compendium-document-get-raw, or uuid-resolve when you already hold the document UUID (what the filter tools return). Use compendium-browse to find document IDs. |
| compendium-document-get-raw | Get the complete raw JSON data of a compendium document including all system fields. Use this when you need the full statblock data for calculations or detailed information. |
| compendium-list | List all available compendium packs. Compendiums contain pre-made content like monsters, items, spells, etc. Use this to discover what compendiums are available, then use compendium-browse to see their contents. |
| compendium-search | Search for documents across ALL compendiums by name. Useful when you want to find a monster, item, or spell but don't know which compendium it's in. Name matching only — for structured filters (CR, level, rarity, traits, price...) use dnd5e-compendium-filter-* / pf2e-compendium-filter-*; for rules/lore TEXT inside journal packs use compendium-page-search (this tool does not see page content); when you already hold a UUID, use uuid-resolve. |
| compendium-page-search | Full-text search inside JournalEntry compendium packs — matches page NAMES and page CONTENT. This is the tool for rules/lore text questions: compendium-search only sees document names in pack indexes, so rule pages, spell lists, and class write-ups are invisible to it. Requires bridge module 8.11.0+. WHEN TO USE - "What does the grappled condition say?" → query: "grappled", pageTypes: ["rule"] - Find a class/subclass rules page, a spell list page, or any lore text - Locate which journal a phrase appears in WORKFLOW - Each match carries the PAGE uuid — pass it to uuid-resolve for the full page text. - matchedIn tells what matched; name matches win (content is not scanned then) and their snippet is always null. - Content matches include a ~200-char plain-text snippet around the first hit. SEMANTICS - Query is a case-insensitive substring. - Packs are scanned lazily in order until limit is reached; results are in scan order, unsorted. - Explicit unknown packIds error with "Pack not found: <id>"; non-journal packs with "Compendium pack is not an JournalEntry pack: <id>". |
| uuid-resolve | Resolve any ABSOLUTE Foundry UUID to its full document in one call: world documents ("Actor.<id>"), compendium documents ("Compendium.<scope>.<pack>.<DocType>.<id>"), and embedded/nested ones ("Actor.<id>.Item.<id>", journal pages). Returns core fields plus the complete raw document data. Requires bridge module 8.11.0+. UUIDs are NOT guessed — take them from the uuid fields of other tools: compendium-browse, compendium-page-search, the compendium filter tools, or reference fields inside a previously resolved document (e.g. a dnd5e class item's system.advancement[].configuration.items[].uuid). WHEN TO USE - Walk a reference graph one hop per call: class → granted features → their effects; spell-list page → individual spells. - Fetch the full text of a page found via compendium-page-search. - Inspect any document when a UUID is all you have. LIMITS - Relative UUIDs (starting with ".") are not supported. - Both a missing and a malformed UUID return "Document not found for UUID: <uuid>". |
| dnd5e-compendium-filter-actors | Search COMPENDIUM packs for actors with D&D 5e structured filters (dnd5e worlds only). Compendium counterpart of actor-filter, which searches world actors; for a plain name lookup use compendium-search. CRITICAL DATA FORMATS - CR is a NUMBER from the exact set 0, 0.125, 0.25, 0.5, 1..30 ("1/4" -> 0.25; 0.3 is rejected). - Sizes are SHORT codes: tiny, sm, med, lg, huge, grg. creatureType: the 14 lowercase SRD types, no subtypes ("demon" -> "fiend"). - level applies only to type "character" (NPCs have CR). World-only filters (folder, hasPlayerOwner, currentHp) do not exist here. SEMANTICS: filters combine with AND, values inside one array with OR. Ranges are {min?, max?}, inclusive (min = max for exact). Documents lacking a filtered field are silently excluded. limit 1..200 (default 50), offset; the response has total and hasMore. Results are {name, uuid} entries: follow up with uuid-resolve, or compendium-browse with ids to batch-load. Requires bridge module 8.11.0+. EXAMPLES { "type": ["npc"], "cr": { "min": 0.25, "max": 0.25 } } { "packIds": ["dnd5e.monsters"], "creatureType": ["dragon"], "size": ["huge", "grg"] } |
| dnd5e-compendium-filter-items | Search COMPENDIUM packs for items with D&D 5e structured filters (dnd5e worlds only): gear, spells, feats, class features and other Item documents. Compendium counterpart of world-item-filter. CRITICAL DATA FORMATS - rarity is camelCase: veryRare (not "very rare"). spellSchool is the full word (evocation, not "evo"). - spellLevel 0..9 (0 = cantrip) only affects type "spell"; other types are silently excluded by it. - price in GP (denominations normalized), weight in lb, decimals allowed. SEMANTICS: filters combine with AND, values inside one array with OR. Ranges are {min?, max?}, inclusive (min = max for exact). Documents lacking a filtered field are silently excluded. limit 1..200 (default 50), offset; the response has total and hasMore. Results are {name, uuid} entries: follow up with uuid-resolve, or compendium-browse with ids to batch-load. Requires bridge module 8.11.0+. EXAMPLES { "type": ["spell"], "spellLevel": { "min": 0, "max": 0 }, "spellSchool": ["evocation", "illusion"] } { "requiresAttunement": true, "price": { "max": 5000 }, "rarity": ["rare", "veryRare"] } |
| pf2e-compendium-filter-actors | Search COMPENDIUM packs for actors with Pathfinder 2e structured filters (pf2e worlds only): bestiary browsing by level, traits, rarity, size, HP, AC. CRITICAL DATA FORMATS - level is an INTEGER range; negative bounds are valid ({ "min": -1 }). - traits are ALL-OF (every listed trait must be present), an open set of lowercase slugs ("undead", "kobold"). - rarity: common, uncommon, rare, unique (PF2e ladder). Sizes: tiny, sm, med, lg, huge, grg. SEMANTICS: filters combine with AND, values inside one array with OR. Ranges are {min?, max?}, inclusive (min = max for exact). Documents lacking a filtered field are silently excluded. limit 1..200 (default 50), offset; the response has total and hasMore. Results are {name, uuid} entries: follow up with uuid-resolve, or compendium-browse with ids to batch-load. Requires bridge module 8.11.0+. Results carry level (null when absent), sorted by level then name. EXAMPLES { "type": ["npc"], "traits": ["kobold"], "level": { "min": -1, "max": 1 } } { "rarity": ["unique"], "level": { "min": 15 } } |
| pf2e-compendium-filter-items | Search COMPENDIUM packs for items with Pathfinder 2e structured filters (pf2e worlds only): equipment, spells, feats, ancestries, classes and 20 more Item types. CRITICAL DATA FORMATS - For spells, level is the spell RANK. - traits are ALL-OF (every trait present); traditions are ANY-OF (arcane, divine, occult, primal). Do not confuse the two. - category is the feat category (class, skill, general, ancestry, ...). rarity: common, uncommon, rare, unique. - priceGold is gp with decimals (5 sp -> 0.5), per batch for batched goods like arrows. SEMANTICS: filters combine with AND, values inside one array with OR. Ranges are {min?, max?}, inclusive (min = max for exact). Documents lacking a filtered field are silently excluded. limit 1..200 (default 50), offset; the response has total and hasMore. Results are {name, uuid} entries: follow up with uuid-resolve, or compendium-browse with ids to batch-load. Requires bridge module 8.11.0+. Results carry level (null when absent), sorted by level then name. EXAMPLES { "type": ["spell"], "level": { "min": 3, "max": 3 }, "traditions": ["arcane"] } { "type": ["consumable"], "priceGold": { "max": 5 } } |
| effect-create | Add a custom active effect to an actor (buff, debuff, custom condition). Each change targets a data path with a mode; values are strings. EXAMPLE changes: [{"key": "system.attributes.ac.bonus", "value": "2", "mode": 2}] adds +2 AC. Paths are dnd5e; other systems differ. |
| effect-delete | Remove an active effect from an actor. Use effect-list first to find effect IDs. |
| effect-list | Get all active effects on an actor, including conditions, buffs, debuffs, and custom effects. Effects modify actor stats, grant abilities, or apply conditions. |
| effect-toggle-status | Toggle a D&D 5e condition/status on an actor (dnd5e worlds only; in PF2e worlds use pf2e-set-condition / pf2e-remove-condition). Adds or removes conditions like blinded, poisoned, prone. Core D&D 5e status IDs: blinded, charmed, deafened, exhaustion, frightened, grappled, incapacitated, invisible, paralyzed, petrified, poisoned, prone, restrained, stunned, unconscious. |
| effect-update | Update an existing active effect on an actor. Can modify name, icon, disabled state, or changes. |
| handout-template-get | Get the full HTML of a handout template. Use this as a STYLE REFERENCE — do not copy it verbatim. Generate a unique variation with the required content, using inline style="" attributes (Foundry VTT strips <style> tags). Save the result via journal-page-create with type "text". |
| handout-template-list | List available handout templates (wanted posters, letters, scrolls, etc.). Returns template IDs and descriptions. Use handout-template-get to read the full HTML. Then generate a unique variation with your own content and save via journal-page-create. |
| dnd5e-item-activate | Activate an item with full Foundry automation — triggers Midi-QOL and other automation module hooks. Use for combat actions: melee/ranged attacks, spell casting, abilities. Pass targetTokenIds for attacks — Midi-QOL will auto-roll attack, check AC, roll damage, apply HP loss. For AoE spells pass templatePosition. Circle AoE (Fireball): x,y = center of effect (avg target positions). Cone/Line AoE (Cone of Cold, Lightning Bolt): x,y = caster token position, direction = angle toward targets (direction = atan2(targetY - casterY, targetX - casterX) * 180 / PI, add 360 if negative). Pixel coords: pixel = gridCoord * gridSize + gridSize / 2. Unlike dnd5e-item-use, this does NOT suppress hooks or dialogs, so automation modules work fully. Use scene-get to find target token IDs and grid info, item-list to find item IDs. Prefer this over dnd5e-item-use when targets, templates or automation matter. |
| item-create | Create a new item directly in an actor's inventory (dnd5e data model). Use for custom items, loot, or simple gear; for official SRD content use item-create-from-compendium. For an item that lives in the world Items Directory rather than on an actor use world-item-create. |
| item-create-from-compendium | Add an item (weapon, spell, feat, gear) from a compendium pack to an actor's inventory with its full data. Pass either uuid — the "Compendium.<scope>.<pack>.Item.<id>" value returned by dnd5e-compendium-filter-items, pf2e-compendium-filter-items and compendium-search — or packId + itemId from compendium-browse. |
| item-delete | Remove an item from actor's inventory permanently. Use item-list FIRST to find itemId. Cannot be undone! An item that is already gone counts as deleted (success), so retries are safe. |
| item-list | List an ACTOR's inventory (embedded items: weapons, gear, spells, feats, class features) with descriptions, damage, and range. Not the world Items Directory — use world-item-filter for that. Filter by type, equipped status, or hasActivities (usable abilities). Item IDs from here feed dnd5e-item-use, dnd5e-item-activate, dnd5e-roll-attack. |
| item-update | Update an item in actor's inventory. Use item-list FIRST to find itemId. system is DEEP-MERGED into the existing data: pass only the fields you change, e.g. {"quantity": 3} or {"uses": {"value": 0}}; arrays are replaced whole. |
| dnd5e-item-use | Use an item from an actor's inventory via item.use() with dialogs suppressed: consumables (potions, scrolls), spells, weapons, features. Returns the raw use result as JSON. CHOOSING: this tool for quick, dialog-free usage without targets; dnd5e-item-activate when targets, AoE templates, or automation modules (Midi-QOL) matter. |
| journal-create | Create a new journal entry, optionally with a first page. content is HTML (see journal-page-create for the HTML rules). folder takes a folder ID; a unique folder NAME is resolved to its ID. |
| journal-delete | Delete a journal entry and all its pages. This action cannot be undone! |
| journal-folder-list | List journal folders by name with entry and page counts — a quick overview of journal organization. Then use journal-list with a folder name, or omit folder to list all journals. Folder IDs (for journal-create / journal-update / folder-get) come from folder-list with type "JournalEntry". |
| journal-get | Get a journal entry by ID with all its pages as plain text (default) or as raw JSON with HTML and page metadata (formatAsText=false). Use journal-list or journal-search to find journal IDs; for one page of a long journal use journal-page-get. |
| journal-list | List journal entries with IDs, grouped by folder. Omit folder to list ALL journals. Returns IDs needed for journal-get. Use journal-search if you know the name. |
| journal-page-create | Add a page to an existing journal entry. Text pages take HTML content: style with inline style="" attributes (Foundry strips <style> and <script>), link documents with @UUID[Actor.<id>]{Label}. handout-template-list offers ready-made layouts. |
| journal-page-delete | Delete a specific page from a journal. This action cannot be undone! |
| journal-page-get | Get a specific page from a journal. Useful when you only need one page from a multi-page journal. Returns plain text content by default. |