Skip to main content
Glama

mcp-noita-data

powered by dsh

把 Noita 解包后的 data/ 目录以 只读 MCP 工具暴露给模型。

只做数据获取,不做计算:不执行 Lua、不推导法术属性、不解析图片内容, 只负责把磁盘上的 XML / Lua / 文本原样读出来。

工具

工具

作用

list_dir(path="")

列出目录直接子项(名称、路径、类型、大小、扩展名)

read_text(path, offset=1, limit=400)

按行读取文本文件,返回总行数以便翻页

read_xml(path, max_nodes=200)

解析 XML 为嵌套字典(属性平铺、同名子节点转数组)

search(query, glob="**/*", regex=False, ...)

在文本内容中检索,返回文件 + 行号 + 行内容;有译文时支持中文查询

translate(text, limit=20)

在译文表里互查:$key → 译文,译文 → $key

spell(spell_id, max_tables=10)

把一个法术在 scripts/gun/*.lua 各版本表里的条目并列返回

spell_bundle(spell_id)

一次汇总:卡牌字段 + 全部组件(合并 <Base>)+ 粒子颜色 + 图集帧 + 音效 + 换算值

entity(path)

读取任意实体,合并一层 <Base>,返回未筛选的全部组件

路径统一使用游戏内写法,data/ 前缀可省略:

data/scripts/gun/gun_actions.lua
scripts/gun/gun_actions.lua        # 等价

Related MCP server: obsidian-mcp

安装与运行

uv sync
uv run noita-data-mcp --data-dir ./data

默认按以下顺序查找数据目录:

  1. 环境变量 NOITA_DATA_DIR

  2. 当前工作目录下的 data/

  3. 仓库根目录下的 data/

客户端配置

{
  "mcpServers": {
    "noita-data": {
      "command": "uv",
      "args": [
        "run", "--directory", "C:/Users/dynas/Documents/Code/mcp-noita-data",
        "noita-data-mcp", "--data-dir", "C:/Users/dynas/Documents/Code/mcp-noita-data/data"
      ]
    }
  }
}

设计说明

  • 路径隔离:所有路径先 resolve() 再校验是否位于数据根之下,.. 与绝对路径一律拒绝。

  • 只读:没有任何写盘操作;文件系统权限交给操作系统。

  • 不预扫描:4,000+ XML、1,000+ Lua 全部按需读取,避免启动时全量索引。

  • 返回有上限:read_text 按行分页,read_xml 按节点数截断并标记 _truncated, search 默认最多 50 条,避免单次结果撑爆上下文。

  • 二进制识别:按扩展名 + NUL 字节双重判断,图片/音频不会被当作文本读出。

  • UTF-8:启动时把 stdin/stdout 强制为 UTF-8,避免 Windows 控制台 GBK 破坏 JSON-RPC。

返回示例

read_text("scripts/gun/gun_actions.lua", offset=1, limit=2)
{
  "path": "data/scripts/gun/gun_actions.lua",
  "total_lines": 11126,
  "start_line": 1,
  "end_line": 2,
  "lines": ["dofile_once(\"data/scripts/gun/procedural/gun_action_utils.lua\")",
            "dofile_once(\"data/scripts/lib/utilities.lua\")"],
  "truncated": true
}

结构

src/noita_data/
├─ paths.py     # data/xxx -> 绝对路径,越界与盘符一律拒绝
├─ text.py      # 编码嗅探、二进制判定、按行分页
├─ xmljson.py   # XML -> 嵌套字典(多根兜底、节点预算)
├─ search.py    # glob + 正则/子串检索
└─ server.py    # MCP 工具与入口

本地化(translations)

译文来自 Noita 原生的 data/translations/*.csv(形如 "$action_light_bullet","火花弹")。 放进去即生效,也可以用环境变量指定:

set NOITA_TRANSLATIONS=D:\path\to\common.csv     # 或一个目录

有译文表时:

  • search("火花弹") 会先反查成 $action_light_bullet 再搜,命中行附带 translations;

  • translate("火花弹") 返回对应 key,translate("$action_light_bullet") 返回译文;

  • 没有译文表时两者安全降级,只是不能按中文查。

当前这份 dump 不含 data/translations/,所以开箱只能用 id 搜索。

开发

uv run pytest          # 10 个用例,覆盖路径、分页、XML、检索

示例:复刻一个法术需要什么

spell_bundle("POLLEN") 一次返回整条链(节选):

{
  "card": {"mana": "10", "price": "110", "spawn_level": "0,1,3,4",
           "action_effects": ["c.fire_rate_wait = c.fire_rate_wait + 2",
                              "c.spread_degrees = c.spread_degrees + 20"]},
  "projectiles": [{
    "body":   {"damage": "0.2", "lifetime": "750", "speed_min": "150", "speed_max": "250"},
    "velocity": {"gravity_y": "10", "air_friction": "2.8", "mass": "0.35"},
    "homing": {"homing_targeting_coeff": "10.0", "homing_velocity_multiplier": "0.89"},
    "particles": [{"material": "spark_white", "color": "7fFEFEFF", "glow": "90"}],
    "sprite": {"animation": {"frame_count": "4", "frame_width": "11", "frame_wait": "0.09"}},
    "audio": {"event_root": "player_projectiles/bullet_arrow"}
  }],
  "not_available": ["贴图像素", "音频采样", "引擎侧公式(追踪/碰撞/伤害换算)"]
}

数值来自 gun_actions.lua → related_projectiles → 实体 XML(合并一层 <Base>)→ materials.xml 的材质颜色 → projectiles_gfx/*.xml 的帧定义。全部只读。

同一法术的多份定义

scripts/gun/ 下有多张法术表(普通 / 有限法术 / 无限 / petri),字段并不相同。 spell("LIGHT_BULLET") 会把这些表里的条目并列列出(含行号区间):

_gun_actions_unlimited.lua  L1052-1067  mana=5  price=-    max_uses=-    name="Spark bolt"
gun_actions.lua             L43-63      mana=5  price=100  max_uses=-    name="$action_light_bullet"
gun_actions_limited.lua     L1146-1162  mana=5  price=-    max_uses=100  name="Spark bolt"
gun_actions_petri.lua       L1146-1162  mana=5  price=-    max_uses=-    name="Spark bolt"
gun_actions_unlimited.lua   L1052-1067  mana=5  price=-    max_uses=-    name="Spark bolt"

它按源码文本解析,不执行 Lua;要读函数体就用返回的 source 区间再 read_text。

范围

明确不做的事情:执行 Lua、计算法术派生数值、切分图集、渲染图片。 需要这类派生数据时应当在调用方完成,或另建一个构建期脚本,而不是塞进 MCP 工具。

致谢

Design inspired by Noita_Lib (GPL); no code copied.

Available Tools

8 tools
entityB

读取任意实体 XML,合并一层 ,返回它的全部组件。

组件不做筛选(Projectile / DamageModel / Homing / ParticleEmitter … 都保留), 适合自己实现行为逻辑时逐个组件取值。

Inputs: path (required). Returns: object

list_dirA

列出 data/ 下某个目录的直接子项(不递归)。

返回每一项的名称、游戏内路径、类型、大小与扩展名,用于定位文件。

Inputs: path. Returns: object

read_textA

按行读取一个文本文件(xml / lua / txt / csv 等)。

offset 为 1 起始行号,limit 为最多返回行数; 返回 total_lines 便于继续翻页。二进制文件会被拒绝。

Inputs: path (required), limit, offset. Returns: object

read_xmlB

把 XML 解析成嵌套字典返回。

属性直接平铺为键;同名子节点合并成数组;文本放在 "_text"。 max_nodes 限制节点总数,超出部分标记 "_truncated"。

Inputs: path (required), max_nodes. Returns: object

spellA

把一个法术在 scripts/gun/gun_actions*.lua 各版本表里的条目并列返回。

只解析源码文本,不执行 Lua、不做取舍:每个版本给出字段与行号区间, 需要看函数体时再用 read_text 按行区间读取。

Inputs: spell_id (required), max_tables. Returns: object

spell_bundleA

一次性汇总一个法术的数值:卡牌字段 + 投射物实体 + 特效 + 音效。

会自动跟随 related_projectiles、合并一层 、查 materials.xml 的粒子颜色、 读取 SpriteComponent 指向的图集帧定义。只读,不执行 Lua、不做换算。 拿不到的东西列在 not_available 里(贴图像素、音频采样、引擎公式)。

Inputs: spell_id (required). Returns: object

translateA

查询本地化词条:给 key 返回译文,给译文返回 key。

数据来自 data/translations/*.csv;文件不存在时 available=False, 此时搜索仍然可用,只是不能按中文等译文反查。

Inputs: text (required), limit. Returns: object

Tool Schema Changelog

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

Loading tool schema changelog…

    TDQS

    A3.7/5.0

    Scored across 8 tools

    Disambiguation4/5

    Most tools have clearly distinct purposes (directory listing, raw text read, XML parse, search, translation, entity read). There is mild overlap between spell / spell_bundle (both about spells, though one returns aggregated numbers and the other Lua source entries) and between entity / read_xml (both read entity XML), but the descriptions clarify the boundaries well enough.

    Naming Consistency3/5

    A partial verb_noun pattern exists (list_dir, read_text, read_xml), but it is broken by bare nouns (entity, spell) and noun compounds (spell_bundle), plus a bare verb (search, translate). Mixed conventions but each name is still readable and unambiguous.

    Tool Count5/5

    Eight tools is well-scoped for a read-only data-inspection server, and each tool covers a distinct layer (listing, raw IO, parsing, search, localization, domain-specific aggregation). No redundant or filler tools.

    Completeness4/5

    The surface covers the core read-only lifecycle: locate files, read raw text, parse XML, search content, resolve translations, and domain-specific entity/spell inspection. Minor gaps like a spell/entity index or bulk listing exist but search plus list_dir let agents work around them.

    Maintenance

    ActivityMaintained
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers