@cyanheads/calculator-mcp-server 0.1.23 → 0.1.25

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 CHANGED
@@ -1,8 +1,8 @@
1
1
  # Agent Protocol
2
2
 
3
3
  **Server:** calculator-mcp-server
4
- **Version:** 0.1.23
5
- **Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.9.4`
4
+ **Version:** 0.1.25
5
+ **Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.9.13`
6
6
  **Engines:** Bun ≥1.3.0, Node ≥24.0.0
7
7
  **MCP SDK:** `@modelcontextprotocol/sdk` 1.29.0
8
8
  **Zod:** 4.4.3
@@ -52,6 +52,7 @@ Tailor suggestions to what's actually missing or stale — don't recite the full
52
52
  - **Use `ctx.state`** for tenant-scoped storage. Never access persistence directly.
53
53
  - **Check `ctx.elicit` / `ctx.sample`** for presence before calling.
54
54
  - **Secrets in env vars only** — never hardcoded.
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.
55
56
 
56
57
  ---
57
58
 
@@ -154,6 +155,11 @@ Handlers receive a unified `ctx` object. Key properties:
154
155
  | Property | Description |
155
156
  |:---------|:------------|
156
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.elicit` | Ask user for structured input. **Check for presence first:** `if (ctx.elicit) { ... }` |
160
+ | `ctx.sample` | Request LLM completion from the client. **Check for presence first:** `if (ctx.sample) { ... }` |
161
+ | `ctx.signal` | `AbortSignal` for cancellation. |
162
+ | `ctx.progress` | Task progress (present when `task: true`) — `.setTotal(n)`, `.increment()`, `.update(message)`. |
157
163
  | `ctx.requestId` | Unique request ID. |
158
164
  | `ctx.tenantId` | Tenant ID from JWT or `'default'` for stdio. |
159
165
 
@@ -168,6 +174,8 @@ Handlers throw — the framework catches, classifies, and formats.
168
174
  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.
169
175
 
170
176
  ```ts
