Skip to main content
Glama
destiny-telling

destiny-telling

by cph0512

destiny-telling

給 AI agent 與本機程式使用的北派紫微、八字、疊宮及雙向交叉計算。只提供數值與結構資料,以及本機 stdio MCP;不提供模型 API 呼叫、HTTP 服務、外部 KB 存取、預測解讀文章或資料持久化。計算期間不需 API key,也不會把輸入送往遠端。

結果為傾向非定論、不構成醫療法律投資建議

解讀知識庫是另一個私有服務(destinytelling.life),不在本 repo

上面兩句是範圍與免責聲明,不是解讀知識庫。本專案不產生吉凶評分、投資指令或醫療法律判斷。

安裝與執行範圍

預定 GitHub 來源是 cph0512/destiny-telling。以下安裝指令適用於該 repository 已建立、且呼叫者有讀取權限時;本文件不宣稱遠端已建立、已公開或已發布至 npm。

git clone https://github.com/cph0512/destiny-telling.git
cd destiny-telling
npm ci --ignore-scripts
  • package.json 要求 Node >=25.9.0;目前實測的 runtime 是 Node v25.9.0,沒有第二個 Node 版本或其他作業系統的相容性測試結論。

  • 專案是 ESM,root entry 為 index.js;不需 build。

  • private: true 刻意防止 npm publish,與 GitHub repository 的 PRIVATE/PUBLIC 可見性無關。不要把套件名稱當作 npm 已發布的證據。

  • MCP 已實測直接執行 node /absolute/path/destiny-telling/mcp/server.js,以及測試擁有的 destiny-telling-mcp symlink(透過 Node 與可執行 shebang 兩種啟動)。這是入口回歸測試,尚未驗證真正 npm 安裝後的 bin。

  • stdio server 由 client 啟動為子程序;stdout 保留給 JSON-RPC,不能在該程序插入一般 log。它不是 HTTP endpoint,不監聽網路 port。

Related MCP server: tool-mcp-bridge

Claude / Cursor 的本機 stdio 設定

下列各是一份 mcpServers JSON 設定片段,不是已替你安裝到 client 的設定,也不宣稱任何特定 client 版本已實測。將 /absolute/path/destiny-telling 換成自己的 checkout 絕對路徑;若 client 的 PATH 找不到 node,將 command 換成自己的 Node 執行檔絕對路徑。不要把兩者當成同一個路徑。

Claude:

{
  "mcpServers": {
    "destiny-telling": {
      "command": "node",
      "args": ["/absolute/path/destiny-telling/mcp/server.js"]
    }
  }
}

Cursor:

{
  "mcpServers": {
    "destiny-telling": {
      "command": "node",
      "args": ["/absolute/path/destiny-telling/mcp/server.js"]
    }
  }
}

將片段合併進自己 client 的 MCP 設定後,由該 client 啟動。server 不需要登入、金鑰或環境變數。MCP 只有下面五個工具,沒有 KB、儲存或模型工具。

輸入共通規則

所有 MCP 工具都接受一個 JSON object。root object 與 cross_sihua.a/b 均拒絕未知欄位(additionalProperties: false)。不要傳 id、姓名、時區或其他未列欄位。字串不會被轉成數字;不自動修正日期、取整數或轉換性別。省略與 null 不同;下表的 optional 欄位不能以 null 代替。

scope 與 levels 的跨欄位依存由 server refinement 執行,並寫在 descriptions 與下列表格;不要假設 tools/list 的 JSON Schema 已把所有條件編碼為 if/then。欄位出現在 properties 中不表示任何 scope 都能傳。

共用 Birth:

欄位

型別 / 驗證範圍

必填

省略時

birthDate

string,補零 YYYY-MM-DD,真實公曆日期

是

無預設

hour

integer,0..23,出生當地民用小時

是

無預設

minute

integer,0..59,出生分鐘

否

0

gender

string,只接受 男 或 女

是

無預設

所有日期欄位均使用同一驗證:四位年份 0001..9999、月份 01..12、日數符合公曆閏年與該月天數,不接受時間尾碼或未補零日期。這是輸入驗證範圍,不是上游曆法在所有年份皆可計算的保證;上游不支援的計算可能被拒絕,或在原先允許的分支以 null 標明時間層缺失,不補造結果。實測覆蓋以後面的測試段落為準。

