@cyanheads/calculator-mcp-server 0.4.0 → 0.4.1
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/AGENTS.md +20 -17
- package/CLAUDE.md +20 -17
- package/Dockerfile +14 -10
- package/LICENSE +1 -1
- package/README.md +42 -3
- package/changelog/0.1.x/0.1.0.md +20 -0
- package/changelog/0.1.x/0.1.1.md +28 -0
- package/changelog/0.1.x/0.1.10.md +25 -0
- package/changelog/0.1.x/0.1.11.md +29 -0
- package/changelog/0.1.x/0.1.12.md +21 -0
- package/changelog/0.1.x/0.1.13.md +20 -0
- package/changelog/0.1.x/0.1.14.md +18 -0
- package/changelog/0.1.x/0.1.15.md +20 -0
- package/changelog/0.1.x/0.1.16.md +26 -0
- package/changelog/0.1.x/0.1.17.md +24 -0
- package/changelog/0.1.x/0.1.18.md +21 -0
- package/changelog/0.1.x/0.1.19.md +18 -0
- package/changelog/0.1.x/0.1.2.md +22 -0
- package/changelog/0.1.x/0.1.20.md +21 -0
- package/changelog/0.1.x/0.1.21.md +26 -0
- package/changelog/0.1.x/0.1.22.md +33 -0
- package/changelog/0.1.x/0.1.23.md +32 -0
- package/changelog/0.1.x/0.1.24.md +16 -0
- package/changelog/0.1.x/0.1.25.md +23 -0
- package/changelog/0.1.x/0.1.26.md +16 -0
- package/changelog/0.1.x/0.1.3.md +19 -0
- package/changelog/0.1.x/0.1.4.md +20 -0
- package/changelog/0.1.x/0.1.5.md +19 -0
- package/changelog/0.1.x/0.1.6.md +26 -0
- package/changelog/0.1.x/0.1.7.md +19 -0
- package/changelog/0.1.x/0.1.8.md +18 -0
- package/changelog/0.1.x/0.1.9.md +29 -0
- package/changelog/0.2.x/0.2.0.md +18 -0
- package/changelog/0.3.x/0.3.0.md +19 -0
- package/changelog/0.3.x/0.3.1.md +30 -0
- package/changelog/0.3.x/0.3.2.md +18 -0
- package/changelog/0.3.x/0.3.3.md +27 -0
- package/changelog/0.3.x/0.3.4.md +17 -0
- package/changelog/0.3.x/0.3.5.md +23 -0
- package/changelog/0.4.x/0.4.0.md +28 -0
- package/changelog/0.4.x/0.4.1.md +28 -0
- package/changelog/template.md +168 -0
- package/dist/mcp-server/resources/definitions/help.resource.d.ts.map +1 -1
- package/dist/mcp-server/resources/definitions/help.resource.js +1 -0
- package/dist/mcp-server/resources/definitions/help.resource.js.map +1 -1
- package/dist/mcp-server/tools/definitions/calculate.tool.d.ts +3 -3
- package/dist/mcp-server/tools/definitions/calculate.tool.js.map +1 -1
- package/dist/services/math/math-service.d.ts.map +1 -1
- package/dist/services/math/math-service.js.map +1 -1
- package/package.json +23 -13
- package/server.json +3 -3
package/AGENTS.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# Agent Protocol
|
|
2
2
|
|
|
3
3
|
**Server:** calculator-mcp-server
|
|
4
|
-
**Version:** 0.4.
|
|
5
|
-
**Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.
|
|
4
|
+
**Version:** 0.4.1
|
|
5
|
+
**Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.12.3`
|
|
6
6
|
**Engines:** Bun ≥1.3.0, Node ≥24.0.0
|
|
7
|
-
**MCP SDK:** `@modelcontextprotocol/
|
|
7
|
+
**MCP SDK:** `@modelcontextprotocol/server` 2.0.0
|
|
8
8
|
**Zod:** 4.4.3
|
|
9
9
|
|
|
10
10
|
> **Read the framework docs first:** `node_modules/@cyanheads/mcp-ts-core/CLAUDE.md` contains the full API reference — builders, Context, error codes, exports, patterns. This file covers server-specific conventions only.
|
|
@@ -50,7 +50,7 @@ Tailor suggestions to what's actually missing or stale — don't recite the full
|
|
|
50
50
|
- **Logic throws, framework catches.** Tool/resource handlers are pure — throw on failure, no `try/catch`. Plain `Error` is fine; the framework catches, classifies, and formats. Use error factories (`notFound()`, `validationError()`, etc.) when the error code matters.
|
|
51
51
|
- **Use `ctx.log`** for request-scoped logging. No `console` calls.
|
|
52
52
|
- **Use `ctx.state`** for tenant-scoped storage. Never access persistence directly.
|
|
53
|
-
- **
|
|
53
|
+
- **Need input the caller didn't supply?** `return ctx.requestInput(...)` and read `ctx.inputs` when the handler is re-entered. Never `await` for user input mid-handler.
|
|
54
54
|
- **Secrets in env vars only** — never hardcoded.
|
|
55
55
|
- **Close the loop on issues.** When implementing work tracked by a GitHub issue, comment on the issue with what landed and close it. Do both — a comment without a close leaves stale issues open; a close without a comment leaves no record of what shipped. The comment is for future readers — state the concrete changes, not the conversation that produced them.
|
|
56
56
|
|
|
@@ -121,6 +121,9 @@ export const helpResource = resource('calculator://help', {
|
|
|
121
121
|
|
|
122
122
|
```ts
|
|
123
123
|
// src/config/server-config.ts — lazy-parsed, separate from framework config
|
|
124
|
+
import { z } from '@cyanheads/mcp-ts-core';
|
|
125
|
+
import { parseEnvConfig } from '@cyanheads/mcp-ts-core/config';
|
|
126
|
+
|
|
124
127
|
const ServerConfigSchema = z.object({
|
|
125
128
|
maxExpressionLength: z.coerce.number().int().min(10).max(10_000).default(1000)
|
|
126
129
|
.describe('Maximum allowed expression string length (10–10,000)'),
|
|
@@ -131,10 +134,10 @@ const ServerConfigSchema = z.object({
|
|
|
131
134
|
});
|
|
132
135
|
let _config: z.infer<typeof ServerConfigSchema> | undefined;
|
|
133
136
|
export function getServerConfig() {
|
|
134
|
-
_config ??= ServerConfigSchema
|
|
135
|
-
maxExpressionLength:
|
|
136
|
-
evaluationTimeoutMs:
|
|
137
|
-
maxResultLength:
|
|
137
|
+
_config ??= parseEnvConfig(ServerConfigSchema, {
|
|
138
|
+
maxExpressionLength: 'CALC_MAX_EXPRESSION_LENGTH',
|
|
139
|
+
evaluationTimeoutMs: 'CALC_EVALUATION_TIMEOUT_MS',
|
|
140
|
+
maxResultLength: 'CALC_MAX_RESULT_LENGTH',
|
|
138
141
|
});
|
|
139
142
|
return _config;
|
|
140
143
|
}
|
|
@@ -154,13 +157,13 @@ Handlers receive a unified `ctx` object. Key properties:
|
|
|
154
157
|
|
|
155
158
|
| Property | Description |
|
|
156
159
|
|:---------|:------------|
|
|
157
|
-
| `ctx.log` | Request-scoped logger — `.debug()`, `.info()`, `.notice()`, `.warning()`, `.error()`. Auto-correlates requestId, traceId, tenantId. |
|
|
158
|
-
| `ctx.state` | Tenant-scoped KV — `.get(key)`, `.set(key, value, { ttl? })`, `.delete(key)`, `.list(prefix, { cursor, limit })`. Accepts any serializable value. |
|
|
159
|
-
| `ctx.
|
|
160
|
-
| `ctx.
|
|
160
|
+
| `ctx.log` | Request-scoped logger — `.debug()`, `.info()`, `.notice()`, `.warning()`, `.error()`. Auto-correlates requestId, traceId, tenantId. Dual-sink: Pino and `notifications/message` to the client, so treat it as client-visible. |
|
|
161
|
+
| `ctx.state` | Tenant-scoped KV — `.get(key)`, `.set(key, value, { ttl? })`, `.delete(key)`, `.getMany(keys)`, `.list(prefix, { cursor, limit })`. Accepts any serializable value. |
|
|
162
|
+
| `ctx.requestInput` | Suspend and ask the caller for more input — `return ctx.requestInput({ inputRequests: { key: inputRequired.elicit({ message, requestedSchema }) } })`. Never returns; the handler is re-entered with the answers. Always present. |
|
|
163
|
+
| `ctx.inputs` | Reader over a retried request's responses — `.accepted(key, schema)`, `.view(key)`, `.state()`, `.dropped`. Empty on the first round. |
|
|
164
|
+
| `ctx.enrich` | Success-path agent context — `ctx.enrich(...)` or `.notice()` / `.total()` / `.echo()` / `.truncated()`. Reaches both response surfaces only when the definition declares an `enrichment` block. |
|
|
165
|
+
| `ctx.content` | Non-text content blocks — `.image(data, mimeType)`, `.audio(data, mimeType)`, or `ctx.content(block)`. Prepended to `content[]`; never enters `structuredContent`. |
|
|
161
166
|
| `ctx.signal` | `AbortSignal` for cancellation. |
|
|
162
|
-
| `ctx.progress` | Task progress (present when `task: true`) — `.setTotal(n)`, `.increment()`, `.update(message)`. |
|
|
163
|
-
| `ctx.enrich` | Success-path enrichment — `.notice(text)`, `.total(n)`, `.echo(query)`, `.delta({ field, before, after })`. Merges into `structuredContent` and `content[]` trailer automatically. |
|
|
164
167
|
| `ctx.requestId` | Unique request ID. |
|
|
165
168
|
| `ctx.tenantId` | Tenant ID from JWT or `'default'` for stdio. |
|
|
166
169
|
|
|
@@ -170,7 +173,7 @@ Handlers receive a unified `ctx` object. Key properties:
|
|
|
170
173
|
|
|
171
174
|
Handlers throw — the framework catches, classifies, and formats.
|
|
172
175
|
|
|
173
|
-
**Recommended: typed error contract.** Declare `errors: [{ reason, code, when, recovery, retryable? }]` on `tool()` / `resource()` to receive
|
|
176
|
+
**Recommended: typed error contract.** Declare `errors: [{ reason, code, when, recovery, retryable? }]` on `tool()` / `resource()` to receive `ctx.fail(reason, …)` typed against the reason union. TypeScript catches typos, `data.reason` is auto-populated for observability, and the linter enforces conformance against the handler body. `recovery` is required (≥ 5 words) and is the single source of truth for the agent's next move. Pass `ctx.recoveryFor('reason')` as the throw's data to put it on the wire; override with an explicit recovery hint only when dynamic context matters. Baseline codes (`InternalError`, `ServiceUnavailable`, `Timeout`, `ValidationError`, `SerializationError`) bubble freely and don't need declaring.
|
|
174
177
|
|
|
175
178
|
On the wire, tool errors mirror the success-path `format-parity` invariant — both `content[]` (markdown, read by clients like Claude Desktop) and `structuredContent.error` (JSON `{ code, message, data? }`, read by clients like Claude Code) carry the same payload, with `data.recovery.hint` mirrored into the markdown text when present.
|
|
176
179
|
|
|
@@ -184,7 +187,7 @@ errors: [
|
|
|
184
187
|
],
|
|
185
188
|
async handler(input, ctx) {
|
|
186
189
|
const item = await db.find(input.id);
|
|
187
|
-
if (!item) throw ctx.fail('no_match', `No item ${input.id}
|
|
190
|
+
if (!item) throw ctx.fail('no_match', `No item ${input.id}`, ctx.recoveryFor('no_match'));
|
|
188
191
|
return item;
|
|
189
192
|
}
|
|
190
193
|
```
|
|
@@ -280,7 +283,7 @@ Available skills:
|
|
|
280
283
|
| `api-auth` | Auth modes, scopes, JWT/OAuth |
|
|
281
284
|
| `api-canvas` | DataCanvas: register tabular data, run SQL, export, plus the `spillover()` helper for big result sets — Tier 3 opt-in |
|
|
282
285
|
| `api-config` | AppConfig, parseConfig, env vars |
|
|
283
|
-
| `api-context` | Context interface, logger, state,
|
|
286
|
+
| `api-context` | Context interface, logger, state, input requests, enrichment |
|
|
284
287
|
| `api-errors` | McpError, JsonRpcErrorCode, error patterns |
|
|
285
288
|
| `api-linter` | Definition linter rule catalog — invoked by `bun run lint:mcp` and `devcheck` |
|
|
286
289
|
| `api-mirror` | MirrorService: persistent SQLite-backed local mirror of bulk upstream datasets — Tier 3 opt-in, Node/Bun only |
|
package/CLAUDE.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# Agent Protocol
|
|
2
2
|
|
|
3
3
|
**Server:** calculator-mcp-server
|
|
4
|
-
**Version:** 0.4.
|
|
5
|
-
**Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.
|
|
4
|
+
**Version:** 0.4.1
|
|
5
|
+
**Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.12.3`
|
|
6
6
|
**Engines:** Bun ≥1.3.0, Node ≥24.0.0
|
|
7
|
-
**MCP SDK:** `@modelcontextprotocol/
|
|
7
|
+
**MCP SDK:** `@modelcontextprotocol/server` 2.0.0
|
|
8
8
|
**Zod:** 4.4.3
|
|
9
9
|
|
|
10
10
|
> **Read the framework docs first:** `node_modules/@cyanheads/mcp-ts-core/CLAUDE.md` contains the full API reference — builders, Context, error codes, exports, patterns. This file covers server-specific conventions only.
|
|
@@ -50,7 +50,7 @@ Tailor suggestions to what's actually missing or stale — don't recite the full
|
|
|
50
50
|
- **Logic throws, framework catches.** Tool/resource handlers are pure — throw on failure, no `try/catch`. Plain `Error` is fine; the framework catches, classifies, and formats. Use error factories (`notFound()`, `validationError()`, etc.) when the error code matters.
|
|
51
51
|
- **Use `ctx.log`** for request-scoped logging. No `console` calls.
|
|
52
52
|
- **Use `ctx.state`** for tenant-scoped storage. Never access persistence directly.
|
|
53
|
-
- **
|
|
53
|
+
- **Need input the caller didn't supply?** `return ctx.requestInput(...)` and read `ctx.inputs` when the handler is re-entered. Never `await` for user input mid-handler.
|
|
54
54
|
- **Secrets in env vars only** — never hardcoded.
|
|
55
55
|
- **Close the loop on issues.** When implementing work tracked by a GitHub issue, comment on the issue with what landed and close it. Do both — a comment without a close leaves stale issues open; a close without a comment leaves no record of what shipped. The comment is for future readers — state the concrete changes, not the conversation that produced them.
|
|
56
56
|
|
|
@@ -121,6 +121,9 @@ export const helpResource = resource('calculator://help', {
|
|
|
121
121
|
|
|
122
122
|
```ts
|
|
123
123
|
// src/config/server-config.ts — lazy-parsed, separate from framework config
|
|
124
|
+
import { z } from '@cyanheads/mcp-ts-core';
|
|
125
|
+
import { parseEnvConfig } from '@cyanheads/mcp-ts-core/config';
|
|
126
|
+
|
|
124
127
|
const ServerConfigSchema = z.object({
|
|
125
128
|
maxExpressionLength: z.coerce.number().int().min(10).max(10_000).default(1000)
|
|
126
129
|
.describe('Maximum allowed expression string length (10–10,000)'),
|
|
@@ -131,10 +134,10 @@ const ServerConfigSchema = z.object({
|
|
|
131
134
|
});
|
|
132
135
|
let _config: z.infer<typeof ServerConfigSchema> | undefined;
|
|
133
136
|
export function getServerConfig() {
|
|
134
|
-
_config ??= ServerConfigSchema
|
|
135
|
-
maxExpressionLength:
|
|
136
|
-
evaluationTimeoutMs:
|
|
137
|
-
maxResultLength:
|
|
137
|
+
_config ??= parseEnvConfig(ServerConfigSchema, {
|
|
138
|
+
maxExpressionLength: 'CALC_MAX_EXPRESSION_LENGTH',
|
|
139
|
+
evaluationTimeoutMs: 'CALC_EVALUATION_TIMEOUT_MS',
|
|
140
|
+
maxResultLength: 'CALC_MAX_RESULT_LENGTH',
|
|
138
141
|
});
|
|
139
142
|
return _config;
|
|
140
143
|
}
|
|
@@ -154,13 +157,13 @@ Handlers receive a unified `ctx` object. Key properties:
|
|
|
154
157
|
|
|
155
158
|
| Property | Description |
|
|
156
159
|
|:---------|:------------|
|
|
157
|
-
| `ctx.log` | Request-scoped logger — `.debug()`, `.info()`, `.notice()`, `.warning()`, `.error()`. Auto-correlates requestId, traceId, tenantId. |
|
|
158
|
-
| `ctx.state` | Tenant-scoped KV — `.get(key)`, `.set(key, value, { ttl? })`, `.delete(key)`, `.list(prefix, { cursor, limit })`. Accepts any serializable value. |
|
|
159
|
-
| `ctx.
|
|
160
|
-
| `ctx.
|
|
160
|
+
| `ctx.log` | Request-scoped logger — `.debug()`, `.info()`, `.notice()`, `.warning()`, `.error()`. Auto-correlates requestId, traceId, tenantId. Dual-sink: Pino and `notifications/message` to the client, so treat it as client-visible. |
|
|
161
|
+
| `ctx.state` | Tenant-scoped KV — `.get(key)`, `.set(key, value, { ttl? })`, `.delete(key)`, `.getMany(keys)`, `.list(prefix, { cursor, limit })`. Accepts any serializable value. |
|
|
162
|
+
| `ctx.requestInput` | Suspend and ask the caller for more input — `return ctx.requestInput({ inputRequests: { key: inputRequired.elicit({ message, requestedSchema }) } })`. Never returns; the handler is re-entered with the answers. Always present. |
|
|
163
|
+
| `ctx.inputs` | Reader over a retried request's responses — `.accepted(key, schema)`, `.view(key)`, `.state()`, `.dropped`. Empty on the first round. |
|
|
164
|
+
| `ctx.enrich` | Success-path agent context — `ctx.enrich(...)` or `.notice()` / `.total()` / `.echo()` / `.truncated()`. Reaches both response surfaces only when the definition declares an `enrichment` block. |
|
|
165
|
+
| `ctx.content` | Non-text content blocks — `.image(data, mimeType)`, `.audio(data, mimeType)`, or `ctx.content(block)`. Prepended to `content[]`; never enters `structuredContent`. |
|
|
161
166
|
| `ctx.signal` | `AbortSignal` for cancellation. |
|
|
162
|
-
| `ctx.progress` | Task progress (present when `task: true`) — `.setTotal(n)`, `.increment()`, `.update(message)`. |
|
|
163
|
-
| `ctx.enrich` | Success-path enrichment — `.notice(text)`, `.total(n)`, `.echo(query)`, `.delta({ field, before, after })`. Merges into `structuredContent` and `content[]` trailer automatically. |
|
|
164
167
|
| `ctx.requestId` | Unique request ID. |
|
|
165
168
|
| `ctx.tenantId` | Tenant ID from JWT or `'default'` for stdio. |
|
|
166
169
|
|
|
@@ -170,7 +173,7 @@ Handlers receive a unified `ctx` object. Key properties:
|
|
|
170
173
|
|
|
171
174
|
Handlers throw — the framework catches, classifies, and formats.
|
|
172
175
|
|
|
173
|
-
**Recommended: typed error contract.** Declare `errors: [{ reason, code, when, recovery, retryable? }]` on `tool()` / `resource()` to receive
|
|
176
|
+
**Recommended: typed error contract.** Declare `errors: [{ reason, code, when, recovery, retryable? }]` on `tool()` / `resource()` to receive `ctx.fail(reason, …)` typed against the reason union. TypeScript catches typos, `data.reason` is auto-populated for observability, and the linter enforces conformance against the handler body. `recovery` is required (≥ 5 words) and is the single source of truth for the agent's next move. Pass `ctx.recoveryFor('reason')` as the throw's data to put it on the wire; override with an explicit recovery hint only when dynamic context matters. Baseline codes (`InternalError`, `ServiceUnavailable`, `Timeout`, `ValidationError`, `SerializationError`) bubble freely and don't need declaring.
|
|
174
177
|
|
|
175
178
|
On the wire, tool errors mirror the success-path `format-parity` invariant — both `content[]` (markdown, read by clients like Claude Desktop) and `structuredContent.error` (JSON `{ code, message, data? }`, read by clients like Claude Code) carry the same payload, with `data.recovery.hint` mirrored into the markdown text when present.
|
|
176
179
|
|
|
@@ -184,7 +187,7 @@ errors: [
|
|
|
184
187
|
],
|
|
185
188
|
async handler(input, ctx) {
|
|
186
189
|
const item = await db.find(input.id);
|
|
187
|
-
if (!item) throw ctx.fail('no_match', `No item ${input.id}
|
|
190
|
+
if (!item) throw ctx.fail('no_match', `No item ${input.id}`, ctx.recoveryFor('no_match'));
|
|
188
191
|
return item;
|
|
189
192
|
}
|
|
190
193
|
```
|
|
@@ -280,7 +283,7 @@ Available skills:
|
|
|
280
283
|
| `api-auth` | Auth modes, scopes, JWT/OAuth |
|
|
281
284
|
| `api-canvas` | DataCanvas: register tabular data, run SQL, export, plus the `spillover()` helper for big result sets — Tier 3 opt-in |
|
|
282
285
|
| `api-config` | AppConfig, parseConfig, env vars |
|
|
283
|
-
| `api-context` | Context interface, logger, state,
|
|
286
|
+
| `api-context` | Context interface, logger, state, input requests, enrichment |
|
|
284
287
|
| `api-errors` | McpError, JsonRpcErrorCode, error patterns |
|
|
285
288
|
| `api-linter` | Definition linter rule catalog — invoked by `bun run lint:mcp` and `devcheck` |
|
|
286
289
|
| `api-mirror` | MirrorService: persistent SQLite-backed local mirror of bulk upstream datasets — Tier 3 opt-in, Node/Bun only |
|
package/Dockerfile
CHANGED
|
@@ -4,15 +4,17 @@
|
|
|
4
4
|
# This stage installs all dependencies (including dev), builds the TypeScript
|
|
5
5
|
# source code into JavaScript, and prepares the production assets.
|
|
6
6
|
# ==============================================================================
|
|
7
|
-
FROM oven/bun:1.
|
|
7
|
+
FROM --platform=$BUILDPLATFORM oven/bun:1.4.0 AS build
|
|
8
8
|
|
|
9
9
|
WORKDIR /usr/src/app
|
|
10
10
|
|
|
11
11
|
# Copy dependency manifests for optimized layer caching
|
|
12
12
|
COPY package.json bun.lock ./
|
|
13
13
|
|
|
14
|
-
# Install all dependencies (including dev dependencies for building)
|
|
15
|
-
|
|
14
|
+
# Install all dependencies (including dev dependencies for building).
|
|
15
|
+
# The BuildKit cache mount persists Bun's global package cache across builds.
|
|
16
|
+
RUN --mount=type=cache,target=/root/.bun/install/cache \
|
|
17
|
+
bun install --frozen-lockfile --ignore-scripts
|
|
16
18
|
|
|
17
19
|
# Copy the rest of the source code
|
|
18
20
|
COPY . .
|
|
@@ -28,7 +30,7 @@ RUN bun run build
|
|
|
28
30
|
# application. It uses a slim base image and only includes production
|
|
29
31
|
# dependencies and build artifacts.
|
|
30
32
|
# ==============================================================================
|
|
31
|
-
FROM oven/bun:1.
|
|
33
|
+
FROM oven/bun:1.4.0-slim AS production
|
|
32
34
|
|
|
33
35
|
WORKDIR /usr/src/app
|
|
34
36
|
|
|
@@ -39,7 +41,7 @@ ENV NODE_ENV=production
|
|
|
39
41
|
# OCI image metadata (https://github.com/opencontainers/image-spec/blob/main/annotations.md)
|
|
40
42
|
ARG APP_VERSION
|
|
41
43
|
LABEL org.opencontainers.image.title="calculator-mcp-server"
|
|
42
|
-
LABEL org.opencontainers.image.description="
|
|
44
|
+
LABEL org.opencontainers.image.description="Evaluate, simplify, and differentiate mathematical expressions via MCP. STDIO or Streamable HTTP."
|
|
43
45
|
LABEL org.opencontainers.image.source="https://github.com/cyanheads/calculator-mcp-server"
|
|
44
46
|
LABEL org.opencontainers.image.licenses="Apache-2.0"
|
|
45
47
|
LABEL org.opencontainers.image.version="${APP_VERSION}"
|
|
@@ -47,16 +49,18 @@ LABEL org.opencontainers.image.version="${APP_VERSION}"
|
|
|
47
49
|
# Copy dependency manifests
|
|
48
50
|
COPY package.json bun.lock ./
|
|
49
51
|
|
|
50
|
-
# Install only production dependencies, ignoring
|
|
51
|
-
# that are not needed in the final production image.
|
|
52
|
-
RUN bun
|
|
52
|
+
# Install only production dependencies, ignoring optional peer tiers and lifecycle
|
|
53
|
+
# scripts that are not needed in the final production image.
|
|
54
|
+
RUN --mount=type=cache,target=/root/.bun/install/cache \
|
|
55
|
+
bun install --production --omit=peer --frozen-lockfile --ignore-scripts
|
|
53
56
|
|
|
54
57
|
# Conditionally install OpenTelemetry optional peer dependencies (Tier 3).
|
|
55
58
|
# These are not bundled by default to keep the base image lean. Enable at build time
|
|
56
59
|
# with: docker build --build-arg OTEL_ENABLED=true
|
|
57
60
|
ARG OTEL_ENABLED=true
|
|
58
|
-
RUN
|
|
59
|
-
|
|
61
|
+
RUN --mount=type=cache,target=/root/.bun/install/cache \
|
|
62
|
+
if [ "$OTEL_ENABLED" = "true" ]; then \
|
|
63
|
+
bun add --omit=dev --omit=peer --ignore-scripts @hono/otel \
|
|
60
64
|
@opentelemetry/instrumentation-http \
|
|
61
65
|
@opentelemetry/exporter-metrics-otlp-http \
|
|
62
66
|
@opentelemetry/exporter-trace-otlp-http \
|
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
<div align="center">
|
|
9
9
|
|
|
10
|
-
[](./CHANGELOG.md) [](./LICENSE) [](https://github.com/users/cyanheads/packages/container/package/calculator-mcp-server) [](https://modelcontextprotocol.io/) [](https://www.npmjs.com/package/@cyanheads/calculator-mcp-server) [](https://www.typescriptlang.org/) [](https://bun.sh/)
|
|
11
11
|
|
|
12
12
|
</div>
|
|
13
13
|
|
|
@@ -69,7 +69,7 @@ Calculator-specific:
|
|
|
69
69
|
|
|
70
70
|
- Hardened math.js v15 instance — dangerous functions disabled, evaluation sandboxed via `vm.runInNewContext()` with timeout
|
|
71
71
|
- No auth required — all operations are read-only and stateless
|
|
72
|
-
- Input validation: expression length limits, expression separator rejection (semicolons and newlines),
|
|
72
|
+
- Input validation: expression length limits, expression separator rejection (semicolons and newlines), numeric-only scope values
|
|
73
73
|
- Result validation: blocked result types (functions, parsers, result sets), configurable max result size
|
|
74
74
|
- Scope sanitization: numeric-only values, prototype pollution prevention (blocked `__proto__`, `constructor`, etc.)
|
|
75
75
|
|
|
@@ -94,7 +94,7 @@ A public instance is available at `https://calculator.caseyjhand.com/mcp` — no
|
|
|
94
94
|
|
|
95
95
|
### Self-Hosted / Local
|
|
96
96
|
|
|
97
|
-
Add to your MCP client
|
|
97
|
+
Add one of the following to your MCP client configuration file:
|
|
98
98
|
|
|
99
99
|
```json
|
|
100
100
|
{
|
|
@@ -108,6 +108,38 @@ Add to your MCP client config (e.g., `claude_desktop_config.json`):
|
|
|
108
108
|
}
|
|
109
109
|
```
|
|
110
110
|
|
|
111
|
+
Or with npx (no Bun required):
|
|
112
|
+
|
|
113
|
+
```json
|
|
114
|
+
{
|
|
115
|
+
"mcpServers": {
|
|
116
|
+
"calculator-mcp-server": {
|
|
117
|
+
"type": "stdio",
|
|
118
|
+
"command": "npx",
|
|
119
|
+
"args": ["-y", "@cyanheads/calculator-mcp-server@latest"]
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Or with Docker:
|
|
126
|
+
|
|
127
|
+
```json
|
|
128
|
+
{
|
|
129
|
+
"mcpServers": {
|
|
130
|
+
"calculator-mcp-server": {
|
|
131
|
+
"type": "stdio",
|
|
132
|
+
"command": "docker",
|
|
133
|
+
"args": [
|
|
134
|
+
"run", "-i", "--rm",
|
|
135
|
+
"-e", "MCP_TRANSPORT_TYPE=stdio",
|
|
136
|
+
"ghcr.io/cyanheads/calculator-mcp-server:latest"
|
|
137
|
+
]
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
111
143
|
### Prerequisites
|
|
112
144
|
|
|
113
145
|
- [Bun v1.3.0](https://bun.sh/) or higher
|
|
@@ -139,10 +171,15 @@ bun install
|
|
|
139
171
|
| `CALC_EVALUATION_TIMEOUT_MS` | Maximum evaluation time in milliseconds (100–30,000). | `5000` |
|
|
140
172
|
| `CALC_MAX_RESULT_LENGTH` | Maximum result string length in characters (1,000–1,000,000). | `100000` |
|
|
141
173
|
| `MCP_TRANSPORT_TYPE` | Transport: `stdio` or `http`. | `stdio` |
|
|
174
|
+
| `MCP_HTTP_HOST` | Hostname for the HTTP server. | `localhost` |
|
|
142
175
|
| `MCP_HTTP_PORT` | Port for HTTP server. | `3010` |
|
|
176
|
+
| `MCP_HTTP_ENDPOINT_PATH` | Path for the HTTP MCP endpoint. | `/mcp` |
|
|
177
|
+
| `MCP_HTTP_MAX_BODY_BYTES` | Maximum inbound HTTP request size; `0` disables the limit. | `1048576` |
|
|
143
178
|
| `MCP_AUTH_MODE` | Auth mode: `none`, `jwt`, or `oauth`. | `none` |
|
|
144
179
|
| `MCP_LOG_LEVEL` | Log level (RFC 5424). | `info` |
|
|
145
180
|
|
|
181
|
+
See [`.env.example`](./.env.example) for optional session, resumability, logging, and telemetry settings.
|
|
182
|
+
|
|
146
183
|
---
|
|
147
184
|
|
|
148
185
|
## Running the Server
|
|
@@ -168,6 +205,8 @@ docker build -t calculator-mcp-server .
|
|
|
168
205
|
docker run -p 3010:3010 calculator-mcp-server
|
|
169
206
|
```
|
|
170
207
|
|
|
208
|
+
The image defaults to Streamable HTTP on port `3010`, stateless sessions, and logs at `/var/log/calculator-mcp-server`.
|
|
209
|
+
|
|
171
210
|
---
|
|
172
211
|
|
|
173
212
|
## Project Structure
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "Initial project scaffold and design."
|
|
3
|
+
breaking: false
|
|
4
|
+
security: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 0.1.0 — 2026-03-28
|
|
8
|
+
|
|
9
|
+
Initial project scaffold and design.
|
|
10
|
+
|
|
11
|
+
## Added
|
|
12
|
+
|
|
13
|
+
- Project scaffold from `@cyanheads/mcp-ts-core` framework
|
|
14
|
+
- Design document (`docs/design.md`) covering tool surface, resource design, security model, service architecture, and implementation plan
|
|
15
|
+
- Agent protocol (`CLAUDE.md`) with server-specific conventions, MCP surface reference, security model, and configuration
|
|
16
|
+
- Server metadata (`server.json`) with stdio and streamable-http transport configurations
|
|
17
|
+
- Directory structure documentation (`docs/tree.md`)
|
|
18
|
+
- Server configuration schema with `CALC_MAX_EXPRESSION_LENGTH` and `CALC_EVALUATION_TIMEOUT_MS` env vars
|
|
19
|
+
- CI scaffolding: Dockerfile, `.env.example`, Biome config, Vitest config, devcheck config
|
|
20
|
+
- GitHub issue templates (bug report, feature request)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "Package metadata, documentation, and agent protocol polish."
|
|
3
|
+
breaking: false
|
|
4
|
+
security: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 0.1.1 — 2026-03-28
|
|
8
|
+
|
|
9
|
+
Package metadata, documentation, and agent protocol polish.
|
|
10
|
+
|
|
11
|
+
## Added
|
|
12
|
+
|
|
13
|
+
- README.md with tool/resource reference, configuration, getting started, and project structure
|
|
14
|
+
- LICENSE (Apache 2.0)
|
|
15
|
+
- `bunfig.toml` for Bun runtime configuration
|
|
16
|
+
- Server-specific env vars (`CALC_MAX_EXPRESSION_LENGTH`, `CALC_EVALUATION_TIMEOUT_MS`) in `server.json` package definitions
|
|
17
|
+
- `depcheck` devDependency
|
|
18
|
+
|
|
19
|
+
## Changed
|
|
20
|
+
|
|
21
|
+
- Scoped package name to `@cyanheads/calculator-mcp-server`
|
|
22
|
+
- Updated `server.json` name to `io.github.cyanheads/calculator-mcp-server` with `bun` runtime hint
|
|
23
|
+
- Updated agent protocol (CLAUDE.md) with actual calculator tool/resource patterns; trimmed unused context properties
|
|
24
|
+
- Expanded package.json with keywords, homepage, bugs, author, and bun engine metadata
|
|
25
|
+
- Updated Dockerfile labels with description and source URL
|
|
26
|
+
- Updated `.env.example` with calculator-specific env vars
|
|
27
|
+
- Updated `devcheck.config.json` to ignore `depcheck` and `tsx` deps
|
|
28
|
+
- Regenerated `docs/tree.md`
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "Framework bump to `@cyanheads/mcp-ts-core` 0.5.3, `parseEnvConfig` adoption, and skill sync."
|
|
3
|
+
breaking: false
|
|
4
|
+
security: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 0.1.10 — 2026-04-20
|
|
8
|
+
|
|
9
|
+
Framework bump to `@cyanheads/mcp-ts-core` 0.5.3, `parseEnvConfig` adoption, and skill sync.
|
|
10
|
+
|
|
11
|
+
## Added
|
|
12
|
+
|
|
13
|
+
- Adopted `parseEnvConfig` in `src/config/server-config.ts` — validation errors now name the actual env var (`CALC_MAX_EXPRESSION_LENGTH`) instead of the internal Zod path
|
|
14
|
+
|
|
15
|
+
## Changed
|
|
16
|
+
|
|
17
|
+
- Upgraded `@cyanheads/mcp-ts-core` from `^0.3.5` to `^0.5.3` (spans 9 tags — new `parseEnvConfig` helper, format-parity linter rule with sentinel injection, devcheck CLAUDE.md/AGENTS.md sync check, Vitest 4 projects pattern, and multiple fixes)
|
|
18
|
+
- Upgraded `typescript` from `^6.0.2` to `^6.0.3`
|
|
19
|
+
- Synced seven external skills from the package (`add-tool`, `api-config`, `design-mcp-server`, `field-test`, `maintenance`, `polish-docs-meta`, `setup`) and mirrored all skills into `.claude/skills/`
|
|
20
|
+
- Regenerated `bun.lock` from a clean state
|
|
21
|
+
- Bumped package, server metadata, README badge, and agent protocol files to `0.1.10`
|
|
22
|
+
|
|
23
|
+
## Fixed
|
|
24
|
+
|
|
25
|
+
- Cleared the transitive hono moderate-severity advisory (GHSA-458j-xx4x-4375) via fresh lockfile resolution
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "Framework bump to `@cyanheads/mcp-ts-core` 0.7.0, handler simplification, and skill sync."
|
|
3
|
+
breaking: false
|
|
4
|
+
security: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 0.1.11 — 2026-04-24
|
|
8
|
+
|
|
9
|
+
Framework bump to `@cyanheads/mcp-ts-core` 0.7.0, handler simplification, and skill sync.
|
|
10
|
+
|
|
11
|
+
## Added
|
|
12
|
+
|
|
13
|
+
- Three new external skills from the framework: `api-linter` (rule reference), `release-and-publish` (post-wrapup publish workflow), and `security-pass` (8-axis MCP-specific audit)
|
|
14
|
+
- Three framework scripts newly synced into `scripts/`: `build-changelog.ts`, `check-docs-sync.ts`, `check-skills-sync.ts` (per the `maintenance` skill's new Phase C)
|
|
15
|
+
|
|
16
|
+
## Changed
|
|
17
|
+
|
|
18
|
+
- Upgraded `@cyanheads/mcp-ts-core` from `^0.5.3` to `^0.7.0` (spans 18 tags — landing page at `/`, SEP-1649 Server Card, directory-based changelog system, recursive `describe-on-fields` linter, flattened ZodError messages with structured `data.issues`, `MCP_PUBLIC_URL` TLS-proxy override, per-request HTTP close race fix, `HtmlExtractor` utility, and the new skills above)
|
|
19
|
+
- Upgraded `@biomejs/biome` from `^2.4.12` to `^2.4.13` (patch) and `vitest` from `^4.1.4` to `^4.1.5` (patch)
|
|
20
|
+
- Resynced 15 external skills to match framework 0.7.0 versions (`add-tool` 1.6→1.8, `design-mcp-server` 2.4→2.7, `field-test` 1.2→2.0, `polish-docs-meta` 1.4→1.7, `setup` 1.3→1.5, `maintenance` 1.3→1.5, and nine others)
|
|
21
|
+
- Resynced `scripts/devcheck.ts` and `scripts/tree.ts` from the framework (devcheck now runs Docs Sync, Skills Sync, and Changelog Sync steps)
|
|
22
|
+
- Simplified the `calculate` tool handler — destructured `input` once, spread `MathResult` into the return, dropped per-case block scopes; ~40% fewer lines, same 27/27 tests passing
|
|
23
|
+
- Agent protocol (`CLAUDE.md` / `AGENTS.md`): added `security-pass` and `release-and-publish` to the What's Next? progression, added `api-linter` / `security-pass` / `release-and-publish` to the skills table, rewrote the Publishing section to point at the `release-and-publish` skill
|
|
24
|
+
- `.github/ISSUE_TEMPLATE/` descriptions now use the scoped package name (`@cyanheads/calculator-mcp-server`) for consistency
|
|
25
|
+
- Bumped package, server metadata, README badge, and agent protocol files to `0.1.11`
|
|
26
|
+
|
|
27
|
+
## Fixed
|
|
28
|
+
|
|
29
|
+
- Added `.describe()` to each variant of the `variable` and `precision` unions in the `calculate` input schema — the 0.6.16 framework bump extended `describe-on-fields` to recurse into union options, which flagged the previously-bare `z.literal('')` and sibling variants
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "Framework patch-series bump and a small `MathService` cleanup."
|
|
3
|
+
breaking: false
|
|
4
|
+
security: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 0.1.12 — 2026-04-27
|
|
8
|
+
|
|
9
|
+
Framework patch-series bump and a small `MathService` cleanup.
|
|
10
|
+
|
|
11
|
+
## Changed
|
|
12
|
+
|
|
13
|
+
- Upgraded `@cyanheads/mcp-ts-core` from `^0.7.0` to `^0.7.5` (spans five patch releases — HTTP Origin guard now fails closed for remote browser origins (loopback-only when `MCP_ALLOWED_ORIGINS` is unset), landing-page `requireAuth` validates bearer tokens, raw caller payloads removed from default logs, opt-in `LOG_LLM_INTERACTIONS`, `vitest.config` shipped as `.mjs` to avoid Node 22.7+ type-strip failure, new `Framework Antipatterns` devcheck step, `format-parity` numeric normalization tightened to reject lossy decimal-shift transforms, `describe-on-fields` linter exempts `z.literal` union variants, `landing.connectSnippets` operator override, and Cloudflare email-rewrite defense in connect snippets)
|
|
14
|
+
- Renamed `MathService.sanitizeScope` to `validateScope` — function only validated and threw, never sanitized; new name and `void` return reflect actual behavior
|
|
15
|
+
- Resynced 5 external skills from the framework (`maintenance` 1.5→1.6, `api-linter` 1.1→1.2, plus content-only updates to `api-utils`, `design-mcp-server`, `field-test`)
|
|
16
|
+
- Resynced `scripts/devcheck.ts` from the framework (adds the new `Framework Antipatterns` check step)
|
|
17
|
+
- Bumped package, server metadata, README badge, and agent protocol files to `0.1.12`
|
|
18
|
+
|
|
19
|
+
## Added
|
|
20
|
+
|
|
21
|
+
- `scripts/check-framework-antipatterns.ts` — pulled in alongside the updated `devcheck.ts` so the new check has a script to invoke. (Required because the `maintenance` skill's Phase C currently uses a hardcoded script list — see [cyanheads/mcp-ts-core#69](https://github.com/cyanheads/mcp-ts-core/issues/69).)
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "Patch release: framework `0.7.5 → 0.7.6` bump, [#2](https://github.com/cyanheads/calculator-mcp-server/issues/2) fix lifting the single-expression contract into the `calculate` tool's published JSON Schema, and adoption of the framework template's new `start` script."
|
|
3
|
+
breaking: false
|
|
4
|
+
security: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 0.1.13 — 2026-04-27
|
|
8
|
+
|
|
9
|
+
Patch release: framework `0.7.5 → 0.7.6` bump, [#2](https://github.com/cyanheads/calculator-mcp-server/issues/2) fix lifting the single-expression contract into the `calculate` tool's published JSON Schema, and adoption of the framework template's new `start` script.
|
|
10
|
+
|
|
11
|
+
## Changed
|
|
12
|
+
|
|
13
|
+
- Tightened the `calculate` tool descriptions so the single-expression contract is visible at tool-discovery time, preempting LLM callers that batch with `;` or newlines (closes [#2](https://github.com/cyanheads/calculator-mcp-server/issues/2)). Tool-level description gains `One expression per call.`; the `expression` field describe leads with the constraint and disambiguates `;` semantics — `One mathematical expression per call — neither \`;\` nor newlines separate statements. Inside matrices, \`;\` separates rows (e.g. \`[1, 2; 3, 4]\`).` Existing runtime guard (`hasExpressionSeparator` in `math-service.ts`) unchanged — purely a discoverability improvement.
|
|
14
|
+
- Upgraded `@cyanheads/mcp-ts-core` from `^0.7.5` to `^0.7.6` (patch — `maintenance` skill Phase C now enumerates the installed `scripts/*.ts` directly instead of a hardcoded list, and `release-and-publish` / `setup` / `maintenance` skill prose was reworded so agents pick whichever git tooling is available rather than literal `git <cmd>` invocations)
|
|
15
|
+
- Resynced 3 external skills from the framework (`maintenance` 1.6→1.7, `release-and-publish` 2.1→2.2, `setup` 1.5→1.6)
|
|
16
|
+
- Bumped package, server metadata, README badge, and agent protocol files to `0.1.13`
|
|
17
|
+
|
|
18
|
+
## Added
|
|
19
|
+
|
|
20
|
+
- `start` script in `package.json` (`"start": "node dist/index.js"`) — adopted from the framework template's 0.7.6 update so external MCP runners that assume the npm-canonical `start` script work out of the box. The new script defers to `.env` for transport selection (no inline `MCP_TRANSPORT_TYPE` override); existing `start:stdio` / `start:http` variants unchanged.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "Patch release surfacing two field-test findings in the `calculate` tool: numeric results no longer flip into scientific notation at math.js's default `exp ≥ 5` threshold, and the schema descriptions stop naming a specific consumer."
|
|
3
|
+
breaking: false
|
|
4
|
+
security: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 0.1.14 — 2026-04-27
|
|
8
|
+
|
|
9
|
+
Patch release surfacing two field-test findings in the `calculate` tool: numeric results no longer flip into scientific notation at math.js's default `exp ≥ 5` threshold, and the schema descriptions stop naming a specific consumer.
|
|
10
|
+
|
|
11
|
+
## Fixed
|
|
12
|
+
|
|
13
|
+
- **`calculate` numeric formatting** — widen `math.format()` thresholds to `lowerExp: -6, upperExp: 21` (matching JS `Number.toString`) so normal-magnitude integers render as plain digits. `12345 * 6789` now returns `"83810205"` instead of `"8.3810205e+7"`; `factorial(10)` returns `"3628800"` instead of `"3.6288e+6"`. BigNumbers and very-tiny / very-large doubles still use exponential notation, and the `precision` parameter is unaffected. Implementation: `src/services/math/math-service.ts`.
|
|
14
|
+
|
|
15
|
+
## Changed
|
|
16
|
+
|
|
17
|
+
- **`calculate` schema descriptions** — drop "for form-based clients" / "Blank values from form-based clients" phrasings from `variable.anyOf[0]`, `variable`, `precision.anyOf[0]`, and `precision` `.describe()` strings. The schema no longer references a specific consumer; the empty-string compat behavior is preserved. Implementation: `src/mcp-server/tools/definitions/calculate.tool.ts`.
|
|
18
|
+
- Bumped package, server metadata, README badge, and agent protocol files to `0.1.14`.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "Patch release: framework `0.7.6 → 0.8.0` bump, agent protocol Errors section rewritten to lead with the new typed error contract pattern, and three external skills resynced from the framework."
|
|
3
|
+
breaking: false
|
|
4
|
+
security: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 0.1.15 — 2026-04-28
|
|
8
|
+
|
|
9
|
+
Patch release: framework `0.7.6 → 0.8.0` bump, agent protocol Errors section rewritten to lead with the new typed error contract pattern, and three external skills resynced from the framework.
|
|
10
|
+
|
|
11
|
+
## Changed
|
|
12
|
+
|
|
13
|
+
- Upgraded `@cyanheads/mcp-ts-core` from `^0.7.6` to `^0.8.0` (minor — adds typed error contracts via `errors: [{ reason, code, when, retryable? }]` on `tool()` / `resource()` with typed `ctx.fail(reason, …)`, advertises the failure surface in `tools/list` under `_meta['mcp-ts-core/errors']`; ships `httpErrorFromResponse` and `partialResult` utilities, three new error factories (`internalError`, `serializationError`, `databaseError`), and handler-body + error-contract conformance lint rules. Fully backwards compatible).
|
|
14
|
+
- Agent protocol files (`CLAUDE.md` / `AGENTS.md`) — Errors section rewritten to lead with the typed error contract as the recommended path, demote factories + auto-classification to the fallback. Added `add-app-tool` to the skills table. Added a form-client safety bullet to the checklist.
|
|
15
|
+
- Resynced 3 external skills from the framework (`maintenance` 1.7→1.8, `report-issue-framework` 1.3→1.4, `security-pass` 1.1→1.2 — `security-pass` Axis 7 leakage check now greps `ctx.fail(` and `httpErrorFromResponse(` alongside `new McpError`).
|
|
16
|
+
- Bumped package, server metadata, README badge, and agent protocol files to `0.1.15`.
|
|
17
|
+
|
|
18
|
+
## Added
|
|
19
|
+
|
|
20
|
+
- `scripts/split-changelog.ts` adopted from the framework template — supports the directory-based changelog convention used upstream. The calculator continues to use a flat `CHANGELOG.md`; the script is in place for a future migration.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "Adopt framework 0.8.0 typed error contract on `calculate`. Reclassify input-validation failures from `InvalidParams` (-32602) to `ValidationError` (-32007). 10 contract reasons declared. Wire-shape conformance test suite. Closes #3, #4."
|
|
3
|
+
breaking: false
|
|
4
|
+
security: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 0.1.16 — 2026-04-28
|
|
8
|
+
|
|
9
|
+
Patch release: adopt the framework `0.8.0` typed error contract on the `calculate` tool and reclassify input-validation failures from JSON-RPC `InvalidParams` (`-32602`) to the framework's purpose-built `ValidationError` (`-32007`). Closes [#3](https://github.com/cyanheads/calculator-mcp-server/issues/3) and [#4](https://github.com/cyanheads/calculator-mcp-server/issues/4).
|
|
10
|
+
|
|
11
|
+
## Changed
|
|
12
|
+
|
|
13
|
+
- **`calculate` error codes** — swapped 8 `invalidParams` (`-32602`) throws to `validationError` (`-32007`) across `src/services/math/math-service.ts` (7 sites) and `src/mcp-server/tools/definitions/calculate.tool.ts` (1 site). `serviceUnavailable` on evaluation timeout retained. Observability dashboards keyed on `mcp_error_classified_code` will now group these under `Client: Validation` instead of the unmapped JSON-RPC bucket. Closes [#3](https://github.com/cyanheads/calculator-mcp-server/issues/3).
|
|
14
|
+
- **`calculate` typed error contract** — declared all 10 failure modes as `errors: [{ reason, code, when, retryable? }]` on the tool definition; published in `tools/list` under `_meta['mcp-ts-core/errors']`. Reasons: `empty_expression`, `expression_too_long`, `multiple_expressions`, `reserved_scope_key`, `disallowed_result_type`, `result_too_large`, `undefined_result`, `parse_failed`, `derivative_missing_variable`, `evaluation_timeout` (`ServiceUnavailable`, `retryable: false`). The handler-side cross-field check now routes through `ctx.fail('derivative_missing_variable', …)`; service throws carry `data: { reason }` so the framework's auto-classifier preserves a stable identifier on the wire. Closes [#4](https://github.com/cyanheads/calculator-mcp-server/issues/4).
|
|
15
|
+
|
|
16
|
+
## Added
|
|
17
|
+
|
|
18
|
+
- **Wire-shape conformance test suite** (`tests/mcp-server/tools/definitions/calculate.tool.test.ts`) — one test per contract reason (10 total) asserting the thrown `McpError`'s `code` and `data.reason` match the contract entry. Compensates for the framework lint's blind spot on service-thrown reasons. `result_too_large` and `evaluation_timeout` use a directly-constructed `MathService` with shrunken config (5-char limit / 1ms timeout) since the singleton's defaults can't trigger them.
|
|
19
|
+
|
|
20
|
+
## Fixed
|
|
21
|
+
|
|
22
|
+
- **Test helper now wires `ctx.fail`** — existing `derivative` failure tests had been passing accidentally: `createMockContext()` doesn't attach `ctx.fail`, the resulting `TypeError` happened to serialize a substring `vitest.toThrow()` matched. New `mockCtx()` helper passes `errors: calculateTool.errors` so `ctx.fail` is properly available in tests.
|
|
23
|
+
|
|
24
|
+
## Meta
|
|
25
|
+
|
|
26
|
+
- Bumped package, server metadata, README badge, and agent protocol files to `0.1.16`.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "Natural-language ergonomics: `calculate` now accepts `average`/`avg` aliases for `mean`, and `mph`, `knot`, `lightyear` units (with plurals and standard abbreviations). Closes #5, #6."
|
|
3
|
+
breaking: false
|
|
4
|
+
security: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 0.1.17 — 2026-04-28
|
|
8
|
+
|
|
9
|
+
Patch release: natural-language ergonomics — the `calculate` tool now accepts `average`/`avg` as aliases for `mean`, and the `mph`, `knot`, and `lightyear` units (with their plurals and standard abbreviations). Closes [#5](https://github.com/cyanheads/calculator-mcp-server/issues/5) and [#6](https://github.com/cyanheads/calculator-mcp-server/issues/6).
|
|
10
|
+
|
|
11
|
+
## Added
|
|
12
|
+
|
|
13
|
+
- **Function aliases** — `average` and `avg` registered as aliases for `mean` via `math.import()` in `MathService` constructor (`src/services/math/math-service.ts`). Both resolve to the same typed function as `mean`. Closes [#5](https://github.com/cyanheads/calculator-mcp-server/issues/5).
|
|
14
|
+
- **Custom units** — `mph` (= `1 mile/hour`), `knot` (= `1852 m/hour`, with aliases `knots`, `kt`, `kts`), and `lightyear` (= `9460730472580800 m`, with aliases `lightyears`, `ly`) registered via `math.createUnit()` in the constructor before the disabling step clobbers `createUnit` in the expression scope. Definitions use exact SI-derived values. Closes [#6](https://github.com/cyanheads/calculator-mcp-server/issues/6).
|
|
15
|
+
- **5 wire-shape tests** for the new aliases and units in `tests/mcp-server/tools/definitions/calculate.tool.test.ts` covering `average`/`avg` evaluation and `60 mph → m/s`, `1 lightyear → km`, `10 knots → m/s` conversions.
|
|
16
|
+
|
|
17
|
+
## Changed
|
|
18
|
+
|
|
19
|
+
- **Help resource** (`calculator://help`) — Statistics line now reads `mean (aliases: average, avg)`; Common units line now includes `lightyear (ly)`, `mph`, `knot (kt)`. Discovery surface stays in sync with the registered surface.
|
|
20
|
+
|
|
21
|
+
## Meta
|
|
22
|
+
|
|
23
|
+
- Bumped package, server metadata, README badge, and agent protocol files to `0.1.17`.
|
|
24
|
+
- [#7](https://github.com/cyanheads/calculator-mcp-server/issues/7) (intermediate overflow on factorial ratios) — left open with a [rejection comment](https://github.com/cyanheads/calculator-mcp-server/issues/7#issuecomment-4339684505) on the proposed BigNumber-as-default fix and a counter-proposal for an opt-in `numericType` tool parameter.
|