#
tokens: 7506/50000 20/20 files
lines: on (toggle) GitHub
raw markdown copy reset
# Directory Structure

```
├── .changeset
│   ├── config.json
│   └── update-tyme4ts.md
├── .github
│   └── workflows
│       ├── release.yml
│       └── update-tyme4ts.yml
├── .gitignore
├── .nvmrc
├── biome.json
├── CHANGELOG.md
├── Dockerfile
├── icon.svg
├── LICENSE
├── package.json
├── pnpm-lock.yaml
├── README.en.md
├── README.md
├── rslib.config.ts
├── smithery.yaml
├── src
│   ├── almanac.ts
│   ├── index.ts
│   ├── server.ts
│   ├── types.ts
│   └── utils.ts
├── tests
│   ├── index.test.ts
│   └── tsconfig.json
├── tsconfig.json
└── vitest.config.ts
```

# Files

--------------------------------------------------------------------------------
/.nvmrc:
--------------------------------------------------------------------------------

```
1 | 18 
```

--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------

```
 1 | # Local
 2 | .DS_Store
 3 | *.local
 4 | *.log*
 5 | 
 6 | # Dist
 7 | node_modules
 8 | dist/
 9 | 
10 | # IDE
11 | .vscode/*
12 | !.vscode/extensions.json
13 | .idea
14 | 
```

--------------------------------------------------------------------------------
/README.en.md:
--------------------------------------------------------------------------------

```markdown
 1 | # Tung Shing MCP Server
 2 | 
 3 | [![smithery badge](https://smithery.ai/badge/@baranwang/mcp-tung-shing)](https://smithery.ai/server/@baranwang/mcp-tung-shing)
 4 | [![NPM Version](https://img.shields.io/npm/v/mcp-tung-shing.svg)](https://www.npmjs.com/package/mcp-tung-shing)
 5 | [![License](https://img.shields.io/npm/l/mcp-tung-shing.svg)](https://github.com/baranwang/mcp-tung-shing/blob/main/LICENSE)
 6 | 
 7 | [中文文档](./README.md) | English
 8 | 
 9 | > Chinese Traditional Almanac calculation service based on Model Context Protocol (MCP)
10 | 
11 | ## ✨ Features
12 | 
13 | - 📅 **Calendar Conversion** - Convert between Gregorian and Chinese lunar calendar
14 | - 🍀 **Daily Guidance** - Detailed information on recommended and avoided activities for each day
15 | - 🕐 **Time Periods** - Fortune information for the twelve traditional Chinese time periods
16 | - 🔮 **Metaphysical Elements** - Detailed data on five elements, deities, star constellations and other traditional metaphysical information
17 | 
18 | ## 🚀 Installation & Usage
19 | 
20 | Add the following to your MCP configuration file:
21 | 
22 | ```json
23 | {
24 |   "mcpServers": {
25 |     "tung-shing": {
26 |       "command": "npx",
27 |       "args": [
28 |         "-y",
29 |         "mcp-tung-shing@latest"
30 |       ]
31 |     }
32 |   }
33 | }
34 | ```
35 | 
36 | ## ⚙️ Tools
37 | 
38 | ### get-tung-shing
39 | 
40 | Get almanac information for specified date(s)
41 | 
42 | **Parameters:**
43 | 
44 | | Parameter | Type | Required | Default | Description |
45 | |-----------|------|----------|---------|-------------|
46 | | `startDate` | String | No | Today | Start date, format: "YYYY-MM-DD" |
47 | | `days` | Number | No | 1 | Number of days to retrieve |
48 | | `includeHours` | Boolean | No | false | Whether to include hourly information |
49 | | `tabooFilters` | Array | No | - | Filter for recommended and avoided activities, conditions are in OR relationship |
50 | | `tabooFilters[].type` | 1 \| 2 | Yes | - | Filter type: recommends(1), avoids(2) |
51 | | `tabooFilters[].value` | String | Yes | - | The activity to filter |
52 | 
53 | ## 🤝 Contributing
54 | 
55 | Issues and Pull Requests are welcome to improve this project.
56 | 
```

