compare-translations
Compare Korean Bible translations side-by-side to analyze verse differences across multiple versions. Enter book, chapter, and verse to view parallel translations.
Instructions
Compare a verse across different Korean translations
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| book | Yes | Book name (English or Korean) or code | |
| chapter | Yes | Chapter number | |
| verse | Yes | Verse number | |
| versions | No | Array of version codes to compare (default: all versions) |
Implementation Reference
- src/index.ts:520-562 (handler)The main handler logic for the 'compare-translations' tool within the CallToolRequestSchema switch statement. It parses arguments, finds the book code, fetches the verse from multiple Bible translations using fetchChapter, handles errors, and returns a markdown comparison.case "compare-translations": { const { book, chapter, verse, versions } = args as { book: string; chapter: number; verse: number; versions?: string[]; }; const bookCode = findBookCode(book); if (!bookCode) { return { content: [ { type: "text", text: `Error: Book '${book}' not found.`, }, ], }; } const versionsToCompare = versions || Object.keys(TRANSLATIONS); let result = `# ${book} ${chapter}:${verse} - Translation Comparison\n\n`; for (const versionCode of versionsToCompare) { try { const chapterData = await fetchChapter(bookCode, chapter, versionCode); const verseData = chapterData.verses.find((v) => v.number === verse); if (verseData) { result += `## ${TRANSLATIONS[versionCode] || versionCode}\n`; result += `${verseData.text}\n\n`; } } catch (error) { result += `## ${TRANSLATIONS[versionCode] || versionCode}\n`; result += `(Error loading this version)\n\n`; } } return { content: [{ type: "text", text: result }], }; }
- src/index.ts:349-371 (schema)Input schema definition for the compare-translations tool, defining the expected arguments: book (string), chapter (number), verse (number), and optional versions (array of strings).inputSchema: { type: "object", properties: { book: { type: "string", description: "Book name (English or Korean) or code", }, chapter: { type: "number", description: "Chapter number", }, verse: { type: "number", description: "Verse number", }, versions: { type: "array", items: { type: "string" }, description: "Array of version codes to compare (default: all versions)", }, }, required: ["book", "chapter", "verse"], },
- src/index.ts:346-372 (registration)The tool registration object included in the 'tools' array used by ListToolsRequestSchema handler. This exposes the tool's name, description, and schema to MCP clients.{ name: "compare-translations", description: "Compare a verse across different Korean translations", inputSchema: { type: "object", properties: { book: { type: "string", description: "Book name (English or Korean) or code", }, chapter: { type: "number", description: "Chapter number", }, verse: { type: "number", description: "Verse number", }, versions: { type: "array", items: { type: "string" }, description: "Array of version codes to compare (default: all versions)", }, }, required: ["book", "chapter", "verse"], }, },
- src/index.ts:143-194 (helper)Key helper function used by the handler to fetch and parse a Bible chapter's HTML from the website, extract verses using cheerio, and return structured Chapter data.async function fetchChapter( bookCode: string, chapter: number, version: string = "GAE" ): Promise<Chapter> { const url = `https://www.bskorea.or.kr/bible/korbibReadpage.php?version=${version}&book=${bookCode}&chap=${chapter}`; const response = await fetch(url); const html = await response.text(); const $ = cheerio.load(html); const verses: Verse[] = []; // Parse verses from span elements // The website uses span elements where verse text starts with verse number $("span").each((i, elem) => { const text = $(elem).text().trim(); // Look for pattern: number followed by spaces and text const match = text.match(/^(\d+)\s+(.+)$/s); if (match) { const verseNum = parseInt(match[1]); let verseText = match[2]; // Remove footnote markers (like 1), 2), etc.) verseText = verseText.replace(/\d+\)/g, "").trim(); // Remove explanatory text that comes after line breaks (like "또는 ...") const lines = verseText.split("\n"); verseText = lines[0].trim(); // Avoid duplicate verses (website has multiple spans per verse) if (!verses.find((v) => v.number === verseNum)) { verses.push({ number: verseNum, text: verseText, }); } } }); const bookInfo = getBookInfo(bookCode); return { book: bookInfo?.name || bookCode, bookKorean: bookInfo?.korean || "", chapter, version, versionName: TRANSLATIONS[version] || version, verses, }; }
- src/index.ts:109-130 (helper)Helper function to resolve book name (English, Korean, or code) to the internal book code used in URLs.function findBookCode(bookName: string): string | null { const normalized = bookName.toLowerCase().trim(); // Try direct match for (const [name, info] of Object.entries(BIBLE_BOOKS)) { if (name.toLowerCase() === normalized || info.korean === bookName || info.code === normalized) { return info.code; } } // Try partial match for (const [name, info] of Object.entries(BIBLE_BOOKS)) { if (name.toLowerCase().includes(normalized) || info.korean.includes(bookName)) { return info.code; } } return null; }