日期與小時不做時區、夏令時間或真太陽時校正。呼叫者須先決定要送入的民用日期與時間。hour/minute 是出生時分;targetHour/targetMinute 才是目標流時,不可互換。

出生分鐘會保留在正規化的 input,但上游紫微(含 overlay/cross)與 finance 不套用分鐘;八字將出生分鐘傳給 lunar-javascript。targetMinute 保留但上游流時不套用,不代表分鐘級精度。root daily 計算使用出生分鐘 0,並明列限制。

共通輸出 envelope

以下所有型別區塊都是 schema/shape 說明,不是執行結果,也不是可直接解析的 JSON。未提供任何臆造的數值輸出;後面的 JSON 範例均為合成輸入。

成功的 MCP tools/call result:

{
  structuredContent: Envelope,
  content: [{ type: "text", text: JSON.stringify(Envelope) }]
}

structuredContent 與唯一 text 解碼後的 object 完全相等。成功不另加 isError: false。所有計算的 JSON companion 都回傳 envelope object,不是已序列化的字串。

Envelope = {
  schema: "destiny-telling.calc/v1",
  kind: string,                      // 見各工具 / root API 對照
  input: object,                     // 正規化輸入,見各工具
  referenceDate: DateString | null,  // 不放在 input 裡冒充出生欄位
  config: {
    school: "north",
    gengMutagens: ["太陽", "武曲", "天同", "天相"]
  },
  data: object,                      // 各工具專屬 schema
  omitted: string[],                 // 明列未輸出的欄位路徑
  limitations: string[]              // 機器可讀限制碼
}

DateString 是上述日期字串,S 是 string,N 是有限 number,I 是有限 integer;T[] 為陣列、Record<S,T> 為以字串作 key 的 object、? 表示該欄位可能不存在。這些符號只是文件型別記法,沒有隱藏欄位。

無效輸入回 isError: true 與 text content,不回 structuredContent。handler 計算例外的固定訊息是 Calculation rejected: invalid or unsupported input.;SDK 前置 schema 驗證的文字可能不同。不要依賴錯誤文字作 schema,亦不要把錯誤當作空盤。測試檢查錯誤不回顯整份輸入或合成出生日期,不代表已窮盡任意惡意字串。

共用資料型別(shape,非結果)

LocatedHua = { star: S, hua: S, zhi: S | null, gongName: S }
Effect = { star: S, hua: S, source: S }
ChartPeriod = {
  ganZhi: S, sihua: S[], mingGongZhi: S,
  dieBenGong: S, palaceNames: S[]
}
FinancePalace = { gan: S, zhi: S, stars: S[], minor: S[] }
FinanceTemporalPalace = FinancePalace & { dieBen: S }

星名、宮名、干支、四化名稱及 detail/sourceLabel 等字串是計算標籤或事實列舉,不是解讀文章。原本本命四化的短標籤與各層標籤保留原行為,agent 不應自行把它們正規化後宣稱與原演算法相同。

五個 MCP 工具

1. ziwei_chart

輸入:Birth 全部欄位,加上:

欄位

型別

必填

省略時

referenceDate

DateString

否

執行時程序的實際本地日期

以該日期建立時間層;明確給定日期才能避免「今天」造成結果隨執行日變動。不是只替輸出加日期標籤。

合成輸入(fixture S1;fixture 的 id 不送入工具):

{"birthDate":"2001-03-07","hour":6,"minute":10,"gender":"女","referenceDate":"2026-10-24"}

輸出:kind = "ziwei.chart",input = Birth(含補上的 minute),referenceDate 是實際使用日期,data = ZiweiChart:

ZiweiChart = {
  basic: {
    solarDate: S, lunarDate: S, yearGanZhi: S, shiChen: S,
    gender: "男" | "女", yinYang: S, mingGong: S, mingGongZhi: S,
    shenGong: S, commandStar: S, bodyStar: S, wuXingJu: S,
    lunarMonth: I, shiChenIdx: I
  },
  gongs: Record<S, {
    name: S, stars: S[], minor: S[], sihua: S[], changSheng: S
  }>,
  gongGan: Record<S,S>,
  daXian: { zhi: S, startAge: N, endAge: N }[],
  siHua: Record<S,S>,
  feiHua: Record<S, { gan: S, sihua: S[] }>,
  horoscope: null | {
    decadal: ChartPeriod,
    yearly: ChartPeriod,
    age: { nominalAge: N, ganZhi: S, sihua: S[], dieBenGong: S }
  }
}