--------------------------------------------------------------------------------
/.changeset/update-tyme4ts.md:
--------------------------------------------------------------------------------

```markdown
1 | ---
2 | "mcp-tung-shing": patch
3 | ---
4 | 
5 | bump tyme4ts version to 1.3.4
6 | 
```

--------------------------------------------------------------------------------
/tests/tsconfig.json:
--------------------------------------------------------------------------------

```json
1 | {
2 |   "extends": "../tsconfig.json",
3 |   "include": [".", "../vitest.setup.ts"]
4 | }
5 | 
```

--------------------------------------------------------------------------------
/vitest.config.ts:
--------------------------------------------------------------------------------

```typescript
1 | import { defineConfig } from 'vitest/config';
2 | 
3 | export default defineConfig({
4 |   // Configure Vitest (https://vitest.dev/config/)
5 |   test: {},
6 | });
7 | 
```

--------------------------------------------------------------------------------
/.changeset/config.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "$schema": "https://unpkg.com/@changesets/[email protected]/schema.json",
 3 |   "changelog": "@changesets/cli/changelog",
 4 |   "commit": false,
 5 |   "fixed": [],
 6 |   "linked": [],
 7 |   "access": "public",
 8 |   "baseBranch": "main",
 9 |   "updateInternalDependencies": "patch",
10 |   "ignore": []
11 | }
12 | 
```

--------------------------------------------------------------------------------
/smithery.yaml:
--------------------------------------------------------------------------------

```yaml
 1 | # Smithery configuration file: https://smithery.ai/docs/config#smitheryyaml
 2 | startCommand:
 3 |   type: stdio
 4 |   configSchema:
 5 |     {}
 6 |   commandFunction:
 7 |     # A JS function that produces the CLI command based on the given config to start the MCP on stdio.
 8 |     |-
 9 |     (config) => ({
10 |       command: 'node',
11 |       args: ['dist/index.cjs'],
12 |     })
13 | 
```

--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "compilerOptions": {
 3 |     "lib": ["ES2021"],
 4 |     "module": "ESNext",
 5 |     "noEmit": true,
 6 |     "strict": true,
 7 |     "skipLibCheck": true,
 8 |     "isolatedModules": true,
 9 |     "resolveJsonModule": true,
10 |     "moduleResolution": "bundler",
11 |     "useDefineForClassFields": true,
12 |     "allowImportingTsExtensions": true
13 |   },
14 |   "include": ["src"]
15 | }
16 | 
```

--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------

```dockerfile
 1 | FROM node:18-alpine as builder
 2 | 
 3 | WORKDIR /app
 4 | 
 5 | RUN npm install -g pnpm
 6 | 
 7 | COPY package.json pnpm-lock.yaml ./
 8 | 
 9 | RUN pnpm install --frozen-lockfile
10 | 
11 | COPY . .
12 | 
13 | RUN pnpm run build
14 | 
15 | 
16 | FROM node:18-alpine as runner
17 | 
18 | WORKDIR /app
19 | 
20 | COPY --from=builder /app/dist ./dist
21 | COPY --from=builder /app/package.json ./package.json
22 | 
23 | CMD ["node", "dist/index.cjs"]
24 | 
```

--------------------------------------------------------------------------------
/rslib.config.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { defineConfig } from '@rslib/core';
 2 | import { version } from "./package.json";
 3 | 
 4 | export default defineConfig({
 5 |   lib: [
 6 |     {
 7 |       format: 'esm',
 8 |       syntax: 'es2021',
 9 |       dts: true,
10 |     },
11 |     {
12 |       format: 'cjs',
13 |       syntax: 'es2021',
14 |     },
15 |   ],
16 |   source: {
17 |     define: {
18 |       'process.env.PACKAGE_VERSION': JSON.stringify(version),
19 |     }
20 |   }
21 | });
22 | 
```

--------------------------------------------------------------------------------
/biome.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "$schema": "https://biomejs.dev/schemas/1.8.0/schema.json",
 3 |   "organizeImports": {
 4 |     "enabled": true
 5 |   },
 6 |   "vcs": {
 7 |     "enabled": true,
 8 |     "clientKind": "git",
 9 |     "useIgnoreFile": true
10 |   },
11 |   "formatter": {
12 |     "indentStyle": "space"
13 |   },
14 |   "javascript": {
15 |     "formatter": {
16 |       "quoteStyle": "single"
17 |     }
18 |   },
19 |   "css": {
20 |     "parser": {
21 |       "cssModules": true
22 |     }
23 |   },
24 |   "linter": {
25 |     "enabled": true,
26 |     "rules": {
27 |       "recommended": true
28 |     }
29 |   }
30 | }
31 | 
```

