@cyanheads/calculator-mcp-server 0.1.6
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.
- package/CLAUDE.md +323 -0
- package/Dockerfile +99 -0
- package/LICENSE +190 -0
- package/README.md +177 -0
- package/dist/config/server-config.d.ts +15 -0
- package/dist/config/server-config.d.ts.map +1 -0
- package/dist/config/server-config.js +39 -0
- package/dist/config/server-config.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp-server/resources/definitions/help.resource.d.ts +8 -0
- package/dist/mcp-server/resources/definitions/help.resource.d.ts.map +1 -0
- package/dist/mcp-server/resources/definitions/help.resource.js +15 -0
- package/dist/mcp-server/resources/definitions/help.resource.js.map +1 -0
- package/dist/mcp-server/tools/definitions/calculate.tool.d.ts +22 -0
- package/dist/mcp-server/tools/definitions/calculate.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/calculate.tool.js +91 -0
- package/dist/mcp-server/tools/definitions/calculate.tool.js.map +1 -0
- package/dist/services/math/math-service.d.ts +40 -0
- package/dist/services/math/math-service.d.ts.map +1 -0
- package/dist/services/math/math-service.js +333 -0
- package/dist/services/math/math-service.js.map +1 -0
- package/dist/services/math/types.d.ts +12 -0
- package/dist/services/math/types.d.ts.map +1 -0
- package/dist/services/math/types.js +6 -0
- package/dist/services/math/types.js.map +1 -0
- package/package.json +70 -0
- package/server.json +141 -0
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Hardened math.js wrapper for secure expression evaluation.
|
|
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.
|
|
5
|
+
* @module services/math/math-service
|
|
6
|
+
*/
|
|
7
|
+
import vm from 'node:vm';
|
|
8
|
+
import { invalidParams, serviceUnavailable } from '@cyanheads/mcp-ts-core/errors';
|
|
9
|
+
import { all, create } from 'mathjs';
|
|
10
|
+
/**
|
|
11
|
+
* Custom simplification rules extending math.js defaults.
|
|
12
|
+
* math.js ships with algebraic rules only — these add common trig identities.
|
|
13
|
+
* The `n` wildcard matches any sub-expression (e.g., sin(2x+1)^2).
|
|
14
|
+
*/
|
|
15
|
+
const TRIG_SIMPLIFY_RULES = [
|
|
16
|
+
// Pythagorean identities
|
|
17
|
+
'sin(n)^2 + cos(n)^2 -> 1',
|
|
18
|
+
'cos(n)^2 + sin(n)^2 -> 1',
|
|
19
|
+
'1 - sin(n)^2 -> cos(n)^2',
|
|
20
|
+
'1 - cos(n)^2 -> sin(n)^2',
|
|
21
|
+
// tan / sec / csc / cot relationships
|
|
22
|
+
'tan(n)^2 + 1 -> sec(n)^2',
|
|
23
|
+
'1 + tan(n)^2 -> sec(n)^2',
|
|
24
|
+
'sec(n)^2 - 1 -> tan(n)^2',
|
|
25
|
+
'1 + cot(n)^2 -> csc(n)^2',
|
|
26
|
+
'cot(n)^2 + 1 -> csc(n)^2',
|
|
27
|
+
'csc(n)^2 - 1 -> cot(n)^2',
|
|
28
|
+
// Double-angle identities
|
|
29
|
+
'2 * sin(n) * cos(n) -> sin(2 * n)',
|
|
30
|
+
'cos(n)^2 - sin(n)^2 -> cos(2 * n)',
|
|
31
|
+
];
|
|
32
|
+
/**
|
|
33
|
+
* Functions disabled in the expression scope for security.
|
|
34
|
+
* These are overridden via math.import() — expressions cannot call them.
|
|
35
|
+
* simplify/derivative are called programmatically by the tool handler, not from expressions.
|
|
36
|
+
*/
|
|
37
|
+
const DISABLED_FUNCTIONS = [
|
|
38
|
+
'import',
|
|
39
|
+
'createUnit',
|
|
40
|
+
'evaluate',
|
|
41
|
+
'parse',
|
|
42
|
+
'simplify',
|
|
43
|
+
'derivative',
|
|
44
|
+
'resolve',
|
|
45
|
+
'reviver',
|
|
46
|
+
'compile',
|
|
47
|
+
'chain',
|
|
48
|
+
'config',
|
|
49
|
+
'parser',
|
|
50
|
+
];
|
|
51
|
+
/**
|
|
52
|
+
* `typed` is NOT disabled here — it's used internally by math.js for function dispatch.
|
|
53
|
+
* Overriding it breaks trig/simplify/etc. Instead, `typed()` calls from expressions are
|
|
54
|
+
* caught by the BLOCKED_RESULT_TYPES check (resultType "function" is rejected).
|
|
55
|
+
*/
|
|
56
|
+
/**
|
|
57
|
+
* Constants/properties overridden in the expression scope to prevent info leakage.
|
|
58
|
+
* `version` exposes the exact math.js version (enables targeted CVE research).
|
|
59
|
+
*/
|
|
60
|
+
const REDACTED_CONSTANTS = {
|
|
61
|
+
version: 'redacted',
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* Result types that must never be returned to clients.
|
|
65
|
+
* Function references leak internal source code via toString().
|
|
66
|
+
* ResultSet indicates multi-expression evaluation (newline bypass).
|
|
67
|
+
*/
|
|
68
|
+
const BLOCKED_RESULT_TYPES = new Set(['function', 'Function', 'ResultSet', 'Parser']);
|
|
69
|
+
/**
|
|
70
|
+
* Scope key names that could pollute the object prototype chain or shadow
|
|
71
|
+
* critical Object.prototype methods. Validated before passing to math.js.
|
|
72
|
+
*/
|
|
73
|
+
const BLOCKED_SCOPE_KEYS = new Set([
|
|
74
|
+
'__proto__',
|
|
75
|
+
'__defineGetter__',
|
|
76
|
+
'__defineSetter__',
|
|
77
|
+
'__lookupGetter__',
|
|
78
|
+
'__lookupSetter__',
|
|
79
|
+
'constructor',
|
|
80
|
+
'prototype',
|
|
81
|
+
'toString',
|
|
82
|
+
'valueOf',
|
|
83
|
+
'hasOwnProperty',
|
|
84
|
+
'isPrototypeOf',
|
|
85
|
+
'propertyIsEnumerable',
|
|
86
|
+
'toLocaleString',
|
|
87
|
+
]);
|
|
88
|
+
/**
|
|
89
|
+
* Check for expression separators outside square brackets.
|
|
90
|
+
* Semicolons inside `[...]` are valid matrix row separators.
|
|
91
|
+
* Newlines (`\n`, `\r`) are also expression separators in math.js.
|
|
92
|
+
*/
|
|
93
|
+
function hasExpressionSeparator(expr) {
|
|
94
|
+
let depth = 0;
|
|
95
|
+
for (const ch of expr) {
|
|
96
|
+
if (ch === '[')
|
|
97
|
+
depth++;
|
|
98
|
+
else if (ch === ']')
|
|
99
|
+
depth--;
|
|
100
|
+
else if (ch === '\n' || ch === '\r')
|
|
101
|
+
return true;
|
|
102
|
+
else if (ch === ';' && depth === 0)
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
export class MathService {
|
|
108
|
+
evaluate;
|
|
109
|
+
simplify;
|
|
110
|
+
derivative;
|
|
111
|
+
simplifyRules;
|
|
112
|
+
format;
|
|
113
|
+
typeOf;
|
|
114
|
+
config;
|
|
115
|
+
constructor(config) {
|
|
116
|
+
this.config = config;
|
|
117
|
+
// biome-ignore lint/style/noNonNullAssertion: math.js types declare `all` as potentially undefined, but it's always defined at runtime
|
|
118
|
+
const math = create(all);
|
|
119
|
+
// Save references before overriding — these bypass the expression scope restrictions
|
|
120
|
+
this.evaluate = math.evaluate.bind(math);
|
|
121
|
+
this.simplify = math.simplify.bind(math);
|
|
122
|
+
this.derivative = math.derivative.bind(math);
|
|
123
|
+
this.simplifyRules = [...math.simplify.rules, ...TRIG_SIMPLIFY_RULES];
|
|
124
|
+
this.format = math.format.bind(math);
|
|
125
|
+
this.typeOf = math.typeOf.bind(math);
|
|
126
|
+
// Disable dangerous functions in expression scope
|
|
127
|
+
const disabled = {};
|
|
128
|
+
for (const fn of DISABLED_FUNCTIONS) {
|
|
129
|
+
disabled[fn] = () => {
|
|
130
|
+
throw new Error(`Function "${fn}" is disabled for security.`);
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
// Redact constants that leak implementation details
|
|
134
|
+
for (const [key, value] of Object.entries(REDACTED_CONSTANTS)) {
|
|
135
|
+
disabled[key] = value;
|
|
136
|
+
}
|
|
137
|
+
math.import(disabled, { override: true });
|
|
138
|
+
}
|
|
139
|
+
/** Evaluate a math expression with optional variable scope and precision. */
|
|
140
|
+
evaluateExpression(expression, scope, precision) {
|
|
141
|
+
this.validateInput(expression);
|
|
142
|
+
const sanitizedScope = scope ? this.sanitizeScope(scope) : undefined;
|
|
143
|
+
const raw = this.runWithTimeout(() => sanitizedScope ? this.evaluate(expression, sanitizedScope) : this.evaluate(expression));
|
|
144
|
+
if (typeof raw === 'number' && !Number.isFinite(raw)) {
|
|
145
|
+
throw invalidParams(`Expression evaluated to ${raw} — this typically means the operation is mathematically undefined (e.g., division by zero, log of zero). Check the expression.`);
|
|
146
|
+
}
|
|
147
|
+
const resultType = this.typeOf(raw);
|
|
148
|
+
this.validateResultType(resultType);
|
|
149
|
+
const result = precision != null ? this.format(raw, { precision }) : this.format(raw);
|
|
150
|
+
this.validateResultSize(result);
|
|
151
|
+
return { result, resultType };
|
|
152
|
+
}
|
|
153
|
+
/** Simplify an algebraic expression symbolically. */
|
|
154
|
+
simplifyExpression(expression) {
|
|
155
|
+
this.validateInput(expression);
|
|
156
|
+
const simplified = this.runWithTimeout(() => this.simplify(expression, this.simplifyRules));
|
|
157
|
+
const result = simplified.toString();
|
|
158
|
+
this.validateResultSize(result);
|
|
159
|
+
return { result, resultType: 'string' };
|
|
160
|
+
}
|
|
161
|
+
/** Compute the symbolic derivative of an expression with respect to a variable. */
|
|
162
|
+
differentiateExpression(expression, variable) {
|
|
163
|
+
this.validateInput(expression);
|
|
164
|
+
const derived = this.runWithTimeout(() => this.derivative(expression, variable));
|
|
165
|
+
const result = derived.toString();
|
|
166
|
+
this.validateResultSize(result);
|
|
167
|
+
return { result, resultType: 'string' };
|
|
168
|
+
}
|
|
169
|
+
/** Get formatted help content listing available functions, operators, and syntax. */
|
|
170
|
+
getHelpContent() {
|
|
171
|
+
return HELP_CONTENT;
|
|
172
|
+
}
|
|
173
|
+
validateInput(expression) {
|
|
174
|
+
if (!expression.trim()) {
|
|
175
|
+
throw invalidParams('Expression cannot be empty.');
|
|
176
|
+
}
|
|
177
|
+
if (expression.length > this.config.maxExpressionLength) {
|
|
178
|
+
throw invalidParams(`Expression exceeds maximum length of ${this.config.maxExpressionLength} characters.`);
|
|
179
|
+
}
|
|
180
|
+
if (hasExpressionSeparator(expression)) {
|
|
181
|
+
throw invalidParams('Multiple expressions are not allowed. Submit one expression per call.');
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
/** Reject scope keys that could pollute the object prototype chain. */
|
|
185
|
+
sanitizeScope(scope) {
|
|
186
|
+
for (const key of Object.keys(scope)) {
|
|
187
|
+
if (BLOCKED_SCOPE_KEYS.has(key)) {
|
|
188
|
+
throw invalidParams(`Scope key "${key}" is not allowed — it conflicts with a reserved property name.`);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
return scope;
|
|
192
|
+
}
|
|
193
|
+
/** Reject result types that leak internals (functions, parsers, multi-expression ResultSets). */
|
|
194
|
+
validateResultType(resultType) {
|
|
195
|
+
if (BLOCKED_RESULT_TYPES.has(resultType)) {
|
|
196
|
+
throw invalidParams(`Expression produced a ${resultType} — only numeric, string, matrix, complex, unit, and boolean results are allowed.`);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
/** Reject results that exceed the configured maximum size. */
|
|
200
|
+
validateResultSize(result) {
|
|
201
|
+
if (result.length > this.config.maxResultLength) {
|
|
202
|
+
throw invalidParams(`Result exceeds maximum size (${this.config.maxResultLength} characters). Reduce matrix dimensions or simplify the expression.`);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
/** Runs a synchronous function inside a vm sandbox with timeout protection. */
|
|
206
|
+
runWithTimeout(fn) {
|
|
207
|
+
const sandbox = { fn, result: undefined };
|
|
208
|
+
const context = vm.createContext(sandbox);
|
|
209
|
+
try {
|
|
210
|
+
vm.runInNewContext('result = fn()', context, { timeout: this.config.evaluationTimeoutMs });
|
|
211
|
+
return sandbox.result;
|
|
212
|
+
}
|
|
213
|
+
catch (err) {
|
|
214
|
+
if (err instanceof Error && 'code' in err && err.code === 'ERR_SCRIPT_EXECUTION_TIMEOUT') {
|
|
215
|
+
throw serviceUnavailable(`Expression evaluation timed out after ${this.config.evaluationTimeoutMs / 1000} seconds. Simplify the expression or reduce matrix dimensions.`);
|
|
216
|
+
}
|
|
217
|
+
// All non-timeout errors from the VM are expression-related
|
|
218
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
219
|
+
throw invalidParams(`Invalid expression: ${message}`);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
// --- Init/accessor pattern ---
|
|
224
|
+
let _service;
|
|
225
|
+
/** Initialize the math service. Call once from createApp setup(). */
|
|
226
|
+
export function initMathService(config) {
|
|
227
|
+
_service = new MathService(config);
|
|
228
|
+
}
|
|
229
|
+
/** Get the initialized math service instance. */
|
|
230
|
+
export function getMathService() {
|
|
231
|
+
if (!_service)
|
|
232
|
+
throw new Error('MathService not initialized — call initMathService() in setup()');
|
|
233
|
+
return _service;
|
|
234
|
+
}
|
|
235
|
+
// --- Help content ---
|
|
236
|
+
const HELP_CONTENT = `# Calculator Help
|
|
237
|
+
|
|
238
|
+
## Operators
|
|
239
|
+
|
|
240
|
+
| Operator | Description | Example |
|
|
241
|
+
|:---------|:------------|:--------|
|
|
242
|
+
| + | Addition | 2 + 3 |
|
|
243
|
+
| - | Subtraction | 5 - 2 |
|
|
244
|
+
| * | Multiplication | 3 * 4 |
|
|
245
|
+
| / | Division | 10 / 3 |
|
|
246
|
+
| ^ | Exponentiation | 2 ^ 10 |
|
|
247
|
+
| % | Modulus | 17 % 5 |
|
|
248
|
+
| ! | Factorial | 5! |
|
|
249
|
+
|
|
250
|
+
## Constants
|
|
251
|
+
|
|
252
|
+
| Name | Value | Description |
|
|
253
|
+
|:-----|:------|:------------|
|
|
254
|
+
| pi | 3.14159... | Ratio of circumference to diameter |
|
|
255
|
+
| e | 2.71828... | Euler's number |
|
|
256
|
+
| phi | 1.61803... | Golden ratio |
|
|
257
|
+
| i | sqrt(-1) | Imaginary unit |
|
|
258
|
+
| Infinity | Infinity | Positive infinity |
|
|
259
|
+
| NaN | NaN | Not a number |
|
|
260
|
+
| true | true | Boolean true |
|
|
261
|
+
| false | false | Boolean false |
|
|
262
|
+
|
|
263
|
+
## Functions
|
|
264
|
+
|
|
265
|
+
### Arithmetic
|
|
266
|
+
abs, ceil, floor, round, sign, sqrt, cbrt, exp, expm1, log, log2, log10, log1p, pow, mod, gcd, lcm, nthRoot, hypot, fix, cube, square, unaryMinus, unaryPlus
|
|
267
|
+
|
|
268
|
+
### Trigonometry
|
|
269
|
+
sin, cos, tan, asin, acos, atan, atan2, sinh, cosh, tanh, asinh, acosh, atanh, sec, csc, cot, asec, acsc, acot, sech, csch, coth
|
|
270
|
+
|
|
271
|
+
### Statistics
|
|
272
|
+
mean, median, mode, std, variance, min, max, sum, prod, quantileSeq, mad, count
|
|
273
|
+
|
|
274
|
+
### Matrix
|
|
275
|
+
det, inv, transpose, trace, zeros, ones, identity, diag, size, reshape, flatten, concat, sort, cross, dot, eigs, expm, sqrtm, kron, pinv, range
|
|
276
|
+
|
|
277
|
+
### Combinatorics
|
|
278
|
+
factorial, gamma, permutations, combinations, catalan, bellNumbers, stirlingS2, composition, multinomial
|
|
279
|
+
|
|
280
|
+
### Complex Numbers
|
|
281
|
+
re, im, conj, arg, complex
|
|
282
|
+
|
|
283
|
+
### Logical
|
|
284
|
+
and, or, xor, not
|
|
285
|
+
|
|
286
|
+
### Comparison
|
|
287
|
+
equal, unequal, larger, largerEq, smaller, smallerEq, compare, deepEqual
|
|
288
|
+
|
|
289
|
+
### Unit Conversion
|
|
290
|
+
Syntax: \`value unit to targetUnit\`
|
|
291
|
+
|
|
292
|
+
Common units: m, cm, mm, km, inch, ft, yard, mile, kg, g, lb, oz, s, min, hour, day, celsius, fahrenheit, kelvin, liter, gallon, joule, watt, newton, pascal, bar, psi, radian, degree
|
|
293
|
+
|
|
294
|
+
## Syntax Examples
|
|
295
|
+
|
|
296
|
+
### Basic arithmetic
|
|
297
|
+
\`2 + 3 * 4\` => 14
|
|
298
|
+
|
|
299
|
+
### Functions
|
|
300
|
+
\`sqrt(144)\` => 12
|
|
301
|
+
\`sin(pi / 2)\` => 1
|
|
302
|
+
\`log(1000, 10)\` => 3
|
|
303
|
+
|
|
304
|
+
### Variables (via scope parameter)
|
|
305
|
+
Provide scope: { "x": 5, "y": 3 }
|
|
306
|
+
Expression: \`x^2 + y\` => 28
|
|
307
|
+
|
|
308
|
+
### Matrices
|
|
309
|
+
\`[1, 2; 3, 4]\` — 2x2 matrix
|
|
310
|
+
\`det([1, 2; 3, 4])\` => -2
|
|
311
|
+
\`inv([1, 2; 3, 4])\` => [[-2, 1], [1.5, -0.5]]
|
|
312
|
+
|
|
313
|
+
### Complex numbers
|
|
314
|
+
\`2 + 3i\` => 2 + 3i
|
|
315
|
+
\`sqrt(-4)\` => 2i
|
|
316
|
+
\`abs(3 + 4i)\` => 5
|
|
317
|
+
|
|
318
|
+
### Unit conversion
|
|
319
|
+
\`5 kg to lbs\` => 11.02 lbs
|
|
320
|
+
\`100 celsius to fahrenheit\` => 212 fahrenheit
|
|
321
|
+
\`1 mile to km\` => 1.60934 km
|
|
322
|
+
|
|
323
|
+
> **Note:** Unit conversions use IEEE 754 floating-point arithmetic. Results may include minor rounding artifacts (e.g., 211.99999999999997 instead of 212). Use the \`precision\` parameter to round.
|
|
324
|
+
|
|
325
|
+
### Precision
|
|
326
|
+
Use the precision parameter (1\u201316 significant digits) for numeric results.
|
|
327
|
+
|
|
328
|
+
### Operations
|
|
329
|
+
- **evaluate** (default): Compute a numeric result
|
|
330
|
+
- **simplify**: Reduce algebraic expressions symbolically (e.g., "2x + 3x" => "5 * x", "sin(x)^2 + cos(x)^2" => 1). Supports algebraic rules and common trigonometric identities (Pythagorean, double-angle, tan/sec/csc/cot relationships).
|
|
331
|
+
- **derivative**: Compute symbolic derivative (requires variable parameter, e.g., variable: "x")
|
|
332
|
+
`;
|
|
333
|
+
//# sourceMappingURL=math-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"math-service.js","sourceRoot":"","sources":["../../../src/services/math/math-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Types for the math service.
|
|
3
|
+
* @module services/math/types
|
|
4
|
+
*/
|
|
5
|
+
/** Result of a math operation. */
|
|
6
|
+
export interface MathResult {
|
|
7
|
+
/** Formatted string representation of the result. */
|
|
8
|
+
result: string;
|
|
9
|
+
/** math.js type name: number, BigNumber, Complex, Matrix, Unit, string, boolean. */
|
|
10
|
+
resultType: string;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/services/math/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,kCAAkC;AAClC,MAAM,WAAW,UAAU;IACzB,qDAAqD;IACrD,MAAM,EAAE,MAAM,CAAC;IACf,oFAAoF;IACpF,UAAU,EAAE,MAAM,CAAC;CACpB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/services/math/types.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
package/package.json
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@cyanheads/calculator-mcp-server",
|
|
3
|
+
"version": "0.1.6",
|
|
4
|
+
"description": "A calculator MCP server that lets any LLM verify mathematical computations. Evaluate, simplify, and differentiate expressions via a single tool. Powered by math.js v15.",
|
|
5
|
+
"mcpName": "io.github.cyanheads/calculator-mcp-server",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "dist/index.js",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"bin": {
|
|
10
|
+
"calculator-mcp-server": "dist/index.js"
|
|
11
|
+
},
|
|
12
|
+
"files": ["dist/", "README.md", "LICENSE", "CLAUDE.md", "Dockerfile", "server.json"],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "bun scripts/build.ts",
|
|
15
|
+
"rebuild": "bun scripts/clean.ts && bun scripts/build.ts",
|
|
16
|
+
"clean": "bun scripts/clean.ts",
|
|
17
|
+
"devcheck": "bun scripts/devcheck.ts",
|
|
18
|
+
"tree": "bun scripts/tree.ts",
|
|
19
|
+
"format": "biome check --write --unsafe .",
|
|
20
|
+
"lint:mcp": "bun scripts/lint-mcp.ts",
|
|
21
|
+
"test": "vitest run",
|
|
22
|
+
"dev:stdio": "MCP_TRANSPORT_TYPE=stdio bun --watch src/index.ts",
|
|
23
|
+
"dev:http": "MCP_TRANSPORT_TYPE=http bun --watch src/index.ts",
|
|
24
|
+
"start:stdio": "MCP_TRANSPORT_TYPE=stdio node dist/index.js",
|
|
25
|
+
"start:http": "MCP_TRANSPORT_TYPE=http node dist/index.js"
|
|
26
|
+
},
|
|
27
|
+
"keywords": [
|
|
28
|
+
"mcp",
|
|
29
|
+
"mcp-server",
|
|
30
|
+
"model-context-protocol",
|
|
31
|
+
"calculator",
|
|
32
|
+
"math",
|
|
33
|
+
"mathjs",
|
|
34
|
+
"llm-tools",
|
|
35
|
+
"typescript"
|
|
36
|
+
],
|
|
37
|
+
"repository": {
|
|
38
|
+
"type": "git",
|
|
39
|
+
"url": "git+https://github.com/cyanheads/calculator-mcp-server.git"
|
|
40
|
+
},
|
|
41
|
+
"homepage": "https://github.com/cyanheads/calculator-mcp-server",
|
|
42
|
+
"bugs": {
|
|
43
|
+
"url": "https://github.com/cyanheads/calculator-mcp-server/issues"
|
|
44
|
+
},
|
|
45
|
+
"author": "cyanheads (https://github.com/cyanheads)",
|
|
46
|
+
"license": "Apache-2.0",
|
|
47
|
+
"engines": {
|
|
48
|
+
"node": ">=22.0.0",
|
|
49
|
+
"bun": ">=1.2.0"
|
|
50
|
+
},
|
|
51
|
+
"packageManager": "bun@1.3.11",
|
|
52
|
+
"publishConfig": {
|
|
53
|
+
"access": "public"
|
|
54
|
+
},
|
|
55
|
+
"dependencies": {
|
|
56
|
+
"@cyanheads/mcp-ts-core": "^0.2.10",
|
|
57
|
+
"mathjs": "^15.1.1",
|
|
58
|
+
"pino-pretty": "^13.1.3"
|
|
59
|
+
},
|
|
60
|
+
"devDependencies": {
|
|
61
|
+
"@biomejs/biome": "^2.4.9",
|
|
62
|
+
"@types/node": "^25.5.0",
|
|
63
|
+
"depcheck": "^1.4.7",
|
|
64
|
+
"ignore": "^7.0.5",
|
|
65
|
+
"tsc-alias": "^1.8.16",
|
|
66
|
+
"tsx": "^4.21.0",
|
|
67
|
+
"typescript": "^6.0.2",
|
|
68
|
+
"vitest": "^4.1.2"
|
|
69
|
+
}
|
|
70
|
+
}
|
package/server.json
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
|
|
3
|
+
"name": "io.github.cyanheads/calculator-mcp-server",
|
|
4
|
+
"description": "Calculator MCP server — evaluate, simplify, and differentiate math expressions. Powered by math.js v15.",
|
|
5
|
+
"repository": {
|
|
6
|
+
"url": "https://github.com/cyanheads/calculator-mcp-server",
|
|
7
|
+
"source": "github"
|
|
8
|
+
},
|
|
9
|
+
"version": "0.1.6",
|
|
10
|
+
"packages": [
|
|
11
|
+
{
|
|
12
|
+
"registryType": "npm",
|
|
13
|
+
"registryBaseUrl": "https://registry.npmjs.org",
|
|
14
|
+
"identifier": "@cyanheads/calculator-mcp-server",
|
|
15
|
+
"runtimeHint": "bun",
|
|
16
|
+
"version": "0.1.6",
|
|
17
|
+
"packageArguments": [
|
|
18
|
+
{
|
|
19
|
+
"type": "positional",
|
|
20
|
+
"value": "run"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"type": "positional",
|
|
24
|
+
"value": "start:stdio"
|
|
25
|
+
}
|
|
26
|
+
],
|
|
27
|
+
"environmentVariables": [
|
|
28
|
+
{
|
|
29
|
+
"name": "CALC_MAX_EXPRESSION_LENGTH",
|
|
30
|
+
"description": "Maximum allowed expression string length.",
|
|
31
|
+
"format": "string",
|
|
32
|
+
"isRequired": false,
|
|
33
|
+
"default": "1000"
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"name": "CALC_EVALUATION_TIMEOUT_MS",
|
|
37
|
+
"description": "Maximum evaluation time in milliseconds.",
|
|
38
|
+
"format": "string",
|
|
39
|
+
"isRequired": false,
|
|
40
|
+
"default": "5000"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"name": "CALC_MAX_RESULT_LENGTH",
|
|
44
|
+
"description": "Maximum result string length in characters.",
|
|
45
|
+
"format": "string",
|
|
46
|
+
"isRequired": false,
|
|
47
|
+
"default": "100000"
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"name": "MCP_LOG_LEVEL",
|
|
51
|
+
"description": "Sets the minimum log level for output (e.g., 'debug', 'info', 'warn').",
|
|
52
|
+
"format": "string",
|
|
53
|
+
"isRequired": false,
|
|
54
|
+
"default": "info"
|
|
55
|
+
}
|
|
56
|
+
],
|
|
57
|
+
"transport": {
|
|
58
|
+
"type": "stdio"
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"registryType": "npm",
|
|
63
|
+
"registryBaseUrl": "https://registry.npmjs.org",
|
|
64
|
+
"identifier": "@cyanheads/calculator-mcp-server",
|
|
65
|
+
"runtimeHint": "bun",
|
|
66
|
+
"version": "0.1.6",
|
|
67
|
+
"packageArguments": [
|
|
68
|
+
{
|
|
69
|
+
"type": "positional",
|
|
70
|
+
"value": "run"
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"type": "positional",
|
|
74
|
+
"value": "start:http"
|
|
75
|
+
}
|
|
76
|
+
],
|
|
77
|
+
"environmentVariables": [
|
|
78
|
+
{
|
|
79
|
+
"name": "CALC_MAX_EXPRESSION_LENGTH",
|
|
80
|
+
"description": "Maximum allowed expression string length.",
|
|
81
|
+
"format": "string",
|
|
82
|
+
"isRequired": false,
|
|
83
|
+
"default": "1000"
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"name": "CALC_EVALUATION_TIMEOUT_MS",
|
|
87
|
+
"description": "Maximum evaluation time in milliseconds.",
|
|
88
|
+
"format": "string",
|
|
89
|
+
"isRequired": false,
|
|
90
|
+
"default": "5000"
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
"name": "CALC_MAX_RESULT_LENGTH",
|
|
94
|
+
"description": "Maximum result string length in characters.",
|
|
95
|
+
"format": "string",
|
|
96
|
+
"isRequired": false,
|
|
97
|
+
"default": "100000"
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
"name": "MCP_HTTP_HOST",
|
|
101
|
+
"description": "The hostname for the HTTP server.",
|
|
102
|
+
"format": "string",
|
|
103
|
+
"isRequired": false,
|
|
104
|
+
"default": "127.0.0.1"
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
"name": "MCP_HTTP_PORT",
|
|
108
|
+
"description": "The port to run the HTTP server on.",
|
|
109
|
+
"format": "string",
|
|
110
|
+
"isRequired": false,
|
|
111
|
+
"default": "3010"
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
"name": "MCP_HTTP_ENDPOINT_PATH",
|
|
115
|
+
"description": "The endpoint path for the MCP server.",
|
|
116
|
+
"format": "string",
|
|
117
|
+
"isRequired": false,
|
|
118
|
+
"default": "/mcp"
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
"name": "MCP_AUTH_MODE",
|
|
122
|
+
"description": "Authentication mode to use: 'none', 'jwt', or 'oauth'.",
|
|
123
|
+
"format": "string",
|
|
124
|
+
"isRequired": false,
|
|
125
|
+
"default": "none"
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
"name": "MCP_LOG_LEVEL",
|
|
129
|
+
"description": "Sets the minimum log level for output (e.g., 'debug', 'info', 'warn').",
|
|
130
|
+
"format": "string",
|
|
131
|
+
"isRequired": false,
|
|
132
|
+
"default": "info"
|
|
133
|
+
}
|
|
134
|
+
],
|
|
135
|
+
"transport": {
|
|
136
|
+
"type": "streamable-http",
|
|
137
|
+
"url": "http://localhost:3010/mcp"
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
]
|
|
141
|
+
}
|