@cyanheads/calculator-mcp-server 0.1.24 → 0.1.26

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.24
5
- **Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.9.6`
4
+ **Version:** 0.1.26
5
+ **Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.9.16`
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
 
@@ -159,6 +160,7 @@ Handlers receive a unified `ctx` object. Key properties:
159
160
  | `ctx.sample` | Request LLM completion from the client. **Check for presence first:** `if (ctx.sample) { ... }` |
160
161
  | `ctx.signal` | `AbortSignal` for cancellation. |
161
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. |
162
164
  | `ctx.requestId` | Unique request ID. |
163
165
  | `ctx.tenantId` | Tenant ID from JWT or `'default'` for stdio. |
164
166
 
@@ -173,6 +175,8 @@ Handlers throw — the framework catches, classifies, and formats.
173
175
  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.
174
176
 
175
177
  ```ts
178
+ import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
179
+
176
180
  errors: [
177
181
  { reason: 'no_match', code: JsonRpcErrorCode.NotFound,
178
182
  when: 'No item matched the query',
@@ -262,7 +266,9 @@ Available skills:
262
266
  | `add-service` | Scaffold a new service integration |
263
267
  | `add-test` | Scaffold test file for a tool, resource, or service |
264
268
  | `field-test` | Exercise tools/resources/prompts with real inputs, verify behavior, report issues |
265
- | `tool-defs-analysis` | Read-only audit of MCP definition language (voice, leaks, recovery hints, structure) |
269
+ | `code-simplifier` | Post-session code review and cleanup against `git diff` — modernize syntax, consolidate duplication, align with codebase |
270
+ | `git-wrapup` | Land working-tree changes as a versioned commit + annotated tag — version bump, changelog, verify, tag. Local only. |
271
+ | `tool-defs-analysis` | Read-only audit of MCP definition language across the surface — voice, leaks, defaults, recovery hints, output descriptions |
266
272
  | `devcheck` | Lint, format, typecheck, audit |
267
273
  | `security-pass` | Audit server for MCP-flavored security gaps: output injection, scope blast radius, input sinks, tenant isolation |
268
274
  | `polish-docs-meta` | Finalize docs, README, metadata, and agent protocol for shipping |
@@ -275,13 +281,12 @@ Available skills:
275
281
  | `api-config` | AppConfig, parseConfig, env vars |
276
282
  | `api-context` | Context interface, logger, state, progress |
277
283
  | `api-errors` | McpError, JsonRpcErrorCode, error patterns |
278
- | `api-linter` | MCP definition linter rules reference (every rule ID + fix) |
284
+ | `api-linter` | Definition linter rule catalog invoked by `bun run lint:mcp` and `devcheck` |
279
285
  | `api-services` | LLM, Speech, Graph services |
280
286
  | `api-telemetry` | OTel catalog: spans, metrics, completion logs, env config, cardinality rules |
281
287
  | `api-testing` | createMockContext, test patterns |
282
288
  | `api-utils` | Formatting, parsing, security, pagination, scheduling, telemetry helpers |
283
289
  | `api-workers` | Cloudflare Workers runtime |
284
- | `migrate-mcp-ts-template` | Migrate a template fork to use `@cyanheads/mcp-ts-core` as a package |
285
290
 
286
291
  When you complete a skill's checklist, check the boxes and add a completion timestamp at the end (e.g., `Completed: 2026-03-11`).
287
292
 
@@ -298,7 +303,8 @@ When you complete a skill's checklist, check the boxes and add a completion time
298
303
  | `bun run audit:refresh` | Delete `bun.lock`, reinstall, and re-run `bun audit`. Use when `devcheck` flags a transitive advisory — Bun's `update` is sticky on transitive resolutions, so the advisory may be a stale-lockfile false positive. If it survives the refresh, it's real. |
299
304
  | `bun run tree` | Generate directory structure doc |
300
305
  | `bun run list-skills` | Print skill index from `skills/` frontmatter |
301
- | `bun run format` | Auto-fix formatting |
306
+ | `bun run format` | Auto-fix formatting (safe fixes only) |
307
+ | `bun run format:unsafe` | Also apply Biome's unsafe autofixes — review the diff; they can change behavior |
302
308
  | `bun run lint:mcp` | Validate MCP definitions |
303
309
  | `bun run lint:packaging` | Validate env var alignment between `manifest.json` and `server.json` |
304
310
  | `bun run bundle` | Build and pack as `.mcpb` for one-click Claude Desktop install |
@@ -316,30 +322,7 @@ When you complete a skill's checklist, check the boxes and add a completion time
316
322
 
317
323
  **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.
318
324
 
319
- **README install badges** drop these in to give users one-click install paths:
320
-
321
- | Client | Mechanism |
322
- |:-------|:----------|
323
- | Claude Desktop | Browser downloads `.mcpb` from latest GitHub Release; OS file handler routes to Claude Desktop. |
324
- | Cursor | `https://cursor.com/en/install-mcp` with base64 JSON config. |
325
- | VS Code | `vscode:mcp/install?...` wrapped in `https://vscode.dev/redirect?url=` (GitHub strips non-HTTP schemes). |
326
- | Claude Code / Codex | CLI only — no URL scheme. |
327
-
328
- ```markdown
329
- [![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)
330
- [![Install in Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en/install-mcp?name=calculator-mcp-server&config=<BASE64_CONFIG>)
331
- [![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>)
332
- ```
333
-
334
- Generate encoded configs:
335
-
336
- ```bash
337
- # Cursor
338
- echo -n '{"command":"npx -y @cyanheads/calculator-mcp-server"}' | base64
339
-
340
- # VS Code
341
- node -p 'encodeURIComponent(JSON.stringify({name:"@cyanheads/calculator-mcp-server",command:"npx",args:["-y","@cyanheads/calculator-mcp-server"]}))'
342
- ```
325
+ **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`.
343
326
 
344
327
  ---
345
328
 
@@ -362,8 +345,12 @@ security: false # optional — true flags security fi
362
345
 
363
346
  `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`.
364
347
 
348
+ `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.
349
+
365
350
  **Section order** (Keep a Changelog): Added, Changed, Deprecated, Removed, Fixed, Security. Include only sections with entries — don't ship empty headers.