--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------

```typescript
 1 | #!/usr/bin/env node
 2 | 
 3 | import dayjs from 'dayjs';
 4 | import { PluginLunar } from 'dayjs-plugin-lunar';
 5 | import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
 6 | import { createServer } from './server';
 7 | 
 8 | // 初始化日期插件
 9 | dayjs.extend(PluginLunar);
10 | 
11 | // 启动服务器
12 | (async () => {
13 |   try {
14 |     const server = createServer();
15 |     const transport = new StdioServerTransport();
16 |     await server.connect(transport);
17 |     console.error('Tung Shing MCP server started');
18 |   } catch (error) {
19 |     console.error('Failed to start Tung Shing MCP server:', error);
20 |     process.exit(1);
21 |   }
22 | })();
23 | 
```

--------------------------------------------------------------------------------
/tests/index.test.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { Client } from '@modelcontextprotocol/sdk/client/index.js';
 2 | import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
 3 | import { beforeAll, expect, test } from 'vitest';
 4 | 
 5 | const transport = new StdioClientTransport({
 6 |   command: "node",
 7 |   args: ["."]
 8 | });
 9 | 
10 | const client = new Client({
11 |   name: 'test-client',
12 |   version: '0.0.0',
13 | });
14 | 
15 | beforeAll(async () => {
16 |   await client.connect(transport);
17 | });
18 | 
19 | test('get-tung-shing', async () => {
20 |   const resp = await client.callTool({
21 |     name: 'get-tung-shing',
22 |     arguments: {
23 |       startDate: '2025-01-21'
24 |     }
25 |   })
26 | 
27 |   expect(resp.content).toBeInstanceOf(Array);
28 | });
29 | 
```

--------------------------------------------------------------------------------
/icon.svg:
--------------------------------------------------------------------------------

```
 1 | <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
 2 |   <g transform="translate(256, 256)">
 3 |     <g>
 4 |       <path d="M0,-220 A220,220 0 0,1 0,220 A110,110 0 0,0 0,0 A110,110 0 0,1 0,-220" fill="#111" />
 5 |       <path d="M0,220 A220,220 0 0,1 0,-220 A110,110 0 0,0 0,0 A110,110 0 0,1 0,220" fill="#fff" />
 6 | 
 7 |       <circle cx="0" cy="-110" r="35" fill="#fff" />
 8 |       <circle cx="0" cy="110" r="35" fill="#111" />
 9 |       
10 |       <animateTransform
11 |         attributeName="transform"
12 |         attributeType="XML"
13 |         type="rotate"
14 |         from="0"
15 |         to="360"
16 |         dur="24s"
17 |         repeatCount="indefinite"
18 |       />
19 |     </g>
20 |   </g>
21 | </svg>
22 | 
```

--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------

```yaml
 1 | name: Release
 2 | 
 3 | on:
 4 |   push:
 5 |     branches:
 6 |       - main
 7 | 
 8 | jobs:
 9 |   release:
10 |     runs-on: ubuntu-latest
11 |     steps:
12 |       - uses: actions/checkout@v4
13 |         with:
14 |           fetch-depth: 0
15 |       
16 |       - uses: pnpm/action-setup@v4
17 | 
18 |       - uses: actions/setup-node@v4
19 |         with:
20 |           node-version-file: .nvmrc
21 |           cache: pnpm
22 | 
23 |       - run: pnpm install
24 | 
25 |       - uses: changesets/action@v1
26 |         id: changesets
27 |         with:
28 |           publish: pnpm run release
29 |           title: "chore: version packages"
30 |           commit: "chore: version packages"
31 |         env:
32 |           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
33 |           NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
```

--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "name": "mcp-tung-shing",
 3 |   "version": "1.7.1",
 4 |   "description": "A Model Context Protocol plugin for Chinese Tung Shing (黄历/通勝/通胜) almanac calculations",
 5 |   "type": "module",
 6 |   "exports": {
 7 |     ".": {
 8 |       "types": "./dist/index.d.ts",
 9 |       "import": "./dist/index.js",
10 |       "require": "./dist/index.cjs"
11 |     }
12 |   },
13 |   "main": "./dist/index.cjs",
14 |   "module": "./dist/index.js",
15 |   "types": "./dist/index.d.ts",
16 |   "bin": {
17 |     "mcp-tung-shing": "./dist/index.cjs"
18 |   },
19 |   "files": [
20 |     "dist"
21 |   ],
22 |   "keywords": [
23 |     "mcp",
24 |     "tung shing",
25 |     "almanac",
26 |     "calendar",
27 |     "lunar",
28 |     "chinese"
29 |   ],
30 |   "repository": {
31 |     "type": "git",
32 |     "url": "https://github.com/baranwang/mcp-tung-shing"
33 |   },
34 |   "bugs": {
35 |     "url": "https://github.com/baranwang/mcp-tung-shing/issues"
36 |   },
37 |   "license": "MIT",
38 |   "scripts": {
39 |     "build": "rslib build",
40 |     "check": "biome check --write",
41 |     "dev": "rslib build --watch",
42 |     "format": "biome format --write",
43 |     "inspect": "mcp-inspector",
44 |     "pretest": "rslib build",
45 |     "test": "vitest run",
46 |     "prerelease": "npm run build",
47 |     "release": "changeset publish"
48 |   },
49 |   "dependencies": {
50 |     "@modelcontextprotocol/sdk": "^1.7.0",
51 |     "dayjs": "^1.11.13",
52 |     "dayjs-plugin-lunar": "^1.4.0",
53 |     "tyme4ts": "1.3.4",
54 |     "zod": "^3.24.1",
55 |     "zod-to-json-schema": "^3.24.1"
56 |   },
57 |   "devDependencies": {
58 |     "@biomejs/biome": "1.9.2",
59 |     "@changesets/cli": "^2.28.1",
60 |     "@modelcontextprotocol/inspector": "^0.8.0",
61 |     "@rslib/core": "^0.5.4",
62 |     "@types/node": "^22.8.1",
63 |     "typescript": "^5.7.3",
64 |     "vitest": "^3.0.1"
65 |   },
66 |   "packageManager": "[email protected]"
67 | }
68 | 
```

--------------------------------------------------------------------------------
/.github/workflows/update-tyme4ts.yml:
--------------------------------------------------------------------------------

