UNPKG

endfield-mcp

Version:

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

123 lines • 5.72 kB
/** * Runtime configuration for Endfield-MCP. * * Path design mirrors PRTS-MCP's config layer, adapted for the Endfield * data-source reality: * * - Wiki content is fetched live from endfield.wiki.gg (MediaWiki 1.43.6), * not from a local sync. The WAF there requires browser-like headers, * so USER_AGENT / WIKI_REFERER / WIKI_ACCEPT are first-class config. * * - GameData is mirrored to a self-hosted release repository (text-only * JSON tables, no binary assets). EF_DATA_PATH points at the on-disk * location where auto-sync writes those tables. A user-set EF_DATA_PATH * disables auto-sync exactly like PRTS-MCP's GAMEDATA_PATH. * * Path priority (highest → lowest): * 1. EF_DATA_PATH env var — user-supplied; auto-sync DISABLED. * 2. /data/endfield — Docker volume (detected via * EF_MCP_ROOT == "/app"). * 3. Per-user data dir — %LOCALAPPDATA%\endfield-mcp\ (Win) * ~/.local/share/endfield-mcp/ (Unix). */ import { existsSync, statSync } from "node:fs"; import { homedir } from "node:os"; import { dirname, join } from "node:path"; import { fileURLToPath } from "node:url"; // --------------------------------------------------------------------------- // Wiki endpoint constants // --------------------------------------------------------------------------- /** * Default MediaWiki API endpoint for the Endfield Talos Wiki. * endfield.wiki.gg runs MediaWiki 1.43.6; its WAF blocks bare/curl-like * User-Agents, so requests must carry a browser UA + Referer (see * endfieldWiki.ts). */ export const DEFAULT_WIKI_ENDPOINT = "https://endfield.wiki.gg/api.php"; /** * Referer sent with every wiki request. wiki.gg's WAF keyed on this during * probing — without it, api.php returns the "Blocked - wiki.gg" stub. */ export const DEFAULT_WIKI_REFERER = "https://endfield.wiki.gg/"; /** * Browser-style User-Agent. The WAF rejects the short bot UA we use for * GitHub; a realistic Chrome UA passes cleanly. Configurable via EF_WIKI_UA. */ export const DEFAULT_WIKI_UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 " + "(KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"; /** Minimum seconds between wiki API requests (politeness, not WAF-driven). */ export const RATE_LIMIT_INTERVAL = 1.5; // --------------------------------------------------------------------------- // Package + bundled paths // --------------------------------------------------------------------------- const _PACKAGE_ROOT = dirname(dirname(fileURLToPath(import.meta.url))); export const BUNDLED_DATA_PATH = join(_PACKAGE_ROOT, "data", "endfield"); // --------------------------------------------------------------------------- // GameData path resolution // --------------------------------------------------------------------------- /** Fixed volume mount-point inside the Docker image. */ const DOCKER_VOLUME_PATH = "/data/endfield"; function resolveDefaultDataPath() { if (process.env["EF_MCP_ROOT"] === "/app") return DOCKER_VOLUME_PATH; if (process.platform === "win32") { const base = process.env["LOCALAPPDATA"] ?? join(homedir(), "AppData", "Local"); return join(base, "endfield-mcp", "data"); } const base = process.env["XDG_DATA_HOME"] ?? join(homedir(), ".local", "share"); return join(base, "endfield-mcp", "data"); } export const DEFAULT_DATA_PATH = resolveDefaultDataPath(); export function resolveTransport() { const raw = (process.env["EF_TRANSPORT"] ?? "stdio").toLowerCase(); if (raw === "http" || raw === "streamable-http") return "http"; return "stdio"; } export function loadConfig() { const isCustomDataPath = "EF_DATA_PATH" in process.env; const dataPath = isCustomDataPath ? process.env["EF_DATA_PATH"] : DEFAULT_DATA_PATH; return { wikiEndpoint: process.env["EF_WIKI_ENDPOINT"] ?? DEFAULT_WIKI_ENDPOINT, wikiReferer: process.env["EF_WIKI_REFERER"] ?? DEFAULT_WIKI_REFERER, wikiUserAgent: process.env["EF_WIKI_UA"] ?? DEFAULT_WIKI_UA, dataPath, bundledDataPath: BUNDLED_DATA_PATH, isCustomDataPath, transport: resolveTransport(), httpPort: Number(process.env["PORT"] ?? 3000), httpHost: process.env["HOST"] ?? "0.0.0.0", githubMirrors: parseMirrors(process.env["GITHUB_MIRRORS"] ?? ""), }; } /** Parse GITHUB_MIRRORS env var into proxy base URLs (trailing slash stripped). */ /** Parse a GITHUB_MIRRORS env string into proxy base URLs (trailing slash stripped). */ export function parseMirrors(raw) { return raw .split(",") .map((m) => m.trim()) .filter((m) => m.length > 0) .map((m) => m.replace(/\/+$/, "")); } // --------------------------------------------------------------------------- // Data-completeness probe (used by sync orchestration in v0.2+) // --------------------------------------------------------------------------- /** * Files that must be present for the GameData domain to be considered * "complete". Currently unused — sync orchestration relies on each * dataset's own `requiredFiles` (see datasets.ts) rather than this * global list. Retained as an extension point in case future cross- * dataset completeness probes are needed; safe to leave empty. */ export const REQUIRED_DATA_FILES = []; export function filesComplete(root) { if (REQUIRED_DATA_FILES.length === 0) return false; return REQUIRED_DATA_FILES.every((f) => { const p = join(root, f); return existsSync(p) && statSync(p).isFile(); }); } //# sourceMappingURL=config.js.map