宮位 maps 以地支作 key,siHua 以星名作 key。上游無法取得時間層時 horoscope 為 null,不代表有可用流年資料。omitted = [];limitations = ["UPSTREAM_ZIWEI_BIRTH_MINUTE_NOT_APPLIED"]。

2. ziwei_overlay

輸入:Birth 全部欄位,加上:

欄位

型別 / 範圍

必填 / 可用條件

省略時

scope

year / month / day

是

無預設

targetDate

DateString

是,所有 scope 都需要

無預設

month

integer,1..12,明確斗君月序

僅 month scope,且此時必填

其他 scope 不得傳

targetHour

integer,0..23

僅 day scope

不計算流時,hourly: null

targetMinute

integer,0..59

僅 day,且必須同時有 targetHour

不送入目標分鐘;不影響上游結果

targetDate 會用來重建盤及決定參考年。year 算全部 1..12 斗君月;month 只選明確指定的斗君月。這個 month 不是 targetDate 的公曆月,也不會自動從公曆或農曆日期換算。year/month 不接受目標時分;day 不接受 month;此工具不接受額外 referenceDate。

三個 scope 的合成輸入(S2):

{"birthDate":"1990-11-02","hour":21,"minute":40,"gender":"男","scope":"year","targetDate":"2026-10-24"}
{"birthDate":"1990-11-02","hour":21,"minute":40,"gender":"男","scope":"month","targetDate":"2026-10-24","month":6}
{"birthDate":"1990-11-02","hour":21,"minute":40,"gender":"男","scope":"day","targetDate":"2026-10-24","targetHour":23,"targetMinute":59}

year/month 輸出:kind = "ziwei.transit",input = {...Birth, months: I[]},分別是全部斗君序或單一選定序;envelope 不保留 scope,referenceDate = targetDate。

TransitData = {
  decadal: OverlayPeriod,
  yearly: OverlayPeriod,
  monthly: Record<S, {
    mingGongZhi: S, dieBenGong: S, gan: S | null,
    effects: (Effect & { zhi: S, gongName: S })[]
  }>,
  palaceEffects: Record<S, {
    gongName: S, stars: S[], natal: Effect[], decadal: Effect[],
    yearly: Effect[], monthly: Record<S,Effect[]>
  }>,
  highlights: TransitHighlight[]
} | { result: null }
OverlayPeriod = {
  ganZhi: S, mingGongZhi: S, dieBenGong: S, sihua: LocatedHua[]
}
TransitHighlight =
  { type: "雙祿" | "雙忌" | "祿忌同宮", zhi: S, gongName: S, detail: S }
  | { type: "雙權", zhi: S, gongName: S }
  | { type: "化忌沖", zhi: S, gongName: S, targetGong: S, detail: S }
  | { type: "三祿疊" | "三忌疊", zhi: S, gongName: S, month: I, detail: S }

monthly 的 keys 是所選斗君序的十進位字串,不是日期;palaceEffects 以地支作 key。{result:null} 表示原 overlay 無資料,不是已算出空白的全年。

highlights 是原條件的命中紀錄,不是新評分:雙類各為同類至少 2 筆、祿忌同宮各至少 1 筆;三類包含該斗君月後同類至少 3 筆;沖的對宮結構亦保留。原本本命短標籤的判斷行為未改,不能把紀錄數當作另外定義的機率或風險分數。

  • omitted = ["summary", "_lookup", "highlights[].impact", "highlights[type=雙權].detail"]

  • limitations = ["UPSTREAM_ZIWEI_BIRTH_MINUTE_NOT_APPLIED", "MONTHS_ARE_DOUJUN_ORDER_NOT_CALENDAR_CONVERSION", "RAW_TARGET_YEAR_IS_LABEL_ONLY"]

day 輸出:kind = "ziwei.dayhour",input = {...Birth, targetDate, targetHour?, targetMinute?},只保留實際提供的目標時分,referenceDate = targetDate。

DayHourData = {
  daily: { gan: S, zhi: S, ganZhi: S, sihua: LocatedHua[] },
  hourly: null | {
    gan: S | null, zhi: S, shichenIdx: I,
    ganZhi: S | null, sihua: LocatedHua[]
  },
  highlights: {
    type: "多祿疊" | "多忌疊" | "祿忌同宮", gongName: S, detail: S
  }[]
} | { result: null }

