Jiheng (玑衡) — the exact math layer for AI products
中文 | English
Fractions stay fractions. Radicals stay radicals. Nothing silently rounds.
LLMs are great at reasoning and bad at arithmetic. One silently rounded number can propagate into a price, a report, or a trade. Jiheng does one job: return the exact value, or tell you clearly why it cannot.
Named after the ancient Chinese astronomical instrument xuanji yuheng — measurement
has to be exact, and so does computation. Ships as an MCP server (jiheng-mcp) and
a DSH plugin.
| Capability | Details |
|---|---|
| Exact arithmetic | 1/3, sqrt(2), 2^200 — preserved exactly, with a decimal alongside |
| Symbolic math | solve, diff, integrate, simplify, expand, factor, subs |
| Domain packs | statistics, finance, engineering, units, dates, distributions, linear algebra, ODE, special functions (19 packs) |
| Multi-step | one call with named steps, no round-trip per sub-expression |
| Parallel | calc_shard splits intervals across workers; worker pool 1–16 |
| Discoverable | functions() lists every name; help("name") shows a signature |
| Extensible | hot-reloadable .calc/plugins/*.py packs |
Why Jiheng?
Different tools optimize for different jobs. Jiheng is built for one specific use case: an AI agent that needs a fast, exact, local calculator with a clean tool interface.
| Jiheng | Wolfram (Alpha / Cloud) | SymPy MCP | Code Interpreter | |
|---|---|---|---|---|
| Exact fractions / radicals | ✅ always (1/3, sqrt(2)) |
✅ | ✅ but a low-level API | ⚠️ float unless you write code |
| AI-first tool surface | ✅ steps, functions(), help(), teaching-style errors |
⚠️ docs-oriented | ❌ raw API | ✅ general-purpose |
| Local, no API key | ✅ uvx jiheng-mcp |
❌ cloud / paid | ✅ local | ❌ hosted |
| Warm latency | ~3 ms / call | network round-trip | Python startup per call | seconds |
| Domain coverage | 19 packs: stats, finance, engineering, units, dates, distributions, ODE, linalg… | ✅ very broad | base math only | ⚠️ via libraries |
| Multi-step in one call | ✅ named steps |
⚠️ | ❌ | ✅ code |
| Parallel shards | ✅ calc_shard + worker pool |
❌ | ❌ | ⚠️ manual |
| Symbolic depth | ⚠️ good, not Wolfram-level | ✅ best-in-class | ✅ strong | ⚠️ via SymPy |
| Hard numerical integration | ⚠️ improved, not Wolfram-level | ✅ | ⚠️ | ✅ SciPy |
| Chinese domain conventions | ✅ discount/tax/date/unit templates | ⚠️ | ❌ | ⚠️ |
| License / cost | MIT, free | paid / cloud | BSD, free | free but hosted |
| Measured benchmark | ✅ 97.6% on 1,000 mixed tasks | — | — | — |
Use Jiheng when:
- You are building an AI agent / MCP client and want a dependable calculator tool
- You need exact values (money, fractions, roots) with no silent rounding
- You want one command, local, no API key, with millisecond latency
- You need domain functions (finance, units, dates, engineering) without writing Python
- You want stable, parseable output and errors the model can self-correct
Do not use Jiheng for:
- Risch-level symbolic integration, Meijer-G, PDEs → use Wolfram / Mathematica
- Large CSV/dataframe workflows → use code execution / DuckDB
- Live market data, news, web lookups → fetch data separately, then pass it to Jiheng
- Arbitrary programming → use a code interpreter
Interoperability
Jiheng is a computation layer, not a data layer. It does not open database connections, fetch web pages, or read files. It computes on numbers you already have. Data access belongs to dedicated MCP tools; compose them:
| Need | Use |
|---|---|
| Fetch rows from a database / CSV | database MCP, filesystem MCP, code interpreter |
| Statistics, finance, units, dates | Jiheng |
| Large joins / ETL | DuckDB / code execution |
| Charts | chart MCP |
Typical flow:
DB MCP: SELECT month, revenue FROM finance
↓
[120000, 135000, 149000, 162000]
↓
Jiheng: cagr(162000, 120000, 3) → 0.105...
Jiheng: mean([...]) → 141500
Jiheng: npv(0.08, [...], 1) → discounted value
Why Jiheng does not embed a database client:
- no database credentials
- no SQL execution surface
- no network requests
- small, auditable, offline-friendly calculator
If you need read-only SQLite / DuckDB / CSV access, use a dedicated data tool or MCP server, then pass the numbers to Jiheng.
Quick start
30-second setup (MCP)
1. Install uv (skip if already installed)
# macOS / Linux
curl -LsSf https://astral.sh/uv/install.sh | sh
# Windows PowerShell
irm https://astral.sh/uv/install.ps1 | iex
2. Let your client launch Jiheng
Add this to your MCP client config (Claude Desktop, Cursor, Codex, ...):
{
"mcpServers": {
"jiheng": {
"command": "uvx",
"args": ["jiheng-mcp"]
}
}
}
uvx downloads jiheng-mcp on first launch, then uses the local cache.
3. Restart the client and ask
Use calc to compute 1/3 + 1/6
Use calc to compute mean([12,15,9,22])
Use calc to compute npv(0.08, [623,644,431,286], 1)
Use calc to compute sqrt(2)*sqrt(2)
Other install options
| Method | Command |
|---|---|
| PyPI (pip) | pip install jiheng-mcp |
| Local checkout | uvx --from ./dsh-calc jiheng-mcp |
| From git | uvx --from git+https://github.com/CQQOOQ123/jiheng jiheng-mcp |
DSH plugin
plugin_manager install_bundle target="D:\path\to\dsh-calc"
plugin_manager set_bundle target="@local/jiheng" enabled=true
Run the MCP server directly (debugging)
cd dsh-calc
python -u mcp_server.py # JSON-RPC over stdio
Tool arguments
{
"expr": "final expression (optional when steps are given)",
"steps": [{"name": "d1", "expr": "..."}, {"name": "C", "expr": "..."}],
"defs": {"const": {"k": 1.05}, "fn": {"f": {"p": ["x"], "e": "x^2"}}}
}
Returns content[0].text (decimal-first, with exact form). On errors, isError: true
with a correctable hint.
Usage examples
calc(expr="1/3 + 1/6") → 1/2
calc(expr="sqrt(2)*sqrt(2)") → 2
calc(expr="mean([12,15,9,22])") → 14.5
calc(expr="loan_pmt(1000000, 0.049, 20)") → monthly payment
calc(expr="black_scholes_call(115,113,1,0.05,0.30)")
calc(expr="npv(0.08, [623,644,431,286], 1)") → start=1: first cash flow at year-end
calc(expr="functions()") → all function names
calc(expr="help(\"norm_cdf\")") → norm_cdf(x, mu, sigma) — normal CDF
Multi-step in one call:
{
"steps": [
{"name": "d1", "expr": "(ln(115/113)+(0.05+0.3^2/2)*1)/(0.3*sqrt(1))"},
{"name": "d2", "expr": "d1-0.3*sqrt(1)"},
{"name": "C", "expr": "115*norm_cdf(d1)-113*exp(-0.05)*norm_cdf(d2)"}
]
}
N(expr, digits)is numeric evaluation, not the normal CDF; usenorm_cdf(x).
Functions
- Operators/constants:
+ - * / % ** ^,pi,e - Statistics:
sum mean std std_pop std_sample var_pop var_sample median quantile min max count corr cov regression - Finance:
loan_pmt npv(rate, flows[, start]) annuity_pv discount_factor irr bond_price bond_duration black_scholes_call black_scholes_put - Units:
unit_convert unit_add unit_mul unit_div unit_pow unit_eval convert - Dates:
days_between date_add weekday - Symbolic:
solve diff integrate simplify expand factor subs limit series taylor - Engineering:
stress strain bending_stress beam_cantilever_point heat_flux thermal_resistance - Distributions:
norm_pdf norm_cdf norm_quantile t_pdf chi2_pdf - Discovery:
functions(),help("name")
See AI-USAGE.md for the full contract (60+ functions).
Configuration
Policy
| policy | Behavior |
|---|---|
always |
call the tool for any arithmetic |
complex |
lists/stats, money, units, symbolic, 3+ steps, big numbers (default) |
auto |
let the model decide |
never |
do not register the tool |
custom |
natural-language rules in customRules |
Limits
Settings → Calculator → Limits (stored in <calcHome>/settings.json):
| Limit | Default | Behavior |
|---|---|---|
max_series |
10000 | error |
max_output_items |
200 | summarize list |
max_expr_chars |
2000 | error |
max_steps |
50 | error |
max_symbol_len / max_decimal_len |
120 / 4000 | degrade to numeric + exact=false |
exact_only |
1 | keep exact long symbolic forms (also return d) |
strict_numeric |
0 | 1 = error when not exactly representable |
Worker pool
workers: 1 # 1..maxWorkers, or auto
maxWorkers: 8 # hard cap 16; ~52 MB each
auto: start with 1 and grow when busy- Settings page shows running/ready counts; changes apply immediately
- Routes:
GET/POST /calc/workers,POST /calc/batch(1..200 expressions in parallel) - Workers send
{"ready":true}on startup; resize waits for all to be ready
Environment variables
| Variable | Default | Meaning |
|---|---|---|
DSH_CALC_PYTHON |
auto-detect | worker interpreter |
DSH_CALC_HOME |
./.calc or ~/.calc |
settings/packs directory |
DSH_CALC_TIMEOUT_MS |
8000 | per-evaluation timeout |
DSH_CALC_DEBUG |
empty | forward worker stderr |
DSH_CALC_POLICY |
empty | override policy |
DSH_CALC_BUILTIN_PACKS |
bundled packs/ |
built-in packs directory |
Architecture
DSH Host (Node, resident)
└─ index.js ── registers calc / calc_shard tools
│ spawn 1..N workers
▼
worker.py (resident, JSON-lines protocol, ~3ms/eval)
└─ calc_core.py AST whitelist + Fraction + SymPy
└─ packs/*.py hot-reloadable capability packs
MCP client ──stdio JSON-RPC──▶ mcp_server.py ──▶ calc_core.py + packs/
- Resident worker avoids 250–800ms Python startup per call
- No
eval: AST whitelist only - Exact first: Fraction fast path; SymPy only for radicals/π/transcendentals
Precision contract
- Arithmetic / integer powers / percentages / statistics → exact rationals
- Fractions, radicals, constants stay symbolic, plus a decimal
d - Simplifiable transcendentals are simplified (
sin(pi/6)=1/2,log(1000,10)=3) - Oversized exact fractions degrade to decimals with
exact=false - Never silently round; every approximation is flagged
Error protocol
{"e":"ValueError","msg":"unknown function 'norm_cdf'... did you mean ..."}
{"e":"ValueError","msg":"invalid date '2026-02-30': 2026-02 has 28 days ... Do not roll over."}
{"e":"ValueError","msg":"dimension mismatch: GB (data) vs kg (mass)"}
{"e":"ValueError","msg":"not an expression (hint: multiple statements are not supported ...)"}
HTTP routes (DSH plugin)
/calc/status— version, policy, registration, worker/ready countsPOST /calc/policy—{policy, customRules}GET/POST /calc/limits— limits;{"reset":true}restores defaultsGET/POST /calc/workers— worker poolPOST /calc/batch—{exprs:[...]}evaluated in parallelGET/POST /calc/packs— formula/capability packs
Capability packs
packs/*.py (or .calc/plugins/*.py):
NAME = "stats"
def register(reg):
reg.func("corr", ["x", "y"], corr_impl, doc="Pearson correlation")
- Pure functions, no IO/state, exact values in/out
| Pack | Provides |
|---|---|
|
stats| correlation, covariance, dot product, linear regression | |finance| NPV, annuities, IRR, bonds, Black-Scholes | |calculus| integrate / limit / taylor | |calculus2| nintegrate / summation | |distributions| normal / t / chi-square pdf, cdf, quantiles | |linalg| determinant, inverse, eigenvalues, linear solve, matmul | |ode| first-order ODEdsolve| |special| gamma, erf, Bessel, factorial, binomial, beta, zeta | |strategy| integral checks, integration by parts, partial fractions, trig simplification | |units| unit conversion/mul/div/pow, temperature | |dates| date differences, date arithmetic, weekday | |currency| currency conversion | |percent| share, YoY, tax-inclusive/exclusive, discount, growth multiple | |engineering| stress, strain, beam deflection, bending stress, heat flux, thermal resistance | |templates| quotes, tax, discounts, margin, markup, remaining principal, wastage | |templates_hr| overtime pay, N+1 compensation, income tax, social insurance base | |templates_logistics| volumetric weight, chargeable weight, shipping cost | |templates_manufacturing| yield, OEE, material cost, labor cost | |templates_retail| double discount, rebate, average ticket, sell-through rate |
19 capability packs, bundled and hot-reloaded.
- Hot-reloaded on change; see
PACKS.md
Parallel shards (calc_shard)
calc_shard(expr="x*exp(x)", var="x", from=0, to=1, shards=4, mode="integrate", op="sum")
→ sum(nintegrate) = 1
mode:integrate/sum;op:sum / mean / max / min- Only for decomposable problems (interval integrals, range sums, parameter scans)
Tests & benchmark
python test_cases.py # 63: precision/stats/semantics/errors/security
python test_packs.py # 93: capability packs
python test_worker.py # 12: worker protocol/hot reload/ready
python test_mcp.py # 6: MCP smoke
node test_client_contract.mjs # 8: client contract
node test_routes.mjs http://127.0.0.1:3379 # 26: HTTP routes
Benchmark (1000 mixed tasks, deepseek-v4-flash, natural usage): 97.6% (976/1000).
FAQ
Q: Is std sample or population?
A: std/std_pop/var/var_pop are population; std_sample/var_sample are sample.
sharpe, zscore and cov use the sample convention internally (ddof=1). max_drawdown requires strictly positive prices by default; allow_leading_zeros=1 permits leading zeros.
Q: Why is N(...) not the normal CDF?
A: N(expr, digits) is numeric evaluation; use norm_cdf(x).
Q: Why is the first npv cash flow not discounted?
A: Default start=0 (flows[0] at t=0); use npv(rate, flows, 1) for year-end flows.
Q: What happens with an invalid date?
A: A clear error (e.g. 2026-02-30), never normalized to March 2.
Q: What is api retries exhausted?
A: The model API failed after 6 retries (rate limit/network); not a calculator error.
Quality audit: QUALITY.md
Known limitations
- Not a Python expression language: no comprehensions/loops/assignments (intentional)
- Unit tables cover common categories, not every unit
- Repeating decimals/transcendentals are approximations, flagged with
exact=false calc_shardcannot split single-point symbolic workindex.jschanges need a host restart;calc_core.pyapplies after worker restart
Packaging
uv build --directory dsh-calc
# dist/jiheng_mcp-0.3.5-py3-none-any.whl
# dist/jiheng_mcp-0.3.5.tar.gz
Docker:
docker build -t jiheng-mcp dsh-calc
docker run -i --rm jiheng-mcp
Version & license
- Version:
0.3.5 - MCP package:
jiheng-mcpon PyPI - DSH plugin id:
@local/jiheng - License: MIT (see LICENSE)
Metadata
Release files for jiheng-mcp 0.3.5
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| jiheng_mcp-0.3.5.tar.gz | 53.9 kB | With provenance | Details for jiheng_mcp-0.3.5.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| jiheng_mcp-0.3.5-py3-none-any.whl | Python 3 | none | any | Details for jiheng_mcp-0.3.5-py3-none-any.whl |
Total release size: 101.2 kB
Release files / jiheng_mcp-0.3.5.tar.gz
| Download URL | jiheng_mcp-0.3.5.tar.gz |
|---|---|
| Size | 53.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
8b296ab49cfcebf18f98b98ae69fedd43e01c8b2e9c66e8dc1d5d4818d6d72ed
|
|
BLAKE2b-256 checksum How to use checksums |
0a64900f626b2445e1119946b4590a79621c2fc1faf51f05c72a117757ae0af1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 4, 2026.
Transparency logRelease files / jiheng_mcp-0.3.5-py3-none-any.whl
| Download URL | jiheng_mcp-0.3.5-py3-none-any.whl |
|---|---|
| Size | 47.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
cf99694da259ecad20df6831b3676fa7b26fbd6beda497a0ec0820c3d19a2ab5
|
|
BLAKE2b-256 checksum How to use checksums |
5d3451a8e3108396e3a4def6dd1116f66b3b0935a3d3b3039c2a9d5993049bd1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 4, 2026.
Transparency logSecurity for jiheng-mcp 0.3.5
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for jiheng_mcp-0.3.5.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 4, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.