Skip to main content
Glama
legendsviewer-mcp

legendsviewer-mcp

by Hadows

legendsviewer-mcp

An MCP server that lets a language model read and query the history of a Dwarf Fortress world: search the deeds recorded in the legends, read the biography of a figure or the history of a civilization, and check whether what looks remarkable actually is.

It is a thin client over the analysis API added by LegendsViewer-AIPowered, a fork of Kromtec/LegendsViewer-Next.

Requirements

LegendsViewer-AIPowered must be running. This server owns no world state: parsing a large export takes about 30 seconds and 800 MB, which is fine once per application run and unacceptable per MCP session. It therefore queries a long-lived backend rather than loading anything itself.

# in the LegendsViewer-AIPowered checkout
dotnet run --project LegendsViewer.Backend

A stock LegendsViewer-Next will not work: it has no /api/Analysis routes. world_status says so explicitly if you point this at one.

Related MCP server: genskill-mcp

Install

npm install
npm run build

Then register it with your MCP client. For Claude Code:

{
  "mcpServers": {
    "legendsviewer": {
      "command": "node",
      "args": ["/absolute/path/to/legendsviewer-mcp/dist/index.js"]
    }
  }
}

Set LEGENDSVIEWER_URL if the backend does not listen on http://localhost:15421.

Tools

Tool

Purpose

world_status

is the backend reachable, is a world loaded, which object types exist

list_worlds

worlds opened before, with the XML path each loads from

load_world

parse an export into memory (~30 s)

world_summary

overview: civilizations, eras, wars, most eventful figures

read_object

one object's history, full or digest

search_objects

find by name

search_properties

find by goal, race, position, affiliation

search_events

full text search over the prose of every event

base_rates

how common a property value is

rankings

who holds the maximum of a numeric measure

breakdown

one property grouped by another, with aggregates

Two of these deserve emphasis, because they cover what the others cannot. Only search_events finds deeds, which appear in no property; only search_properties finds goals and affiliations, which appear in no event.

And base_rates is the one to reach for before concluding anything. A trait shared by three notable figures looks like a pattern until you learn that half the world shares it — most properties are recorded for only part of the objects, so the tool reports both denominators rather than letting you assume one.

breakdown is the one to reach for when the question has two halves — age at death by caste, casualties by attacker race. The other tools each read a single property, so such a question used to be answered by pulling the objects and joining them by hand, which for the classic API means recovering ids from HTML anchors. Do not do that: if a property needed for the join is missing, add it as a facet in the backend instead.

Arguments are validated strictly: an unknown parameter is an error, not a silently dropped key. The tool's cap is maxEvents for both detail levels, whereas the backend route behind the digest calls it maxNotableEvents — passing the backend's name used to look like it worked while the server default applied instead.

Two habits worth having

Ask for the digest first. read_object defaults to it. The full dossier of a large civilization can exceed 600 KB, most of it recurring festivals; the digest is around 17 KB and keeps the events that are rare for that object.

Filter event searches when you can. There is no index — the text only exists once the prose has been rendered — so an unfiltered search on a large world renders every event and takes a few seconds. Passing eventTypes brings it to milliseconds.

Drop q to read history rather than search it. search_events with only fromYear/toYear returns everything that happened then, which is the one question no keyword can express. It is also the fastest call in the set: with no text to match, nothing is rendered at all — a full year of a 494,436 event world comes back in 9 ms.

Development

npm test          # unit tests, plus an in-memory MCP client exercising every tool
npm run watch     # recompile on change

The tests use no network: the HTTP client is stubbed, and the MCP surface is driven through the SDK's in-memory transport.

License

MIT.

Available Tools

10 tools
base_ratesBase rates of a propertyA

How common each value of a property is. Call it before concluding that a shared trait is meaningful: most properties are recorded for only part of the objects, so the answer reports both the objects carrying the field and the whole scope, and divides by the former. Omit field to list the queryable fields.

Inputs: type, field, limit.

list_worldsList known worldsA

Worlds LegendsViewer has opened before, with the XML path each one loads from. Use it to find the argument for load_world.

Inputs: no named parameters.

load_worldLoad a worldA