找不到星時保留 zhi: null 與事實標記 gongName: "(本命無此星)",不補造宮位。shichenIdx 為時辰索引,不是分鐘。

  • omitted = ["summary", "highlights[].impact"]

  • limitations = ["UPSTREAM_ZIWEI_BIRTH_MINUTE_NOT_APPLIED", "UPSTREAM_TARGET_MINUTE_NOT_APPLIED"]

3. bazi_chart

輸入恰為 Birth:必填 birthDate/hour/gender,minute 可省略而為 0;不接受 referenceDate 或目標日期。

合成輸入(S1):

{"birthDate":"2001-03-07","hour":6,"minute":10,"gender":"女"}

輸出:kind = "bazi.chart",input = Birth,referenceDate = null,omitted = [],limitations = []。

BaziData = {
  solarDate: S, lunarDate: S, gender: "男" | "女", shiChen: S,
  pillars: { year: Pillar, month: Pillar, day: Pillar, time: Pillar },
  dayMaster: S, dayWuXing: S,
  wuXing: { 金: I, 木: I, 水: I, 火: I, 土: I },
  daYun: { ganZhi: S, startAge: N, startYear: N }[],
  startAge: N, shengXiao: S
}
Pillar = {
  ganZhi: S, naYin: S, shiShenGan: S, shiShenZhi: S[], hideGan: S[]
}

空的 limitations 不是對曆法或命理有效性的全面保證,只表示這個 wrapper 沒有附加限制碼。

4. cross_sihua

欄位

型別 / 範圍

必填 / 可用條件

省略時

a

strict Birth object

是

無預設;內層 minute 仍預設 0

b

strict Birth object

是

無預設;內層 minute 仍預設 0

referenceDate

DateString

是

無預設;用同一天建立雙盤

levels

下列 enum 的非空、無重複陣列,1..8 個

否

["natal","palace","decadal","yearly"]

month

integer,1..12,明確斗君月序

選 monthly 時必填,未選不得傳

無自動換算

targetDate

DateString

選 daily 時必填,未選不得傳

無預設

levels 的合法值及輸出 layer:natal → L1、palace → L2、decadal → L3、yearly → L4、pastDecadal → L3b、pastDecadal2 → L3c、monthly → L5、daily → L6。

referenceDate 選雙盤時間層及相對歷史大限;targetDate 只供選中的流日計算,不把雙盤參考日偷偷換成該日。month 同樣是斗君序,與 targetDate 月份無自動對應。pastDecadal/pastDecadal2 依原 daXian 陣列索引取得前一與前兩個位置,不重新排序;不存在的歷史大限不產生該層 flights,不報成計算錯誤,也不補造星曜。

合成輸入(S3/S4,八層包含 monthly/daily/前兩大限):

{
  "a":{"birthDate":"1975-07-19","hour":0,"minute":20,"gender":"女"},
  "b":{"birthDate":"1963-12-30","hour":23,"minute":30,"gender":"男"},
  "referenceDate":"2026-10-24",
  "levels":["natal","palace","decadal","yearly","pastDecadal","pastDecadal2","monthly","daily"],
  "month":6,
  "targetDate":"2026-10-25"
}

輸出:kind = "cross.sihua",input = {a: Birth, b: Birth, levels: S[], month?, targetDate?},條件欄位只在所選層存在。referenceDate 為雙盤參考日。

CrossData = {
  flights: { aToB: Flight[], bToA: Flight[] },
  meta: { levels: S[], nameA: "甲方", nameB: "乙方" }
}
Flight = {
  layer: "L1" | "L2" | "L3" | "L4" | "L3b" | "L3c" | "L5" | "L6",
  layerLabel: S, sourceLabel: S,
  fromPalace: S | null,
  fromPalaceZhi?: S, fromGan?: S,
  star: S, hua: S, toPalace: S, toPalaceZhi: S,
  starKind: "major" | "minor"
}

