UNPKG

endfield-mcp

Version:

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

182 lines • 10.4 kB
/** * GameData tool registrations — character domain (v0.3.0). * * Five `ef_` tools over the CharacterTable, split by use case to mirror * PRTS-MCP's proven three-way separation: * * - ef_get_character_archives → background story text (fan-creation core) * - ef_get_character_voices → voice line text (fan-creation core) * - ef_get_character_basic_info → numeric info (profession/rarity/CV) * - ef_list_characters → roster listing * - ef_search_characters → regex search across key fields * * Tool descriptions are Chinese; data returned uses the process-default * language (CN) unless the tool exposes a `lang` option. */ import { z } from "zod"; import { getCharacterArchives, getCharacterVoices, } from "../data/characterProfiles.js"; import { getCharacterInfo, listCharacters, searchCharacters, } from "../data/characters.js"; import { SUPPORTED_LANGUAGES } from "../data/datasets.js"; import { withGracefulError } from "./toolRuntime.js"; const langSchema = z .enum(SUPPORTED_LANGUAGES) .default("CN"); export function registerGamedataTools(server) { // ----- Fan-creation core: archives + voices ----- server.tool("ef_get_character_archives", [ "读取角色的档案资料(背景故事文本,人物向同人创作的核心素材)。", "返回角色的基础档案、人事简述、档案资料等背景故事文本。需要角色 ID(从 ef_list_characters 获取)或准确角色名(默认语言或英文)。", "适用场景:写同人需要角色的背景设定、身世、人际关系等叙事素材时使用。若要台词语气用 ef_get_character_voices,若要职业/星级等数值用 ef_get_character_basic_info。", ].join(" "), { id_or_name: z .string() .describe("角色 ID(如 chr_0002_endminm)或准确角色名(如「管理员」「Endministrator」)。"), lang: langSchema.describe("返回内容使用的语言,默认 CN(简体中文)。"), }, withGracefulError("GameData", async ({ id_or_name, lang }) => { const archives = getCharacterArchives(id_or_name, lang); if (archives === null) { return { content: [ { type: "text", text: `未找到角色「${id_or_name}」的档案数据。请用 ef_list_characters 查看所有可用 ID 或名称。`, }, ], }; } if (archives.length === 0) { return { content: [{ type: "text", text: `角色「${id_or_name}」暂无档案资料。` }], }; } const parts = archives.map((a) => `## ${a.title}\n\n${a.text}`); return { content: [{ type: "text", text: parts.join("\n\n---\n\n") }] }; })); server.tool("ef_get_character_voices", [ "读取角色的语音台词(塑造角色语气和语言风格的核心素材)。", "返回约 55 条带触发条件(如「行动准备1」「编入队伍1」「观看作战记录」)及对应台词文本的完整列表。需要角色 ID 或准确角色名。", "适用场景:要让角色「开口说话」、还原其说话习惯/口头禅/语气,或需要战斗/日常台词原文时使用。若要背景故事用 ef_get_character_archives,若要数值定位用 ef_get_character_basic_info。", ].join(" "), { id_or_name: z .string() .describe("角色 ID(如 chr_0005_chen)或准确角色名(如「陈千语」「Chen Qianyu」)。"), lang: langSchema.describe("返回内容使用的语言,默认 CN。"), }, withGracefulError("GameData", async ({ id_or_name, lang }) => { const voices = getCharacterVoices(id_or_name, lang); if (voices === null) { return { content: [ { type: "text", text: `未找到角色「${id_or_name}」的语音数据。请用 ef_list_characters 查看所有可用 ID 或名称。`, }, ], }; } if (voices.length === 0) { return { content: [{ type: "text", text: `角色「${id_or_name}」暂无语音台词。` }], }; } const lines = voices.map((v) => `**[${v.index}] ${v.title}**:${v.text}`); return { content: [{ type: "text", text: lines.join("\n") }] }; })); // ----- Numeric info ----- server.tool("ef_get_character_basic_info", [ "查询角色的基本数值信息(职业、星级、属性、武器、声优等)。", "返回职业、稀有度(星级)、属性、武器类型、声优(中/英/日/韩)、阵营等结构化字段。需要角色 ID 或准确角色名。", "适用场景:需要快速确认角色定位、属性克制、星级、声优或所属阵营时使用。若要背景故事用 ef_get_character_archives,若要台词用 ef_get_character_voices。", ].join(" "), { id_or_name: z .string() .describe("角色 ID(如 chr_0002_endminm)或准确角色名。"), lang: langSchema.describe("名称字段使用的语言,默认 CN。声优字段始终返回全部四种语言。"), }, withGracefulError("GameData", async ({ id_or_name, lang }) => { const info = getCharacterInfo(id_or_name, lang); if (info === null) { return { content: [ { type: "text", text: `未找到角色「${id_or_name}」。请用 ef_list_characters 查看所有可用 ID 或名称。`, }, ], }; } const lines = [ `# ${info.name}${info.engName ? ` (${info.engName})` : ""}`, "", `- **ID**: ${info.id}`, `- **职业**: ${info.profession} (code ${info.professionCode})`, `- **稀有度**: ${info.rarity}★`, `- **属性**: ${info.charType}`, `- **武器类型**: ${info.weaponType} (code ${info.weaponTypeCode})`, `- **阵营**: ${info.department}`, `- **默认武器**: ${info.defaultWeaponId || "(无)"}`, ]; const cv = info.cvNames; if (cv.chinese || cv.english || cv.japanese || cv.korean) { lines.push("- **声优**:"); if (cv.chinese) lines.push(` - 中文: ${cv.chinese}`); if (cv.english) lines.push(` - 英文: ${cv.english}`); if (cv.japanese) lines.push(` - 日文: ${cv.japanese}`); if (cv.korean) lines.push(` - 韩文: ${cv.korean}`); } return { content: [{ type: "text", text: lines.join("\n") }] }; })); // ----- Roster listing + search ----- server.tool("ef_list_characters", [ "列出《明日方舟:终末地》的所有可玩角色(浏览角色名册)。", "返回每个角色的 ID、名称、职业、稀有度、属性和阵营的简表,按游戏内排序。这是探索角色数据的第一步——先拿准确 ID 或名称,再传给 ef_get_character_archives(档案)/ ef_get_character_voices(语音)/ ef_get_character_basic_info(数值)。", "适用场景:不确定角色 ID 或准确名、想浏览全部角色、或需要批量获取角色列表时使用。若已知要找的角色特征(职业/属性/阵营),用 ef_search_characters 更直接。", ].join(" "), { lang: langSchema.describe("返回内容使用的语言,默认 CN(简体中文)。"), }, withGracefulError("GameData", async ({ lang }) => { const list = listCharacters(lang); if (list.length === 0) { return { content: [{ type: "text", text: "角色表为空或数据未同步。" }], }; } const header = `# 角色(共 ${list.length} 个)\n`; const body = list .map((c) => `- **${c.id}** ${c.name}${c.engName ? ` (${c.engName})` : ""} — ${c.profession} / ${c.rarity}★ / ${c.charType} / ${c.department}`) .join("\n"); return { content: [{ type: "text", text: header + body }] }; })); server.tool("ef_search_characters", [ "按特征模糊查找角色(正则搜索名称/职业/属性/阵营等字段)。", "用于按职业、属性、星级、阵营等特征定位角色,如「近卫」「6」「Physical」「ENDFIELD」。搜索范围:名称(默认语言 + 英文)、ID、职业、属性(含中文映射)、阵营,返回匹配字段和简短摘要。", "适用场景:知道角色特征但不知确切名(如「找一个 6 星火属性重装」)、或要按阵营/职业筛选一批角色时使用。若想浏览全部角色用 ef_list_characters,拿到 ID 后再查档案/语音/数值。", ].join(" "), { pattern: z .string() .max(200, "搜索模式过长(上限 200 字符),请缩短后重试。") .describe("正则表达式(大小写不敏感,上限 200 字符),如「近卫」「6」「Physical」「ENDFIELD」。无效正则会退化为字面子串匹配。"), max_results: z .number() .int() .min(1) .max(100) .default(30) .describe("返回结果数量上限,默认 30。"), lang: langSchema.describe("名称字段使用的语言,默认 CN。"), }, withGracefulError("GameData", async ({ pattern, max_results, lang }) => { const results = searchCharacters(pattern, max_results, lang); if (results.length === 0) { return { content: [{ type: "text", text: `未找到匹配「${pattern}」的角色。` }], }; } const header = `# 搜索「${pattern}」(${results.length} 条匹配)\n`; const body = results .map((r) => `**${r.id}** ${r.name}\n${r.snippet}`) .join("\n\n---\n\n"); return { content: [{ type: "text", text: header + body }] }; })); } //# sourceMappingURL=gamedataTools.js.map