```yaml
 1 | name: Update tyme4ts
 2 | 
 3 | on:
 4 |   schedule:
 5 |     - cron: '0 0 * * 1'
 6 |   workflow_dispatch:
 7 | 
 8 | jobs:
 9 |   update-dependency:
10 |     runs-on: ubuntu-latest
11 |     permissions:
12 |       contents: write
13 |     steps:
14 |       - uses: actions/checkout@v4
15 |         with:
16 |           fetch-depth: 0
17 |       
18 |       - uses: pnpm/action-setup@v4
19 | 
20 |       - uses: actions/setup-node@v4
21 |         with:
22 |           node-version-file: .nvmrc
23 |           cache: pnpm
24 | 
25 |       - run: pnpm install
26 | 
27 |       - name: Check tyme4ts version
28 |         id: check-version
29 |         run: |
30 |           # 获取当前依赖的版本
31 |           CURRENT_VERSION=$(node -p "require('./package.json').dependencies.tyme4ts.replace('^', '')")
32 |           echo "current_version=$CURRENT_VERSION" >> $GITHUB_OUTPUT
33 |           
34 |           # 获取最新版本
35 |           LATEST_VERSION=$(npm view tyme4ts version)
36 |           echo "latest_version=$LATEST_VERSION" >> $GITHUB_OUTPUT
37 |           
38 |           # 比较版本
39 |           if [ "$CURRENT_VERSION" != "$LATEST_VERSION" ]; then
40 |             echo "needs_update=true" >> $GITHUB_OUTPUT
41 |           else
42 |             echo "needs_update=false" >> $GITHUB_OUTPUT
43 |           fi
44 | 
45 |       - name: Update tyme4ts
46 |         if: steps.check-version.outputs.needs_update == 'true'
47 |         run: |
48 |           # 更新依赖版本
49 |           pnpm add tyme4ts@${{ steps.check-version.outputs.latest_version }}
50 |           
51 |           # 创建 changeset
52 |           cat << EOF > .changeset/update-tyme4ts.md
53 |           ---
54 |           "mcp-tung-shing": patch
55 |           ---
56 |           
57 |           bump tyme4ts version to ${{ steps.check-version.outputs.latest_version }}
58 |           EOF
59 | 
60 |       - name: Commit and push changes
61 |         if: steps.check-version.outputs.needs_update == 'true'
62 |         run: |
63 |           git config --global user.name "github-actions[bot]"
64 |           git config --global user.email "github-actions[bot]@users.noreply.github.com"
65 |           git add package.json pnpm-lock.yaml .changeset/
66 |           git commit -m "chore: bump tyme4ts version to ${{ steps.check-version.outputs.latest_version }}"
67 |           git push origin main
68 |         env:
69 |           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 
```

--------------------------------------------------------------------------------
/src/almanac.ts:
--------------------------------------------------------------------------------