fromPalaceZhi/fromGan 只在 L2,且 L2 的 fromPalace 為字串;其他層 fromPalace 為 null。同一方向的執行順序固定為 L1、L2、L3、L4、L3b、L3c、L5、L6,與呼叫者排列 levels 的次序不同;meta.levels 保留選擇次序。JSON/MCP 不接受 nameA/nameB 或人物身分,固定使用甲方/乙方。

  • omitted = ["summary"]

  • limitations = ["UPSTREAM_ZIWEI_BIRTH_MINUTE_NOT_APPLIED", "MONTHS_ARE_DOUJUN_ORDER_NOT_CALENDAR_CONVERSION", "MISSING_HISTORICAL_DECADES_PRODUCE_NO_FLIGHTS"]

5. finance_chart

輸入:Birth 全部欄位,加上 optional referenceDate: DateString;省略時取程序實際本地日期。沒有其他欄位或預設。出生分鐘只保留,不參與上游計算。

合成輸入(S2):

{"birthDate":"1990-11-02","hour":21,"minute":40,"gender":"男","referenceDate":"2026-10-24"}

輸出:kind = "finance.chart",input = Birth,referenceDate 為實際使用日期:

FinanceData = {
  basic: {
    solarDate: S, lunarDate: S, chineseDate: S, gender: "男" | "女",
    mingGong: S, shenGong: S, juName: S, yearSihua: Record<S,S>
  },
  benMing: Record<S,FinancePalace | null>,
  keyFeiHua: Record<S,{ gan: S, sihua: S[] }>,
  decadal: FinancePeriod,
  yearly: FinancePeriod,
  months: { month: I, ganZhi: S, sihua: S[], caiBo?: FinanceTemporalPalace }[],
  age: { nominalAge: N, ganZhi: S, sihua: S[] }
}
FinancePeriod = {
  ganZhi: S, sihua: S[], palaces: Record<S,FinanceTemporalPalace>
}

本命/時間宮位 maps 以宮名作 key;yearSihua 以星名作 key。benMing 選取命宮、財帛、官祿、遷移、福德、田宅、子女、交友等原始宮位資料,不輸出投資建議。

注意:finance.data.months[].month 是原實作在參考年每個公曆月 15 日取樣的 1..12 索引,與 ziwei_overlay/cross_sihua 的輸入斗君序不是同一個介面。此工具沒有供呼叫者指定的 month 欄位;不要把取樣結果誤當全年每一天或自動換算後的斗君月。

omitted = [];limitations = ["UPSTREAM_FINANCE_HOUR_PRECISION_MINUTE_NOT_APPLIED"]。

Root ESM API

在 checkout 根目錄旁的 ESM 程式使用相對 import,或自行換成實際 module URL:

import {
  calculateChartJson, calculateCrossSihuaJson,
  calculateBaziJson, calculateFinanceJson, calculateDailyJson,
  getMonthlySihuaStarsJson
} from './index.js';

const birth = { birthDate: '2001-03-07', hour: 6, minute: 10, gender: '女' };
const chart = calculateChartJson({ ...birth, referenceDate: '2026-10-24' });
const monthly = getMonthlySihuaStarsJson(chart.data, 6);
// chart 與 monthly 都是 envelope object;此範例沒有宣稱任何計算數值。

以下列全計算函式與 JSON companions。y/m/d 是整數公曆日期組件;birth 指上述 strict Birth。建議跨程序傳輸都用 Json 版本;原 raw 簽章彼此時分/性別的參數次序不同,不能任意交換。

Raw / helper 簽章

JSON companion 與輸入

kind / data

calculateChart(y,m,d,hour,minute,gender,options={})

calculateChartJson({...birth,referenceDate?})

ziwei.chart / 上述 ZiweiChart

calculateTransitOverlay(chart,targetYear=null,targetMonths=null)

calculateTransitOverlayJson({...birth,referenceDate,months?})

ziwei.transit / 上述 TransitData

calculateDayHourOverlay(chart,y,m,d,hour=null,minute=null)

calculateDayHourOverlayJson({...birth,targetDate,targetHour?,targetMinute?})

ziwei.dayhour / 上述 DayHourData

formatChartByTianGan(y,m,d,gender)(事實字串)

calculateChartByTianGanJson({birthDate,gender})

ziwei.tiangan / 見下方

getMonthlySihuaStars(chart,month)

getMonthlySihuaStarsJson(chart,month)

ziwei.monthlyStars / {stars: S[] | null}

getDailySihuaStars(chart,y,m,d)

getDailySihuaStarsJson(chart,y,m,d)

ziwei.dailyStars / {stars: S[] | null}