177
+ import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
178
+
171
179
  errors: [
172
180
  { reason: 'no_match', code: JsonRpcErrorCode.NotFound,
173
181
  when: 'No item matched the query',
@@ -257,7 +265,9 @@ Available skills:
257
265
  | `add-service` | Scaffold a new service integration |
258
266
  | `add-test` | Scaffold test file for a tool, resource, or service |
259
267
  | `field-test` | Exercise tools/resources/prompts with real inputs, verify behavior, report issues |
260
- | `tool-defs-analysis` | Read-only audit of MCP definition language (voice, leaks, recovery hints, structure) |
268
+ | `code-simplifier` | Post-session code review and cleanup against `git diff` — modernize syntax, consolidate duplication, align with codebase |
269
+ | `git-wrapup` | Land working-tree changes as a versioned commit + annotated tag — version bump, changelog, verify, tag. Local only. |
270
+ | `tool-defs-analysis` | Read-only audit of MCP definition language across the surface — voice, leaks, defaults, recovery hints, output descriptions |
261
271
  | `devcheck` | Lint, format, typecheck, audit |
262
272
  | `security-pass` | Audit server for MCP-flavored security gaps: output injection, scope blast radius, input sinks, tenant isolation |
263
273
  | `polish-docs-meta` | Finalize docs, README, metadata, and agent protocol for shipping |
@@ -270,13 +280,12 @@ Available skills:
270
280
  | `api-config` | AppConfig, parseConfig, env vars |
271
281
  | `api-context` | Context interface, logger, state, progress |
272
282
  | `api-errors` | McpError, JsonRpcErrorCode, error patterns |
273
- | `api-linter` | MCP definition linter rules reference (every rule ID + fix) |
283
+ | `api-linter` | Definition linter rule catalog invoked by `bun run lint:mcp` and `devcheck` |
274
284
  | `api-services` | LLM, Speech, Graph services |
275
285
  | `api-telemetry` | OTel catalog: spans, metrics, completion logs, env config, cardinality rules |
276
286
  | `api-testing` | createMockContext, test patterns |
277
287
  | `api-utils` | Formatting, parsing, security, pagination, scheduling, telemetry helpers |
278
288
  | `api-workers` | Cloudflare Workers runtime |
279
- | `migrate-mcp-ts-template` | Migrate a template fork to use `@cyanheads/mcp-ts-core` as a package |
280
289
 
281
290
  When you complete a skill's checklist, check the boxes and add a completion timestamp at the end (e.g., `Completed: 2026-03-11`).
282
291
 
@@ -311,30 +320,34 @@ When you complete a skill's checklist, check the boxes and add a completion time
311
320
 
312
321
  **Adding an env var requires both files:** `server.json` (`environmentVariables[]`) and `manifest.json` (`mcp_config.env` + `user_config`). `lint:packaging` (run by `devcheck`) verifies env var names match.
313
322
 
314
- **README install badges** drop these in to give users one-click install paths:
323
+ **README install badges** (Claude Desktop `.mcpb`, Cursor, VS Code) and the `base64` / `encodeURIComponent` config-generation commands are ship-time concerns — run the `polish-docs-meta` skill, which carries the badge format, layout, and generation snippets in `skills/polish-docs-meta/references/readme.md`.
324
+
325
+ ---
326
+
327
+ ## Changelog
328
+
329
+ Directory-based, grouped by minor series via the `.x` semver-wildcard convention. Source of truth: `changelog/<major.minor>.x/<version>.md` (e.g. `changelog/0.1.x/0.1.0.md`) — one file per release, shipped in the npm package. At release, author the per-version file with a concrete version and date, then run `bun run changelog:build` to regenerate the rollup. `changelog/template.md` is a **pristine format reference** — never edited or moved; read it for the frontmatter + section layout when scaffolding. `CHANGELOG.md` is a **navigation index** (header + link + summary per version), regenerated by `bun run changelog:build` — devcheck hard-fails on drift; never hand-edit it.
315
330
 
316
- | Client | Mechanism |
317
- |:-------|:----------|
318
- | Claude Desktop | Browser downloads `.mcpb` from latest GitHub Release; OS file handler routes to Claude Desktop. |
319
- | Cursor | `https://cursor.com/en/install-mcp` with base64 JSON config. |
320
- | VS Code | `vscode:mcp/install?...` wrapped in `https://vscode.dev/redirect?url=` (GitHub strips non-HTTP schemes). |
321
- | Claude Code / Codex | CLI only — no URL scheme. |
331
+ Each per-version file opens with YAML frontmatter:
322
332
 
323
333
  ```markdown
324
- [![Install in Claude Desktop](https://img.shields.io/badge/Install_in-Claude_Desktop-D97757?style=for-the-badge&logo=anthropic&logoColor=white)](https://github.com/cyanheads/calculator-mcp-server/releases/latest/download/calculator-mcp-server.mcpb)
325
- [![Install in Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en/install-mcp?name=calculator-mcp-server&config=<BASE64_CONFIG>)
326
- [![Install in VS Code](https://img.shields.io/badge/VS_Code-Install_Server-0098FF?style=for-the-badge&logo=visualstudiocode&logoColor=white)](https://vscode.dev/redirect?url=vscode:mcp/install?<URLENCODED_JSON>)
334
+ ---
335
+ summary: "One-line headline, ≤350 chars" # required — powers the rollup index
336
+ breaking: false # optional — true flags breaking changes
337
+ security: false # optional — true flags security fixes
338
+ ---
339
+
340
+ # 0.1.0 — YYYY-MM-DD
341
+ ...
327
342
  ```
328
343
 
329
- Generate encoded configs:
344
+ `breaking: true` renders a `· ⚠️ Breaking` badge — use it when consumers must update code on upgrade (signature changes, removed APIs, config renames). `security: true` renders a `· 🛡️ Security` badge and pairs with a `## Security` body section. When both are set, badges render `· ⚠️ Breaking · 🛡️ Security`.
330
345
 
331
- ```bash
332
- # Cursor
333
- echo -n '{"command":"npx -y @cyanheads/calculator-mcp-server"}' | base64
346
+ `agent-notes` is an optional free-form field for maintenance agents processing the release downstream. Content here won't appear in the rendered CHANGELOG — it's consumed by agents running the `maintenance` skill. Use it for adoption instructions that don't fit the human-facing sections. Omit entirely when there's nothing to say.
334
347
 
335
- # VS Code
336
- node -p 'encodeURIComponent(JSON.stringify({name:"@cyanheads/calculator-mcp-server",command:"npx",args:["-y","@cyanheads/calculator-mcp-server"]}))'
337
- ```
348
+ **Section order** (Keep a Changelog): Added, Changed, Deprecated, Removed, Fixed, Security. Include only sections with entries — don't ship empty headers.
349
+
350
+ **Tag annotations** render as GitHub Release bodies via `--notes-from-tag`. They must be structured markdown — never a flat comma-separated string. Subject omits the version number (GitHub prepends it). See `changelog/template.md` for the full format reference.
338
351
 
339
352
  ---
340
353
 
@@ -397,4 +410,7 @@ import { getServerConfig } from '@/config/server-config.js';
397
410
  - [ ] `format()` renders all data the LLM needs — different clients forward different surfaces (Claude Code → `structuredContent`, Claude Desktop → `content[]`); both must carry the same data
398
411
  - [ ] Registered in `createApp()` arrays (directly or via barrel exports)
399
412
  - [ ] Tests use `createMockContext()` from `@cyanheads/mcp-ts-core/testing`
413
+ - [ ] `.codex-plugin/plugin.json` populated — `name`, `version`, `description`, `repository`, `license` from `package.json`; `interface.displayName` = package name; `interface.shortDescription` from `package.json` description
414
+ - [ ] `.codex-plugin/mcp.json` updated — server name key matches `package.json` name; env vars added for any required API keys
415
+ - [ ] `.claude-plugin/plugin.json` populated — `name`, `version`, `description`, `repository`, `license` from `package.json`; inline `mcpServers` entry with server name key, env vars for any required API keys
400
416
  - [ ] `bun run devcheck` passes
package/CLAUDE.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # Agent Protocol
2
2
 
3
3
  **Server:** calculator-mcp-server
4
- **Version:** 0.1.23
5
- **Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.9.4`
4
+ **Version:** 0.1.25
5
+ **Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.9.13`
6
6
  **Engines:** Bun ≥1.3.0, Node ≥24.0.0
7
7
  **MCP SDK:** `@modelcontextprotocol/sdk` 1.29.0
8
8
  **Zod:** 4.4.3
@@ -52,6 +52,7 @@ Tailor suggestions to what's actually missing or stale — don't recite the full
52
52
  - **Use `ctx.state`** for tenant-scoped storage. Never access persistence directly.
53
53
  - **Check `ctx.elicit` / `ctx.sample`** for presence before calling.
54
54
  - **Secrets in env vars only** — never hardcoded.
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.
55
56
 
56
57
  ---
57
58
 
@@ -154,6 +155,11 @@ Handlers receive a unified `ctx` object. Key properties:
154
155
  | Property | Description |
155
156
  |:---------|:------------|
156
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.elicit` | Ask user for structured input. **Check for presence first:** `if (ctx.elicit) { ... }` |
160
+ | `ctx.sample` | Request LLM completion from the client. **Check for presence first:** `if (ctx.sample) { ... }` |
161
+ | `ctx.signal` | `AbortSignal` for cancellation. |
162
+ | `ctx.progress` | Task progress (present when `task: true`) — `.setTotal(n)`, `.increment()`, `.update(message)`. |
157
163
  | `ctx.requestId` | Unique request ID. |
158
164
  | `ctx.tenantId` | Tenant ID from JWT or `'default'` for stdio. |
159
165
 
@@ -168,6 +174,8 @@ Handlers throw — the framework catches, classifies, and formats.
168
174
  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.
169
175
 
170
176
  ```ts
177
+ import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
178
+
171
179
  errors: [
172
180
  { reason: 'no_match', code: JsonRpcErrorCode.NotFound,
173
181
  when: 'No item matched the query',
@@ -257,7 +265,9 @@ Available skills:
257
265
  | `add-service` | Scaffold a new service integration |
258
266
  | `add-test` | Scaffold test file for a tool, resource, or service |
259
267
  | `field-test` | Exercise tools/resources/prompts with real inputs, verify behavior, report issues |
260
- | `tool-defs-analysis` | Read-only audit of MCP definition language (voice, leaks, recovery hints, structure) |
268
+ | `code-simplifier` | Post-session code review and cleanup against `git diff` — modernize syntax, consolidate duplication, align with codebase |
269
+ | `git-wrapup` | Land working-tree changes as a versioned commit + annotated tag — version bump, changelog, verify, tag. Local only. |
270
+ | `tool-defs-analysis` | Read-only audit of MCP definition language across the surface — voice, leaks, defaults, recovery hints, output descriptions |
261
271
  | `devcheck` | Lint, format, typecheck, audit |
262
272
  | `security-pass` | Audit server for MCP-flavored security gaps: output injection, scope blast radius, input sinks, tenant isolation |
263
273
  | `polish-docs-meta` | Finalize docs, README, metadata, and agent protocol for shipping |
@@ -270,13 +280,12 @@ Available skills:
270
280
  | `api-config` | AppConfig, parseConfig, env vars |
271
281
  | `api-context` | Context interface, logger, state, progress |
272
282
  | `api-errors` | McpError, JsonRpcErrorCode, error patterns |
273
- | `api-linter` | MCP definition linter rules reference (every rule ID + fix) |
283
+ | `api-linter` | Definition linter rule catalog invoked by `bun run lint:mcp` and `devcheck` |
274
284
  | `api-services` | LLM, Speech, Graph services |
275
285
  | `api-telemetry` | OTel catalog: spans, metrics, completion logs, env config, cardinality rules |
276
286
  | `api-testing` | createMockContext, test patterns |
277
287
  | `api-utils` | Formatting, parsing, security, pagination, scheduling, telemetry helpers |
278
288
  | `api-workers` | Cloudflare Workers runtime |
279
- | `migrate-mcp-ts-template` | Migrate a template fork to use `@cyanheads/mcp-ts-core` as a package |
280
289
 
281
290
  When you complete a skill's checklist, check the boxes and add a completion timestamp at the end (e.g., `Completed: 2026-03-11`).
282
291
 
@@ -311,30 +320,34 @@ When you complete a skill's checklist, check the boxes and add a completion time
311
320
 
312
321
  **Adding an env var requires both files:** `server.json` (`environmentVariables[]`) and `manifest.json` (`mcp_config.env` + `user_config`). `lint:packaging` (run by `devcheck`) verifies env var names match.
313
322
 
314
- **README install badges** drop these in to give users one-click install paths:
323
+ **README install badges** (Claude Desktop `.mcpb`, Cursor, VS Code) and the `base64` / `encodeURIComponent` config-generation commands are ship-time concerns — run the `polish-docs-meta` skill, which carries the badge format, layout, and generation snippets in `skills/polish-docs-meta/references/readme.md`.
324
+
325
+ ---
326
+
327
+ ## Changelog
328
+
329
+ Directory-based, grouped by minor series via the `.x` semver-wildcard convention. Source of truth: `changelog/<major.minor>.x/<version>.md` (e.g. `changelog/0.1.x/0.1.0.md`) — one file per release, shipped in the npm package. At release, author the per-version file with a concrete version and date, then run `bun run changelog:build` to regenerate the rollup. `changelog/template.md` is a **pristine format reference** — never edited or moved; read it for the frontmatter + section layout when scaffolding. `CHANGELOG.md` is a **navigation index** (header + link + summary per version), regenerated by `bun run changelog:build` — devcheck hard-fails on drift; never hand-edit it.
315
330
 
316
- | Client | Mechanism |
317
- |:-------|:----------|
318
- | Claude Desktop | Browser downloads `.mcpb` from latest GitHub Release; OS file handler routes to Claude Desktop. |
319
- | Cursor | `https://cursor.com/en/install-mcp` with base64 JSON config. |
320
- | VS Code | `vscode:mcp/install?...` wrapped in `https://vscode.dev/redirect?url=` (GitHub strips non-HTTP schemes). |
321
- | Claude Code / Codex | CLI only — no URL scheme. |
331
+ Each per-version file opens with YAML frontmatter:
322
332
 
323
333
  ```markdown
324
- [![Install in Claude Desktop](https://img.shields.io/badge/Install_in-Claude_Desktop-D97757?style=for-the-badge&logo=anthropic&logoColor=white)](https://github.com/cyanheads/calculator-mcp-server/releases/latest/download/calculator-mcp-server.mcpb)
325
- [![Install in Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en/install-mcp?name=calculator-mcp-server&config=<BASE64_CONFIG>)
326
- [![Install in VS Code](https://img.shields.io/badge/VS_Code-Install_Server-0098FF?style=for-the-badge&logo=visualstudiocode&logoColor=white)](https://vscode.dev/redirect?url=vscode:mcp/install?<URLENCODED_JSON>)
334
+ ---
335
+ summary: "One-line headline, ≤350 chars" # required — powers the rollup index
336
+ breaking: false # optional — true flags breaking changes
337
+ security: false # optional — true flags security fixes
338
+ ---
339
+
340
+ # 0.1.0 — YYYY-MM-DD
341
+ ...
327
342
  ```
328
343
 
329
- Generate encoded configs:
344
+ `breaking: true` renders a `· ⚠️ Breaking` badge — use it when consumers must update code on upgrade (signature changes, removed APIs, config renames). `security: true` renders a `· 🛡️ Security` badge and pairs with a `## Security` body section. When both are set, badges render `· ⚠️ Breaking · 🛡️ Security`.
330
345
 
331
- ```bash
332
- # Cursor
333
- echo -n '{"command":"npx -y @cyanheads/calculator-mcp-server"}' | base64
346
+ `agent-notes` is an optional free-form field for maintenance agents processing the release downstream. Content here won't appear in the rendered CHANGELOG — it's consumed by agents running the `maintenance` skill. Use it for adoption instructions that don't fit the human-facing sections. Omit entirely when there's nothing to say.
334
347
 
335
- # VS Code
336
- node -p 'encodeURIComponent(JSON.stringify({name:"@cyanheads/calculator-mcp-server",command:"npx",args:["-y","@cyanheads/calculator-mcp-server"]}))'
337
- ```
348
+ **Section order** (Keep a Changelog): Added, Changed, Deprecated, Removed, Fixed, Security. Include only sections with entries — don't ship empty headers.
349
+
350
+ **Tag annotations** render as GitHub Release bodies via `--notes-from-tag`. They must be structured markdown — never a flat comma-separated string. Subject omits the version number (GitHub prepends it). See `changelog/template.md` for the full format reference.
338
351
 
339
352
  ---
340
353
 
@@ -397,4 +410,7 @@ import { getServerConfig } from '@/config/server-config.js';
397
410
  - [ ] `format()` renders all data the LLM needs — different clients forward different surfaces (Claude Code → `structuredContent`, Claude Desktop → `content[]`); both must carry the same data
398
411
  - [ ] Registered in `createApp()` arrays (directly or via barrel exports)
399
412
  - [ ] Tests use `createMockContext()` from `@cyanheads/mcp-ts-core/testing`
413
+ - [ ] `.codex-plugin/plugin.json` populated — `name`, `version`, `description`, `repository`, `license` from `package.json`; `interface.displayName` = package name; `interface.shortDescription` from `package.json` description
414
+ - [ ] `.codex-plugin/mcp.json` updated — server name key matches `package.json` name; env vars added for any required API keys
415
+ - [ ] `.claude-plugin/plugin.json` populated — `name`, `version`, `description`, `repository`, `license` from `package.json`; inline `mcpServers` entry with server name key, env vars for any required API keys
400
416
  - [ ] `bun run devcheck` passes
package/README.md CHANGED
@@ -7,13 +7,13 @@
7
7
 
8
8
  <div align="center">
9
9
 
10
- [![Version](https://img.shields.io/badge/Version-0.1.23-blue.svg?style=flat-square)](./CHANGELOG.md) [![License](https://img.shields.io/badge/License-Apache%202.0-orange.svg?style=flat-square)](./LICENSE) [![Docker](https://img.shields.io/badge/Docker-ghcr.io-2496ED?style=flat-square&logo=docker&logoColor=white)](https://github.com/users/cyanheads/packages/container/package/calculator-mcp-server) [![MCP SDK](https://img.shields.io/badge/MCP%20SDK-%5E1.29.0-green.svg?style=flat-square)](https://modelcontextprotocol.io/) [![npm](https://img.shields.io/npm/v/@cyanheads/calculator-mcp-server?style=flat-square&logo=npm&logoColor=white)](https://www.npmjs.com/package/@cyanheads/calculator-mcp-server) [![TypeScript](https://img.shields.io/badge/TypeScript-%5E6.0.3-3178C6.svg?style=flat-square)](https://www.typescriptlang.org/) [![Bun](https://img.shields.io/badge/Bun-v1.3.0-blueviolet.svg?style=flat-square)](https://bun.sh/)
10
+ [![Version](https://img.shields.io/badge/Version-0.1.25-blue.svg?style=flat-square)](./CHANGELOG.md) [![License](https://img.shields.io/badge/License-Apache%202.0-orange.svg?style=flat-square)](./LICENSE) [![Docker](https://img.shields.io/badge/Docker-ghcr.io-2496ED?style=flat-square&logo=docker&logoColor=white)](https://github.com/users/cyanheads/packages/container/package/calculator-mcp-server) [![MCP SDK](https://img.shields.io/badge/MCP%20SDK-%5E1.29.0-green.svg?style=flat-square)](https://modelcontextprotocol.io/) [![npm](https://img.shields.io/npm/v/@cyanheads/calculator-mcp-server?style=flat-square&logo=npm&logoColor=white)](https://www.npmjs.com/package/@cyanheads/calculator-mcp-server) [![TypeScript](https://img.shields.io/badge/TypeScript-%5E6.0.3-3178C6.svg?style=flat-square)](https://www.typescriptlang.org/) [![Bun](https://img.shields.io/badge/Bun-v1.3.0-blueviolet.svg?style=flat-square)](https://bun.sh/)
11
11
 
12
12
  </div>
13
13
 
14
14
  <div align="center">
15
15
 
16
- [![Install in Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en/install-mcp?name=calculator-mcp-server&config=eyJjb21tYW5kIjoibnB4IC15IEBjeWFuaGVhZHMvY2FsY3VsYXRvci1tY3Atc2VydmVyIn0=) [![Install in VS Code](https://img.shields.io/badge/VS_Code-Install_Server-0098FF?style=for-the-badge&logo=visualstudiocode&logoColor=white)](https://vscode.dev/redirect?url=vscode:mcp/install?%7B%22name%22%3A%22calculator-mcp-server%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40cyanheads%2Fcalculator-mcp-server%22%5D%7D)
16
+ [![Install in Claude Desktop](https://img.shields.io/badge/Install_in-Claude_Desktop-D97757?style=for-the-badge&logo=anthropic&logoColor=white)](https://github.com/cyanheads/calculator-mcp-server/releases/latest/download/calculator-mcp-server.mcpb) [![Install in Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en/install-mcp?name=calculator-mcp-server&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkBjeWFuaGVhZHMvY2FsY3VsYXRvci1tY3Atc2VydmVyIl19) [![Install in VS Code](https://img.shields.io/badge/VS_Code-Install_Server-0098FF?style=for-the-badge&logo=visualstudiocode&logoColor=white)](https://vscode.dev/redirect?url=vscode:mcp/install?%7B%22name%22%3A%22calculator-mcp-server%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40cyanheads%2Fcalculator-mcp-server%22%5D%7D)
17
17
 
18
18
  [![Framework](https://img.shields.io/badge/Built%20on-@cyanheads/mcp--ts--core-67E8F9?style=flat-square)](https://www.npmjs.com/package/@cyanheads/mcp-ts-core)
19
19
 
@@ -3,7 +3,11 @@
3
3
  * @module config/server-config
4
4
  */
5
5
  import { z } from '@cyanheads/mcp-ts-core';
6
- declare const ServerConfigSchema: any;
6
+ declare const ServerConfigSchema: z.ZodObject<{
7
+ maxExpressionLength: z.ZodPreprocess<z.ZodDefault<z.ZodCoercedNumber<unknown>>>;
8
+ evaluationTimeoutMs: z.ZodPreprocess<z.ZodDefault<z.ZodCoercedNumber<unknown>>>;
9
+ maxResultLength: z.ZodPreprocess<z.ZodDefault<z.ZodCoercedNumber<unknown>>>;
10
+ }, z.core.$strip>;
7
11
  export type ServerConfig = z.infer<typeof ServerConfigSchema>;
8
12
  /** Lazy-parsed server config from env vars. */
9
13
  export declare function getServerConfig(): ServerConfig;
@@ -1 +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;AAG3C,QAAA,MAAM,kBAAkB,KAsBtB,CAAC;AAEH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAI9D,+CAA+C;AAC/C,wBAAgB,eAAe,IAAI,YAAY,CAO9C"}
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;AAO3C,QAAA,MAAM,kBAAkB;;;;iBA+BtB,CAAC;AAEH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAI9D,+CAA+C;AAC/C,wBAAgB,eAAe,IAAI,YAAY,CAO9C"}
@@ -4,28 +4,30 @@
4
4
  */
5
5
  import { z } from '@cyanheads/mcp-ts-core';
6
6
  import { parseEnvConfig } from '@cyanheads/mcp-ts-core/config';
7
+ /** Strip MCPB placeholder strings (e.g. `${user_config.X}`) to undefined so .default() applies. */
8
+ const stripPlaceholder = (v) => typeof v === 'string' && v.startsWith('${') ? undefined : v;
7
9
  const ServerConfigSchema = z.object({
8
- maxExpressionLength: z.coerce
10
+ maxExpressionLength: z.preprocess(stripPlaceholder, z.coerce
9
11
  .number()
10
12
  .int()
11
13
  .min(10)
12
14
  .max(10_000)
13
15
  .default(1000)
14
- .describe('Maximum allowed expression string length (10–10,000)'),
15
- evaluationTimeoutMs: z.coerce
16
+ .describe('Maximum allowed expression string length (10–10,000)')),
17
+ evaluationTimeoutMs: z.preprocess(stripPlaceholder, z.coerce
16
18
  .number()
17
19
  .int()
18
20
  .min(100)
19
21
  .max(30_000)
20
22
  .default(5000)
21
- .describe('Maximum evaluation time in milliseconds (100–30,000)'),
22
- maxResultLength: z.coerce
23
+ .describe('Maximum evaluation time in milliseconds (100–30,000)')),
24
+ maxResultLength: z.preprocess(stripPlaceholder, z.coerce
23
25
  .number()
24
26
  .int()
25
27
  .min(1_000)
26
28
  .max(1_000_000)
27
29
  .default(100_000)
28
- .describe('Maximum result string length in characters (1,000–1,000,000)'),
30
+ .describe('Maximum result string length in characters (1,000–1,000,000)')),
29
31
  });
30
32
  let _config;
31
33
  /** Lazy-parsed server config from env vars. */
@@ -1 +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;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAE/D,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,cAAc,CAAC,kBAAkB,EAAE;QAC7C,mBAAmB,EAAE,4BAA4B;QACjD,mBAAmB,EAAE,4BAA4B;QACjD,eAAe,EAAE,wBAAwB;KAC1C,CAAC,CAAC;IACH,OAAO,OAAO,CAAC;AACjB,CAAC"}
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;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAE/D,mGAAmG;AACnG,MAAM,gBAAgB,GAAG,CAAC,CAAU,EAAE,EAAE,CACtC,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;AAE9D,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IAClC,mBAAmB,EAAE,CAAC,CAAC,UAAU,CAC/B,gBAAgB,EAChB,CAAC,CAAC,MAAM;SACL,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,CACpE;IACD,mBAAmB,EAAE,CAAC,CAAC,UAAU,CAC/B,gBAAgB,EAChB,CAAC,CAAC,MAAM;SACL,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,CACpE;IACD,eAAe,EAAE,CAAC,CAAC,UAAU,CAC3B,gBAAgB,EAChB,CAAC,CAAC,MAAM;SACL,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;CACF,CAAC,CAAC;AAIH,IAAI,OAAiC,CAAC;AAEtC,+CAA+C;AAC/C,MAAM,UAAU,eAAe;IAC7B,OAAO,KAAK,cAAc,CAAC,kBAAkB,EAAE;QAC7C,mBAAmB,EAAE,4BAA4B;QACjD,mBAAmB,EAAE,4BAA4B;QACjD,eAAe,EAAE,wBAAwB;KAC1C,CAAC,CAAC;IACH,OAAO,OAAO,CAAC;AACjB,CAAC"}
package/dist/index.js CHANGED
@@ -15,6 +15,7 @@ await createApp({
15
15
  landing: {
16
16
  repoRoot: 'https://github.com/cyanheads/calculator-mcp-server',
17
17
  tagline: 'A hardened math.js calculator MCP server — evaluate, simplify, and differentiate expressions.',
18
+ requireAuth: false,
18
19
  },
19
20
  setup() {
20
21
  initMathService(getServerConfig());
package/dist/index.js.map CHANGED
@@ -1 +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,YAAY,EACV,wdAAwd;IAC1d,OAAO,EAAE;QACP,QAAQ,EAAE,oDAAoD;QAC9D,OAAO,EACL,+FAA+F;KAClG;IACD,KAAK;QACH,eAAe,CAAC,eAAe,EAAE,CAAC,CAAC;IACrC,CAAC;CACF,CAAC,CAAC"}
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,YAAY,EACV,wdAAwd;IAC1d,OAAO,EAAE;QACP,QAAQ,EAAE,oDAAoD;QAC9D,OAAO,EACL,+FAA+F;QACjG,WAAW,EAAE,KAAK;KACnB;IACD,KAAK;QACH,eAAe,CAAC,eAAe,EAAE,CAAC,CAAC;IACrC,CAAC;CACF,CAAC,CAAC"}
@@ -2,5 +2,7 @@
2
2
  * @fileoverview Help resource — static reference of available functions, operators, and syntax.
3
3
  * @module mcp-server/resources/definitions/help.resource
4
4
  */
5
- export declare const helpResource: import("@cyanheads/mcp-ts-core").ResourceDefinition<ZodObject<ZodRawShape>, undefined, undefined>;
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, undefined>;
6
8
  //# sourceMappingURL=help.resource.d.ts.map
@@ -1 +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,mGAWvB,CAAC"}
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;;wDAWvB,CAAC"}
@@ -3,8 +3,23 @@
3
3
  * Single tool covering 100% of the server's purpose.
4
4
  * @module mcp-server/tools/definitions/calculate.tool
5
5
  */
6
+ import { z } from '@cyanheads/mcp-ts-core';
6
7
  import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
7
- export declare const calculateTool: import("@cyanheads/mcp-ts-core").ToolDefinition<any, any, readonly [{
8
+ export declare const calculateTool: import("@cyanheads/mcp-ts-core").ToolDefinition<z.ZodObject<{
9
+ expression: z.ZodString;
10
+ operation: z.ZodDefault<z.ZodEnum<{
11
+ evaluate: "evaluate";
12
+ simplify: "simplify";
13
+ derivative: "derivative";
14
+ }>>;
15
+ variable: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"">, z.ZodString]>>;
16
+ scope: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodNumber>>;
17
+ precision: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"">, z.ZodNumber]>>;
18
+ }, z.core.$strip>, z.ZodObject<{
19
+ result: z.ZodString;
20
+ resultType: z.ZodString;
21
+ expression: z.ZodString;
22
+ }, z.core.$strip>, readonly [{
8
23
  readonly reason: "empty_expression";
9
24
  readonly code: JsonRpcErrorCode.ValidationError;
10
25
  readonly when: "Expression is empty or whitespace-only.";
@@ -1 +1 @@
1
- {"version":3,"file":"calculate.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/calculate.tool.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAGjE,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqKxB,CAAC"}
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;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAGjE,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqKxB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cyanheads/calculator-mcp-server",
3
- "version": "0.1.23",
3
+ "version": "0.1.25",
4
4
  "description": "Evaluate, simplify, and differentiate mathematical expressions via MCP. STDIO or Streamable HTTP.",
5
5
  "mcpName": "io.github.cyanheads/calculator-mcp-server",
6
6
  "type": "module",
@@ -38,7 +38,10 @@
38
38
  "math",
39
39
  "mathjs",
40
40
  "llm-tools",
41
- "typescript"
41
+ "typescript",
42
+ "bun",
43
+ "stdio",
44
+ "streamable-http"
42
45
  ],
43
46
  "repository": {
44
47
  "type": "git",
@@ -72,13 +75,13 @@
72
75
  "zod": "^4.4.3"
73
76
  },
74
77
  "dependencies": {
75
- "@cyanheads/mcp-ts-core": "^0.9.4",
78
+ "@cyanheads/mcp-ts-core": "^0.9.13",
76
79
  "mathjs": "^15.2.0",
77
80
  "pino-pretty": "^13.1.3",
78
81
  "zod": "^4.4.3"
79
82
  },
80
83
  "devDependencies": {
81
- "@biomejs/biome": "^2.4.15",
84
+ "@biomejs/biome": "^2.4.16",
82
85
  "@types/node": "^25.9.1",
83
86
  "depcheck": "^1.4.7",
84
87
  "ignore": "^7.0.5",
package/server.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "url": "https://github.com/cyanheads/calculator-mcp-server",
7
7
  "source": "github"
8
8
  },
9
- "version": "0.1.23",
9
+ "version": "0.1.25",
10
10
  "remotes": [
11
11
  {
12
12
  "type": "streamable-http",
@@ -19,7 +19,7 @@
19
19
  "registryBaseUrl": "https://registry.npmjs.org",
20
20
  "identifier": "@cyanheads/calculator-mcp-server",
21
21
  "runtimeHint": "bun",
22
- "version": "0.1.23",
22
+ "version": "0.1.25",
23
23
  "packageArguments": [
24
24
  {
25
25
  "type": "positional",
@@ -69,7 +69,7 @@
69
69
  "registryBaseUrl": "https://registry.npmjs.org",
70
70
  "identifier": "@cyanheads/calculator-mcp-server",
71
71
  "runtimeHint": "bun",
72
- "version": "0.1.23",
72
+ "version": "0.1.25",
73
73
  "packageArguments": [
74
74
  {
75
75
  "type": "positional",