@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
package/README.md
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
<h1>@cyanheads/calculator-mcp-server</h1>
|
|
3
|
+
<p><b>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.</b></p>
|
|
4
|
+
<p><b>1 Tool · 1 Resource</b></p>
|
|
5
|
+
</div>
|
|
6
|
+
|
|
7
|
+
<div align="center">
|
|
8
|
+
|
|
9
|
+
[](./CHANGELOG.md) [](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) [](https://modelcontextprotocol.io/) [](./LICENSE) [](https://www.typescriptlang.org/)
|
|
10
|
+
|
|
11
|
+
</div>
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Tools
|
|
16
|
+
|
|
17
|
+
One tool for all mathematical operations:
|
|
18
|
+
|
|
19
|
+
| Tool Name | Description |
|
|
20
|
+
|:----------|:------------|
|
|
21
|
+
| `calculate` | Evaluate math expressions, simplify algebraic expressions, or compute symbolic derivatives. |
|
|
22
|
+
|
|
23
|
+
### `calculate`
|
|
24
|
+
|
|
25
|
+
A single tool covering 100% of the server's purpose. The `operation` parameter defaults to `evaluate`, so the common case is just `{ expression: "..." }`.
|
|
26
|
+
|
|
27
|
+
- **Evaluate** — arithmetic, trigonometry, logarithms, statistics, matrices, complex numbers, unit conversion, combinatorics
|
|
28
|
+
- **Simplify** — reduce algebraic expressions symbolically (e.g., `2x + 3x` -> `5 * x`). Supports algebraic and trigonometric identities
|
|
29
|
+
- **Derivative** — compute symbolic derivatives (e.g., `3x^2 + 2x + 1` -> `6 * x + 2`)
|
|
30
|
+
- Variable scope via `scope` parameter: `{ "x": 5, "y": 3 }`
|
|
31
|
+
- Configurable precision for numeric results
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Resources
|
|
36
|
+
|
|
37
|
+
| URI Pattern | Description |
|
|
38
|
+
|:------------|:------------|
|
|
39
|
+
| `calculator://help` | Available functions, operators, constants, and syntax reference. |
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Features
|
|
44
|
+
|
|
45
|
+
Built on [`@cyanheads/mcp-ts-core`](https://github.com/cyanheads/mcp-ts-core):
|
|
46
|
+
|
|
47
|
+
- Declarative tool definitions — single file per tool, framework handles registration and validation
|
|
48
|
+
- Unified error handling across all tools
|
|
49
|
+
- Structured logging with optional OpenTelemetry tracing
|
|
50
|
+
- Runs locally (stdio/HTTP) or in Docker
|
|
51
|
+
|
|
52
|
+
Calculator-specific:
|
|
53
|
+
|
|
54
|
+
- Hardened math.js v15 instance — dangerous functions disabled, evaluation sandboxed via `vm.runInNewContext()` with timeout
|
|
55
|
+
- No auth required — all operations are read-only and stateless
|
|
56
|
+
- Input validation: expression length limits, expression separator rejection (semicolons and newlines), variable name regex enforcement
|
|
57
|
+
- Result validation: blocked result types (functions, parsers, result sets), configurable max result size
|
|
58
|
+
- Scope sanitization: numeric-only values, prototype pollution prevention (blocked `__proto__`, `constructor`, etc.)
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## Getting Started
|
|
63
|
+
|
|
64
|
+
### MCP Client Configuration
|
|
65
|
+
|
|
66
|
+
Add to your MCP client config (e.g., `claude_desktop_config.json`):
|
|
67
|
+
|
|
68
|
+
```json
|
|
69
|
+
{
|
|
70
|
+
"mcpServers": {
|
|
71
|
+
"calculator": {
|
|
72
|
+
"type": "stdio",
|
|
73
|
+
"command": "bunx",
|
|
74
|
+
"args": ["@cyanheads/calculator-mcp-server@latest"]
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Prerequisites
|
|
81
|
+
|
|
82
|
+
- [Bun v1.2.0](https://bun.sh/) or higher
|
|
83
|
+
|
|
84
|
+
### Installation
|
|
85
|
+
|
|
86
|
+
1. **Clone the repository:**
|
|
87
|
+
```sh
|
|
88
|
+
git clone https://github.com/cyanheads/calculator-mcp-server.git
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
2. **Navigate into the directory:**
|
|
92
|
+
```sh
|
|
93
|
+
cd calculator-mcp-server
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
3. **Install dependencies:**
|
|
97
|
+
```sh
|
|
98
|
+
bun install
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## Configuration
|
|
104
|
+
|
|
105
|
+
| Variable | Description | Default |
|
|
106
|
+
|:---------|:------------|:--------|
|
|
107
|
+
| `CALC_MAX_EXPRESSION_LENGTH` | Maximum allowed expression string length (10–10,000). | `1000` |
|
|
108
|
+
| `CALC_EVALUATION_TIMEOUT_MS` | Maximum evaluation time in milliseconds (100–30,000). | `5000` |
|
|
109
|
+
| `CALC_MAX_RESULT_LENGTH` | Maximum result string length in characters (1,000–1,000,000). | `100000` |
|
|
110
|
+
| `MCP_TRANSPORT_TYPE` | Transport: `stdio` or `http`. | `stdio` |
|
|
111
|
+
| `MCP_HTTP_PORT` | Port for HTTP server. | `3010` |
|
|
112
|
+
| `MCP_AUTH_MODE` | Auth mode: `none`, `jwt`, or `oauth`. | `none` |
|
|
113
|
+
| `MCP_LOG_LEVEL` | Log level (RFC 5424). | `info` |
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## Running the Server
|
|
118
|
+
|
|
119
|
+
### Local Development
|
|
120
|
+
|
|
121
|
+
- **Build and run the production version:**
|
|
122
|
+
```sh
|
|
123
|
+
bun run build
|
|
124
|
+
bun run start:http # or start:stdio
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
- **Run checks and tests:**
|
|
128
|
+
```sh
|
|
129
|
+
bun run devcheck # Lints, formats, type-checks
|
|
130
|
+
bun run test # Runs test suite
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Docker
|
|
134
|
+
|
|
135
|
+
```sh
|
|
136
|
+
docker build -t calculator-mcp-server .
|
|
137
|
+
docker run -p 3010:3010 calculator-mcp-server
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## Project Structure
|
|
143
|
+
|
|
144
|
+
| Directory | Purpose |
|
|
145
|
+
|:----------|:--------|
|
|
146
|
+
| `src/mcp-server/tools/` | Tool definitions (`*.tool.ts`). |
|
|
147
|
+
| `src/mcp-server/resources/` | Resource definitions (`*.resource.ts`). |
|
|
148
|
+
| `src/services/` | Domain service integrations (MathService). |
|
|
149
|
+
| `src/config/` | Environment variable parsing and validation with Zod. |
|
|
150
|
+
| `docs/` | Generated directory tree. |
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## Development Guide
|
|
155
|
+
|
|
156
|
+
See [`CLAUDE.md`](./CLAUDE.md) for development guidelines and architectural rules. The short version:
|
|
157
|
+
|
|
158
|
+
- Handlers throw, framework catches — no `try/catch` in tool logic
|
|
159
|
+
- Use `ctx.log` for logging
|
|
160
|
+
- Register new tools and resources in `src/index.ts`
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## Contributing
|
|
165
|
+
|
|
166
|
+
Issues and pull requests are welcome. Run checks before submitting:
|
|
167
|
+
|
|
168
|
+
```sh
|
|
169
|
+
bun run devcheck
|
|
170
|
+
bun run test
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## License
|
|
176
|
+
|
|
177
|
+
Apache-2.0 — see [LICENSE](LICENSE) for details.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Server-specific configuration for calculator-mcp-server.
|
|
3
|
+
* @module config/server-config
|
|
4
|
+
*/
|
|
5
|
+
import { z } from '@cyanheads/mcp-ts-core';
|
|
6
|
+
declare const ServerConfigSchema: z.ZodObject<{
|
|
7
|
+
maxExpressionLength: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
8
|
+
evaluationTimeoutMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
9
|
+
maxResultLength: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
10
|
+
}, z.core.$strip>;
|
|
11
|
+
export type ServerConfig = z.infer<typeof ServerConfigSchema>;
|
|
12
|
+
/** Lazy-parsed server config from env vars. */
|
|
13
|
+
export declare function getServerConfig(): ServerConfig;
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=server-config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-config.d.ts","sourceRoot":"","sources":["../../src/config/server-config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAE3C,QAAA,MAAM,kBAAkB;;;;iBAsBtB,CAAC;AAEH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAI9D,+CAA+C;AAC/C,wBAAgB,eAAe,IAAI,YAAY,CAO9C"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Server-specific configuration for calculator-mcp-server.
|
|
3
|
+
* @module config/server-config
|
|
4
|
+
*/
|
|
5
|
+
import { z } from '@cyanheads/mcp-ts-core';
|
|
6
|
+
const ServerConfigSchema = z.object({
|
|
7
|
+
maxExpressionLength: z.coerce
|
|
8
|
+
.number()
|
|
9
|
+
.int()
|
|
10
|
+
.min(10)
|
|
11
|
+
.max(10_000)
|
|
12
|
+
.default(1000)
|
|
13
|
+
.describe('Maximum allowed expression string length (10–10,000)'),
|
|
14
|
+
evaluationTimeoutMs: z.coerce
|
|
15
|
+
.number()
|
|
16
|
+
.int()
|
|
17
|
+
.min(100)
|
|
18
|
+
.max(30_000)
|
|
19
|
+
.default(5000)
|
|
20
|
+
.describe('Maximum evaluation time in milliseconds (100–30,000)'),
|
|
21
|
+
maxResultLength: z.coerce
|
|
22
|
+
.number()
|
|
23
|
+
.int()
|
|
24
|
+
.min(1_000)
|
|
25
|
+
.max(1_000_000)
|
|
26
|
+
.default(100_000)
|
|
27
|
+
.describe('Maximum result string length in characters (1,000–1,000,000)'),
|
|
28
|
+
});
|
|
29
|
+
let _config;
|
|
30
|
+
/** Lazy-parsed server config from env vars. */
|
|
31
|
+
export function getServerConfig() {
|
|
32
|
+
_config ??= ServerConfigSchema.parse({
|
|
33
|
+
maxExpressionLength: process.env.CALC_MAX_EXPRESSION_LENGTH,
|
|
34
|
+
evaluationTimeoutMs: process.env.CALC_EVALUATION_TIMEOUT_MS,
|
|
35
|
+
maxResultLength: process.env.CALC_MAX_RESULT_LENGTH,
|
|
36
|
+
});
|
|
37
|
+
return _config;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=server-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-config.js","sourceRoot":"","sources":["../../src/config/server-config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAE3C,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IAClC,mBAAmB,EAAE,CAAC,CAAC,MAAM;SAC1B,MAAM,EAAE;SACR,GAAG,EAAE;SACL,GAAG,CAAC,EAAE,CAAC;SACP,GAAG,CAAC,MAAM,CAAC;SACX,OAAO,CAAC,IAAI,CAAC;SACb,QAAQ,CAAC,sDAAsD,CAAC;IACnE,mBAAmB,EAAE,CAAC,CAAC,MAAM;SAC1B,MAAM,EAAE;SACR,GAAG,EAAE;SACL,GAAG,CAAC,GAAG,CAAC;SACR,GAAG,CAAC,MAAM,CAAC;SACX,OAAO,CAAC,IAAI,CAAC;SACb,QAAQ,CAAC,sDAAsD,CAAC;IACnE,eAAe,EAAE,CAAC,CAAC,MAAM;SACtB,MAAM,EAAE;SACR,GAAG,EAAE;SACL,GAAG,CAAC,KAAK,CAAC;SACV,GAAG,CAAC,SAAS,CAAC;SACd,OAAO,CAAC,OAAO,CAAC;SAChB,QAAQ,CAAC,8DAA8D,CAAC;CAC5E,CAAC,CAAC;AAIH,IAAI,OAAiC,CAAC;AAEtC,+CAA+C;AAC/C,MAAM,UAAU,eAAe;IAC7B,OAAO,KAAK,kBAAkB,CAAC,KAAK,CAAC;QACnC,mBAAmB,EAAE,OAAO,CAAC,GAAG,CAAC,0BAA0B;QAC3D,mBAAmB,EAAE,OAAO,CAAC,GAAG,CAAC,0BAA0B;QAC3D,eAAe,EAAE,OAAO,CAAC,GAAG,CAAC,sBAAsB;KACpD,CAAC,CAAC;IACH,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;GAGG"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* @fileoverview calculator-mcp-server entry point.
|
|
4
|
+
* @module index
|
|
5
|
+
*/
|
|
6
|
+
import { createApp } from '@cyanheads/mcp-ts-core';
|
|
7
|
+
import { getServerConfig } from './config/server-config.js';
|
|
8
|
+
import { helpResource } from './mcp-server/resources/definitions/help.resource.js';
|
|
9
|
+
import { calculateTool } from './mcp-server/tools/definitions/calculate.tool.js';
|
|
10
|
+
import { initMathService } from './services/math/math-service.js';
|
|
11
|
+
await createApp({
|
|
12
|
+
tools: [calculateTool],
|
|
13
|
+
resources: [helpResource],
|
|
14
|
+
setup() {
|
|
15
|
+
initMathService(getServerConfig());
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,qDAAqD,CAAC;AACnF,OAAO,EAAE,aAAa,EAAE,MAAM,kDAAkD,CAAC;AACjF,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAElE,MAAM,SAAS,CAAC;IACd,KAAK,EAAE,CAAC,aAAa,CAAC;IACtB,SAAS,EAAE,CAAC,YAAY,CAAC;IACzB,KAAK;QACH,eAAe,CAAC,eAAe,EAAE,CAAC,CAAC;IACrC,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Help resource — static reference of available functions, operators, and syntax.
|
|
3
|
+
* @module mcp-server/resources/definitions/help.resource
|
|
4
|
+
*/
|
|
5
|
+
export declare const helpResource: import("@cyanheads/mcp-ts-core").ResourceDefinition<import("zod").ZodObject<Readonly<{
|
|
6
|
+
[k: string]: import("zod/v4/core").$ZodType<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>>;
|
|
7
|
+
}>, import("zod/v4/core").$strip>, undefined>;
|
|
8
|
+
//# sourceMappingURL=help.resource.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"help.resource.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/resources/definitions/help.resource.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,eAAO,MAAM,YAAY;;6CAOvB,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Help resource — static reference of available functions, operators, and syntax.
|
|
3
|
+
* @module mcp-server/resources/definitions/help.resource
|
|
4
|
+
*/
|
|
5
|
+
import { resource } from '@cyanheads/mcp-ts-core';
|
|
6
|
+
import { getMathService } from '../../../services/math/math-service.js';
|
|
7
|
+
export const helpResource = resource('calculator://help', {
|
|
8
|
+
name: 'Calculator Help',
|
|
9
|
+
description: 'Available functions, operators, constants, and syntax reference.',
|
|
10
|
+
mimeType: 'text/markdown',
|
|
11
|
+
handler() {
|
|
12
|
+
return getMathService().getHelpContent();
|
|
13
|
+
},
|
|
14
|
+
});
|
|
15
|
+
//# sourceMappingURL=help.resource.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"help.resource.js","sourceRoot":"","sources":["../../../../src/mcp-server/resources/definitions/help.resource.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAEjE,MAAM,CAAC,MAAM,YAAY,GAAG,QAAQ,CAAC,mBAAmB,EAAE;IACxD,IAAI,EAAE,iBAAiB;IACvB,WAAW,EAAE,kEAAkE;IAC/E,QAAQ,EAAE,eAAe;IACzB,OAAO;QACL,OAAO,cAAc,EAAE,CAAC,cAAc,EAAE,CAAC;IAC3C,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Calculate tool — evaluate, simplify, or differentiate math expressions.
|
|
3
|
+
* Single tool covering 100% of the server's purpose.
|
|
4
|
+
* @module mcp-server/tools/definitions/calculate.tool
|
|
5
|
+
*/
|
|
6
|
+
import { z } from '@cyanheads/mcp-ts-core';
|
|
7
|
+
export declare const calculateTool: import("@cyanheads/mcp-ts-core").ToolDefinition<z.ZodObject<{
|
|
8
|
+
expression: z.ZodString;
|
|
9
|
+
operation: z.ZodDefault<z.ZodEnum<{
|
|
10
|
+
evaluate: "evaluate";
|
|
11
|
+
simplify: "simplify";
|
|
12
|
+
derivative: "derivative";
|
|
13
|
+
}>>;
|
|
14
|
+
variable: z.ZodOptional<z.ZodString>;
|
|
15
|
+
scope: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodNumber>>;
|
|
16
|
+
precision: z.ZodOptional<z.ZodNumber>;
|
|
17
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
18
|
+
result: z.ZodString;
|
|
19
|
+
resultType: z.ZodString;
|
|
20
|
+
expression: z.ZodString;
|
|
21
|
+
}, z.core.$strip>>;
|
|
22
|
+
//# sourceMappingURL=calculate.tool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"calculate.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/calculate.tool.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAIjD,eAAO,MAAM,aAAa;;;;;;;;;;;;;;kBA0GxB,CAAC"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Calculate tool — evaluate, simplify, or differentiate math expressions.
|
|
3
|
+
* Single tool covering 100% of the server's purpose.
|
|
4
|
+
* @module mcp-server/tools/definitions/calculate.tool
|
|
5
|
+
*/
|
|
6
|
+
import { tool, z } from '@cyanheads/mcp-ts-core';
|
|
7
|
+
import { invalidParams } from '@cyanheads/mcp-ts-core/errors';
|
|
8
|
+
import { getMathService } from '../../../services/math/math-service.js';
|
|
9
|
+
export const calculateTool = tool('calculate', {
|
|
10
|
+
description: 'Evaluate math expressions, simplify algebraic expressions, or compute symbolic derivatives. ' +
|
|
11
|
+
'Supports arithmetic, trigonometry, statistics, matrices, complex numbers, units, and combinatorics. ' +
|
|
12
|
+
'Powered by math.js — use calculator://help for the full function reference.',
|
|
13
|
+
annotations: {
|
|
14
|
+
readOnlyHint: true,
|
|
15
|
+
idempotentHint: true,
|
|
16
|
+
openWorldHint: false,
|
|
17
|
+
},
|
|
18
|
+
input: z.object({
|
|
19
|
+
expression: z
|
|
20
|
+
.string()
|
|
21
|
+
.min(1)
|
|
22
|
+
.describe('Mathematical expression to evaluate. Supports standard notation: ' +
|
|
23
|
+
'arithmetic (+, -, *, /, ^, %), functions (sin, cos, sqrt, log, abs, round, etc.), ' +
|
|
24
|
+
'constants (pi, e, phi, i), matrices ([1, 2; 3, 4]), units (5 kg to lbs), ' +
|
|
25
|
+
'and variables (when scope is provided).'),
|
|
26
|
+
operation: z
|
|
27
|
+
.enum(['evaluate', 'simplify', 'derivative'])
|
|
28
|
+
.default('evaluate')
|
|
29
|
+
.describe('Operation to perform. ' +
|
|
30
|
+
'"evaluate" computes a numeric result (default). ' +
|
|
31
|
+
'"simplify" reduces an algebraic expression symbolically (e.g., "2x + 3x" -> "5 * x"). Supports algebraic and trigonometric identities. ' +
|
|
32
|
+
'"derivative" computes the symbolic derivative (requires variable parameter).'),
|
|
33
|
+
variable: z
|
|
34
|
+
.string()
|
|
35
|
+
.max(50)
|
|
36
|
+
.regex(/^[a-zA-Z_][a-zA-Z0-9_]*$/, 'Variable name must be alphanumeric (a-z, A-Z, 0-9, _).')
|
|
37
|
+
.optional()
|
|
38
|
+
.describe('Variable to differentiate with respect to. Required when operation is "derivative". Example: "x".'),
|
|
39
|
+
scope: z
|
|
40
|
+
.record(z.string(), z.number())
|
|
41
|
+
.optional()
|
|
42
|
+
.describe('Variable assignments for the expression. Example: { "x": 5, "y": 3 } makes "x + y" evaluate to 8.'),
|
|
43
|
+
precision: z
|
|
44
|
+
.number()
|
|
45
|
+
.int()
|
|
46
|
+
.min(1)
|
|
47
|
+
.max(16)
|
|
48
|
+
.optional()
|
|
49
|
+
.describe('Significant digits (1\u201316) for numeric results. Omit for full precision. Ignored for symbolic operations (simplify, derivative).'),
|
|
50
|
+
}),
|
|
51
|
+
output: z.object({
|
|
52
|
+
result: z.string().describe('The computed result as a string.'),
|
|
53
|
+
resultType: z
|
|
54
|
+
.string()
|
|
55
|
+
.describe('Type of result as reported by math.js: number, BigNumber, Complex, DenseMatrix, Unit, string, boolean. Symbolic operations return "string".'),
|
|
56
|
+
expression: z.string().describe('The original expression as received.'),
|
|
57
|
+
}),
|
|
58
|
+
handler(input, ctx) {
|
|
59
|
+
const math = getMathService();
|
|
60
|
+
switch (input.operation) {
|
|
61
|
+
case 'evaluate': {
|
|
62
|
+
const { result, resultType } = math.evaluateExpression(input.expression, input.scope, input.precision);
|
|
63
|
+
ctx.log.info('Evaluated expression', { expression: input.expression });
|
|
64
|
+
return { result, resultType, expression: input.expression };
|
|
65
|
+
}
|
|
66
|
+
case 'simplify': {
|
|
67
|
+
const { result, resultType } = math.simplifyExpression(input.expression);
|
|
68
|
+
ctx.log.info('Simplified expression', { expression: input.expression });
|
|
69
|
+
return { result, resultType, expression: input.expression };
|
|
70
|
+
}
|
|
71
|
+
case 'derivative': {
|
|
72
|
+
if (!input.variable) {
|
|
73
|
+
throw invalidParams("The 'variable' parameter is required when operation is 'derivative'.");
|
|
74
|
+
}
|
|
75
|
+
const { result, resultType } = math.differentiateExpression(input.expression, input.variable);
|
|
76
|
+
ctx.log.info('Differentiated expression', {
|
|
77
|
+
expression: input.expression,
|
|
78
|
+
variable: input.variable,
|
|
79
|
+
});
|
|
80
|
+
return { result, resultType, expression: input.expression };
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
format: (output) => [
|
|
85
|
+
{
|
|
86
|
+
type: 'text',
|
|
87
|
+
text: `**Expression:** \`${output.expression}\`\n**Result:** ${output.result}\n**Type:** ${output.resultType}`,
|
|
88
|
+
},
|
|
89
|
+
],
|
|
90
|
+
});
|
|
91
|
+
//# sourceMappingURL=calculate.tool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"calculate.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/calculate.tool.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
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 type { ServerConfig } from '../../config/server-config.js';
|
|
8
|
+
import type { MathResult } from './types.js';
|
|
9
|
+
export declare class MathService {
|
|
10
|
+
private readonly evaluate;
|
|
11
|
+
private readonly simplify;
|
|
12
|
+
private readonly derivative;
|
|
13
|
+
private readonly simplifyRules;
|
|
14
|
+
private readonly format;
|
|
15
|
+
private readonly typeOf;
|
|
16
|
+
private readonly config;
|
|
17
|
+
constructor(config: ServerConfig);
|
|
18
|
+
/** Evaluate a math expression with optional variable scope and precision. */
|
|
19
|
+
evaluateExpression(expression: string, scope?: Record<string, number>, precision?: number): MathResult;
|
|
20
|
+
/** Simplify an algebraic expression symbolically. */
|
|
21
|
+
simplifyExpression(expression: string): MathResult;
|
|
22
|
+
/** Compute the symbolic derivative of an expression with respect to a variable. */
|
|
23
|
+
differentiateExpression(expression: string, variable: string): MathResult;
|
|
24
|
+
/** Get formatted help content listing available functions, operators, and syntax. */
|
|
25
|
+
getHelpContent(): string;
|
|
26
|
+
private validateInput;
|
|
27
|
+
/** Reject scope keys that could pollute the object prototype chain. */
|
|
28
|
+
private sanitizeScope;
|
|
29
|
+
/** Reject result types that leak internals (functions, parsers, multi-expression ResultSets). */
|
|
30
|
+
private validateResultType;
|
|
31
|
+
/** Reject results that exceed the configured maximum size. */
|
|
32
|
+
private validateResultSize;
|
|
33
|
+
/** Runs a synchronous function inside a vm sandbox with timeout protection. */
|
|
34
|
+
private runWithTimeout;
|
|
35
|
+
}
|
|
36
|
+
/** Initialize the math service. Call once from createApp setup(). */
|
|
37
|
+
export declare function initMathService(config: ServerConfig): void;
|
|
38
|
+
/** Get the initialized math service instance. */
|
|
39
|
+
export declare function getMathService(): MathService;
|
|
40
|
+
//# sourceMappingURL=math-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"math-service.d.ts","sourceRoot":"","sources":["../../../src/services/math/math-service.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAsG7C,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA4D;IACrF,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,CAA+D;IACtF,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA6B;IACpD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAe;gBAE1B,MAAM,EAAE,YAAY;IA2BhC,6EAA6E;IAC7E,kBAAkB,CAChB,UAAU,EAAE,MAAM,EAClB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,SAAS,CAAC,EAAE,MAAM,GACjB,UAAU;IAkBb,qDAAqD;IACrD,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,UAAU;IAQlD,mFAAmF;IACnF,uBAAuB,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,UAAU;IAQzE,qFAAqF;IACrF,cAAc,IAAI,MAAM;IAIxB,OAAO,CAAC,aAAa;IAcrB,uEAAuE;IACvE,OAAO,CAAC,aAAa;IAWrB,iGAAiG;IACjG,OAAO,CAAC,kBAAkB;IAQ1B,8DAA8D;IAC9D,OAAO,CAAC,kBAAkB;IAQ1B,+EAA+E;IAC/E,OAAO,CAAC,cAAc;CAiBvB;AAMD,qEAAqE;AACrE,wBAAgB,eAAe,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI,CAE1D;AAED,iDAAiD;AACjD,wBAAgB,cAAc,IAAI,WAAW,CAG5C"}
|