getDecadalSihuaStarsAtOffset(chart,offset=0)

getDecadalSihuaStarsAtOffsetJson(chart,offset=0)

ziwei.decadalStars / {result: DecadalResult | null}

calculateCrossSihua(chartA,chartB,opts={})

calculateCrossSihuaJson({a,b,referenceDate,levels?,month?,targetDate?})

cross.sihua / 上述 CrossData

calculateBazi(y,m,d,hour,gender,minute=0)

calculateBaziJson(birth)

bazi.chart / 上述 BaziData

calculateFinance(y,m,d,hour,gender,options={})

calculateFinanceJson({...birth,referenceDate?})

finance.chart / 上述 FinanceData

calculateDaily({birth_date,birth_hour=12,gender='男',target_date})

calculateDailyJson({...birth,targetDate})

daily.chart / 見下方

Raw 與 JSON 的差別

  • chart/finance 的 raw options 只接受 referenceDate;省略取實際本地日期。JSON chart/finance 同義,其他 JSON 函式的必要日期不可省略。

  • raw transit 的 targetYear 只改 legacy 年份標籤,不重建盤、不重算流年。要換參考年必須重建 chart,或用要求 referenceDate 的 JSON companion。raw targetMonths 為斗君序選擇;JSON months 預設全部 1..12,明傳須為非空、無重複的整數 1..12 陣列。

  • raw transit 含 _lookup 函式,不能當純 JSON 傳輸;JSON 版明列省略 _lookup/summary 等欄位。不要用 JSON.stringify(raw) 靜默吞函式後冒充完整資料。

  • raw day/hour 的目標 minute 不參與上游計算。JSON 版另驗證日期及目標時分依存,不接受只有 targetMinute。

  • raw cross 的 opts 可帶 levels、nameA/nameB(預設甲方/乙方),以及 pastDecadalSihua/pastDecadal2Sihua/monthlySihua/dailySihua(各為 {a,b} 星名陣列或缺資料)及相對應的 pastDecadalLabel/pastDecadal2Label/monthlyLabel/dailyLabel。raw 不會替這些 extras 計算時間層;JSON 版改從雙盤及日期呼叫原 helpers,且不接受 caller labels 或姓名。

  • raw helpers 保留原邊界/null 行為;JSON companions 才驗證 month 整數 1..12、日期及 offset 整數。offset 不保證有對應大限,超出資料範圍為 null。三個 helper 的 input 分別為 {chart,month}、{chart,targetDate}、{chart,offset};都不知道 chart 建立時的參考日,因此 envelope referenceDate: null,limitations 含 CHART_REFERENCE_DATE_UNKNOWN。每日 helper 的目標日不冒充 chart 參考日。

  • monthly helper 另有 MONTHS_ARE_DOUJUN_ORDER_NOT_CALENDAR_CONVERSION;decadal helper 另有 MISSING_DECADAL_GAN_NORMALIZED_TO_NULL,僅將缺失的 gan: undefined 明確改成 null。它們 omitted 均為空陣列。

  • helpers 的原始陣列/null 放在 data.stars 或 data.result 內;不直接以陣列/null 冒充 envelope。DecadalResult = {stars: S[] | null, gan: S | null, zhi: S, startAge: N, endAge: N}。

  • 所有 JSON 輸出先做 lossless JSON 驗證,不以序列化刪除 unsupported values 作為修正。

TianGan 參考盤

calculateChartByTianGanJson 只接受必填 birthDate/gender,不接受 hour/minute。使用上游 index 0 的參考盤,不是未知時辰的推定結果,也不是「已知出生時間」盤;不能據此宣稱主星/宮位不受時辰影響。

kind = "ziwei.tiangan"
input = { birthDate: DateString, gender: "男" | "女" }
referenceDate = null
data = {
  solarDate: S, lunarDate: S, yearGanZhi: S, yearGan: S,
  gender: "男" | "女", referenceShiChenIdx: 0, yearSiHua: S[],
  starMap: Record<S,{gan: S, stars: S[]}>,
  feiHua: Record<S,{gan: S, sihua: S[]}>
}
omitted = []
limitations = ["INDEX0_REFERENCE_CHART_NOT_KNOWN_BIRTHTIME"]

Root daily(不是第六個 MCP 工具)