366
351
 
352
+ **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.
353
+
367
354
  ---
368
355
 
369
356
  ## Publishing
@@ -425,4 +412,7 @@ import { getServerConfig } from '@/config/server-config.js';
425
412
  - [ ] `format()` renders all data the LLM needs — different clients forward different surfaces (Claude Code → `structuredContent`, Claude Desktop → `content[]`); both must carry the same data
426
413
  - [ ] Registered in `createApp()` arrays (directly or via barrel exports)
427
414
  - [ ] Tests use `createMockContext()` from `@cyanheads/mcp-ts-core/testing`
415
+ - [ ] `.codex-plugin/plugin.json` populated — `name`, `version`, `description`, `repository`, `license` from `package.json`; `interface.displayName` = package name; `interface.shortDescription` from `package.json` description
416
+ - [ ] `.codex-plugin/mcp.json` updated — server name key matches `package.json` name; env vars added for any required API keys
417
+ - [ ] `.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
428
418
  - [ ] `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.24
5
- **Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.9.6`
4
+ **Version:** 0.1.26
5
+ **Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.9.16`
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
 
@@ -159,6 +160,7 @@ Handlers receive a unified `ctx` object. Key properties:
159
160
  | `ctx.sample` | Request LLM completion from the client. **Check for presence first:** `if (ctx.sample) { ... }` |
160
161
  | `ctx.signal` | `AbortSignal` for cancellation. |
161
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. |
162
164
  | `ctx.requestId` | Unique request ID. |
163
165
  | `ctx.tenantId` | Tenant ID from JWT or `'default'` for stdio. |
164
166
 
@@ -173,6 +175,8 @@ Handlers throw — the framework catches, classifies, and formats.
173
175
  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.
174
176
 
