# KundaliMCP — full tool reference

> Generated from a live `tools/list` call against the endpoint below. This document is rendered per request, never checked in, so it cannot drift from the server.

- Endpoint: `https://mcp.kundalimcp.com/mcp` (MCP Streamable HTTP + SSE, JSON-RPC 2.0)
- Protocol: 2026-07-28
- Engine: 17.5.4
- Rules corpus: 1.75.0
- Tools: 10
- Auth: `Authorization: Bearer <sutra_… API key>` or an OAuth 2.1 access token.

Human-readable version: https://kundalimcp.com/docs

## Conventions

> Served by the endpoint as MCP `instructions` (on `initialize` and `server/discover`). True of every tool below.

KundaliMCP — agentic-AI Vedic Jyotish MCP. Authenticated tier. See https://kundalimcp.com/docs.

TIME: every datetime input is naive local clock time at the relevant location (no 'Z', no ±HH:MM offset); the server resolves the historical UTC offset from latitude + longitude. Every emitted datetime is likewise naive local clock time, read against the ONE zone the root declares — `tz_iana` + `tz_offset_minutes` on <kundalimcp>. There is no UTC twin, no `_local` suffix and no Julian Day. A block for a different zone (a milan party's birth) carries its own `tz_iana` / `tz_offset_minutes` and those govern its subtree.

## Contents

- [`chat`](#chat)
- [`get_version`](#getversion)
- [`kundali`](#kundali)
- [`kundali_milan`](#kundalimilan)
- [`lifemap`](#lifemap)
- [`muhurat`](#muhurat)
- [`panchang`](#panchang)
- [`pramaan`](#pramaan)
- [`submit_feedback`](#submitfeedback)
- [`tithi`](#tithi)

---

## chat

Open-ended Jyotish conversation grounded in citations from the classical canon (BPHS, Phaladeepika, Saravali, and curated commentaries). Birth data is OPTIONAL.

Behavior:
  · No birth data + general question → answered from the corpus, no chart computed.
  · Birth data present + chart question → grounded in the computed chart.
  · Chart question with NO birth data → an ask-back (<needs>, below); the engine never guesses, and that turn is FREE, not billed.
  · `thread_context` supersedes the engine's short internal memory. IT IS STORED: with a session identifier, the question and the answer are written to per-session thread memory, encrypted at rest (AES-256-GCM) and expiring 4 hours after the last turn. Omit the session identifier and nothing is written.

Returns:
  · ONE XML document in content[0].text — `<kundalimcp tool="chat" schema="1" locale=… tool_class="conversational" answered=… needs_birth_data=… [time_known]>` — and NO structuredContent.
  · <headline>, then <answer>: the composed prose.
  · <claims n> of <claim>: a claim with no resolved citation carries kind="uncited". On an LLM-generated answer effectively every claim is uncited BY DESIGN — the generator writes prose with no inline markers, and a marker is forgeable.
  · <citations kind="grounding" n> of <citation concept [name] [locus] [source]>: the GROUNDING SET — what the engine knew about this chart and question, not evidence the answer cited.
  · <citations kind="addressed" n> of <provenance concept>: the subset the answer actually engaged with.
  · <needs kind="birth_data" n> of <need field>: the fields still required, present only when needs_birth_data is true.
  · <classification tier="tier1|tier2|tier3" category on_topic [specialty] [intent_kind]>: a tier="tier1" (crisis) turn ships NO <answer> element, <claims n="0">, answered="false" and <metadata route="tier1_crisis">. It carries no crisis-resource content of its own; `tier` and `route` are the only signals it emits.
  · <metadata validator_passed route [thread_context_chars]>: `route` names how the turn was produced — `llm_synthesis` for a composed answer; `off_topic`, `ask_back`, `milan_ask_back`, `tier1_crisis`, `longevity_gate`, `diagnosis_gate`, `classify_unavailable`, `safety_review_unavailable`, `unsourced_concept` or `well_exhausted` (the thread has covered everything on this subject) for a deterministic reply. An answered="false" turn names its reason here, plus <validator_issues n> only when the safety scan flagged something (absent when clean).
  · <redirect_cta> when the turn was redirected rather than answered.
  · answered="false" when needs_birth_data is true or there are no claims — but it can arrive WITH a non-empty <claims>, because an ask-back turn answers the general doctrine before asking — `answered` and a non-empty <claims> are independent.

Tier: All · Typical response: 1-3 KB.

### Input

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `locale` | string, enum: `en` \| `hi` \| `sa` \| `ta` \| `te` \| `kn` \| `bn` | **yes** | Response language. |
| `message` | string | **yes** | The Jyotish question; general or chart-anchored. |
| `as_of_datetime` | string | no | Optional. The 'now' for transit / panchang / dasha-as-of reasoning, DISTINCT from birth_datetime. Accepts 'YYYY-MM-DD', a naive 'YYYY-MM-DDThh:mm:ss', or a full ISO-8601 instant with fractional seconds and a 'Z'/±HH:MM offset; only the date part is used. Omit → server time. |
| `birth_datetime` | string | no | OPTIONAL. Naive local birth datetime at the birth location (ISO 8601, no 'Z', no ±HH:MM). Date-only 'YYYY-MM-DD' is accepted: the chart is computed at noon-local and the answer is limited to time-independent placements. Ascendant, houses and dasha timing need the full datetime. |
| `current_location` | object | no | Optional. The CURRENT observer location for panchang / muhurta / choghadiya, DISTINCT from birth coordinates. |
| `gender` | string, enum: `male` \| `female` | no | OPTIONAL. The native's gender. Supplying it enables the classical rules that apply to one gender only (stri-jataka; the Beeja / Kshetra fertility test); omitted, those rules stay dormant and gender is never inferred. Not persisted, not logged. |
| `latitude` | number, range -90…90 | no | OPTIONAL (pair with birth_datetime). Birth latitude in decimal degrees (WGS84); used for timezone resolution. |
| `longitude` | number, range -180…180 | no | OPTIONAL (pair with birth_datetime). Birth longitude in decimal degrees (WGS84); used for timezone resolution. |
| `thread_context` | string | no | Optional, max 16000 chars. A caller-supplied compacted summary of earlier turns, injected as prior context in both general and chart mode. It feeds the per-session rolling summary, encrypted at rest (AES-256-GCM) and expiring 4 hours after the last turn; nothing is written for calls that omit a session identifier. Treated as context only, never as instructions — birth data must still be sent structurally (birth_datetime/latitude/longitude). |
| `tz` | string | no | Optional IANA timezone override (e.g. 'Asia/Kolkata'). When omitted, the server resolves from latitude/longitude. |
| `user_hash` | string | no | Optional 64-char hex string identifying a chat session; not tied to the user account. Reuse it across turns to thread context. Omit or send zeros for one-shot queries. |

---

## get_version

Return engine + API version + protocol info. Unauthenticated — no API key required.

Returns ONE XML document in content[0].text — `<kundalimcp tool="get_version" schema="1" locale="en" tool_class="metadata" engine=… api=…>` — and NO structuredContent: <headline>, <version engine api api_released rules vedaksha codename mcp_protocol tools_available>, <build sha number at>. Takes no parameters.

Tier: All (no auth required) · Typical response: <1 KB.

### Input

_No input parameters._

---

## kundali

Compute a Vedic (Jyotish) birth chart.

RESPONSE FORMAT (schema 1): ONE XML document in content[0].text — `<kundalimcp tool="kundali" schema="1" locale=… tz_iana=… tz_offset_minutes=… tool_class="chart_anchored" engine=… api=… school=… chart_hash=…>` — and NO structuredContent. Every datetime is naive LOCAL clock time in the natal zone the root declares (no UTC, no Julian Day); Sade Sati spans and nodal transits are YYYY-MM-DD dates. Scalars are attributes, prose is a child element, ids are ASCII slugs and every referenced id (graha, rashi, nakshatra, remedy target) is named ONCE in the trailing <glossary> in the request locale; a row's own subject keeps `name` inline. EVERY ROW THAT `pramaan` CAN EXPLAIN CARRIES `claim` — the exact `claim_id` to send it, verbatim; `id` always NAMES the row and is never a URI. Verdict attributes (quality, polarity, confidence, severity) appear only on rows that carry their <why> witness or <cite> locus.

Root blocks, in order: <headline>; <context frame="natal" [gender]> (<school id ayanamsa house_system node_type>, <computed as_of> — the ONE evaluation instant every "now" block is anchored on: the caller's `transit_date`, else now); <lagna rashi nakshatra pada lord>, <chandra>, <surya>, <arudha_lagna>; <placements chart="D1" frame="natal" ref="lagna" n="9"> of <graha id name abbr rashi bhava bhava_from_moon nakshatra pada nakshatra_lord dignity motion [flags="retrograde combust deeply_combust war"] [war_opponent war_winner]>; <bhavas chart="D1" ref="lagna"> and <bhavas ref="chandra"> (the Chandra kundali) of <bhava n rashi lord_in occupants>; <yutis>; <aspects frame="natal"> of <aspect from from_bhava to_bhava [to] ordinal>; <yogas chart="D1" n of active> of <yoga id name claim category quality rarity bhavas grahas> rows each with a <narrative domain=…> child, and under `include=provenance` their <why><cond>…</cond></why>, <cite> and <description>; <afflictions> of <affliction id claim type affected cause_kind [cause] bhavas severity cancelled> with its mechanism as <why> under `include=provenance`; <active_dasha system as_of> of <period level lord ends> rows (plus <period rel="next">); <sade_sati active as_of [phase]> with <span rel start end>; <nodal_transit as_of> of <graha id rashi bhava bhava_from_moon since until>; <placements frame="transit" as_of> of <graha id rashi bhava bhava_from_moon [flags]>; <aspects frame="transit" as_of n of> of <aspect from to ordinal>; <dashas system="vimshottari" frame="natal" depth n total_years [branch]> of nested <period level lord start end days> — the FIRST mahadasha's `start` is the token `birth`, not a timestamp, because the Vimshottari clock begins at the nativity; <dashas kind="forecast" as_of> (the period active at `eval_date`, its <label kind="theme">s and the next changes); <mangal_dosha present base_severity [mitigations]> with <bhava n ref> rows; <panchanga frame="birth"> of <limb kind id name …> (the same limb shape as the `panchang` tool); <chara_karakas>; <profession>; <marakas>; <shadbala unit="virupa"> (the seven grahas Surya to Shani; BPHS Ch.27 excludes the nodes), <ashtakavarga kind="sarva" points>, <vimshopak>, <functional_classifications> (each graha with <relations kind="compound">; the naisargika and tatkalika tables are NOT emitted — the first is a universal constant, the second a pure function of signs already in <placements>), <boundary_margins> of <graha id sensitive>, <dispositions> of <bhava n disposition readings>; <synthesis kind="yogas">; <remedies n top overall_confidence> of <remedy id name type addresses>; then the opt-in blocks, <absent not_requested=…> plus one <absent section reason>text</absent> per section that had nothing to say (not_applicable) or broke (failed), <disclaimers>, <glossary>.

OPT-IN, via `include`: `classical_rules` adds <insights n of [limit bhavas omitted]> — one <insight rule claim topic bhava polarity confidence grahas [suppressed_by]> per cited rule that fired, with <why>, <cite>, <title>, <reading>; pass `classical_rules_limit` (per-bhava cap, the <bhava n shown of> marker rows keep the totals) and/or `classical_rules_bhavas`. `provenance` adds THE GROUNDS for every claim in the response: the <why> witness (which limb of the classical condition held on THIS chart), the <cite> locus, the rule source text (<description>, <reading>) and a <trace significator shadbala strength_ratio> under each insight. Without it a row still states its verdict and carries `claim` — the exact `claim_id` to send `pramaan` for that one row. Same token and meaning on `lifemap`, `kundali_milan`, `muhurat` and `pramaan`. `vargas` adds, per requested divisional, <placements chart="D9" kind="varga" lagna reliability> of <graha id rashi bhava dignity amsa [flags]> (+ <label kind="devata">) and <bhavas chart="D9" kind="varga">. `events` adds <events frame="natal" kind="forecast" as_of age n of suppressed [horizon_to]> of <event id name claim life_area band confidence [peaks]> rows, with their <why> witness under `include=provenance` — a snapshot at `eval_date`, or a weekly scan to `events_until`. `transit_events` (needs `transit_start` / `transit_end`) adds <events frame="transit" kind="ingress" start end n major_ingresses sade_sati_changes return_events> of <event date graha from to bhava significance> rows. `narrative` (needs `domain`) adds <synthesis kind="narrative" domain claim band insights> with <paragraph> and <cite rule>. `idl` enriches in place: every active yoga (no cap) with practitioner notes and cancellations, <ashtakavarga kind="bhinna">, the forecast's interpretation, the per-varga yoga assessment. Default-on sections (active_yogas, dashas, dasha_forecast, transits, remedies, planets, panchanga) ship on every call.

sensitive="true" on a <graha> in <boundary_margins> means that placement straddles a classical boundary: its nakshatra, pada and D9 position can change with a small shift in birth time. The chart artifact is auto-cached encrypted, keyed off the API key, TTL up to 30 days; `cache: "skip"` disables the read and the write for one call.

Tier: All · Typical default response: ~51 KB.

### Input

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `birth_datetime` | string | **yes** | Local clock time at the birth location, ISO 8601 naive form (e.g. '1990-06-15T06:30:00'). NO 'Z' suffix, NO ±HH:MM offset. The server resolves the historical UTC offset from latitude + longitude. A DST fall-back ambiguity resolves to the pre-transition offset and is reported as a <note> child of <context> (or of <party> on kundali_milan); a DST spring-forward gap (a clock face that never existed locally) returns -32602 InvalidParams. |
| `latitude` | number, range -90…90 | **yes** | Birth latitude in decimal degrees, WGS84. |
| `locale` | string, enum: `en` \| `hi` \| `sa` \| `ta` \| `te` \| `kn` \| `bn` | **yes** | Response language. Required. |
| `longitude` | number, range -180…180 | **yes** | Birth longitude in decimal degrees, WGS84. Used for tz resolution. |
| `school` | string, enum: `parashari` \| `jaimini` \| `kp` | **yes** | Jyotish school for interpretation. Required. |
| `ayanamsa` | string | no |  |
| `cache` | string, enum: `skip` | no | Optional. "skip" suppresses the cache read AND write for this call, so no entry is stored. |
| `dasha_branch` | string | no | Which antardasha to drill BELOW, as "<maha-lord>/<antar-lord>" graha slugs — e.g. "shani/budha". REQUIRED whenever dasha_depth > 2, ignored otherwise. Levels below antardasha are returned for this branch only; every other antardasha stops at level 2. Slugs: surya, chandra, mangala, budha, guru, shukra, shani, rahu, ketu. |
| `dasha_depth` | integer, range 1…5 | no | How many levels the `dashas` TIMELINE renders: 1=mahadasha, 2=+antardasha (DEFAULT), 3=+pratyantar, 4=+sookshma, 5=+prana. ANY VALUE ABOVE 2 REQUIRES `dasha_branch` and drills into that ONE antardasha; the full mahadasha/antardasha spine is still returned. Response sizes: 1=3 KB, 2=26 KB, 3=29 KB, 4=52 KB, 5=260 KB. |
| `dasha_max_level` | integer, range 0…4 | no | How deep the dasha tree is COMPUTED (0=Maha, 1=+Antar, 2=+Pratyantar, 3=+Sookshma, 4=+Prana). DEFAULT 1, raised automatically when `dasha_depth` needs more. Distinct from `dasha_depth`, which decides how much of the computed tree the `dashas` section RENDERS. |
| `domain` | string | no | Life area for the `narrative` section: career, marriage, health, wealth, education, spirituality, relationships, longevity, fame, family. Requires include=narrative. |
| `eval_date` | string | no | Date (YYYY-MM-DD) the `dasha_forecast` section is evaluated at. Omit for now. |
| `gender` | string, enum: `male` \| `female` | no | OPTIONAL. The native's gender. Supplying it enables the classical rules that apply to one gender only (stri-jataka; the Beeja / Kshetra fertility test); omitted, those rules stay dormant and gender is never inferred. Not persisted, not logged. |
| `house_system` | string | no |  |
| `include` | string | no | Comma-separated SECTIONS to add; several in one call cost one computation. Opt-in: classical_rules (Cited classical rules that fired on this chart, each with its source locus. ~61 KB; `classical_rules_limit: N` keeps the N highest-confidence rules PER BHAVA, and the per-bhava totals stay on the section marker.) [params: classical_rules_limit, classical_rules_bhavas] · events (Lifetime forecast events with likelihood band, confidence, why-clauses and per-factor breakdown, evaluated at `eval_date` (default: now). Two modes: `eval_date` alone gives a point-in-time SNAPSHOT of what is firing then; adding `events_until` (YYYY-MM-DD) runs a weekly SCAN across the window, keeping each event's strongest firing. There is no default horizon. Zero-confidence entries are withheld and counted in `suppressed_zero_confidence`.) [params: eval_date, events_until] · transit_events (Sign-ingresses, retrograde stations and returns across a date range. Needs `transit_start` and `transit_end`. Scans the window, so it costs compute.) [params: transit_start, transit_end] · vargas (Divisional charts. Defaults to D9 when the section is named without the parameter.) [params: vargas] · narrative (Plain-language reading for one life domain.) [params: domain] · provenance (The GROUNDS for every claim in this response: the <why> witness (which limb of the classical condition actually held on THIS chart), the <cite> classical locus, the rule's source text (<description>, <reading>) and the Vivek <trace> under each insight. Same token and same meaning as `kundali_milan` and `muhurat`. Without it a row still states its verdict and carries `claim` — the exact `claim_id` to send `pramaan` for the reasoning about that one row.) · idl (The raw deterministic artifact, pre-shaping. LARGE.). Default-on: active_yogas, dashas, dasha_forecast, transits, remedies, planets, panchanga. |
| `transit_date` | string | no | Moment for the `transits` section, local clock time. Omit for now. |
| `transit_end` | string | no | Window end (YYYY-MM-DD) for the `transit_events` section. Max 5 years from transit_start. |
| `transit_start` | string | no | Window start (YYYY-MM-DD) for the `transit_events` section. Requires include=transit_events. |
| `vargas` | array, items: string | no | Divisional charts, e.g. ["D9","D10"]. Requires include=vargas. Defaults to ["D9"]. |

---

## kundali_milan

Compute Ashtakoota compatibility between two Vedic birth charts.

Inputs are `groom: {birth_datetime, latitude, longitude}` and `bride: {birth_datetime, latitude, longitude}`.

RESPONSE FORMAT (schema 1): ONE XML document in content[0].text — `<kundalimcp tool="kundali_milan" schema="1" locale=… tz_iana=… tz_offset_minutes=… tool_class="chart_anchored" engine=… api=… school=…>` — and NO structuredContent. The root declares the GROOM's zone and every pair-level instant reads in it; each <party role="groom|bride" tz_iana tz_offset_minutes> declares its own zone and every party-level instant reads in it. Root blocks, in order: <headline>, <context frame="pair"> (two <party> + <computed as_of>), <kootas kind="ashtakoota" n total of verdict> of <koota id name score of passes groom bride><why><cond>verdict sentence</cond></why></koota> rows, <doshas> of <dosha id name [groom bride] present [cancelled] severity> rows each with <why><cond rule=…>fired cancellation</cond></why>, <cite source_class=…>, <reading> and — when Mars sits in a dosha house the source exempts — <non_arising exemptions> with <bhava n ref> rows and the reasons, <temporal as_of> (<sade_sati groom bride band>, <afflictions kind="ashtama_shani">, <overlaps kind="nodal"> with <overlap from direction to_bhava> rows and one <yoga id="kaal-sarpa" party state …> per partner, <spans kind="antardasha_sync">, <dashas kind="transitions">, <paragraph>), the cross-chart blocks (<placements chart="D1|D9" frame="pair" kind="overlay|karaka">, <bhavas frame="pair">, <dashas kind="compatibility">, <synthesis kind="longevity">), <kootas kind="dashakoota">, <synthesis kind="composite|consensus|confidence">, <evidence kind="concepts"> — every koota, dosha and temporal concept ONCE with its <description>, mechanism/significance <note>s, <cite>s and source_class, keyed by the ids the rows carry — then <absent>, <disclaimers>, <glossary> (every graha, rashi, koota class and the verdict token named once, in the request locale).

OPT-IN, via `include`: `provenance` adds <evidence kind="rules"> — the compendium rule overlay, one <rule id slug stage role anchor> per rule that applied to this pair with its <label> indication, source text <note> and <cite> loci — and <synthesis kind="verdict">. ~110 KB.

Tier: All · Typical default response: ~33 KB.

### Input

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `bride` | object | **yes** |  |
| `groom` | object | **yes** |  |
| `locale` | string, enum: `en` \| `hi` \| `sa` \| `ta` \| `te` \| `kn` \| `bn` | **yes** | Response language. Required. |
| `school` | string, enum: `parashari` \| `jaimini` \| `kp` | **yes** | Jyotish school for interpretation. Required. |
| `cache` | string, enum: `skip` | no | Optional. "skip" suppresses the cache read AND write for this call, so no entry is stored. |
| `eval_date` | string | no | Optional. Evaluation moment for the temporal-compatibility block. Date-only `YYYY-MM-DD` is treated as noon UT; full `YYYY-MM-DDTHH:MM[:SS]` as UT. Defaults to the server's current time. NOT location-anchored. |
| `include` | string | no | Comma-separated SECTIONS to add; several in one call cost one computation. Opt-in: provenance (The compendium rule overlay: every matching rule that applied to this pair — koota scoring, dosha detection and cancellation, cross-chart and temporal slices, aggregation thresholds — as <evidence kind="rules"> rows with the rule's indication, its source text and its classical loci, plus the assembled <synthesis kind="verdict"> narrative. Large (~80 rules).). |

---

## lifemap

Compute a lifetime Vedic forecast across Vimshottari dasha periods.

RESPONSE FORMAT (schema 1): ONE XML document in content[0].text — `<kundalimcp tool="lifemap" schema="1" locale=… tz_iana=… tz_offset_minutes=… tool_class="chart_anchored" engine=… api=… school=… chart_hash=…>` — and NO structuredContent. Every datetime is LOCAL clock time in the natal zone the root declares; dasha boundaries, Sade Sati spans, returns and event windows are YYYY-MM-DD dates. Root blocks, in order: <headline>, <context frame="natal"> (<computed as_of lookahead_years>), <active_dasha system as_of> with a <period level="mahadasha" lord ends> and <period level="antardasha"> row (each with <label kind="theme"> children; reason="beyond_timeline" when the native has outlived the computed timeline), <dashas rel="next" n> of <period lord start end years> rows, <sade_sati active [phase]> with <span rel="previous|next" start end>, <returns n> of <return graha ord age date> rows, <events frame="life" kind="key" n> of <event kind age date><title/></event> rows, then the opt-in blocks, <absent not_requested=…>, <disclaimers>, and a <glossary> naming every id (graha lords, in the request locale) once.

OPT-IN, via `include`: `life_events` adds <events frame="life" kind="forecast" n of windows …census…> — one <event id name bhava related_bhavas frequency> per forecast event with its <why><cond kind=…> witness, its <cite> sources and one <when from to from_age to_age md ad score status tier nth [flags="headline"]> row per dasha window (Raman's tier: par_excellence | ordinary | limited | feeble) — plus <windows frame="life" kind="fructification"> (per-bhava windows, each with <why><cond ref=event-id/>), <ashtakavarga kind="sarva" points> and <vimshopak> rows. `trajectories` adds <trajectories authority="experimental" step n>: twelve <bhava n band values> curves over ONE <sample age md ad width> spine (~10 KB). Default-on sections (active_dasha, dashas, sade_sati, returns, events) ship on every call.

Tier: All · Typical default response: ~2 KB.

### Input

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `birth_datetime` | string | **yes** | Local clock time at the birth location, ISO 8601 naive form (e.g. '1990-06-15T06:30:00'). NO 'Z' suffix, NO ±HH:MM offset. The server resolves the historical UTC offset from latitude + longitude. A DST fall-back ambiguity resolves to the pre-transition offset and is reported as a <note> child of <context> (or of <party> on kundali_milan); a DST spring-forward gap (a clock face that never existed locally) returns -32602 InvalidParams. |
| `latitude` | number, range -90…90 | **yes** | Birth latitude in decimal degrees, WGS84. |
| `locale` | string, enum: `en` \| `hi` \| `sa` \| `ta` \| `te` \| `kn` \| `bn` | **yes** | Response language. |
| `longitude` | number, range -180…180 | **yes** | Birth longitude in decimal degrees, WGS84. Used for tz resolution. |
| `school` | string, enum: `parashari` \| `jaimini` \| `kp` | **yes** | Jyotish school for interpretation. |
| `ayanamsa` | string | no |  |
| `cache` | string, enum: `skip` | no | Optional. "skip" suppresses the cache read AND write for this call, so no entry is stored. |
| `gender` | string, enum: `male` \| `female` | no | OPTIONAL. The native's gender. Supplying it enables the classical rules that apply to one gender only (stri-jataka; the Beeja / Kshetra fertility test); omitted, those rules stay dormant and gender is never inferred. Not persisted, not logged. |
| `house_system` | string | no |  |
| `include` | string | no | Comma-separated SECTIONS to add; several in one call cost one computation. Opt-in: life_events (The lifetime forecast-event list (<events frame="life" kind="forecast">, each event with its witness, its sources and one <when> row per dasha window carrying Raman's tier and rank), the per-bhava fructification windows (<windows frame="life" kind="fructification">), and the strength evidence behind them (<ashtakavarga>, <vimshopak>, <strength_profiles>), with the census denominators on the two blocks. Large — tens of KB.) · provenance (The GROUNDS for every life-event row: the <why> witness (which natal and dasha limbs actually held on THIS chart) and the <cite> classical locus. Without it a row still states its bands and windows and carries `claim` — the exact `claim_id` to send `pramaan` for the reasoning about that one event.) · trajectories (The per-bhava journey curve: twelve <bhava n band values> rows over ONE shared <sample age md ad width> spine (~126 samples at the default step). Heuristic values, marked authority="experimental". ~10 KB.). Default-on: active_dasha, dashas, sade_sati, returns, events. |
| `sample_step` | number, enum: `0.5` \| `0.8` \| `1` \| `2` | no | Trajectory sampling step in years (default 0.8). Higher = coarser + smaller payload. |

---

## muhurat

RESPONSE FORMAT (schema 1): ONE XML document in content[0].text — `<kundalimcp tool="muhurat" schema="1" locale=… tz_iana=… tz_offset_minutes=… tool_class="location_anchored" engine=… api=… school=…>` — and NO structuredContent. Root blocks, in order: <headline>, <context frame="election" event=… event_type=…> (<observer lat lng> + <span kind="range" start end>), <windows frame="election" kind="recommended" n of order> and <windows … kind="blocked" …> of <window id name quality band [favorable] start end> rows — every window is a JUDGEMENT ROW carrying its reason: <why> with one <cond ref=…/> per rule or inauspicious span that decided it (ids named in the trailing <glossary>) and a text <cond> per personal verdict; then in scan mode <scan days_scanned windows_examined windows_recommended windows_blocked days_without_windows> with <day date recommended blocked best_quality> and <blocker id kind windows of_windows days of_days first last> rows (blocker ids are glossary-named), <personalization doctrine applied not_evaluated><note>, then <unchecked family name><note>, <coverage own general reached equivalent_to_general>, <evidence> (include=provenance), <absent not_requested=…>, <disclaimers>, <glossary>. Every datetime is naive LOCAL clock time in the zone the root declares; `quality` is 0.00–1.00 and `band` its favorability token. An empty windows block carries n="0" with `of` (the count examined) and a reason. `order` says how the list is sorted (quality_desc / time_asc / moment). Spec: docs/specs/2026-09-09-xml-document-model.md.

Find auspicious windows (muhurtha) for an event.

TWO MODES:
  · SINGLE MOMENT (default) — judges the `datetime` supplied. Returns at most one window, `[datetime, datetime + 2h)`, on a day-level panchanga verdict; quality does not vary by hour.
  · RANGE SCAN (`scan_end` present) — scans every day from `datetime`'s date through `scan_end`. Max 31 days; a longer range is REJECTED, never truncated. A scanned window is an auspicious choghadiya part (Labha, Amrita, Shubha) or the Abhijit muhurta, bounded by sunrise/sunset-derived transitions and judged on the panchanga at its own midpoint.

Scan-mode blocks:
  · <windows kind="recommended"> — ranked by quality; 10 rows by default, capped by `max_windows`.
  · <windows kind="blocked"> — ruled-out windows in time order with their <why>, same cap; a SPREAD sample across the range (first, last, evenly between), not the first N chronologically.
  · <evidence> — OPT-IN via `include=provenance`. A dictionary holding each distinct rule, window scheme and blocker ONCE, keyed by its stable id, with its localised `name` and `classical_locus`. A window's provenance REFERENCES those ids, grouped by effect: `structural` (one id), `favorable`/`unfavorable`/`blocker` (arrays of ids), `personal` (FULL entries inline, NOT ids). `classical_locus` is OMITTED where no verified citation is held, including rahu kalam and yamaganda.
  · <scan> — untruncated denominators: days_scanned, windows_examined, windows_recommended, windows_blocked, days_without_windows, plus one <day date recommended blocked best_quality> row per day.
  · <scan>/<blocker> — one row per blocker over EVERY window judged (the window lists are samples; this is the population): {id, kind (rule|span|personal), name, windows/of_windows, days/of_days, first_date, last_date}, most-blocking first. `days` can exceed `of_days` by one: a night window beginning after midnight starts on the next civil date.
  · <personalization doctrine applied not_evaluated> — whether this event type has a personal doctrine and whether it was applied; `not_evaluated` names the doctrines skipped for this event_type and this set of charts.
  · <unchecked family name> — rule families this tool does not check at all (Holashtak, Pitru paksha), each with a localized name and a reason.
  · <coverage own general reached equivalent_to_general> — `general_auspicious`'s rules are added to every event; `equivalent_to_general="true"` means the event's own rules cannot change WHICH windows qualify, only their ranking.

`native` is OPTIONAL and scan-mode only. It adds the Tarabala and Chandra Shuddhi checks and, on `general_auspicious`, a natal-lagna Upachaya check; for `marriage_ceremony` it also accepts `{bride, groom}`, which adds Guru Shuddhi (from the bride) and Ravi Shuddhi (from the groom). Without it the date-only method is used and <personalization> says so. Varjya kala (visha ghati) is evaluated as a blocker and appears as `varjya_kala` in a window's provenance.

`event_type` selects the rule set; there are 24 event ids. An unrecognised value is REJECTED.

Tier: All · Typical response: ~2.4 KB single-moment, ~8.7 KB for a 31-day scan.

### Input

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `datetime` | string | **yes** | The moment to judge, as local clock time AT THE EVENT LOCATION (`latitude`/`longitude` below), ISO 8601 naive (e.g. '2026-05-16T10:30:00'). NO 'Z' suffix. In scan mode (`scan_end` present) only the DATE part is used: it is the first day of the scan. |
| `event_type` | string, enum: `annaprashan` \| `bhoomi_pujan` \| `business_opening` \| `contract_signing` \| `convocation` \| `engagement` \| `exam_start` \| `general_auspicious` \| `griha_pravesh` \| `journey_start` \| `loan_repayment` \| `marriage_ceremony` \| `medicine_start` \| `mundana` \| `name_ceremony` \| `partnership` \| `pilgrimage` \| `property_purchase` \| `puja` \| `surgery` \| `treatment_start` \| `upanayana` \| `vehicle_purchase` \| `vidyarambha` | **yes** | The event being scheduled; selects which rules apply. `general_auspicious` is the universal set and is included in EVERY other event's evaluation. An unrecognised value is REJECTED, not silently treated as general. |
| `latitude` | number, range -90…90 | **yes** | Event latitude in decimal degrees, WGS84. |
| `locale` | string, enum: `en` \| `hi` \| `sa` \| `ta` \| `te` \| `kn` \| `bn` | **yes** | Response language. Required. |
| `longitude` | number, range -180…180 | **yes** | Event longitude in decimal degrees, WGS84. Used for tz resolution. |
| `school` | string, enum: `parashari` \| `jaimini` \| `kp` | **yes** | Jyotish school for interpretation. Required. |
| `cache` | string, enum: `skip` | no | Optional. "skip" suppresses the cache read AND write for this call, so no entry is stored. |
| `include` | string | no | Comma-separated SECTIONS to add. Opt-in: `provenance` — the <evidence> dictionary: every rule, window scheme and inauspicious span a window's verdict rests on, ONCE each, with its concept URI and classical locus (<rule id concept><cite>…</cite></rule>), plus each personal verdict's concept and locus inline on its window. Accepted and inert on single-moment calls (no `scan_end`). |
| `max_windows` | integer, range 1…250 | no | OPTIONAL, scan mode only. How many windows to return in EACH of the recommended and blocked <windows> blocks. Default 10; out-of-range values are CLAMPED, not rejected. <scan> always reports the untruncated totals. |
| `native` | — | no | OPTIONAL birth data for the person the event is for. Scan mode only; ignored for a single-moment call. Adds Tarabala, Chandra Shuddhi and, on `general_auspicious`, the natal-lagna Upachaya check. TWO SHAPES: a single birth block, OR — for `marriage_ceremony` only — `{"bride": {...}, "groom": {...}}`, which adds Guru Shuddhi (from the bride) and Ravi Shuddhi (from the groom). Either role may be given alone; the doctrine keyed to the missing party is then reported as not evaluated rather than reckoned from the wrong chart. A flat block on a marriage is accepted and still yields Tarabala + Chandra Shuddhi. |
| `scan_end` | string | no | OPTIONAL. A last date (YYYY-MM-DD) switches the tool from judging ONE moment to SCANNING A RANGE. The scan runs from the date part of `datetime` through this date, inclusive. Maximum 31 days; a longer range is REJECTED, never truncated. Omit for single-moment behaviour. |

---

## panchang

Compute the Vedic panchanga (five-limbed almanac) for any date, time, and location.

RESPONSE FORMAT (schema 1): ONE XML document in content[0].text — `<kundalimcp tool="panchang" schema="1" locale=… tz_iana=… tz_offset_minutes=… tool_class=… engine=… api=…>` — and NO structuredContent. Root blocks, in order: <headline>, <context frame="observer"> (<observer lat lng> + <moment at>), <panchanga frame="moment"> with one <limb kind=…> per tithi/nakshatra/yoga/karana/vara, <sun>, <moon>, <day>, <agnivasa>, <calendar>, <day_yogas>, <windows frame="day" kind=…> (inauspicious always; choghadiya/hora/muhurta under include=windows), <eclipses>, <timeline> (include=timeline), <absent not_requested=…>, <disclaimers>, <glossary>. Scalars are attributes; EVERY datetime is naive LOCAL clock time in the zone the root declares (tz_iana + tz_offset_minutes) — no UTC, no Julian Day, exactly the form the `datetime` input takes; ids are ASCII slugs and every referenced id is named in the trailing <glossary> in the request locale; `quality` is an ASCII token (auspicious/neutral/inauspicious) whose localized band name is a glossary term. A computed "none" is the literal token none with a reason (polar day). Spec: docs/specs/2026-09-09-xml-document-model.md.

Returns for each of the five limbs (tithi, nakshatra, yoga, karana, vara):
  · Entity (id + localized name)
  · Quality, lord, pada as applicable
  · Remaining degrees until the limb changes
  · End time

Also returns:
  · Sunrise, sunset and meridian transit of Sun and Moon, day/night length, moon elongation and illumination, agnivasa
  · Rahu Kalam, Gulika Kalam, Yamaganda windows with active flag
  · Calendar: masa (with adhika/kshaya flags), samvatsara, Vikrama and Shaka year, ayana, ritu, and the next sankranti
  · Day yogas: anandadi yoga + the active dainika yogas (Sarvartha Siddhi, Amrita Siddhi, Ravi, Dagdha, etc.), each tier-tagged standard (Drik-Panchang set) or classical (extended)
  · Moon's rashi (Chandra rashi — the Vedic moon sign), localized
  · Eclipses: next solar + next lunar eclipse (grahana) — <eclipse kind certainty in_days at>

Tier: All · Typical response: ~4 KB.

### Input

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `datetime` | string | **yes** | Local clock time at the given location, ISO 8601 naive (e.g. '2026-05-16T10:30:00'). NO 'Z' suffix. |
| `latitude` | number, range -90…90 | **yes** |  |
| `locale` | string, enum: `en` \| `hi` \| `sa` \| `ta` \| `te` \| `kn` \| `bn` | **yes** | Response language. |
| `longitude` | number, range -180…180 | **yes** |  |
| `cache` | string, enum: `skip` | no | Optional. "skip" suppresses the cache read AND write for this call, so no entry is stored. |
| `include` | string | no | Comma-separated SECTIONS to add; several in one call cost one computation. Opt-in: windows (Day divisions: choghadiya (16), hora (24), and the brahma / abhijit / amrita / varjya / dur muhurtas.) · timeline (Every segment of each limb (tithi, nakshatra, yoga, karana, vara) intersecting the queried local day, each with its own start and end. Overhang at both ends is real, not clamped: the first segment opens before local midnight and the last closes after it. Boundaries only — no per-segment pada, lord or quality. ~12 segments a day. The default response carries only the CURRENT segment plus its successor's name.). Default-on: calendar, day_yogas, inauspicious, eclipses. |

---

## pramaan

Explain WHY a specific Jyotish claim is true for a chart — the claim's own trigger-limb witness, its supporting and counter factors with weights, and (opt-in) the full Vivek provenance chain.

RESPONSE FORMAT (schema 1): ONE XML document in content[0].text — `<kundalimcp tool="pramaan" schema="1" locale=… tz_iana=… tz_offset_minutes=… tool_class="chart_anchored" engine=… api=… school=… chart_hash=…>` — and NO structuredContent. Root blocks, in order: <headline>, <context frame="natal">, <claim id name tier grounded domain> carrying <why><cond>…</cond></why> when the claim has a trigger limb (yoga and natal-event claims; domain and affliction claims have none), <supporting n> and <counter n> of <factor id name weight> rows each with a <description> when the concept has one, then the opt-ins, <absent not_requested=…>, <disclaimers>, <glossary>. Every datetime is naive LOCAL clock time in the zone the root declares (the birth zone); ids are ASCII slugs and every referenced id (the `domain` lens, the grahas) is named in the trailing <glossary> in the request locale. Spec: docs/specs/2026-09-09-xml-document-model.md.

`claim_id` is the `claim` attribute of a `kundali` row, verbatim — every explainable row carries one. The families are: `concept:yoga/<id>`, `concept:natal-event/<rule>`, `concept:affliction/<type>/<graha>/<cause>`, `concept:domain/<slug>`, `concept:life-event/<rule>`, `concept:cancellation/<rule>`. An id this chart cannot answer is refused (-32602) naming the addressable families.

Opt-in via `include=` (comma-separated; an unknown token is an error naming the valid set):
  · provenance — <provenance n> with one <trace stage> per Vivek stage (ephemeris → chart casting → bhava selection → factor collection → weighted roll-up), and on every <factor> its `kind`, `grahas`, `bhavas` and its own identification <trace>. This channel is English structural data on every locale; on a non-English document each of its text children carries lang="en".
  · detail  — <claims kind="disputed" n> rows: conclusions other schools dispute for this domain, `agree`/`disagree` school keys, <title> and <note>. n="0" reason="consensus" when every school agrees.
  · metrics — <shadbala n unit="virupa">: a <component id name> legend (six classical components, each with its <description>) and one <graha id total meets_minimum sthana dig kala chesta naisargika drik> row per participating graha.

This tool returns no classical locus of its own; `<factor id>` is a concept slug.

Tier: All · Typical default response: ~3-5 KB; all three opt-ins add ~10-20 KB.

### Input

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `chart_ref` | object | **yes** |  |
| `claim_id` | string | **yes** |  |
| `locale` | string, enum: `en` \| `hi` \| `sa` \| `ta` \| `te` \| `kn` \| `bn` | **yes** | Response language. Required. |
| `school` | string, enum: `parashari` \| `jaimini` \| `kp` | **yes** | Jyotish school for interpretation. Required. |
| `include` | string | no | Comma-separated SECTIONS to add; several in one call cost one computation. Opt-in: provenance (The Vivek provenance chain (ephemeris → chart casting → bhava selection → factor collection → weighted roll-up) as <provenance> rows, plus each factor's kind, grahas, bhavas and its own identification trace. Its text is English on every locale and marked lang="en".) · detail (Claims other schools dispute for this domain, as <claims kind="disputed"> rows. Empty (n="0") when every school agrees.) · metrics (Shadbala per participating graha — the six classical components and the total in virupas — as <shadbala> rows.). |

---

## submit_feedback

Submit feedback on a chart / claim / explanation. Stored anonymously for engine improvement — no birth data is retained; the claim_id is the only correlator.

Returns ONE XML document in content[0].text — `<kundalimcp tool="submit_feedback" schema="1" locale="en" tool_class="metadata">` — and NO structuredContent: <headline>, then <feedback kind rating [claim] recorded="true">. No identifier for the stored row is returned. Requires an authenticated caller (-32001 otherwise); an unknown `feedback_type` or a `rating` outside 1-5 is -32602.

Tier: All · Typical response: <1 KB.

### Input

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `feedback_type` | string, enum: `accuracy` \| `completeness` \| `relevance` \| `clarity` | **yes** |  |
| `rating` | integer, range 1…5 | **yes** |  |
| `claim_id` | string | no |  |
| `notes` | string | no |  |

---

## tithi

Which civil day each recurring TITHI-derived observance falls on, over a DATE RANGE, resolved by the sunrise rule — Ekadashi, Purnima, Amavasya, Sankashti Chaturthi, Masik Shivaratri, Trayodashi, and the three weekday-qualified amavasyas that carry names (Somavati, Bhaumavati, Shani). Sankranti ingress moments are SOLAR, not tithi-derived, and ship in their own <sankrantis> block (no vyapti applies).

DOES NOT RETURN named festivals — Diwali, Holi, Navaratri, Janmashtami, Ganesh Chaturthi, Karwa Chauth, Onam, Pongal, Ugadi: each needs a nirnaya ruling that is not encoded. `<coverage absent=…>` lists them on every response with the reason in its note. No sub-day windows (nishitha, aparahna, madhyahna, arunodaya) are resolved.

RESPONSE FORMAT (schema 1): ONE XML document in content[0].text — `<kundalimcp tool="tithi" schema="1" locale=… tz_iana=… tz_offset_minutes=… tool_class="location_anchored" engine=… api=…>` — and NO structuredContent. Root blocks, in order: <headline>, <context frame="observer"> (<observer lat lng> + <span kind="range" start end days>), <observances n scheme> of one-line <observance kind tithi tithi_number date sunrise masa paksha adhika kshaya vyapti rule rejected fasted first_of_kind [qualifies] [split split_resolved split_rule]> rows (+ <astronomy sunset moonrise moonset> under include=astronomy), <sankrantis n> of <sankranti rashi rashi_index at>, <kshaya_tithis n> of <kshaya_tithi tithi tithi_number after>, <spans n> of <span id kind … effect boundary_rule start end> with <cite> and <note>s, <coverage resolution_rule computed absent> with two <note>s, <evidence n> — the rules the rows reference by `rule=`, each ONCE with its <label>, <cite> or the note saying why there is none — then <absent not_requested=…>, <disclaimers>, <glossary>. Every datetime is naive LOCAL clock time in the zone the root declares; `date` is the civil day (YYYY-MM-DD) and `sunrise` the instant that named it; ids (tithi, masa, rashi) are ASCII slugs named in the trailing <glossary> in the request locale. An empty block carries n="0" and a reason (`no_sunrise_in_range` at the pole, `none_in_range` otherwise). The engine's own English disclosures carry lang="en" on a non-English document. Spec: docs/specs/2026-09-09-xml-document-model.md.

RESOLUTION: the tithi holding a day's sunrise names that day. `vyapti` on each <observance> says which case it is — one sunrise, NONE (`kshaya`, destroyed) or TWO (`vriddhi`, added) — and `rejected` says whether that disqualifies it for auspicious acts. <kshaya_tithis> lists the tithis no sunrise in the range held. `first_of_kind="true"` marks the earliest row of each kind in the requested range.

Inputs: `start_date`, `end_date` (naive local dates, YYYY-MM-DD), `latitude`, `longitude`, `locale`, optional `masa_scheme` (amanta | purnimanta). Max 400 days; a longer range is REJECTED, never truncated.

Tier: All · Typical response: ~4 KB for a week, ~12 KB for 45 days. It grows with the number of observances in the range.

### Input

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `end_date` | string | **yes** | Last local civil date, YYYY-MM-DD. Must not precede start_date; the span must be 400 days or fewer. |
| `latitude` | number, range -90…90 | **yes** |  |
| `locale` | string, enum: `en` \| `hi` \| `sa` \| `ta` \| `te` \| `kn` \| `bn` | **yes** | Response language. |
| `longitude` | number, range -180…180 | **yes** |  |
| `start_date` | string | **yes** | First local civil date in the range, YYYY-MM-DD. |
| `cache` | string, enum: `skip` | no | Optional. "skip" suppresses the cache read AND write for this call, so no entry is stored. |
| `include` | string | no | OPTIONAL, comma-separated. One token is recognised: `astronomy`, which adds the per-day <astronomy> block (moonrise/moonset, sunrise/sunset) to every observance row. Off by default; it is costly on a long range. An unrecognised token is REJECTED with an error naming the valid set; `all` is not accepted. |
| `masa_scheme` | string, enum: `amanta` \| `purnimanta` | no | OPTIONAL. Which lunar-month scheme labels each observance's masa. `amanta` (new-moon bounded) is the default; `purnimanta` is full-moon bounded. An unknown value is REJECTED, never silently defaulted. |