calculateDailyJson 接受 strict Birth 加必填 targetDate;出生時分仍依 Birth 規則驗證,但實際 daily 上游使用分鐘 0。raw daily 使用 snake_case,上游保留的介面可接受未補零日期;JSON companion 僅接受補零日期,且要求明確 hour/gender,不能套用 raw 的省略預設。

kind = "daily.chart"
input = { ...Birth, targetDate: DateString }
referenceDate = targetDate
data = {
  ziwei: {
    natal: { mingGong: S, mingGongStars: S[] },
    decadal: DailyPeriodWithOverlay,
    yearly: DailyPeriodWithOverlay,
    monthly: DailyPeriod,
    daily: DailyPeriodWithOverlay
  },
  bazi: {
    natal: { year: S, month: S, day: S, hour: S, dayMaster: S },
    daily: {
      dayPillar: S, monthPillar: S, yearPillar: S, dayNayin: S, lunarDate: S
    },
    interaction: {
      relationCode: S, relationTerm: S,
      natalDayStem?: S, natalElement?: S, dailyStem?: S, dailyElement?: S
    }
  },
  target_date: S, birth_date: S
}
DailyPeriod = { ganZhi: S, mutagen: S[], palaceNames: S[] }
DailyPeriodWithOverlay = DailyPeriod & { dieBenGong: S }
omitted = ["bazi.daily.dayYi", "bazi.daily.dayJi", "bazi.interaction.relation"]
limitations = ["UPSTREAM_DAILY_BIRTH_MINUTE_ZERO"]

relationCode 為 SAME、NATAL_GENERATES_DAILY、DAILY_GENERATES_NATAL、NATAL_CONTROLS_DAILY、DAILY_CONTROLS_NATAL 或 UNKNOWN;只是五行關係代碼。UNKNOWN 分支沒有四個 stem/element 欄位,不輸出解讀句子。

Formatters、常數及共用 exports

以下函式只回傳事實表格/字串,不回傳 envelope:formatChart(chart)、formatChartCompact(chart)、formatChartByTianGan(y,m,d,gender)、formatBazi(chart)、formatBaziCompact(chart)、formatFinance(chart)。若要 transport 請選對應 JSON calculator,而不是把格式化字串當作可解析資料。

root 亦匯出 SHI_CHEN_RANGE、DI_ZHI、TIAN_GAN 以及底層 __internals(cross 的定位/分層 helpers 與表)。它們不是額外 MCP tools。

共用函式

行為

normalizeBirthInput(input)

驗證 strict Birth,補 minute 0,回傳新 object

normalizeDate(value,{allowUnpadded=false}={})

驗證公曆日期並回傳補零字串;JSON calculators 不啟用未補零選項

birthFromParts(year,month,day,hour,gender,minute=0)

驗證整數日期組件及 Birth,回傳正規化 Birth;注意 gender 在 minute 前

assertRecord(value,name='input')

要求 plain object,不接受 array/null/其他 prototype

assertKeys(value,keys)

拒絕未知 key、symbol、非 enumerable 或 accessor 欄位

assertJsonData(value)

驗證有限數字、dense array、plain object 等可無損 JSON 值;拒絕 undefined/函式/循環/-0 等

createJsonEnvelope(kind,input,data,{referenceDate=null,omitted=[],limitations=[]}={})

建立上面完整 envelope、驗證後回傳 JSON object;沒有替 caller 解讀資料

保留的北派設定與精度界線

庚干固定為「太陽祿、武曲權、天同科、天相忌」,共享設定的星序是 ['太陽','武曲','天同','天相']。此設定及流月斗君、流日/流時算術、交叉層級邏輯均保留既有計算;不因包裝成 MCP 而更換門派表或修補上游特殊行為。

固定 referenceDate 可重現時間層;沒有明確日期的 chart/finance 呼叫不應只憑 MCP 的 idempotent hint 當成永久固定結果。helper 不知道傳入 raw chart 的日期時會明列未知,不從內容猜測。沒有完整曆年、所有出生組合或分鐘級準確度的驗證承諾。

測試:區分完整 gate 與無原檔的 smoke

完整 gate:

npm test

這不只是一般 unit tests:它直接 import 授權且未變更的原始計算檔,做數值/結構 parity、SHA256 before/after 檢查及從原檔於記憶體取得禁止片段的中性掃描。五個原始計算檔的 hashes 與 tests/fixtures/source-manifest.json 比對;另外兩個上游測試檔的 hashes 在 parity suite 比對。不是複製一份計算輸出 baseline 作為「原檔」。

