UNPKG

@xzkcz/iztro-mcp-server

Version:

MCP server exposing iztro astrology methods for Zi Wei Dou Shu astrolabe generation and horoscope analysis

239 lines 9.96 kB
#!/usr/bin/env node import { FastMCP } from 'fastmcp'; import { astro } from 'iztro'; import { z } from 'zod'; import { VERSION } from './version'; /** * Convert 24-hour format to Chinese timeIndex (0-12) * Based on traditional Chinese time periods (十二时辰) * @param hour - Hour in 24-hour format (0-23) * @returns timeIndex - Chinese hour index (0-12) */ function hourToTimeIndex(hour) { if (hour < 0 || hour > 23 || !Number.isInteger(hour)) { throw new Error('Hour must be an integer between 0 and 23'); } // Chinese time periods mapping (十二时辰) with early/late Zi distinction: // 早子时 (Early Zi): 00:00-01:00 -> timeIndex 0 // 丑时 (Chou): 01:00-03:00 -> timeIndex 1 // 寅时 (Yin): 03:00-05:00 -> timeIndex 2 // 卯时 (Mao): 05:00-07:00 -> timeIndex 3 // 辰时 (Chen): 07:00-09:00 -> timeIndex 4 // 巳时 (Si): 09:00-11:00 -> timeIndex 5 // 午时 (Wu): 11:00-13:00 -> timeIndex 6 // 未时 (Wei): 13:00-15:00 -> timeIndex 7 // 申时 (Shen): 15:00-17:00 -> timeIndex 8 // 酉时 (You): 17:00-19:00 -> timeIndex 9 // 戌时 (Xu): 19:00-21:00 -> timeIndex 10 // 亥时 (Hai): 21:00-23:00 -> timeIndex 11 // 晚子时 (Late Zi): 23:00-00:00 -> timeIndex 12 if (hour >= 0 && hour < 1) { return 0; // 早子时 (Early Zi) - 00:00-01:00 } else if (hour >= 1 && hour < 3) { return 1; // 丑时 (Chou) - 01:00-03:00 } else if (hour >= 3 && hour < 5) { return 2; // 寅时 (Yin) - 03:00-05:00 } else if (hour >= 5 && hour < 7) { return 3; // 卯时 (Mao) - 05:00-07:00 } else if (hour >= 7 && hour < 9) { return 4; // 辰时 (Chen) - 07:00-09:00 } else if (hour >= 9 && hour < 11) { return 5; // 巳时 (Si) - 09:00-11:00 } else if (hour >= 11 && hour < 13) { return 6; // 午时 (Wu) - 11:00-13:00 } else if (hour >= 13 && hour < 15) { return 7; // 未时 (Wei) - 13:00-15:00 } else if (hour >= 15 && hour < 17) { return 8; // 申时 (Shen) - 15:00-17:00 } else if (hour >= 17 && hour < 19) { return 9; // 酉时 (You) - 17:00-19:00 } else if (hour >= 19 && hour < 21) { return 10; // 戌时 (Xu) - 19:00-21:00 } else if (hour >= 21 && hour < 23) { return 11; // 亥时 (Hai) - 21:00-23:00 } else { // hour == 23 return 12; // 晚子时 (Late Zi) - 23:00-00:00 } } // Create the FastMCP server instance const server = new FastMCP({ name: 'iztro-astrology-server', version: VERSION }); // Tool: Generate astrolabe by solar date server.addTool({ name: 'generate_astrolabe_by_solar', description: 'Generate an astrolabe using solar calendar date for Zi Wei Dou Shu astrology analysis', parameters: z.object({ date: z.string().describe('Birth date in YYYY-M-D format (e.g., "2000-8-16")'), hour: z.number().min(0).max(23).describe('Birth hour in 24-hour format (0-23)'), gender: z.enum(['male', 'female']).describe('Gender of the person'), isDST: z.boolean().optional().default(false).describe('Whether daylight saving time was in effect'), locale: z.string().optional().default('en-US').describe('Locale for the output (e.g., "en-US", "zh-CN", "zh-TW")') }), execute: async (args) => { try { // Convert hour to timeIndex for iztro library const timeIndex = hourToTimeIndex(args.hour); // Generate astrolabe using iztro's bySolar method const astrolabe = astro.bySolar(args.date, timeIndex, args.gender, args.isDST, args.locale); return JSON.stringify({ success: true, data: { astrolabe: astrolabe, metadata: { birthDate: args.date, birthHour: args.hour, timeIndex: timeIndex, gender: args.gender, isDST: args.isDST, locale: args.locale, generatedAt: new Date().toISOString() } }, message: 'Astrolabe generated successfully' }, null, 2); } catch (error) { return JSON.stringify({ success: false, error: error instanceof Error ? error.message : 'Unknown error occurred', message: 'Failed to generate astrolabe' }, null, 2); } } }); // Tool: Get horoscope analysis server.addTool({ name: 'get_horoscope_analysis', description: 'Get horoscope analysis for a specific date using an existing astrolabe', parameters: z.object({ date: z.string().describe('Birth date in YYYY-M-D format (e.g., "2000-8-16")'), hour: z.number().min(0).max(23).describe('Birth hour in 24-hour format (0-23)'), gender: z.enum(['male', 'female']).describe('Gender of the person'), isDST: z.boolean().optional().default(false).describe('Whether daylight saving time was in effect'), locale: z.string().optional().default('en-US').describe('Locale for the output (e.g., "en-US", "zh-CN", "zh-TW")'), targetDate: z.string().optional().describe('Target date for horoscope analysis (defaults to current date if not provided)') }), execute: async (args) => { try { // Convert hour to timeIndex for iztro library const timeIndex = hourToTimeIndex(args.hour); // First generate the astrolabe const astrolabe = astro.bySolar(args.date, timeIndex, args.gender, args.isDST, args.locale); // Get horoscope for the target date (or current date if not specified) const analysisDate = args.targetDate ? new Date(args.targetDate) : new Date(); const horoscope = astrolabe.horoscope(analysisDate); return JSON.stringify({ success: true, data: { horoscope: horoscope, astrolabe: astrolabe, metadata: { birthDate: args.date, birthHour: args.hour, timeIndex: timeIndex, gender: args.gender, isDST: args.isDST, locale: args.locale, analysisDate: analysisDate.toISOString(), generatedAt: new Date().toISOString() } }, message: 'Horoscope analysis completed successfully' }, null, 2); } catch (error) { return JSON.stringify({ success: false, error: error instanceof Error ? error.message : 'Unknown error occurred', message: 'Failed to generate horoscope analysis' }, null, 2); } } }); // Tool: Get palace information server.addTool({ name: 'get_palace_info', description: 'Get detailed information about all palaces in an astrolabe', parameters: z.object({ date: z.string().describe('Birth date in YYYY-M-D format (e.g., "2000-8-16")'), hour: z.number().min(0).max(23).describe('Birth hour in 24-hour format (0-23)'), gender: z.enum(['male', 'female']).describe('Gender of the person'), isDST: z.boolean().optional().default(false).describe('Whether daylight saving time was in effect'), locale: z.string().optional().default('en-US').describe('Locale for the output (e.g., "en-US", "zh-CN", "zh-TW")') }), execute: async (args) => { try { // Convert hour to timeIndex for iztro library const timeIndex = hourToTimeIndex(args.hour); // Generate astrolabe const astrolabe = astro.bySolar(args.date, timeIndex, args.gender, args.isDST, args.locale); return JSON.stringify({ success: true, data: { palaces: astrolabe.palaces, palaceCount: astrolabe.palaces.length, metadata: { birthDate: args.date, birthHour: args.hour, timeIndex: timeIndex, gender: args.gender, isDST: args.isDST, locale: args.locale, generatedAt: new Date().toISOString() } }, message: 'Palace information retrieved successfully' }, null, 2); } catch (error) { return JSON.stringify({ success: false, error: error instanceof Error ? error.message : 'Unknown error occurred', message: 'Failed to retrieve palace information' }, null, 2); } } }); // Start the server async function main() { try { await server.start({ transportType: 'stdio' }); console.error('🌟 iztro MCP Server started successfully!'); console.error('Available tools:'); console.error(' - generate_astrolabe_by_solar: Generate astrolabe using solar date'); console.error(' - get_horoscope_analysis: Get horoscope analysis for a specific date'); console.error(' - get_palace_info: Get detailed palace information'); } catch (error) { console.error('Failed to start server:', error); process.exit(1); } } // Handle graceful shutdown process.on('SIGINT', async () => { console.error('\n🛑 Shutting down iztro MCP Server...'); process.exit(0); }); process.on('SIGTERM', async () => { console.error('\n🛑 Shutting down iztro MCP Server...'); process.exit(0); }); // Start the server main().catch(console.error); //# sourceMappingURL=index.js.map