175
177
  ```ts
178
+ import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
179
+
176
180
  errors: [
177
181
  { reason: 'no_match', code: JsonRpcErrorCode.NotFound,
178
182
  when: 'No item matched the query',
@@ -262,7 +266,9 @@ Available skills:
262
266
  | `add-service` | Scaffold a new service integration |
263
267
  | `add-test` | Scaffold test file for a tool, resource, or service |
264
268
  | `field-test` | Exercise tools/resources/prompts with real inputs, verify behavior, report issues |
265
- | `tool-defs-analysis` | Read-only audit of MCP definition language (voice, leaks, recovery hints, structure) |
269
+ | `code-simplifier` | Post-session code review and cleanup against `git diff` — modernize syntax, consolidate duplication, align with codebase |
270
+ | `git-wrapup` | Land working-tree changes as a versioned commit + annotated tag — version bump, changelog, verify, tag. Local only. |
271
+ | `tool-defs-analysis` | Read-only audit of MCP definition language across the surface — voice, leaks, defaults, recovery hints, output descriptions |
266
272
  | `devcheck` | Lint, format, typecheck, audit |
267
273
  | `security-pass` | Audit server for MCP-flavored security gaps: output injection, scope blast radius, input sinks, tenant isolation |
268
274
  | `polish-docs-meta` | Finalize docs, README, metadata, and agent protocol for shipping |
@@ -275,13 +281,12 @@ Available skills:
275
281
  | `api-config` | AppConfig, parseConfig, env vars |
276
282
  | `api-context` | Context interface, logger, state, progress |
277
283
  | `api-errors` | McpError, JsonRpcErrorCode, error patterns |
278
- | `api-linter` | MCP definition linter rules reference (every rule ID + fix) |
284
+ | `api-linter` | Definition linter rule catalog invoked by `bun run lint:mcp` and `devcheck` |
279
285
  | `api-services` | LLM, Speech, Graph services |
280
286
  | `api-telemetry` | OTel catalog: spans, metrics, completion logs, env config, cardinality rules |
281
287
  | `api-testing` | createMockContext, test patterns |
282
288
  | `api-utils` | Formatting, parsing, security, pagination, scheduling, telemetry helpers |
283
289
  | `api-workers` | Cloudflare Workers runtime |
284
- | `migrate-mcp-ts-template` | Migrate a template fork to use `@cyanheads/mcp-ts-core` as a package |
285
290
 
286
291
  When you complete a skill's checklist, check the boxes and add a completion timestamp at the end (e.g., `Completed: 2026-03-11`).
287
292
 
@@ -298,7 +303,8 @@ When you complete a skill's checklist, check the boxes and add a completion time
298
303
  | `bun run audit:refresh` | Delete `bun.lock`, reinstall, and re-run `bun audit`. Use when `devcheck` flags a transitive advisory — Bun's `update` is sticky on transitive resolutions, so the advisory may be a stale-lockfile false positive. If it survives the refresh, it's real. |
299
304
  | `bun run tree` | Generate directory structure doc |
300
305
  | `bun run list-skills` | Print skill index from `skills/` frontmatter |
301
- | `bun run format` | Auto-fix formatting |
306
+ | `bun run format` | Auto-fix formatting (safe fixes only) |
307
+ | `bun run format:unsafe` | Also apply Biome's unsafe autofixes — review the diff; they can change behavior |
302
308
  | `bun run lint:mcp` | Validate MCP definitions |
303
309
  | `bun run lint:packaging` | Validate env var alignment between `manifest.json` and `server.json` |
304
310
  | `bun run bundle` | Build and pack as `.mcpb` for one-click Claude Desktop install |
@@ -316,30 +322,7 @@ When you complete a skill's checklist, check the boxes and add a completion time
316
322
 
317
323
  **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.
318
324
 
319
- **README install badges** drop these in to give users one-click install paths:
320
-
321
- | Client | Mechanism |
322
- |:-------|:----------|
323
- | Claude Desktop | Browser downloads `.mcpb` from latest GitHub Release; OS file handler routes to Claude Desktop. |
324
- | Cursor | `https://cursor.com/en/install-mcp` with base64 JSON config. |
325
- | VS Code | `vscode:mcp/install?...` wrapped in `https://vscode.dev/redirect?url=` (GitHub strips non-HTTP schemes). |
326
- | Claude Code / Codex | CLI only — no URL scheme. |
327
-
328
- ```markdown
329
- [![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)
330
- [![Install in Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en/install-mcp?name=calculator-mcp-server&config=<BASE64_CONFIG>)
331
- [![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>)
332
- ```
333
-
334
- Generate encoded configs:
335
-
336
- ```bash
337
- # Cursor
338
- echo -n '{"command":"npx -y @cyanheads/calculator-mcp-server"}' | base64
339
-
340
- # VS Code
341
- node -p 'encodeURIComponent(JSON.stringify({name:"@cyanheads/calculator-mcp-server",command:"npx",args:["-y","@cyanheads/calculator-mcp-server"]}))'
342
- ```
325
+ **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`.
343
326
 
344
327
  ---
345
328
 
@@ -362,8 +345,12 @@ security: false # optional — true flags security fi
362
345
 
363
346
  `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`.
364
347
 
348
+ `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.
349
+
365
350
  **Section order** (Keep a Changelog): Added, Changed, Deprecated, Removed, Fixed, Security. Include only sections with entries — don't ship empty headers.