公開 checkout 不包含那些原始來源,因此單靠本 repo 不保證 npm test 可過;缺少原檔會 fail,不會自動 skip。請只在有授權原檔的環境跑完整 gate,並由呼叫者設定 DT_SRC_MIRROR 與 DT_SRC_API 為各自來源根目錄,或保留 helper 的預設相對布局(repo 的上兩層下有 src-mirror/ 與 src-api/):

  • mirror 根下需有 src/ziwei-calc.js、src/crosssihua.js、src/bazi-calc.js、src/finance-calc.js,及 test-crosssihua.mjs、test-heban-modes.mjs。

  • API 根下需有 calc-daily.mjs。

  • resolve hook 只替指定原始計算檔的依賴解析指向本 repo 已裝套件;不改寫原始演算法。

  • 不要為了變綠而複製私有原檔到公開 repo、替換 hash、建立輸出快照、放寬 parity 或宣稱缺原檔可跳過。

沒有原檔時,可在 checkout 根目錄跑這組自含 smoke/integration:

node --test tests/index-exports.test.mjs tests/integration.test.mjs tests/mcp-smoke.test.mjs

已檢查這三檔及其本地匯入:只用產品、已安裝 dependencies、合成 fixture 與 fixed-clock.mjs,不使用 source hooks/integrity/neutral-scan helper、不讀外部原檔。包含真實 stdio 子程序與五工具呼叫,不是 mock;但它不是 direct-original parity,也不能替代完整發布 gate。test:sol 腳本仍包含需要原檔的掃描,不可把它誤作無原檔替代方案。

實測覆蓋使用七組合成 births 與四個固定日期 2024-02-10、2025-12-31、2026-10-24、2027-01-01。紫微 parity 含每例 12 斗君月、無流時及 24 小時、TianGan index0;cross 以每個 fixture 與下一個環狀配對,檢查雙向八層及歷史缺失,不宣稱測過所有兩兩配對或所有曆日。MCP smoke 檢查 initialization、恰好五工具、三種 overlay scope、cross temporal 層、非法欄位/日期/時分拒絕、stdout JSON-RPC 與子程序清理;另以測試擁有的臨時 symlink 驗證 Node/shebang 啟動的真實 initialization、list、tool call,並清理子程序及臨時目錄。中性掃描是已知片段檢查,不是完整 PII、secret 或語意審查。

測試輸出才是當次通過數的依據;本文件不以舊測試數或單一子集代表最終驗收。直接 Node entry 與測試擁有的 symlink 回歸,也不等於 Claude/Cursor 已在使用者應用程式完成安裝,或 npm-installed bin 已驗證。

授權與依賴致謝

本專案附 MIT LICENSE:Copyright 2026 cph0512 / destinytelling.life。

以下名稱、版本、MIT 授權與 repository URL 已依本地安裝 metadata 及隨附 LICENSE 核對;不是對遠端最新版本或可用性的網路驗證:

直接依賴

已安裝版本

授權

Repository

iztro

2.6.3

MIT

https://github.com/SylarLong/iztro.git

lunar-javascript

1.7.7

MIT

https://github.com/6tail/lunar-javascript.git

@modelcontextprotocol/sdk

1.32.2

MIT

https://github.com/modelcontextprotocol/typescript-sdk.git

zod

4.6.7

MIT

https://github.com/colinhacks/zod.git

感謝 iztro 與 lunar-javascript 提供底層排盤/曆法計算、MCP SDK 提供本機協議傳輸、zod 提供輸入驗證。第三方 copyright 與 MIT 文本見 NOTICE 及各套件隨附 LICENSE;直接依賴清單不冒充完整傳遞依賴授權稽核。

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    A
    maintenance
    Enables LLMs to perform deterministic arithmetic, high-precision decimal math, unit conversions, statistics, finance, matrix operations, complex-number calculations, numerical calculus, probability distributions, date math, and root solving through MCP tools. It supports both Streamable HTTP and stdio transport.
    13
    19 npm
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables MCP-compatible clients such as Claude Desktop, Cursor, and Antigravity to invoke deterministic mathematical modeling and System 2 agent capabilities through a native STDIO JSON-RPC 2.0 server with zero external dependencies.
    7
    MIT