@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
JavaScript
#!/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