legendsviewer-mcp
This server provides MCP tools to query and analyze Dwarf Fortress world history. Key capabilities include:
World management: Check backend status, list previously opened worlds, load a world from XML, and get a high-level summary (civilizations, eras, wars, eventful figures).
Object exploration: Read detailed or condensed histories of figures, civilizations, sites, etc. (
read_object); search objects by name substring (search_objects); and search by structured properties like goals, race, positions, or affiliations (search_properties).Event search: Full-text search over event prose to find specific deeds, with optional filters for year range and event types; also retrieve all events within a timeframe without a keyword.
Statistical analysis: Compute base rates of property values to understand commonality (
base_rates); rank objects by numeric measures like events, kills, or deaths (rankings); and cross-tabulate two properties with aggregates (breakdown).Flexible controls: Most tools support result limits and filters (object type, detail level, year range) to refine queries and improve performance.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@legendsviewer-mcp How common is the goal 'immortality' among necromancers?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
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.BackendA 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 buildThen 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 |
| is the backend reachable, is a world loaded, which object types exist |
| worlds opened before, with the XML path each loads from |
| parse an export into memory (~30 s) |
| overview: civilizations, eras, wars, most eventful figures |
| one object's history, |
| find by name |
| find by goal, race, position, affiliation |
| full text search over the prose of every event |
| how common a property value is |
| who holds the maximum of a numeric measure |
| 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 changeThe 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 toolsbase_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
Scored across 10 tools
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.
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.
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.
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
Related MCP Connectors
Driflyte MCP server which lets AI assistants query topic-specific knowledge from web and GitHub.
An MCP server that gives your AI access to the source code and docs of all public github repos
MCP server for AI dialogue using various LLM models via AceDataCloud
Capability registry for the agentic economy. Semantic search over verified MCP server listings.
Related MCP Servers
- AlicenseAqualityBmaintenanceA 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.58196 npm1Apache 2.0
- AlicenseAqualityCmaintenanceAn MCP server that lets AI agents build on GenLayer by searching documentation, inspecting contracts and transactions over RPC, and scaffolding, linting, and testing Intelligent Contracts.4620 npm1MIT
- AlicenseAqualityBmaintenanceAn 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.3768 npm2ISC
- FlicenseNot gradedqualityDmaintenanceA 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.-