```typescript
  1 | import dayjs from 'dayjs';
  2 | import { PluginLunar } from 'dayjs-plugin-lunar';
  3 | import type { AlmanacContentItem, DailyAlmanac } from './types';
  4 | import { ContentType } from './types';
  5 | import { handleDirection } from './utils';
  6 | import 'dayjs/locale/zh-cn.js';
  7 | 
  8 | dayjs.extend(PluginLunar);
  9 | 
 10 | /**
 11 |  * 获取时辰黄历信息
 12 |  */
 13 | export function getHourlyAlmanac(date: dayjs.Dayjs): AlmanacContentItem {
 14 |   const lunarHour = date.toLunarHour();
 15 |   const sixtyCycle = lunarHour.getSixtyCycle();
 16 |   const heavenStem = sixtyCycle.getHeavenStem();
 17 |   const earthBranch = sixtyCycle.getEarthBranch();
 18 | 
 19 |   return {
 20 |     [ContentType.宜]: lunarHour.getRecommends().map((item) => item.getName()),
 21 |     [ContentType.忌]: lunarHour.getAvoids().map((item) => item.getName()),
 22 |     [ContentType.吉凶]: lunarHour
 23 |       .getTwelveStar()
 24 |       .getEcliptic()
 25 |       .getLuck()
 26 |       .toString(),
 27 |     [ContentType.值神]: lunarHour.getTwelveStar().toString(),
 28 |     [ContentType.五行]: sixtyCycle.getSound().toString(),
 29 |     [ContentType.冲煞]: `冲${earthBranch.getOpposite().getZodiac()}煞${earthBranch.getOminous()}`,
 30 |     [ContentType.方位]: [
 31 |       `喜神${handleDirection(heavenStem.getJoyDirection().toString())}`,
 32 |       `财神${handleDirection(heavenStem.getWealthDirection().toString())}`,
 33 |       `福神${handleDirection(heavenStem.getMascotDirection().toString())}`,
 34 |     ],
 35 |   };
 36 | }
 37 | 
 38 | /**
 39 |  * 获取每日黄历信息
 40 |  */
 41 | export function getDailyAlmanac(
 42 |   date: dayjs.Dayjs,
 43 |   includeHours = false,
 44 | ): DailyAlmanac {
 45 |   const parsedDate = dayjs(date);
 46 |   if (!parsedDate.isValid()) {
 47 |     throw new Error('Invalid date');
 48 |   }
 49 | 
 50 |   const lunarDay = parsedDate.toLunarDay();
 51 |   const solarDay = lunarDay.getSolarDay();
 52 |   const sixtyCycle = lunarDay.getSixtyCycle();
 53 |   const earthBranch = sixtyCycle.getEarthBranch();
 54 |   const twentyEightStar = lunarDay.getTwentyEightStar();
 55 |   const gods = lunarDay.getGods().reduce(
 56 |     (acc, god) => {
 57 |       const category =
 58 |         god.getLuck().getName() === '吉' ? 'auspicious' : 'inauspicious';
 59 |       acc[category].push(god.getName());
 60 |       return acc;
 61 |     },
 62 |     { auspicious: [] as string[], inauspicious: [] as string[] },
 63 |   );
 64 | 
 65 |   const result: DailyAlmanac = {
 66 |     公历: parsedDate.locale('zh-cn').format('YYYY 年 M 月 D日(ddd)'),
 67 |     农历: parsedDate.format('LY年LMLD'),
 68 |     节日: lunarDay.getFestival()?.getName(),
 69 |     节气: solarDay.getTermDay().toString(),
 70 |     七十二候: solarDay.getPhenologyDay().toString(),
 71 |     当日: {
 72 |       [ContentType.宜]: lunarDay.getRecommends().map((item) => item.getName()),
 73 |       [ContentType.忌]: lunarDay.getAvoids().map((item) => item.getName()),
 74 |       [ContentType.吉凶]: lunarDay
 75 |         .getTwelveStar()
 76 |         .getEcliptic()
 77 |         .getLuck()
 78 |         .toString(),
 79 |       [ContentType.五行]: sixtyCycle.getSound().toString(),
 80 |       [ContentType.冲煞]: `冲${earthBranch.getOpposite().getZodiac()}煞${earthBranch.getOminous()}`,
 81 |       [ContentType.值神]: lunarDay.getTwelveStar().toString(),
 82 |       [ContentType.建除十二神]: lunarDay.getDuty().toString(),
 83 |       [ContentType.二十八星宿]: `${twentyEightStar}${twentyEightStar.getSevenStar()}${twentyEightStar.getAnimal()}(${twentyEightStar.getLuck()})`,
 84 |       [ContentType.吉神宜趋]: gods.auspicious,
 85 |       [ContentType.凶煞宜忌]: gods.inauspicious,
 86 |       [ContentType.彭祖百忌]: `${sixtyCycle.getHeavenStem().getPengZuHeavenStem()} ${earthBranch.getPengZuEarthBranch()}`,
 87 |     },
 88 |   };
 89 | 
 90 |   if (includeHours) {
 91 |     result.分时 = {};
 92 |     for (let i = 0; i < 12; i++) {
 93 |       const hour = parsedDate.addLunar(i, 'dual-hour');
 94 |       result.分时[hour.format('LH')] = getHourlyAlmanac(hour);
 95 |     }
 96 |   }
 97 | 
 98 |   return result;
 99 | }
100 | 
```

--------------------------------------------------------------------------------
/src/server.ts:
--------------------------------------------------------------------------------

