@xzkcz/iztro-chart-mcp-server 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 iztro-mcp-server
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,127 @@
1
+ # iztro Chart MCP Server
2
+
3
+ A Model Context Protocol (MCP) server for generating and capturing astrolabe charts from ziwei.pub using FastMCP and Playwright.
4
+
5
+ ## Features
6
+
7
+ - **FastMCP Integration**: Built with the FastMCP TypeScript framework for easy MCP server development
8
+ - **Astrolabe Screenshot Capture**: Automatically captures screenshots of astrolabe charts from ziwei.pub
9
+ - **Playwright Automation**: Uses Playwright for reliable web scraping and screenshot generation
10
+ - **TypeScript Support**: Full TypeScript support with proper type definitions
11
+ - **Parameter Validation**: Uses Zod for robust parameter validation
12
+
13
+ ## Installation
14
+
15
+ ```bash
16
+ npm install @xzkcz/iztro-chart-mcp-server
17
+ ```
18
+
19
+ ## Development
20
+
21
+ ```bash
22
+ npm run dev
23
+ ```
24
+
25
+ ## Building
26
+
27
+ ```bash
28
+ npm run build
29
+ ```
30
+
31
+ ## Running
32
+
33
+ ```bash
34
+ npm start
35
+ ```
36
+
37
+ ## Running with npx
38
+
39
+ ```bash
40
+ npx @xzkcz/iztro-chart-mcp-server
41
+ ```
42
+
43
+ ## Testing with MCP CLI
44
+
45
+ You can test the server using the MCP CLI:
46
+
47
+ ```bash
48
+ # Install MCP CLI if you haven't already
49
+ npm install -g @modelcontextprotocol/cli
50
+
51
+ # Test the server
52
+ npx @mcp/cli src/index.ts
53
+ ```
54
+
55
+ ## Available Tools
56
+
57
+ ### 1. `download_chart`
58
+ Capture a screenshot of an astrolabe chart from ziwei.pub.
59
+
60
+ **Parameters:**
61
+ - `date` (string): Birth date in YYYY-M-D format (e.g., "2000-8-16")
62
+ - `hour` (number): Birth hour in 24-hour format (0-23)
63
+ - `gender` (enum): Gender of the person ("male" or "female")
64
+ - `path` (string, optional): Path to save image (default: "astro-chart.png")
65
+
66
+ **Example:**
67
+ ```json
68
+ {
69
+ "name": "download_chart",
70
+ "arguments": {
71
+ "date": "2000-8-16",
72
+ "hour": 6,
73
+ "gender": "male",
74
+ "path": "my-chart.png"
75
+ }
76
+ }
77
+ ```
78
+
79
+ ## Claude Desktop Integration
80
+
81
+ To use this server with Claude Desktop, add the following to your Claude Desktop configuration:
82
+
83
+ ```json
84
+ {
85
+ "mcpServers": {
86
+ "iztro-chart": {
87
+ "command": "npx",
88
+ "args": ["@xzkcz/iztro-chart-mcp-server"],
89
+ "env": {}
90
+ }
91
+ }
92
+ }
93
+ ```
94
+
95
+ ## Project Structure
96
+
97
+ ```
98
+ ├── src/
99
+ │ ├── index.ts # Main server implementation
100
+ │ ├── astrolabe.ts # Astrolabe screenshot logic
101
+ │ ├── astrolabe.test.ts # Unit tests for astrolabe functionality
102
+ │ └── hourToTimeIndex.ts # Hour to Chinese time index conversion
103
+ ├── dist/ # Compiled JavaScript output
104
+ ├── package.json # Project dependencies and scripts
105
+ ├── tsconfig.json # TypeScript configuration
106
+ ├── vitest.config.ts # Vitest test configuration
107
+ └── README.md # This file
108
+ ```
109
+
110
+ ## Dependencies
111
+
112
+ - **@modelcontextprotocol/sdk**: Core MCP SDK
113
+ - **fastmcp**: FastMCP framework for TypeScript
114
+ - **playwright**: Web automation and screenshot capture
115
+ - **zod**: Schema validation
116
+ - **typescript**: TypeScript compiler
117
+ - **tsx**: TypeScript execution engine
118
+
119
+ ### Development Dependencies
120
+
121
+ - **vitest**: Fast unit testing framework
122
+ - **@vitest/ui**: Visual test interface
123
+ - **jsdom**: DOM implementation for testing
124
+
125
+ ## License
126
+
127
+ MIT
@@ -0,0 +1,7 @@
1
+ export interface AstrolabeParams {
2
+ date: string;
3
+ hour: number;
4
+ gender: 'male' | 'female';
5
+ path: string;
6
+ }
7
+ export declare function downloadChart(params: AstrolabeParams): Promise<string>;
@@ -0,0 +1,48 @@
1
+ import { chromium } from "playwright";
2
+ import * as path from "path";
3
+ import * as fs from "fs";
4
+ import { hourToTimeIndex } from "./hourToTimeIndex.js";
5
+ export async function downloadChart(params) {
6
+ const { date, hour, gender, path: savePath } = params;
7
+ // Convert hour to timeIndex for iztro library
8
+ const timeIndex = hourToTimeIndex(hour);
9
+ // Construct the URL
10
+ const url = `https://ziwei.pub/astrolabe/?d=${date}&t=${timeIndex}&leap=false&g=${gender}&type=solar&n=`;
11
+ let browser;
12
+ try {
13
+ // Launch browser
14
+ browser = await chromium.launch({ headless: true });
15
+ const context = await browser.newContext({
16
+ viewport: { width: 1500, height: 800 }
17
+ });
18
+ const page = await context.newPage();
19
+ // Navigate to the astrolabe page
20
+ await page.goto(url);
21
+ // Wait for the astrolabe element to be visible
22
+ await page.waitForSelector('.iztro-astrolabe', { timeout: 3000 });
23
+ // Take screenshot of the specific element
24
+ const targetSelector = ".iztro-astrolabe";
25
+ const element = await page.locator(targetSelector);
26
+ // Ensure the element is found
27
+ if (!element) {
28
+ throw new Error(`Element ${targetSelector} not found`);
29
+ }
30
+ // Ensure the directory exists
31
+ const fullPath = path.resolve(savePath);
32
+ const dir = path.dirname(fullPath);
33
+ if (!fs.existsSync(dir)) {
34
+ fs.mkdirSync(dir, { recursive: true });
35
+ }
36
+ // Take the screenshot
37
+ await element.screenshot({ path: fullPath });
38
+ await browser.close();
39
+ return `Astrolabe chart downloaded successfully to ${fullPath}. URL: ${url}. Parameters: date=${date}, hour=${hour}, gender=${gender}`;
40
+ }
41
+ catch (error) {
42
+ if (browser) {
43
+ await browser.close();
44
+ }
45
+ const errorMessage = error instanceof Error ? error.message : String(error);
46
+ return `Failed to download astrolabe chart: ${errorMessage}. URL: ${url}. Parameters: date=${date}, hour=${hour}, gender=${gender}`;
47
+ }
48
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,228 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2
+ import { downloadChart } from './astrolabe.js';
3
+ import { chromium } from 'playwright';
4
+ import * as fs from 'fs';
5
+ import * as path from 'path';
6
+ // Mock Playwright
7
+ vi.mock('playwright', () => ({
8
+ chromium: {
9
+ launch: vi.fn()
10
+ }
11
+ }));
12
+ // Mock fs
13
+ vi.mock('fs', () => ({
14
+ existsSync: vi.fn(),
15
+ mkdirSync: vi.fn()
16
+ }));
17
+ // Mock path
18
+ vi.mock('path', () => ({
19
+ resolve: vi.fn(),
20
+ dirname: vi.fn()
21
+ }));
22
+ describe('downloadChart', () => {
23
+ const mockBrowser = {
24
+ newContext: vi.fn(),
25
+ close: vi.fn()
26
+ };
27
+ const mockContext = {
28
+ newPage: vi.fn()
29
+ };
30
+ const mockPage = {
31
+ goto: vi.fn(),
32
+ waitForSelector: vi.fn(),
33
+ locator: vi.fn()
34
+ };
35
+ const mockElement = {
36
+ screenshot: vi.fn()
37
+ };
38
+ beforeEach(() => {
39
+ vi.clearAllMocks();
40
+ // Setup default mock implementations
41
+ vi.mocked(chromium.launch).mockResolvedValue(mockBrowser);
42
+ mockBrowser.newContext.mockResolvedValue(mockContext);
43
+ mockContext.newPage.mockResolvedValue(mockPage);
44
+ mockPage.locator.mockReturnValue(mockElement);
45
+ vi.mocked(fs.existsSync).mockReturnValue(true);
46
+ vi.mocked(path.resolve).mockImplementation((p) => `/resolved/${p}`);
47
+ vi.mocked(path.dirname).mockImplementation((p) => `/dirname/${p}`);
48
+ });
49
+ afterEach(() => {
50
+ vi.restoreAllMocks();
51
+ });
52
+ describe('successful chart download', () => {
53
+ it('should successfully download chart with valid parameters', async () => {
54
+ const params = {
55
+ date: '2000-8-16',
56
+ hour: 6,
57
+ gender: 'male',
58
+ path: 'test-chart.png'
59
+ };
60
+ mockElement.screenshot.mockResolvedValue(undefined);
61
+ const result = await downloadChart(params);
62
+ expect(chromium.launch).toHaveBeenCalledWith({ headless: true });
63
+ expect(mockBrowser.newContext).toHaveBeenCalledWith({
64
+ viewport: { width: 1500, height: 800 }
65
+ });
66
+ expect(mockPage.goto).toHaveBeenCalledWith('https://ziwei.pub/astrolabe/?d=2000-8-16&t=3&leap=false&g=male&type=solar&n=');
67
+ expect(mockPage.waitForSelector).toHaveBeenCalledWith('.iztro-astrolabe', { timeout: 3000 });
68
+ expect(mockPage.locator).toHaveBeenCalledWith('.iztro-astrolabe');
69
+ expect(mockElement.screenshot).toHaveBeenCalledWith({ path: '/resolved/test-chart.png' });
70
+ expect(mockBrowser.close).toHaveBeenCalled();
71
+ expect(result).toContain('Astrolabe chart downloaded successfully');
72
+ expect(result).toContain('/resolved/test-chart.png');
73
+ });
74
+ it('should create directory if it does not exist', async () => {
75
+ const params = {
76
+ date: '2000-8-16',
77
+ hour: 6,
78
+ gender: 'female',
79
+ path: 'charts/test-chart.png'
80
+ };
81
+ vi.mocked(fs.existsSync).mockReturnValue(false);
82
+ mockElement.screenshot.mockResolvedValue(undefined);
83
+ await downloadChart(params);
84
+ expect(fs.mkdirSync).toHaveBeenCalledWith('/dirname//resolved/charts/test-chart.png', { recursive: true });
85
+ });
86
+ it('should handle female gender parameter correctly', async () => {
87
+ const params = {
88
+ date: '1995-12-25',
89
+ hour: 0,
90
+ gender: 'female',
91
+ path: 'female-chart.png'
92
+ };
93
+ mockElement.screenshot.mockResolvedValue(undefined);
94
+ const result = await downloadChart(params);
95
+ expect(mockPage.goto).toHaveBeenCalledWith('https://ziwei.pub/astrolabe/?d=1995-12-25&t=0&leap=false&g=female&type=solar&n=');
96
+ expect(result).toContain('gender=female');
97
+ });
98
+ it('should handle edge case hour values', async () => {
99
+ const params = {
100
+ date: '2023-1-1',
101
+ hour: 12,
102
+ gender: 'male',
103
+ path: 'edge-chart.png'
104
+ };
105
+ mockElement.screenshot.mockResolvedValue(undefined);
106
+ const result = await downloadChart(params);
107
+ expect(mockPage.goto).toHaveBeenCalledWith('https://ziwei.pub/astrolabe/?d=2023-1-1&t=6&leap=false&g=male&type=solar&n=');
108
+ expect(result).toContain('hour=12');
109
+ });
110
+ });
111
+ describe('error handling', () => {
112
+ it('should handle browser launch failure', async () => {
113
+ const params = {
114
+ date: '2000-8-16',
115
+ hour: 6,
116
+ gender: 'male',
117
+ path: 'test-chart.png'
118
+ };
119
+ const error = new Error('Failed to launch browser');
120
+ vi.mocked(chromium.launch).mockRejectedValue(error);
121
+ const result = await downloadChart(params);
122
+ expect(result).toContain('Failed to download astrolabe chart: Failed to launch browser');
123
+ expect(result).toContain('date=2000-8-16');
124
+ expect(result).toContain('hour=6');
125
+ expect(result).toContain('gender=male');
126
+ });
127
+ it('should handle page navigation failure', async () => {
128
+ const params = {
129
+ date: '2000-8-16',
130
+ hour: 6,
131
+ gender: 'male',
132
+ path: 'test-chart.png'
133
+ };
134
+ const error = new Error('Navigation timeout');
135
+ mockPage.goto.mockRejectedValue(error);
136
+ const result = await downloadChart(params);
137
+ expect(mockBrowser.close).toHaveBeenCalled();
138
+ expect(result).toContain('Failed to download astrolabe chart: Navigation timeout');
139
+ });
140
+ it('should handle selector timeout', async () => {
141
+ const params = {
142
+ date: '2000-8-16',
143
+ hour: 6,
144
+ gender: 'male',
145
+ path: 'test-chart.png'
146
+ };
147
+ const error = new Error('Timeout waiting for selector');
148
+ mockPage.waitForSelector.mockRejectedValue(error);
149
+ const result = await downloadChart(params);
150
+ expect(mockBrowser.close).toHaveBeenCalled();
151
+ expect(result).toContain('Failed to download astrolabe chart: Timeout waiting for selector');
152
+ });
153
+ it('should handle screenshot failure', async () => {
154
+ const params = {
155
+ date: '2000-8-16',
156
+ hour: 6,
157
+ gender: 'male',
158
+ path: 'test-chart.png'
159
+ };
160
+ const error = new Error('Screenshot failed');
161
+ mockElement.screenshot.mockRejectedValue(error);
162
+ const result = await downloadChart(params);
163
+ expect(mockBrowser.close).toHaveBeenCalled();
164
+ expect(result).toContain('Failed to download astrolabe chart: Screenshot failed');
165
+ });
166
+ it('should handle non-Error exceptions', async () => {
167
+ const params = {
168
+ date: '2000-8-16',
169
+ hour: 6,
170
+ gender: 'male',
171
+ path: 'test-chart.png'
172
+ };
173
+ vi.mocked(chromium.launch).mockRejectedValue('String error');
174
+ const result = await downloadChart(params);
175
+ expect(result).toContain('Failed to download astrolabe chart: String error');
176
+ });
177
+ });
178
+ describe('URL construction', () => {
179
+ it('should construct correct URL with all parameters', async () => {
180
+ const params = {
181
+ date: '1990-5-20',
182
+ hour: 8,
183
+ gender: 'female',
184
+ path: 'url-test.png'
185
+ };
186
+ mockElement.screenshot.mockResolvedValue(undefined);
187
+ await downloadChart(params);
188
+ expect(mockPage.goto).toHaveBeenCalledWith('https://ziwei.pub/astrolabe/?d=1990-5-20&t=4&leap=false&g=female&type=solar&n=');
189
+ });
190
+ it('should handle special characters in date', async () => {
191
+ const params = {
192
+ date: '2000-12-31',
193
+ hour: 11,
194
+ gender: 'male',
195
+ path: 'special-date.png'
196
+ };
197
+ mockElement.screenshot.mockResolvedValue(undefined);
198
+ await downloadChart(params);
199
+ expect(mockPage.goto).toHaveBeenCalledWith('https://ziwei.pub/astrolabe/?d=2000-12-31&t=6&leap=false&g=male&type=solar&n=');
200
+ });
201
+ });
202
+ describe('file system operations', () => {
203
+ it('should resolve path correctly', async () => {
204
+ const params = {
205
+ date: '2000-8-16',
206
+ hour: 6,
207
+ gender: 'male',
208
+ path: 'relative/path/chart.png'
209
+ };
210
+ mockElement.screenshot.mockResolvedValue(undefined);
211
+ await downloadChart(params);
212
+ expect(path.resolve).toHaveBeenCalledWith('relative/path/chart.png');
213
+ expect(mockElement.screenshot).toHaveBeenCalledWith({ path: '/resolved/relative/path/chart.png' });
214
+ });
215
+ it('should check directory existence', async () => {
216
+ const params = {
217
+ date: '2000-8-16',
218
+ hour: 6,
219
+ gender: 'male',
220
+ path: 'test/chart.png'
221
+ };
222
+ mockElement.screenshot.mockResolvedValue(undefined);
223
+ await downloadChart(params);
224
+ expect(path.dirname).toHaveBeenCalledWith('/resolved/test/chart.png');
225
+ expect(fs.existsSync).toHaveBeenCalledWith('/dirname//resolved/test/chart.png');
226
+ });
227
+ });
228
+ });
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Convert 24-hour format to Chinese timeIndex (0-12)
3
+ * Based on traditional Chinese time periods (十二时辰)
4
+ * @param hour - Hour in 24-hour format (0-23)
5
+ * @returns timeIndex - Chinese hour index (0-12)
6
+ */
7
+ export declare function hourToTimeIndex(hour: number): number;
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Convert 24-hour format to Chinese timeIndex (0-12)
3
+ * Based on traditional Chinese time periods (十二时辰)
4
+ * @param hour - Hour in 24-hour format (0-23)
5
+ * @returns timeIndex - Chinese hour index (0-12)
6
+ */
7
+ export function hourToTimeIndex(hour) {
8
+ if (hour < 0 || hour > 23 || !Number.isInteger(hour)) {
9
+ throw new Error('Hour must be an integer between 0 and 23');
10
+ }
11
+ // Chinese time periods mapping (十二时辰) with early/late Zi distinction:
12
+ // 早子时 (Early Zi): 00:00-01:00 -> timeIndex 0
13
+ // 丑时 (Chou): 01:00-03:00 -> timeIndex 1
14
+ // 寅时 (Yin): 03:00-05:00 -> timeIndex 2
15
+ // 卯时 (Mao): 05:00-07:00 -> timeIndex 3
16
+ // 辰时 (Chen): 07:00-09:00 -> timeIndex 4
17
+ // 巳时 (Si): 09:00-11:00 -> timeIndex 5
18
+ // 午时 (Wu): 11:00-13:00 -> timeIndex 6
19
+ // 未时 (Wei): 13:00-15:00 -> timeIndex 7
20
+ // 申时 (Shen): 15:00-17:00 -> timeIndex 8
21
+ // 酉时 (You): 17:00-19:00 -> timeIndex 9
22
+ // 戌时 (Xu): 19:00-21:00 -> timeIndex 10
23
+ // 亥时 (Hai): 21:00-23:00 -> timeIndex 11
24
+ // 晚子时 (Late Zi): 23:00-00:00 -> timeIndex 12
25
+ if (hour >= 0 && hour < 1) {
26
+ return 0; // 早子时 (Early Zi) - 00:00-01:00
27
+ }
28
+ else if (hour >= 1 && hour < 3) {
29
+ return 1; // 丑时 (Chou) - 01:00-03:00
30
+ }
31
+ else if (hour >= 3 && hour < 5) {
32
+ return 2; // 寅时 (Yin) - 03:00-05:00
33
+ }
34
+ else if (hour >= 5 && hour < 7) {
35
+ return 3; // 卯时 (Mao) - 05:00-07:00
36
+ }
37
+ else if (hour >= 7 && hour < 9) {
38
+ return 4; // 辰时 (Chen) - 07:00-09:00
39
+ }
40
+ else if (hour >= 9 && hour < 11) {
41
+ return 5; // 巳时 (Si) - 09:00-11:00
42
+ }
43
+ else if (hour >= 11 && hour < 13) {
44
+ return 6; // 午时 (Wu) - 11:00-13:00
45
+ }
46
+ else if (hour >= 13 && hour < 15) {
47
+ return 7; // 未时 (Wei) - 13:00-15:00
48
+ }
49
+ else if (hour >= 15 && hour < 17) {
50
+ return 8; // 申时 (Shen) - 15:00-17:00
51
+ }
52
+ else if (hour >= 17 && hour < 19) {
53
+ return 9; // 酉时 (You) - 17:00-19:00
54
+ }
55
+ else if (hour >= 19 && hour < 21) {
56
+ return 10; // 戌时 (Xu) - 19:00-21:00
57
+ }
58
+ else if (hour >= 21 && hour < 23) {
59
+ return 11; // 亥时 (Hai) - 21:00-23:00
60
+ }
61
+ else { // hour == 23
62
+ return 12; // 晚子时 (Late Zi) - 23:00-00:00
63
+ }
64
+ }
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,51 @@
1
+ #!/usr/bin/env node
2
+ import { FastMCP } from "fastmcp";
3
+ import { z } from "zod";
4
+ import { downloadChart } from "./astrolabe.js";
5
+ import versionJson from './version.json' with { type: 'json' };
6
+ const VERSION = versionJson.version;
7
+ // Create a new FastMCP server instance
8
+ const server = new FastMCP({
9
+ name: "@xzkcz/iztro-chart-mcp-server",
10
+ version: VERSION
11
+ });
12
+ // Add astrolabe chart download tool
13
+ server.addTool({
14
+ name: "download_chart",
15
+ description: "Download a screenshot of an astrolabe chart from ziwei.pub",
16
+ parameters: z.object({
17
+ date: z.string().describe('Birth date in YYYY-M-D format (e.g., "2000-8-16")'),
18
+ hour: z.number().min(0).max(23).describe('Birth hour in 24-hour format (0-23)'),
19
+ gender: z.enum(['male', 'female']).describe('Gender of the person'),
20
+ path: z.string().optional().default('chart.png').describe('Path to save image')
21
+ }),
22
+ execute: async (args) => {
23
+ return await downloadChart(args);
24
+ },
25
+ });
26
+ // Start the server
27
+ async function main() {
28
+ try {
29
+ server.start({
30
+ transportType: "stdio",
31
+ });
32
+ console.error(`🌟iztro-chart-mcp-server@${VERSION} started successfully!`);
33
+ console.error('Available tools:');
34
+ console.error(' - download_chart: Download a screenshot of an astrolabe chart from ziwei.pub');
35
+ }
36
+ catch (error) {
37
+ console.error("Server error:", error);
38
+ process.exit(1);
39
+ }
40
+ }
41
+ // Handle graceful shutdown
42
+ process.on('SIGINT', () => {
43
+ console.log('\nShutting down server...');
44
+ process.exit(0);
45
+ });
46
+ process.on('SIGTERM', () => {
47
+ console.log('\nShutting down server...');
48
+ process.exit(0);
49
+ });
50
+ // Start the server
51
+ main().catch(console.error);
@@ -0,0 +1,3 @@
1
+ {
2
+ "version": "1.0.1"
3
+ }
package/package.json ADDED
@@ -0,0 +1,64 @@
1
+ {
2
+ "name": "@xzkcz/iztro-chart-mcp-server",
3
+ "version": "1.0.1",
4
+ "description": "An MCP server for iZtro astrology chart generation",
5
+ "main": "dist/index.js",
6
+ "type": "module",
7
+ "bin": {
8
+ "iztro-chart-mcp-server": "dist/index.js"
9
+ },
10
+ "files": [
11
+ "dist/**/*",
12
+ "README.md",
13
+ "LICENSE"
14
+ ],
15
+ "scripts": {
16
+ "prebuild": "node scripts/generate-version.js",
17
+ "build": "npm run prebuild && tsc",
18
+ "dev": "tsx src/index.ts",
19
+ "start": "node dist/index.js",
20
+ "test": "vitest",
21
+ "test:run": "vitest run",
22
+ "test:ui": "vitest --ui",
23
+ "test:coverage": "vitest run --coverage",
24
+ "clean": "rm -rf dist",
25
+ "prepublishOnly": "npm run clean && npm run build",
26
+ "prepack": "npm run build"
27
+ },
28
+ "keywords": [
29
+ "mcp",
30
+ "astrology",
31
+ "iztro",
32
+ "chart",
33
+ "server"
34
+ ],
35
+ "author": "",
36
+ "license": "ISC",
37
+ "dependencies": {
38
+ "@modelcontextprotocol/sdk": "^1.19.1",
39
+ "fastmcp": "^3.19.0",
40
+ "playwright": "^1.55.1"
41
+ },
42
+ "devDependencies": {
43
+ "@types/node": "^24.6.2",
44
+ "@vitest/ui": "^3.2.4",
45
+ "jsdom": "^27.0.0",
46
+ "tsx": "^4.20.6",
47
+ "typescript": "^5.9.3",
48
+ "vitest": "^3.2.4"
49
+ },
50
+ "repository": {
51
+ "type": "git",
52
+ "url": "git+https://github.com/xzkcz/iztro-chart-mcp-server.git"
53
+ },
54
+ "homepage": "https://github.com/xzkcz/iztro-chart-mcp-server#readme",
55
+ "bugs": {
56
+ "url": "https://github.com/xzkcz/iztro-chart-mcp-server/issues"
57
+ },
58
+ "engines": {
59
+ "node": ">=18.0.0"
60
+ },
61
+ "publishConfig": {
62
+ "access": "public"
63
+ }
64
+ }