Parses a legends export into memory, replacing whatever world was loaded. Takes about 30 seconds and 800 MB for a large world, so call it once and query afterwards. Point it at the -legends.xml file; the _plus.xml beside it is picked up automatically.

Inputs: path (required).

rankingsRank by a numeric measureA

Who holds the maximum of a measure — events, kills, worshippers, deaths and so on. Complements base_rates, which orders by how many objects share a value rather than by the value itself. Returns total, min, median and max beside the leaders, so a first place can be read against the spread. Omit by to list the available measures.

Inputs: by, type, limit, order.

read_objectRead one objectA

The history of a single world object as prose. detail='digest' condenses it to the event type breakdown, an activity histogram and only the events whose type is rare for that object — use it for civilizations and other large objects, whose full dossier can exceed 600 KB. detail='full' returns everything.

Inputs: id (required), type (required), detail, toYear, +3 more.

search_eventsSearch event textA

Full text search over the prose of every event in the world — the only way to find deeds, as opposed to names or properties. There is no index, so an unfiltered query on a large world takes a few seconds; passing eventTypes cuts that to milliseconds because excluded events are never rendered. Omit q to read a span of history instead of searching it: with fromYear/toYear alone it returns everything that happened then, and being free of any text to match it is the fastest query here. Give q or a filter — neither would mean every event in the world.

Inputs: q, limit, toYear, fromYear, +1 more.

search_objectsSearch by nameA

Finds world objects whose name contains the query. Exact matches rank first, then prefixes, then event count.

Inputs: q (required), type, limit.

search_propertiesSearch by propertyA

Searches the structured properties of objects — goal, race, positions, affiliations, worshipped deities — rather than names or event text. These never appear in any event, so this is the only tool that finds them. Each hit reports which field and value matched.

Inputs: q (required), type, field, limit.

world_statusWorld statusA

Whether LegendsViewer is reachable, whether it exposes the analysis layer, and which world is loaded. Also lists the object type names accepted by the other tools. Start here when anything fails.

Inputs: no named parameters.

world_summaryWorld summaryA

Overview of the loaded world: totals per type, main civilizations, eras, largest wars, most eventful figures and the most common event types. About 4 KB. The intended starting point before drilling into anything.

Inputs: no named parameters.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A4.3/5.0

    Scored across 10 tools

    Disambiguation5/5

    Each tool targets a distinct function: world management (list/load), overview (summary/status), object access (read/search), property search, event search, and statistical analysis (rates/rankings). No two tools overlap in purpose, and the descriptions make the boundaries clear.

    Naming Consistency4/5

    Most tools follow a verb_noun pattern (list_worlds, load_world, read_object, search_*), but a few use noun-only names (world_status, world_summary, base_rates, rankings). This is a minor deviation; the names are still readable and self-explanatory, but not fully consistent.

    Tool Count5/5

    10 tools is well within the ideal 3-15 range and matches the complexity of the domain. Each tool earns its place, covering distinct workflows without redundancy.

    Completeness5/5

    The toolset covers the full workflow: locating worlds, loading them, getting summaries, drilling into objects, searching by name/property/event, and performing statistical analysis. There are no obvious missing operations for typical analysis tasks.

    Maintenance

    ActivityInactive
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      A
      quality
      B
      maintenance
      A local-first MCP server that gives AI coding agents persistent memory and controlled commands. Features a git-backed markdown knowledge vault with FTS5 search, surgical section edits, token-aware context budgeting, and a sandboxed command engine with human approval gates. Works with Claude Code, Cursor, Copilot, Gemini, and more.
      58
      196 npm
      1
      Apache 2.0
    • A
      license
      A
      quality
      B
      maintenance
      An MCP server that exposes a live Dwarf Fortress fort to an AI agent as a small set of curated, semantic tools — a fortress co-pilot and early-warning advisor, not an autopilot. It provides read-only sensors and reference tools to observe the game state and retrieve game data.
      37
      68 npm
      2
      ISC
    • F
      license
      Not graded
      quality
      D
      maintenance
      A local MCP server that gives AI agents structured access to a personal Obsidian knowledge vault, with semantic search, organization through Maps of Content, and git-backed history.
      -