```typescript
  1 | import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
  2 | import {
  3 |   CallToolRequestSchema,
  4 |   GetPromptRequestSchema,
  5 |   ListPromptsRequestSchema,
  6 |   ListToolsRequestSchema,
  7 | } from '@modelcontextprotocol/sdk/types.js';
  8 | import dayjs from 'dayjs';
  9 | import { zodToJsonSchema } from 'zod-to-json-schema';
 10 | import { getDailyAlmanac } from './almanac';
 11 | import { ContentType, TabooType, getTungShingParamsSchema } from './types';
 12 | import { getDayTabooNames } from './utils';
 13 | 
 14 | /**
 15 |  * 创建并配置MCP服务器
 16 |  */
 17 | export function createServer() {
 18 |   const mcpServer = new McpServer(
 19 |     {
 20 |       name: 'Tung Shing',
 21 |       version: process.env.PACKAGE_VERSION ?? '0.0.0',
 22 |     },
 23 |     {
 24 |       capabilities: {
 25 |         tools: {},
 26 |         prompts: {},
 27 |       },
 28 |     },
 29 |   );
 30 | 
 31 |   // 注册工具列表处理器
 32 |   mcpServer.server.setRequestHandler(ListToolsRequestSchema, () => ({
 33 |     tools: [
 34 |       {
 35 |         name: 'get-tung-shing',
 36 |         description: '获取通胜黄历,包括公历、农历、宜忌、吉凶、冲煞等信息',
 37 |         inputSchema: zodToJsonSchema(getTungShingParamsSchema),
 38 |       },
 39 |     ],
 40 |   }));
 41 | 
 42 |   // 注册工具调用处理器
 43 |   mcpServer.server.setRequestHandler(CallToolRequestSchema, async (request) => {
 44 |     switch (request.params.name) {
 45 |       case 'get-tung-shing': {
 46 |         const {
 47 |           startDate,
 48 |           days,
 49 |           includeHours,
 50 |           tabooFilters = [],
 51 |         } = getTungShingParamsSchema.parse(request.params.arguments);
 52 |         const start = dayjs(startDate);
 53 |         if (!start.isValid()) {
 54 |           return {
 55 |             content: [
 56 |               {
 57 |                 type: 'text',
 58 |                 text: 'Invalid date',
 59 |               },
 60 |             ],
 61 |             isError: true,
 62 |           };
 63 |         }
 64 | 
 65 |         return {
 66 |           content: Array.from({ length: days }, (_, i) => {
 67 |             const almanac = getDailyAlmanac(start.add(i, 'day'), includeHours);
 68 | 
 69 |             // 如果没有指定taboo过滤,直接返回结果
 70 |             if (!tabooFilters.length) {
 71 |               return {
 72 |                 type: 'text',
 73 |                 text: JSON.stringify(almanac),
 74 |               };
 75 |             }
 76 | 
 77 |             // 提取宜忌内容
 78 |             const recommends = (almanac.当日[ContentType.宜] as string[]) || [];
 79 |             const avoids = (almanac.当日[ContentType.忌] as string[]) || [];
 80 | 
 81 |             // 根据tabooFilters进行过滤,条件之间为或的关系
 82 |             const hasMatch = tabooFilters.some((filter) => {
 83 |               // 宜事项过滤
 84 |               if (filter.type === TabooType.宜) {
 85 |                 return recommends.includes(filter.value);
 86 |               }
 87 |               // 忌事项过滤
 88 |               if (filter.type === TabooType.忌) {
 89 |                 return avoids.includes(filter.value);
 90 |               }
 91 |               return false;
 92 |             });
 93 | 
 94 |             if (hasMatch) {
 95 |               return {
 96 |                 type: 'text',
 97 |                 text: JSON.stringify(almanac),
 98 |               };
 99 |             }
100 |             return null;
101 |           }).filter(Boolean),
102 |         };
103 |       }
104 |       default: {
105 |         return {
106 |           content: [
107 |             {
108 |               type: 'text',
109 |               text: `Unknown tool: ${request.params.name}`,
110 |             },
111 |           ],
112 |           isError: true,
113 |         };
114 |       }
115 |     }
116 |   });
117 | 
118 |   mcpServer.server.setRequestHandler(ListPromptsRequestSchema, () => ({
119 |     prompts: [
120 |       {
121 |         name: 'get-taboo',
122 |         description: '获取宜忌事项类型',
123 |       },
124 |     ],
125 |   }));
126 | 
127 |   mcpServer.server.setRequestHandler(GetPromptRequestSchema, (request) => {
128 |     switch (request.params.name) {
129 |       case 'get-taboo': {
130 |         return {
131 |           messages: [
132 |             {
133 |               role: 'assistant',
134 |               content: {
135 |                 type: 'text',
136 |                 text: `宜忌事项类型清单\n${getDayTabooNames()
137 |                   .map((name) => `- ${name}`)
138 |                   .join('\n')}`,
139 |               },
140 |             },
141 |           ],
142 |         };
143 |       }
144 |       default: {
145 |         return {
146 |           messages: [],
147 |         };
148 |       }
149 |     }
150 |   });
151 | 
152 |   return mcpServer;
153 | }
154 | 
```