366
351
 
352
+ **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.
353
+
367
354
  ---
368
355
 
369
356
  ## Publishing
@@ -425,4 +412,7 @@ import { getServerConfig } from '@/config/server-config.js';
425
412
  - [ ] `format()` renders all data the LLM needs — different clients forward different surfaces (Claude Code → `structuredContent`, Claude Desktop → `content[]`); both must carry the same data
426
413
  - [ ] Registered in `createApp()` arrays (directly or via barrel exports)
427
414
  - [ ] Tests use `createMockContext()` from `@cyanheads/mcp-ts-core/testing`
415
+ - [ ] `.codex-plugin/plugin.json` populated — `name`, `version`, `description`, `repository`, `license` from `package.json`; `interface.displayName` = package name; `interface.shortDescription` from `package.json` description
416
+ - [ ] `.codex-plugin/mcp.json` updated — server name key matches `package.json` name; env vars added for any required API keys
417
+ - [ ] `.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
428
418
  - [ ] `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.24-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.26-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 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=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
 
@@ -4,9 +4,9 @@
4
4
  */
5
5
  import { z } from '@cyanheads/mcp-ts-core';
6
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>>;
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
10
  }, z.core.$strip>;
11
11
  export type ServerConfig = z.infer<typeof ServerConfigSchema>;
12
12
  /** Lazy-parsed server config from env vars. */
@@ -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;;;;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"}
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"}
@@ -70,5 +70,5 @@ export declare const calculateTool: import("@cyanheads/mcp-ts-core").ToolDefinit
70
70
  readonly when: "Expression evaluation exceeded the configured timeout (CALC_EVALUATION_TIMEOUT_MS).";
71
71
  readonly retryable: false;
72
72
  readonly recovery: "Simplify the expression or reduce computational complexity to fit within the timeout.";
73
- }]>;
73
+ }], undefined>;
74
74
  //# sourceMappingURL=calculate.tool.d.ts.map
@@ -1 +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;AACjD,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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAqKxB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cyanheads/calculator-mcp-server",
3
- "version": "0.1.24",
3
+ "version": "0.1.26",
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",
@@ -18,7 +18,8 @@
18
18
  "audit:refresh": "rm -f bun.lock && bun install && bun audit",
19
19
  "tree": "bun scripts/tree.ts",
20
20
  "list-skills": "bun scripts/list-skills.ts",
21
- "format": "biome check --write --unsafe .",
21
+ "format": "biome check --write .",
22
+ "format:unsafe": "biome check --write --unsafe .",
22
23
  "lint:mcp": "bun scripts/lint-mcp.ts",
23
24
  "lint:packaging": "bun scripts/lint-packaging.ts",
24
25
  "bundle": "bun run build && npx -y @anthropic-ai/mcpb pack . dist/calculator-mcp-server.mcpb",
@@ -38,7 +39,10 @@
38
39
  "math",
39
40
  "mathjs",
40
41
  "llm-tools",
41
- "typescript"
42
+ "typescript",
43
+ "bun",
44
+ "stdio",
45
+ "streamable-http"
42
46
  ],
43
47
  "repository": {
44
48
  "type": "git",
@@ -72,13 +76,13 @@
72
76
  "zod": "^4.4.3"
73
77
  },
74
78
  "dependencies": {
75
- "@cyanheads/mcp-ts-core": "^0.9.6",
79
+ "@cyanheads/mcp-ts-core": "^0.9.16",
76
80
  "mathjs": "^15.2.0",
77
81
  "pino-pretty": "^13.1.3",
78
82
  "zod": "^4.4.3"
79
83
  },
80
84
  "devDependencies": {
81
- "@biomejs/biome": "^2.4.15",
85
+ "@biomejs/biome": "^2.4.16",
82
86
  "@types/node": "^25.9.1",
83
87
  "depcheck": "^1.4.7",
84
88
  "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.24",
9
+ "version": "0.1.26",
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.24",
22
+ "version": "0.1.26",
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.24",
72
+ "version": "0.1.26",
73
73
  "packageArguments": [
74
74
  {
75
75
  "type": "positional",