mcp-abacus
以下摘录自该仓库的 README(片段) · 在 GitHub 读完整 README →
**A calculator for the artificial minds — because we know their needs are
different.**
People reach for a calculator to get a number. A language model reaches for one
to get a number it can *trust* and reason about: Was this exact, or rounded? At
what scale? Would a wider type have held more digits? Does this overflow the way
the production code will? A floating-point answer that merely *looks* precise is
worse than no answer — it launders a rounding error into a confident claim.
mcp-abacus is built for that caller. It does **type-faithful calculation**: you
pick a numeric type/mode (fixed-point, IEEE-754 double, exact rational, complex) and the
*whole* expression behaves exactly as that type would in real code — it rounds
where the type rounds, stays exact where the type is exact, and carries the
result onward bit-for-bit. Every answer comes back labelled with its own
precision verdict (exact vs inexact, rounded to N decimals), so the model
never has to guess whether a result is the true value. It does not approximate a
type; it calculates *using* that type.
What it gives you
- **calculate** — evaluate one expression in one numeric type. Modes:
- fixed-point *(default)* — exact scaled integer; money / ERC-20-safe
- floating-point — IEEE-754 double (aliases float64, double)
- rational — exact numerator/denominator; no silent rounding
- complex — a + b*i over two fixed-point parts; write the imaginary unit as
1i (e.g. 3+4i, 2.5i). Exact + - * ((3+4i)*(1+2i) → -5+10i,
sqrt(-1) → 1i), rounds / and the transcendentals onto the grid; no
ordering, bitwise, integer (gcd/factorial), or solver support
A **vector literal** [a, b, …] builds a one-dimensional list of values in the
chosen mode (e.g. [1, 2, 3], the empty [], or [1+1, 2*3] → [2, 6]); it is
an internal container, not a selectable mode. The whole stats family reduces over a
single vector's elements — min/max/avg/median/variance/stddev/sumsq/geomean/harmean
(avg([1, 2, 3]) → 2, sumsq([1, 2, 3]) → 14, geomean([4, 9]) → 6), as do the integer reducers gcd/lcm
(gcd([54, 24, 6]) → 6). The order statistics take a leading point then the
data (a run or one vector): quantile(q, …) for q in [0, 1] and
percentile(p, …) for p in [0, 100] read the value at that rank (type-7
linear interpolation), generalising median — percentile(50, [1, 2, 3, 4])
is the median. And covariance(x, y)/correlation(x, y) take two
equal-length vectors (covariance([1, 2, 3], [4, 5, 6]), Pearson
correlation(...) in [-1, 1]). Going the other way, factor(n) PRODUCES a
vector — the prime factors of a positive integer, ascending with multiplicity
(factor(12) → [2, 2, 3], factor(1) → []). Otherwise vectors only
construct and render — other operators and functions refuse one, there is no
indexing (b[i]), and nesting ([[1,2],[3,4]]) is rejected.
- **analyze** — evaluate an expression and return its whole parse tree, each
node annotated with the value it computed, so you can see *where* a surprising
answer rounded or overflowed (e.g. (1 + 1/2) * 3 is 3 in fixed-point — the
tree shows the 1/2 = 0 leaf that explains it)
- **solver** — find the value(s) of one or more variables that drive an
expression to a target over a bracket: *find-root* (x**2 - 2 over [0, 2] → √2)
or *find-minimum* / *find-maximum*, in the same numeric type and expression
language (constants come from name = expr assignment lines). One unknown uses
*golden-section search* (or *Brent parabolic* via algorithm="brent-parabolic",