mcp ffxiv发光体
用于《最终幻想XIV》游戏数据的MCP(模型上下文协议)服务器,基于 流明娜.
通过MCP stdio传输提供对FFXIV游戏数据表的本地化、可查询访问。专为与Claude Desktop、AI助手和任何兼容MCP的客户端一起使用而设计。
______________________________________________________________________
先决条件
- .NET 10 SDK
- 本地FFXIV安装(PC或Steam——标准配置
SquareEnix/FINAL FANTASY XIV目录) - 游戏必须至少启动过一次,这样EXD数据文件才会出现在磁盘上
______________________________________________________________________
设置
# Clone and build
git clone https://github.com/MelkyWay/mcp-ffxiv-lumina
cd mcp-ffxiv-lumina
dotnet build -c Release
# Run directly, supplying gamePath on the command line
dotnet run --project src/McpLumina -- --McpLumina:GamePath "C:\Program Files (x86)\SquareEnix\FINAL FANTASY XIV - A Realm Reborn"______________________________________________________________________
配置
编辑 src/McpLumina/appsettings.json:
{
"McpLumina": {
"gamePath": "C:\\Program Files (x86)\\SquareEnix\\FINAL FANTASY XIV - A Realm Reborn",
"languageDefault": "en",
"cacheEnabled": true,
"cacheTTLSeconds": 300,
"logLevel": "Information",
"schemaPath": "C:\\path\\to\\EXDSchema"
}
}| 字段 | 类型 | 必填 | 默认 | 描述 |
|---|---|---|---|---|
gamePath | 字符串 | 是 | -- | FFXIV安装根目录的路径 |
languageDefault | string | 否 | "en" | 未指定时的默认语言: en, fr, de, ja |
cacheEnabled | bool | 否 | true | 启用内存中的响应缓存 |
cacheTTLSeconds | int | 否 | 300 | 缓存TTL(秒) |
logLevel | string | 否 | "Information" | 日志冗长(Trace, Debug, Information, Warning, Error) |
schemaPath | string | no | -- | 本地路径 EXD示意图 克隆。当设置时, describe_sheet 报告真实字段名,而不是 Column_N 指数。 |
所有设置也可以通过环境变量使用 McpLumina__ 前缀:
McpLumina__GamePath="C:\..." McpLumina__LanguageDefault=ja dotnet run --project src/McpLumina注: 所有日志记录都会进入stderr。stdout专门为MCP stdio帧流保留。
EXDSchema(可选)
EXD示意图 是一个由社区维护的FFXIV表列定义存储库。通过配置时 schemaPath, describe_sheet 返回真实字段名(例如。 Name, ClassJob)而不是位置索引(Column_0, Column_10),以及 get_row / search_rows 接受这些名字 return_fields 和 text_fields.
git clone https://github.com/xivdev/EXDSchema C:\EXDSchema
cd C:\EXDSchema
git checkout ver/2026.03.17.0000.0000 # branch matching your game version使用 refresh_schema 获取并切换到最新分支,而无需重新启动服务器。
______________________________________________________________________
MCP客户端配置
服务器通过以下方式进行通信 标准 使用MCP协议。任何兼容MCP的客户端(Claude Desktop、Cursor、带MCP扩展的VS Code、自定义代理等)都可以通过启动流程和管道stdio进行连接。
已发布二进制文件(推荐)
dotnet publish src/McpLumina -c Release -r win-x64 --self-contained -o publish/将您的客户端指向二进制文件:
command: C:\path\to\publish\mcp-lumina.exe
env: McpLumina__GamePath = C:\Program Files (x86)\SquareEnix\FINAL FANTASY XIV - A Realm Reborn任何代码更改后,重新运行 dotnet publish 并重新启动MCP客户端以获取新的二进制文件。已发布的二进制文件不会自动更新。当从多个客户端同时运行服务器时(例如Claude Desktop+Codex+自定义代理),强烈推荐这种方法。使用 dotnet run 相反,它将锁定调试二进制文件,并导致任何试图启动服务器的第二个客户端启动失败。
发展(dotnet run)
command: dotnet
args: run --project C:\path\to\mcp-ffxiv-lumina\src\McpLumina --no-launch-profile
env: McpLumina__GamePath = C:\Program Files (x86)\SquareEnix\FINAL FANTASY XIV - A Realm Reborn示例:克劳德桌面(claude_desktop_config.json)
{
"mcpServers": {
"ffxiv": {
"command": "C:\\path\\to\\publish\\mcp-lumina.exe",
"env": {
"McpLumina__GamePath": "C:\\Program Files (x86)\\SquareEnix\\FINAL FANTASY XIV - A Realm Reborn"
}
}
}
}______________________________________________________________________
工具参考
该服务器公开了四类二十七个工具:
- 服务器工具 --健康、模式管理、语言信息
- 通用图纸工具 --任意访问任何游戏数据表
- FFXIV便利工具 --常见游戏实体的预成形响应
- 补充工具 --社区维护的下降和补充数据(通过 转身)
______________________________________________________________________
health()
返回服务器状态、游戏版本、缓存设置和正常运行时间。使用此选项确认服务器是否正常运行,并检查自上次验证服务器以来游戏是否已修补。
{
"status": "ok",
"serverVersion": "1.0.0",
"gamePath": "C:\\...",
"detectedVersion": "2026.03.17.0000.0000",
"validatedVersion": "2026.03.17.0000.0000",
"schemaAvailable": true,
"schemaVersion": "ver/2026.03.17.0000.0000",
"cacheEnabled": true,
"cacheTTLSeconds": 300,
"uptimeSeconds": 42,
"warnings": []
}如果游戏已被修补, status 将是 "degraded" 带着一个 GameVersionMismatch 警告。通用工具(get_row, search_rows等等)不受影响;FFXIV便利工具(get_jobs, get_duties)可能会返回不正确的数据,直到 ServerConstants.cs 已更新。
如果配置了架构,但其分支版本比游戏版本旧 SchemaOutdated 发出警告。呼叫 refresh_schema 为了解决这个问题。
______________________________________________________________________
refresh_schema()
跑 git fetch + git checkout -B 在配置中 schemaPath 目录中提取最新的列定义,然后清除所有缓存的描述和响应数据,以便后续调用使用更新的模式。返回成功或失败的消息。
{ "refreshed": true, "message": "Checked out ver/2026.03.17.0000.0000." }如果 schemaPath 未配置,返回 ConfigError.如果git操作失败,则返回 InternalError 使用git输出。
______________________________________________________________________
list_languages()
返回四种支持的语言中的哪一种(en, fr, de, ja)在此安装中可用。
{
"languages": [
{ "code": "en", "displayName": "English", "available": true },
{ "code": "fr", "displayName": "French", "available": true },
{ "code": "de", "displayName": "German", "available": true },
{ "code": "ja", "displayName": "Japanese", "available": true }
]
}______________________________________________________________________
list_sheets()
返回此安装中可用的所有游戏数据表的名称。工作表名称解析自 exd/root.exl 在启动时进行缓存,并在服务器生命周期内进行缓存。结果按字母顺序排序。
{
"count": 756,
"sheets": ["Achievement", "Action", "BeastTribe", "ClassJob", "ContentFinderCondition", "Item", "..."]
}______________________________________________________________________
describe_sheet(sheet)
返回指定工作表的列元数据和近似行数。以前用这个 get_row 或 search_rows 了解可用字段及其类型。
{
"sheet": "ClassJob",
"rowCountApprox": 42,
"columns": [
{ "index": 0, "name": "Column_0", "type": "string" },
{ "index": 1, "name": "Column_1", "type": "string" },
{ "index": 7, "name": "Column_7", "type": "uint" },
{ "index": 30, "name": "Column_30", "type": "string" }
],
"languages": ["en", "fr", "de", "ja"]
}当配置EXDSchema时, name 值是真实的字段名(例如。 "Name", "ClassJob")而不是 Column_N列类型报告如下: string, bool, int, uint, float.
______________________________________________________________________
get_row(sheet, row_id, languages?)
返回单行的所有列值。当请求多种语言时,字符串列作为语言键词典返回。非字符串列返回标量值。
// Request
{ "sheet": "Item", "row_id": 2, "languages": "en,ja" }
// Response
{
"sheet": "Item",
"rowId": 2,
"languagesRequested": ["en", "ja"],
"languagesReturned": ["en", "ja"],
"fallbackUsed": false,
"fields": {
"Column_0": { "en": "Weathered Shortsword", "ja": "古びたショートソード" },
"Column_1": 1,
"Column_5": 0
}
}fallbackUsed: true 表示请求的语言不可用,已替换为另一种语言。
______________________________________________________________________
get_rows(sheet, row_ids, languages?)
批量 get_row。接受行ID数组。每次通话最多100个ID。缺少行ID的情况在中报告 missingRowIds.
// Request
{ "sheet": "Item", "row_ids": [1, 2, 3], "languages": "en" }
// Response
{
"rows": [...],
"missingRowIds": []
}______________________________________________________________________
search_rows(sheet, query, text_fields?, languages?, limit?, offset?, column_filters?)
在所有字符串列(或特定列)中搜索不区分大小写的子字符串匹配。在文本匹配之前,可以选择按精确的整数值对行进行预过滤。
// Request — all WHM actions containing "Holy"
{
"sheet": "Action",
"query": "Holy",
"text_fields": "Column_0",
"languages": "en",
"column_filters": "Column_10=24"
}
// Response
{
"sheet": "Action",
"query": "Holy",
"columnFilters": { "Column_10": 24 },
"totalMatches": 2,
"offset": 0,
"limit": 50,
"rowsScanned": 49000,
"results": [...]
}演出 这是整张纸的完整O(n)扫描。使用 text_fields 以限制搜索哪些字符串列。使用 column_filters 在文本匹配之前按整数值删除行——这在按引用列(如ClassJob)过滤时特别有效。
| 参数 | 默认值 | 最大值 |
|---|---|---|
limit | 50 | 200 |
offset | 0 | 10 000 |
______________________________________________________________________
get_jobs(languages?)
返回所有用派生角色分组丰富的ClassJob行(基类和作业)。
{
"jobs": [
{
"rowId": 19,
"name": { "en": "paladin", "ja": "ナイト" },
"abbreviation": { "en": "PLD", "ja": "ナイト" },
"role": "Tank",
"isJob": true,
"isLimited": false,
"jobIndex": 1
}
]
}注:name值是存储在游戏数据中的内部小写键(例如。"paladin"),而不是显示大写形式。
isJob: false--基层阶级(如掠夺者);isJob: true--工作(如战士)isLimited: true--蓝色法师role值:Tank,Healer,Melee DPS,Physical Ranged DPS,Magical Ranged DPS,Limited,None
注: role 标签仅为英文。它们是派生值,而不是来自游戏字符串。______________________________________________________________________
get_duties(category?, languages?)
返回ContentFinderCondition行,可选择按类别筛选。省略 category 退还所有税款。
类别: dungeon | trial | raid | ultimate | criterion | unreal
{
"category": "ultimate",
"count": 6,
"duties": [
{
"rowId": 1006,
"name": { "en": "Futures Rewritten (Ultimate)" },
"category": "ultimate",
"isHighEndDuty": true,
"levelRequired": 100,
"itemLevelRequired": 735
}
]
}贴片灵敏度: ContentType ID是针对特定游戏版本验证的硬编码常量(请参见ServerConstants.cs).A.GameVersionMismatch警告来自health()这意味着在依赖这些过滤器之前,应该对其进行重新验证。
______________________________________________________________________
get_items(query?, limit?, offset?, languages?)
按名称搜索项目表。返回物品等级、装备等级、堆栈大小、图标、稀有性、NPC价格和HQ资格。
| 参数 | 说明 |
|---|---|
query | 不区分大小写的名称子字符串过滤器 |
limit / offset | 分页(最大限制200) |
{
"totalMatches": 1,
"items": [
{
"rowId": 4179,
"name": { "en": "Hi-Potion" },
"icon": 20,
"itemLevel": 1,
"equipLevel": 0,
"stackSize": 999,
"rarity": 1,
"filterGroup": 8,
"priceMid": 150,
"canBeHq": false
}
]
}稀有度值: 1 =普通(白色), 2 =不常见(绿色), 3 =稀有(蓝色), 4 =遗迹(紫色)。
注: 项目名称以单数小写语法形式存储(例如。"potion",不"Potion").
______________________________________________________________________
get_actions(query?, classJobId?, limit?, offset?, languages?)
从动作表中搜索玩家动作(能力、法术、武器技能)。仅 IsPlayerAction = true 返回行,过滤掉约47k NPC/系统条目。
| 参数 | 说明 |
|---|---|
query | 不区分大小写的名称子字符串过滤器 |
classJobId | 按ClassJob行ID筛选(例如。 25 黑法师)。 0 =角色/跨类行动 |
limit / offset | 分页(最大限制200) |
{
"totalMatches": 31,
"actions": [
{
"rowId": 162,
"name": { "en": "Flare" },
"icon": 2652,
"classJobId": 25,
"classJobLevel": 50,
"actionCategoryId": 2,
"actionCategoryName": "Spell",
"isRoleAction": false,
"isPvP": false,
"castTimeMs": 2000,
"recastTimeMs": 2500,
"maxCharges": 0
}
]
}操作类别ID: 2 =拼写, 3 =武器, 4 =能力。铸造和重铸时间以毫秒为单位。 maxCharges > 1 表示基于电荷的冷却。
______________________________________________________________________
get_traits(query?, classJobId?, limit?, offset?, languages?)
从特质表中返回被动工作特征。结果按级别排序。
| 参数 | 说明 |
|---|---|
query | 不区分大小写的名称子字符串过滤器 |
classJobId | 按ClassJob行ID筛选(例如。 24 白法师) |
limit / offset | 分页(最大限制200) |
{
"totalMatches": 12,
"traits": [
{
"rowId": 47,
"name": { "en": "Maim and Mend" },
"description": { "en": "Increases the potency of physical attacks by 10% and all healing magic potency by 30%." },
"classJobId": 22,
"level": 20
}
]
}______________________________________________________________________
get_statuses(query?, category?, limit?, offset?, languages?)
从“状态”工作表中搜索状态效果(缓冲和去缓冲)。
| 参数 | 说明 |
|---|---|
query | 不区分大小写的名称子字符串过滤器 |
category | beneficial 或 detrimental.全部省略。 |
limit / offset | 分页(最大限制200) |
{
"totalMatches": 1,
"statuses": [
{
"rowId": 17,
"name": { "en": "Paralysis" },
"description": { "en": "Unable to execute actions." },
"icon": 215003,
"statusCategory": 2,
"statusCategoryName": "detrimental",
"canDispel": true,
"maxStacks": 0
}
]
}maxStacks = 0 表示状态不可堆叠。
______________________________________________________________________
get_mounts(query?, limit?, offset?, languages?)
从“装载”表中搜索装载。
{
"totalMatches": 3,
"mounts": [
{
"rowId": 1,
"name": { "en": "Company Chocobo" },
"icon": 4087,
"isFlying": true,
"extraSeats": 0
}
]
}extraSeats > 0 表示多座安装。
______________________________________________________________________
get_minions(query?, limit?, offset?, languages?)
从“伙伴”表中搜索小黄人(伙伴)。
{
"totalMatches": 1,
"minions": [
{
"rowId": 8,
"name": { "en": "Bahamut" },
"icon": 59114
}
]
}______________________________________________________________________
get_achievements(query?, limit?, offset?, languages?)
从成就表中搜索成就。
{
"totalMatches": 1,
"achievements": [
{
"rowId": 1,
"name": { "en": "To Crush Your Enemies I" },
"description": { "en": "Defeat 100 enemies." },
"points": 5,
"icon": 112001,
"achievementCategoryName": "Battle"
}
]
}______________________________________________________________________
get_races(languages?)
返回比赛表中的所有八场比赛。每个种族都有男性和女性的名字(可能因语言而异)。
行ID: 1=海尔, 2=Elezen, 3=拉拉费尔, 4= 混合, 5= 罗加丁, 6=Au-Ra, 7= 格鲁吉亚, 8= 观看
{
"races": [
{
"rowId": 4,
"masculine": { "en": "Miqo'te", "ja": "ミコッテ" },
"feminine": { "en": "Miqo'te", "ja": "ミコッテ" }
}
]
}______________________________________________________________________
get_worlds(query?)
从世界表中返回公共玩家可访问的世界(服务器)及其数据中心。
{
"totalMatches": 1,
"worlds": [
{
"rowId": 73,
"name": "Cactuar",
"internalName": "Cactuar",
"dataCenterId": 8,
"dataCenterName": "Aether",
"isPublic": true
}
]
}注: 世界名称是专有名词,在所有语言中都是相同的。
______________________________________________________________________
get_weather(query?, limit?, offset?, languages?)
从天气表中搜索天气类型。
{
"totalMatches": 2,
"weathers": [
{
"rowId": 7,
"name": { "en": "Rain", "ja": "雨" },
"icon": 60913
}
]
}______________________________________________________________________
get_titles(query?, limit?, offset?, languages?)
从标题表中搜索玩家标题。每个标题都有男性和女性的形式,以及一个位置标志。
{
"totalMatches": 1,
"titles": [
{
"rowId": 1,
"masculine": { "en": "the Insatiable" },
"feminine": { "en": "the Insatiable" },
"isPrefix": false
}
]
}isPrefix: true --标题出现在角色名称之前(例如。 "Warrior of Light Firstname"). isPrefix: false --出现在(例如。 "Firstname the Insatiable").
______________________________________________________________________
get_currencies(languages?)
从物品表中返回游戏内货币(吉尔、巨石、印章、MGP等)。由...确定 ItemUICategory = 63, FilterGroup = 16, StackSize > 1.
{
"currencies": [
{
"rowId": 1,
"name": { "en": "Gil" },
"icon": 65002,
"stackSize": 999999999
},
{
"rowId": 28,
"name": { "en": "Allagan Tomestone of Poetics" },
"icon": 65023,
"stackSize": 2000
}
]
}stackSize 是每个字符的上限。
______________________________________________________________________
get_materia(query?, stat?, limit?, offset?, languages?)
从物料表中搜索物料项。返回每个材质项目的增强属性、级别(I-XII)和奖励值。结果按统计名称和级别排序。
query--项目名称子字符串过滤器(例如。"Savage Aim")stat--英文统计名称子字符串过滤器(例如。"Critical Hit","Gathering")- 输出中的统计名称始终为英语(专有名词,跨地区相同)
bonus是0适用于前天堂主属性(力量/敏捷性/活力/智力/心智等级I-VI),其中每一等级的值未存储在表格中
{
"totalMatches": 12,
"materia": [
{
"rowId": 5669,
"name": { "en": "Savage Aim Materia I" },
"icon": 20221,
"stat": "Critical Hit",
"baseParamId": 27,
"tier": 1,
"bonus": 1
},
{
"rowId": 41772,
"name": { "en": "Savage Aim Materia XII" },
"icon": 20298,
"stat": "Critical Hit",
"baseParamId": 27,
"tier": 12,
"bonus": 54
}
]
}奖金等级因统计组而异。一些例子:
| 统计组 | I | II | III | IV | V | VI | VIII | IX | X | neneneba十一 | XII | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 战斗子目标(暴击、突袭等) | 1 | 2 | 3 | 4 | 6 | 16 | 8 | 24 | 12 | 36 | 18 | 54 |
| 收集/感知 | 3 | 4 | 5 | 6 | 10 | 15 | 12 | 20 | 14 | 25 | 20 | 36 |
| 工艺 | 3 | 4 | 5 | 6 | 11 | 16 | 14 | 21 | 18 | 27 | 22 | 33 |
| CP/GP | 1 | 2 | 3 | 4 | 6 | 8 | 7 | 9 | 8 | 10 | 9 | 11 |
______________________________________________________________________
get_localized_labels(kind, languages?)
返回知名FFXIV枚举的标签集,适用于填充UI下拉菜单或构建查找表。
种类值: jobs | roles | categories | ultimates | criterion | unreal
{
"kind": "jobs",
"labels": [
{ "rowId": 19, "name": { "en": "Paladin", "ja": "ナイト" } }
]
}______________________________________________________________________
get_tomestone_currencies(status?, languages?)
返回Allagan Tomestone货币 TomestonesItem 纸张,显示其当前的旋转状态。状态来源于稳定 Category 表中的字段——基础项名称会更改每个补丁,但映射不会。
| 状态 | 含义 | 示例(补丁7.2) |
|---|---|---|
current | 活跃有限tomestone(每周上限) | 数学 |
previous | 以前的有限tomestone | 助记 |
older | 旧版限量版tomestone | 太阳测量学 |
poetics | 永恒的无上限巨著 | 诗学的Allagan tomestone |
retired | 不再流通的历史巨著 | 神话、士兵、法律 |
省略 status 全部归还。结果首先按当前排序。
{
"totalMatches": 23,
"currencies": [
{
"rowId": 48,
"name": { "en": "Allagan Tomestone of Mathematics" },
"icon": 65049,
"status": "current",
"stackSize": 2000
},
{
"rowId": 28,
"name": { "en": "Allagan Tomestone of Poetics" },
"icon": 65023,
"status": "poetics",
"stackSize": 2000
}
]
}______________________________________________________________________
get_mob_drops(monsterQuery?, itemQuery?, limit?, offset?, languages?)
从维护的社区返回怪物掉落数据 转身 数据集(2644怪物→项目对)。每个条目都将一个怪物链接到它可以掉落的物品。没有可用的下降率或数量数据,只有对。
| 参数 | 说明 |
|---|---|
monsterQuery | 不区分大小写的怪物名称子字符串过滤器 |
itemQuery | 不区分大小写的项目名称子字符串过滤器 |
limit / offset | 分页(最大限制200) |
{
"totalMatches": 4,
"drops": [
{
"bNpcNameId": 2061,
"mobName": { "en": "elder hapalit" },
"itemId": 5439,
"itemName": { "en": "Ogre Horn" }
}
]
}两者monsterQuery和itemQuery可以组合以将结果缩小到特定的怪物/物品对。
______________________________________________________________________
get_triple_triad_cards(query?, limit?, offset?, languages?)
返回从连接的Triple Triad卡数据 TripleTriadCard 和 TripleTriadCardResident。包括定向游戏价值、明星稀有性、卡片类型、售价、风味文本和获取来源。
| 参数 | 说明 |
|---|---|
query | 不区分大小写的卡片名称子字符串过滤器 |
limit / offset | 分页(最大限制200) |
{
"totalMatches": 465,
"cards": [
{
"rowId": 42,
"name": { "en": "Garuda", "ja": "ガルーダ" },
"description": { "en": "Summoned by the Ixal tribes of Xelphatol..." },
"startsWithVowel": false,
"top": 7,
"bottom": 1,
"left": 7,
"right": 6,
"stars": 3,
"type": "Primal",
"saleValue": 500,
"acquisitionSource": "Challenge: Vorsaile Heuloix",
"obtainTypeIcon": 60051
}
]
}stars--稀有等级1-5(★至★★★★★)type—Normal|Primal|Scion|Society|GarleansaleValue--NPC卖出价格(单位:gil);0意味着无法销售acquisitionSource—"Challenge: [NPC name]"对于从NPC挑战者手中赢得的卡片,"Requires: [Quest name]"用于内容门控卡,或null如果未知obtainTypeIcon--获取方法的图标ID(如果不可用,则为0)type和acquisitionSource以所请求的主要语言解决;top/bottom/left/right语言中立
______________________________________________________________________
错误响应
所有工具在失败时返回结构化错误:
{
"code": "SheetNotFound",
"message": "Sheet 'Foobaz' was not found in the game data.",
"detail": null
}| 代码 | 含义 |
|---|---|
ConfigError | 配置无效或缺失(例如。 schemaPath 通话时未设置 refresh_schema) |
SheetNotFound | 游戏数据中不存在命名表 |
RowNotFound | 工作表中不存在行ID |
LanguageUnavailable | 请求的语言代码无效或未安装 |
ValidationError | 输入参数值错误 |
InternalError | 意外的服务器错误 |
______________________________________________________________________
测试
所有测试
FFXIV_GAME_PATH="C:/Program Files (x86)/SquareEnix/FINAL FANTASY XIV - A Realm Reborn" dotnet test仅进行单元测试(无需安装FFXIV)
dotnet test --filter "Category!=Integration"仅集成测试
FFXIV_GAME_PATH="C:/..." dotnet test --filter "Category=Integration"如果 FFXIV_GAME_PATH 未设置,集成测试已设置 跳过 而不是失败——CI在没有安装游戏的情况下通过。
快照测试
快照基线 get_jobs 和 get_duties (最后通牒)住在 tests/McpLumina.Tests/Integration/Snapshots/他们根据已知的好游戏版本验证工具响应的确切形状和内容。
补丁后,如果快照失败:
- 新增工作或职责→ 更新快照文件(预期漂移)
- 数据混乱或类型错误→ 列索引
ServerConstants.cs需要更新(请参阅下面的维护)
______________________________________________________________________
维护:补丁后运行手册
便利工具(get_jobs, get_duties, get_actions, get_items)使用 Lumina.Excel 键入具有命名属性的工作表,因此游戏数据中的列布局会发生变化 不 需要手动更新索引。唯一对补丁敏感的值是用于职责类别筛选的ContentType ID。
- 检查Lumina的新版本。 Lumina通常在FFXIV主要补丁发布后的几天内发布更新的NuGet包。更新中的版本
src/McpLumina/McpLumina.csproj重建:
dotnet build- 运行集成测试:
FFXIV_GAME_PATH="C:/..." dotnet test --filter "Category=Integration"- 如果职责类别过滤返回错误结果,验证中的ContentType ID
ServerConstants.cs(ContentTypeIds)仍然可以通过检查ContentType表来映射到正确的内容类别get_row.
- 碰撞
KnownGoodGameVersion.Value在ServerConstants.cs到新游戏版本字符串(从game/ffxivgame.ver).
- 运行完整的测试套件 --所有220个测试都应该运行(147个单元通过,无需安装游戏;73个集成需要
FFXIV_GAME_PATH).
- 刷新EXDSchema 如果已配置:
refresh_schema()或手动: cd && git fetch && git checkout ver/.
- 重新发布二进制文件 因此MCP客户端会获取更新的版本:
dotnet publish src/McpLumina -c Release -r win-x64 --self-contained -o publish/然后重新启动所有连接的MCP客户端(Claude Desktop、Codex等)。
- 发布时,请注明已验证的FFXIV补丁版本。
______________________________________________________________________
架构说明
补丁弹性
通用工具(get_row, search_rows等)使用Lumina的非类型化 RawExcelSheet / RawRow API和对修补程序后的列布局更改不敏感。FFXIV专用便利工具(get_jobs, get_duties, get_actions, get_items)使用 Lumina.Excel 源生成的键入工作表(ClassJob, ContentFinderCondition, Action, Item)具有命名属性,因此它们也能适应列布局的变化——只有ContentType ID常量 ServerConstants.cs 补丁后需要手动验证。
缓存
响应以可配置的TTL(默认5分钟)缓存在内存中。工作表列表在服务器生命周期内缓存。 describe_sheet 结果缓存在生命周期字典中(服务器运行时它们不会更改) ResponseCacheService.呼叫 refresh_schema 清除两个缓存,以便立即反映更新的列名。缓存在重新启动后不会持久化。
______________________________________________________________________
已知限制(V1)
- 角色标签仅为英文。
get_jobs回报"Tank","Healer"等作为硬编码的英文字符串,而不是游戏源的本地化标签。 get_actions返回内部操作名称。 操作表存储内部小写名称;显示名称(大写)不能通过简单键入的字段获得。- 没有跨表链接解析。 参考其他表格(例如。
ClassJob → ClassJobCategory)在通用工具中不会自动遵循。 - 没有查询DSL。 没有SQL风格的WHERE子句。使用
search_rows用于文本搜索和get_row/get_rows对于已知的ID。 search_rows这是一次全面扫描。 没有索引。大纸张(操作:~49k行,项目:~44k行)在每次调用时扫描每一行。- ContentType ID是硬编码的。 职责类别过滤依赖于已知的ContentType行ID,这些ID依赖于补丁版本。
- 仅限stdio传输。 V1不支持HTTP/SSE传输。
- 仅限内存缓存。 缓存不会在服务器重新启动时持久化。
______________________________________________________________________
工具合同版本控制
工具输入/输出模式遵循semver约定:
- 补丁 (1.0.x):仅修复Bug;没有架构更改
- 次要的 (1.x.0):仅添加更改——新的可选响应字段、新工具
- 主要的 (x.0.0):中断模式更改;提供迁移说明
除非按要求记录,否则消费者应将所有响应字段视为可能为空,并应忽略未知字段以实现前向兼容性。
