@cyanheads/calculator-mcp-server 0.4.3 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,9 @@
1
1
  /**
2
2
  * @fileoverview Hardened math.js wrapper for secure expression evaluation.
3
3
  * Creates a restricted math.js instance with dangerous functions disabled in
4
- * the expression scope, and wraps evaluation in a vm sandbox with timeout.
4
+ * the expression scope, parses each expression once and checks the tree before
5
+ * anything runs, and evaluates, inspects, and formats the result inside a vm
6
+ * sandbox with a timeout.
5
7
  * @module services/math/math-service
6
8
  */
7
9
  import type { Context } from '@cyanheads/mcp-ts-core';
@@ -10,15 +12,16 @@ import type { MathResult, NumericType } from './types.js';
10
12
  export declare class MathService {
11
13
  /** Default IEEE 754 instance — used for the vast majority of evaluations. */
12
14
  private readonly defaultInstance;
13
- /** BigNumber instance — arbitrary precision; selected via numericType: "BigNumber". */
15
+ /** BigNumber instance — 64 significant digits; selected via numericType: "BigNumber". */
14
16
  private readonly bigNumberInstance;
15
17
  /** Fraction instance — exact rational arithmetic; selected via numericType: "Fraction". */
16
18
  private readonly fractionInstance;
17
- private readonly parse;
18
19
  private readonly simplify;
19
20
  private readonly derivative;
20
21
  private readonly simplifyRules;
21
22
  private readonly config;
23
+ /** vm context reused by every timed call; see {@link runWithTimeout}. */
24
+ private readonly sandbox;
22
25
  constructor(config: ServerConfig);
23
26
  /** Select the pre-initialized evaluate/format/typeOf bundle for a given numeric type. */
24
27
  private instanceFor;
@@ -31,36 +34,72 @@ export declare class MathService {
31
34
  /** Get formatted help content listing available functions, operators, and syntax. */
32
35
  getHelpContent(): string;
33
36
  private validateInput;
37
+ /**
38
+ * Parse once and check the tree before anything evaluates. A parse failure is
39
+ * `parse_failed`. Multiple statements are detected structurally — math.js parses
40
+ * `a; b` and a top-level newline into a `BlockNode` — so `;` inside a matrix or
41
+ * inside either quote style (`"a;b"`, `'a;b'`) is data, transpose `A'` stays an
42
+ * operator, and a real separator is rejected before either statement runs (#32).
43
+ * math.js treats a bare carriage return as a syntax error rather than a
44
+ * separator; when it is what broke the parse, the input is re-parsed with line
45
+ * feeds purely to report `multiple_expressions` — the rewritten text is never
46
+ * evaluated. The same tree then gets the stringifier check, the
47
+ * operation-as-function check (#27), and the notation rename (#24), and yields
48
+ * the names it uses as values that resolve to functions (#38). Every operation
49
+ * starts here, so it also resets the instance's auto unit system (#37).
50
+ */
51
+ private parseExpression;
52
+ /** Whether `expression` parses to multiple statements. */
53
+ private parsesAsBlock;
54
+ private multipleExpressions;
34
55
  /** Reject scope keys that could pollute the object prototype chain. */
35
56
  private validateScope;
36
57
  /** Reject result types that leak internals (functions, parsers, multi-expression ResultSets). */
37
58
  private validateResultType;
38
- /** Reject results holding a non-finite value (Infinity, -Infinity, NaN), including inside matrices and complex numbers. */
39
- private validateFinite;
59
+ /**
60
+ * Inspect a result before it is formatted: reject a `help()` object (its
61
+ * rendering evaluates the documentation examples, #31), a collection too large
62
+ * to ever fit `maxResultLength` (checked before formatting, so it is never
63
+ * stringified), any non-finite number, scalar or nested (#21), and under
64
+ * numericType "Fraction", any float approximation, scalar or nested (#35).
65
+ */
66
+ private validateResultValue;
40
67
  /** Reject results that exceed the configured maximum size. */
41
68
  private validateResultSize;
69
+ private resultTooLarge;
42
70
  /**
43
- * Reject expressions that access `.toString` / `.toLocaleString` on any value.
44
- * math.js permits these methods on function-valued identifiers (`cos.toString()`,
45
- * `import.toString()`), returning the function's source as a plain string — which
46
- * slips past {@link validateResultType}, whose function defense only inspects the
47
- * value AFTER stringification. The check is parse-time and AST-based rather than a
48
- * runtime `Function.prototype` patch: math.js itself calls `toString` on functions
49
- * internally while evaluating units, statistics, and complex results, so patching
50
- * the prototype would reject legitimate expressions. No real calculator expression
51
- * needs `.toString()`/`.toLocaleString()`, so blocking the accessor outright (dot
52
- * or bracket form, on any operand) is both sufficient and side-effect-free. String
53
- * literals that merely contain the text "toString" parse as ConstantNodes, not
54
- * accessors, so they are unaffected.
71
+ * Runs a synchronous function inside a vm sandbox with timeout protection and
72
+ * maps anything it throws to a declared reason via {@link classifyFailure}.
73
+ *
74
+ * The context exists only to carry the timeout — `fn` and everything it calls
75
+ * run in this realm — so one context is reused for every call and cleared
76
+ * afterwards. A fresh context per call costs ~100 µs and, under Bun, retains
77
+ * ~100 KB of memory per call.
55
78
  */
56
- private validateNoFunctionStringification;
79
+ private runWithTimeout;
57
80
  /**
58
- * Runs a synchronous function inside a vm sandbox with timeout protection.
59
- * `numericType` is supplied only by the evaluate path so a Fraction-mode
60
- * conversion failure can be remapped to the actionable `fraction_unsupported`
61
- * error instead of the misleading `parse_failed` (#19).
81
+ * Classify a failure raised after the expression parsed (evaluation, result
82
+ * inspection, formatting, or a symbolic operation). First match wins:
83
+ *
84
+ * 1. Already-classified `McpError`s (result checks) pass through.
85
+ * 2. Timeout → `evaluation_timeout`.
86
+ * 3. A size guard (see size-guard.ts) → `result_too_large`.
87
+ * 4. Fraction mode calling a function with no Fraction implementation (sqrt,
88
+ * sin, log, factorial, …) → `fraction_unsupported` (#19); so does Fraction
89
+ * mode meeting a float with no equal Fraction (`pi * 2/3`, #35).
90
+ * 5. fraction.js `Division by Zero`, in any numericType → `undefined_result` (#21).
91
+ * 6. Name errors (undefined symbol/function/unit, disabled function, blocked
92
+ * property) → `parse_failed`.
93
+ * 7. A symbolic operation (simplify, derivative) that cannot process the parsed
94
+ * tree → `evaluation_failed`, with a hint about the symbolic engine rather
95
+ * than about argument values (see {@link symbolicFailure}).
96
+ * 8. Operand type/unit errors (typed-function `wrongType`, unit mismatch,
97
+ * string-to-number) → `type_mismatch`.
98
+ * 9. Anything else — arity, domain, singular matrix, dimensions, index →
99
+ * `evaluation_failed` (#29). Stage decides, not error class: a runtime
100
+ * `SyntaxError` such as `number("abc")` lands here, never in `parse_failed`.
62
101
  */
63
- private runWithTimeout;
102
+ private classifyFailure;
64
103
  }
65
104
  /** Initialize the math service. Call once from createApp setup(). */
66
105
  export declare function initMathService(config: ServerConfig): void;
@@ -1 +1 @@
1
- {"version":3,"file":"math-service.d.ts","sourceRoot":"","sources":["../../../src/services/math/math-service.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAGtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAgT1D,qBAAa,WAAW;IACtB,6EAA6E;IAC7E,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAe;IAC/C,uFAAuF;IACvF,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAe;IACjD,2FAA2F;IAC3F,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAe;IAEhD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA6B;IACnD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAmE;IAC5F,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA6D;IACxF,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAiB;IAC/C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAe;IAEtC,YAAY,MAAM,EAAE,YAAY,EAmB/B;IAED,yFAAyF;IACzF,OAAO,CAAC,WAAW;IAWnB,4FAA4F;IAC5F,kBAAkB,CAChB,UAAU,EAAE,MAAM,EAClB,GAAG,EAAE,OAAO,EACZ,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,SAAS,CAAC,EAAE,MAAM,EAClB,WAAW,GAAE,WAAsB,GAClC,UAAU,CAuBZ;IAED,qDAAqD;IACrD,kBAAkB,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,GAAG,UAAU,CA0B/D;IAED,mFAAmF;IACnF,uBAAuB,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,GAAG,UAAU,CAQtF;IAED,qFAAqF;IACrF,cAAc,IAAI,MAAM,CAEvB;IAED,OAAO,CAAC,aAAa;IAqBrB,uEAAuE;IACvE,OAAO,CAAC,aAAa;IAWrB,iGAAiG;IACjG,OAAO,CAAC,kBAAkB;IAS1B,2HAA2H;IAC3H,OAAO,CAAC,cAAc;IAStB,8DAA8D;IAC9D,OAAO,CAAC,kBAAkB;IAS1B;;;;;;;;;;;;;OAaG;IACH,OAAO,CAAC,iCAAiC;IAyBzC;;;;;OAKG;IACH,OAAO,CAAC,cAAc;CA6BvB;AAMD,qEAAqE;AACrE,wBAAgB,eAAe,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI,CAE1D;AAED,iDAAiD;AACjD,wBAAgB,cAAc,IAAI,WAAW,CAG5C"}
1
+ {"version":3,"file":"math-service.d.ts","sourceRoot":"","sources":["../../../src/services/math/math-service.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAkBtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAQ9D,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAioB1D,qBAAa,WAAW;IACtB,6EAA6E;IAC7E,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAe;IAC/C,yFAAyF;IACzF,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAe;IACjD,2FAA2F;IAC3F,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAe;IAEhD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA2B;IACpD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA6B;IACxD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAiB;IAC/C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAe;IACtC,yEAAyE;IACzE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA4C;IAEpE,YAAY,MAAM,EAAE,YAAY,EAkB/B;IAED,yFAAyF;IACzF,OAAO,CAAC,WAAW;IAWnB,4FAA4F;IAC5F,kBAAkB,CAChB,UAAU,EAAE,MAAM,EAClB,GAAG,EAAE,OAAO,EACZ,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,SAAS,CAAC,EAAE,MAAM,EAClB,WAAW,GAAE,WAAsB,GAClC,UAAU,CAsCZ;IAED,qDAAqD;IACrD,kBAAkB,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,GAAG,UAAU,CAe/D;IAED,mFAAmF;IACnF,uBAAuB,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,GAAG,UAAU,CAStF;IAED,qFAAqF;IACrF,cAAc,IAAI,MAAM,CAEvB;IAED,OAAO,CAAC,aAAa;IAarB;;;;;;;;;;;;;OAaG;IACH,OAAO,CAAC,eAAe;IA6CvB,0DAA0D;IAC1D,OAAO,CAAC,aAAa;IAQrB,OAAO,CAAC,mBAAmB;IAQ3B,uEAAuE;IACvE,OAAO,CAAC,aAAa;IAYrB,iGAAiG;IACjG,OAAO,CAAC,kBAAkB;IAU1B;;;;;;OAMG;IACH,OAAO,CAAC,mBAAmB;IA0B3B,8DAA8D;IAC9D,OAAO,CAAC,kBAAkB;IAI1B,OAAO,CAAC,cAAc;IAQtB;;;;;;;;OAQG;IACH,OAAO,CAAC,cAAc;IAetB;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,OAAO,CAAC,eAAe;CA8CxB;AAiFD,qEAAqE;AACrE,wBAAgB,eAAe,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI,CAE1D;AAED,iDAAiD;AACjD,wBAAgB,cAAc,IAAI,WAAW,CAG5C"}