UNPKG

endfield-mcp

Version:

MCP Server for Arknights: Endfield (TypeScript / stdio + Streamable HTTP)

176 lines • 9.93 kB
/** * Worldview tool registrations — PRTS archive + in-game encyclopedia. * * Four `ef_` tools over the worldview bundle (v0.4). These expose the * in-game lore system that was previously completely inaccessible — the * PRTS archive (documents/records/multimedia/investigations) and the * in-game encyclopedia (monster/item/weapon entries with cross-linked lore). * * - ef_list_lore_categories → browse the archive + wiki top-level trees * - ef_search_lore → regex search across all PRTS documents * - ef_read_lore_document → read one document's full body text * - ef_get_wiki_entry → read a wiki entry + its linked lore doc */ import { z } from "zod"; import { hasWorldviewData, listLoreCategories as _listLoreCategories, listWikiCategories as _listWikiCategories, readLoreDocument as _readLoreDocument, readWikiEntry as _readWikiEntry, searchWorldview as _searchWorldview, wikiEntriesForPrts as _wikiEntriesForPrts, } from "../data/worldview.js"; import { withGracefulError } from "./toolRuntime.js"; function worldviewNotAvailable() { return { content: [ { type: "text", text: "世界观数据暂不可用。worldview bundle 可能尚未同步——请稍候(后台 sync 进行中)或检查网络连接。", }, ], }; } export function registerWorldviewTools(server) { server.tool("ef_list_lore_categories", [ "列出《明日方舟:终末地》游戏内 PRTS 档案系统与百科系统的分类结构(世界观浏览入口)。", "返回两部分:PRTS 档案分类(collection 收藏/document 文档/media 媒体/paper 报告等,含各分类下的一级条目组数量)+ 游戏内百科分类(building 建筑/equip 装备/item 物品/monster 怪物/weapon 武器等)。拿到分类 ID 后,PRTS 侧用 ef_search_lore 直接检索文档,或用 ef_read_lore_document 读已知 ID 的文档。", "适用场景:想系统浏览世界观素材范围、了解 PRTS 档案有哪些类目、或确认某个主题大致归属哪类时使用。这是探索世界观的第一步。若已知关键词要直接找文档,用 ef_search_lore 更快。", ].join(" "), {}, withGracefulError("worldview bundle", async () => { if (!hasWorldviewData()) return worldviewNotAvailable(); const cats = _listLoreCategories(); const wikiCats = _listWikiCategories(); const parts = []; parts.push(`# PRTS 档案分类(共 ${cats.length} 个)`); if (cats.length === 0) { parts.push("(无)"); } else { parts.push(cats .map((c) => `- **${c.categoryId}** ${c.displayName}(${c.groupCount} 个条目组)`) .join("\n")); } parts.push(""); parts.push(`# 游戏内百科分类(共 ${wikiCats.length} 个)`); if (wikiCats.length === 0) { parts.push("(无)"); } else { parts.push(wikiCats .map((c) => `- **${c.categoryId}** ${c.displayName}(${c.groupCount} 个组)`) .join("\n")); } return { content: [{ type: "text", text: parts.join("\n") }] }; })); server.tool("ef_search_lore", [ "在所有 PRTS 档案文档中执行正则全文搜索(跨世界观找素材)。", "用于按关键词、人名、地名、组织、事件等检索游戏内 PRTS 档案(文档/记录/多媒体),如「塔卫二」「源石」「天使」。搜索范围覆盖每个文档的标题+正文。返回匹配的文档 ID、类型和上下文片段。", "适用场景:记得某个世界观概念但不知具体在哪篇文档、想找某组织的所有提及、或要搜集某个设定/事件的所有出处时使用。拿到文档 ID 后用 ef_read_lore_document 读全文。若想浏览分类结构用 ef_list_lore_categories。", ].join(" "), { pattern: z .string() .max(200, "搜索模式过长(上限 200 字符),请缩短后重试。") .describe("正则表达式(大小写不敏感,上限 200 字符),如「塔卫二」「源石」「天使」。无效正则会退化为字面子串匹配。"), max_results: z .number() .int() .min(1) .max(100) .default(30) .describe("返回结果数量上限,默认 30。"), }, withGracefulError("worldview bundle", async ({ pattern, max_results }) => { if (!hasWorldviewData()) return worldviewNotAvailable(); const results = _searchWorldview(pattern, max_results); if (results.length === 0) { return { content: [{ type: "text", text: `未找到匹配「${pattern}」的世界观文档。` }], }; } const header = `# 搜索「${pattern}」(${results.length} 条匹配)\n`; const body = results .map((r) => `**${r.itemId}** | ${r.type} | ${r.title}\n${r.snippet}`) .join("\n\n---\n\n"); return { content: [{ type: "text", text: header + body }] }; })); server.tool("ef_read_lore_document", [ "读取一个 PRTS 档案文档的完整正文(阅读世界观原文的核心工具)。", "返回该文档的标题、正文全文、所属分类、类型(document/record/multi_media)。需要文档 ID(从 ef_search_lore 获取,如「nar_document_v0d8_10_1」)。若该文档被游戏内百科条目引用,会附上关联的百科条目 ID 列表。", "适用场景:已通过搜索或浏览定位到某个文档、想读它的完整原文时使用。多媒体类文档可能无正文(仅有标题),属正常情况。若还不知文档 ID,先用 ef_search_lore 或 ef_list_lore_categories 查找。", ].join(" "), { doc_id: z .string() .describe("文档 ID(PRTS 条目 id),如「nar_document_v0d8_10_1」「nar_record_map02_1_1」。从 ef_search_lore 获取。"), }, withGracefulError("worldview bundle", async ({ doc_id }) => { if (!hasWorldviewData()) return worldviewNotAvailable(); const doc = _readLoreDocument(doc_id); if (doc === null) { return { content: [ { type: "text", text: `未找到文档「${doc_id}」。请确认 ID 正确(从 ef_search_lore 获取)。`, }, ], }; } const parts = []; parts.push(`# ${doc.title}`); parts.push(`*类型:${doc.type} | 分类:${doc.categoryId || "未知"} | ID:${doc.itemId}*`); if (doc.description.length > 0) { parts.push(""); parts.push(`> ${doc.description}`); } parts.push(""); parts.push(doc.body.length > 0 ? doc.body : "(该文档无正文内容)"); // Surface wiki entries that reference this document (reverse cross-link). const refs = _wikiEntriesForPrts(doc.itemId); if (refs.length > 0) { parts.push(""); parts.push(`**关联百科条目**(${refs.length} 个):`); parts.push(refs.map((id) => `- ${id}`).join("\n")); } return { content: [{ type: "text", text: parts.join("\n") }] }; })); server.tool("ef_get_wiki_entry", [ "读取一个游戏内百科条目(怪物/物品/武器/建筑等条目详情)。", "返回该百科条目的所属分类组、关联的 PRTS 档案文档 ID(若有)、描述。百科条目的 ID 形如「wiki_eny_0018_lbtough」「wiki_item_...」。拿到关联的 prtsId 后可传给 ef_read_lore_document 阅读该条目的世界观背景文档。", "适用场景:想了解某个游戏内实体的百科信息(如某怪物的设定归属)、或要顺藤摸瓜找到它关联的世界观文档时使用。这是连接「游戏机制」与「叙事设定」的桥梁。若要直接搜文档用 ef_search_lore。", ].join(" "), { entry_id: z .string() .describe("百科条目 ID,如「wiki_eny_0018_lbtough」。形如 wiki_eny_/wiki_item_/wiki_equip_ 等。"), }, withGracefulError("worldview bundle", async ({ entry_id }) => { if (!hasWorldviewData()) return worldviewNotAvailable(); const entry = _readWikiEntry(entry_id); if (entry === null) { return { content: [ { type: "text", text: `未找到百科条目「${entry_id}」。请确认 ID 正确(形如 wiki_eny_*/wiki_item_*/wiki_equip_*)。`, }, ], }; } const parts = []; parts.push(`# 百科条目 ${entry.entryId}`); parts.push(`*所属组:${entry.groupName}(${entry.groupId})*`); if (entry.description.length > 0) { parts.push(""); parts.push(`> ${entry.description}`); } if (entry.prtsId) { parts.push(""); parts.push(`**关联世界观文档**:\`${entry.prtsId}\`(用 ef_read_lore_document 阅读全文)`); } if (entry.refItemId || entry.refMonsterTemplateId) { parts.push(""); const refs = []; if (entry.refItemId) refs.push(`物品引用:\`${entry.refItemId}\``); if (entry.refMonsterTemplateId) { refs.push(`怪物模板:\`${entry.refMonsterTemplateId}\``); } parts.push(`*${refs.join(" | ")}*`); } return { content: [{ type: "text", text: parts.join("\n") }] }; })); } //# sourceMappingURL=worldviewTools.js.map