@cyanheads/mcp-ts-core 0.10.8 → 0.10.9

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,7 +1,7 @@
1
1
  # Developer Protocol
2
2
 
3
3
  **Package:** `@cyanheads/mcp-ts-core`
4
- **Version:** 0.10.8
4
+ **Version:** 0.10.9
5
5
  **Engines:** Bun ≥1.3.0, Node ≥24.0.0
6
6
  **MCP SDK:** `@modelcontextprotocol/sdk` ^1.29.0
7
7
  **Zod:** ^4.4.3
package/CLAUDE.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # Developer Protocol
2
2
 
3
3
  **Package:** `@cyanheads/mcp-ts-core`
4
- **Version:** 0.10.8
4
+ **Version:** 0.10.9
5
5
  **Engines:** Bun ≥1.3.0, Node ≥24.0.0
6
6
  **MCP SDK:** `@modelcontextprotocol/sdk` ^1.29.0
7
7
  **Zod:** ^4.4.3
package/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  <div align="center">
7
7
 
8
- [![Version](https://img.shields.io/badge/Version-0.10.8-blue.svg?style=flat-square)](./CHANGELOG.md) [![License](https://img.shields.io/badge/License-Apache%202.0-orange.svg?style=flat-square)](./LICENSE) [![MCP Spec](https://img.shields.io/badge/MCP%20Spec-2025--11--25-8A2BE2.svg?style=flat-square)](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/2025-11-25/changelog.mdx)
8
+ [![Version](https://img.shields.io/badge/Version-0.10.9-blue.svg?style=flat-square)](./CHANGELOG.md) [![License](https://img.shields.io/badge/License-Apache%202.0-orange.svg?style=flat-square)](./LICENSE) [![MCP Spec](https://img.shields.io/badge/MCP%20Spec-2025--11--25-8A2BE2.svg?style=flat-square)](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/2025-11-25/changelog.mdx)
9
9
 
10
10
  [![MCP SDK](https://img.shields.io/badge/MCP%20SDK-^1.29.0-green.svg?style=flat-square)](https://modelcontextprotocol.io/) [![TypeScript](https://img.shields.io/badge/TypeScript-^6.0.3-3178C6.svg?style=flat-square)](https://www.typescriptlang.org/) [![Bun](https://img.shields.io/badge/Bun-v1.3.0%2B-blueviolet.svg?style=flat-square)](https://bun.sh/)
11
11
 
@@ -0,0 +1,16 @@
1
+ ---
2
+ summary: "devcheck gains two static guards: floating dependency specifiers (latest/*/dist-tags) in package.json + bun.lock workspaces, and plugin marketplace manifest correctness (descriptions + scoped/unscoped identity)"
3
+ breaking: false
4
+ security: false
5
+ ---
6
+
7
+ # 0.10.9 — 2026-06-20
8
+
9
+ ## Added
10
+
11
+ - **`check-dependency-specifiers` devcheck step** — new `scripts/check-dependency-specifiers.ts`, registered in `ALL_CHECKS` (`Dependency Specifiers`, flag `--no-dep-specifiers`), hard-fails on floating specifiers in the manifests we control: `package.json`'s four dependency sections and `bun.lock`'s `workspaces` specifier maps (never the `packages` section, which records third-party nested declarations that legitimately float). `latest` fails in every section; `*` and the pre-release dist-tags `next`/`beta`/`canary`/`rc` fail in `dependencies`/`devDependencies` but are allowed in `peerDependencies`/`optionalDependencies` ("any host version"). Catches the case where `bun update --latest` writes a literal `latest` dist-tag into the lock's workspace map — correct at write time, so it clears every other gate, then lets the next `bun install` re-resolve the dep past the `package.json` range and past any intentional hold. Static and local (no network, no git), so it runs in the default and `--fast` passes; ships to consumers via `package.json` `files:`. ([#246](https://github.com/cyanheads/mcp-ts-core/issues/246))
12
+ - **Plugin marketplace manifest checks in `lint:packaging`** — `scripts/lint-packaging.ts` gains check 10, validating `.claude-plugin/plugin.json`, `.codex-plugin/plugin.json`, and `.codex-plugin/mcp.json` when present: non-empty descriptions, display fields (`name`, server key, `interface.displayName`) carrying the **unscoped** machine name, and the `npx -y` install arg carrying the **full** `package.json` name. An unscoped install arg for a scoped package is a guaranteed install 404 — the high-value catch. Gated by a new `devcheck.config.json` `packaging.pluginManifests` flag (default on; surfaced in `templates/devcheck.config.json`); each manifest is skipped cleanly when absent, so HTTP-only and non-plugin consumers are unaffected. The `devcheck` "Packaging" gate, previously skipped unless `manifest.json` existed, now also runs when any plugin manifest is present. `skills/polish-docs-meta` step 10 documents the automated subset. ([#240](https://github.com/cyanheads/mcp-ts-core/issues/240))
13
+
14
+ ## Changed
15
+
16
+ - **Dependency:** `@cloudflare/workers-types` 4.20260619.1 → 4.20260620.1
@@ -1,8 +1,19 @@
1
- {"level":40,"time":1781913320360,"env":"testing","version":"0.10.8","pid":20168,"transport":"http","requestId":"WSD7Y-6FNIU","timestamp":"2026-06-19T23:55:20.360Z","operation":"TransportManager.start","component":"HttpTransportSetup","msg":"MCP_ALLOWED_ORIGINS is not set — CORS is wildcard for CLI clients; browser Origin headers are restricted to loopback. Set MCP_ALLOWED_ORIGINS for production deployments accepting remote browser origins."}
2
- {"level":40,"time":1781913322185,"env":"testing","version":"0.10.8","pid":20168,"component":"HttpTransport","requestId":"Y3XD8-YV6FO","timestamp":"2026-06-19T23:55:22.184Z","operation":"HttpRpcRequest","sessionId":"not-a-real-session-1781913322182","msg":"Session validation failed - invalid or hijacked session"}
3
- {"level":50,"time":1781913329461,"env":"testing","version":"0.0.0-test","pid":20387,"requestId":"5JUEU-0VDJE","timestamp":"2026-06-19T23:55:29.461Z","operation":"HandleToolRequest","critical":false,"errorCode":-32005,"originalErrorType":"McpError","finalErrorType":"McpError","sessionId":"da08fbd6c9656cf3f0b23b60935dfa84e7923c134e40b457be98bda811ed2efc","toolName":"scoped_echo","tenantId":"authz-tenant","auth":{"sub":"authz-user","scopes":["tool:other:read"],"clientId":"authz-client","tenantId":"authz-tenant","token":"[REDACTED]"},"errorData":{"sessionId":"da08fbd6c9656cf3f0b23b60935dfa84e7923c134e40b457be98bda811ed2efc","toolName":"scoped_echo","requestId":"5JUEU-0VDJE","timestamp":"2026-06-19T23:55:29.461Z","tenantId":"authz-tenant","operation":"HandleToolRequest","auth":{"sub":"authz-user","scopes":["tool:other:read"],"clientId":"authz-client","tenantId":"authz-tenant","token":"[REDACTED]"},"originalErrorName":"McpError","originalMessage":"Insufficient permissions.","originalStack":"McpError: Insufficient permissions.\n at forbidden (file:///Users/casey/Developer/github/mcp-ts-core/dist/types-global/errors.js:84:54)\n at withRequiredScopes (file:///Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/transports/auth/lib/authUtils.js:68:15)\n at file:///Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/tools/utils/toolHandlerFactory.js:283:17\n at McpServer.executeToolHandler (file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:233:42)\n at file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:126:43\n at async wrappedHandler (file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/index.js:125:32)"},"stack":"McpError: Insufficient permissions.\n at ErrorHandler.handleError (file:///Users/casey/Developer/github/mcp-ts-core/dist/utils/internal/error-handler/errorHandler.js:170:19)\n at file:///Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/tools/utils/toolHandlerFactory.js:332:26\n at McpServer.executeToolHandler (file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:233:42)\n at file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:126:43\n at async wrappedHandler (file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/index.js:125:32)","msg":"Error in tool:scoped_echo: Insufficient permissions."}
4
- {"level":50,"time":1781913329472,"env":"testing","version":"0.0.0-test","pid":20387,"requestId":"R7MGX-J7GDG","timestamp":"2026-06-19T23:55:29.472Z","operation":"HandleToolRequest","critical":false,"errorCode":-32005,"originalErrorType":"McpError","finalErrorType":"McpError","sessionId":"d784c7b4dd86d4f145dee03c30c3a68ae51a8606097461f46ebb719cfd85d619","toolName":"scoped_echo","tenantId":"authz-tenant","auth":{"sub":"authz-user","scopes":["openid","email","profile","offline_access"],"clientId":"authz-client","tenantId":"authz-tenant","token":"[REDACTED]"},"errorData":{"sessionId":"d784c7b4dd86d4f145dee03c30c3a68ae51a8606097461f46ebb719cfd85d619","toolName":"scoped_echo","requestId":"R7MGX-J7GDG","timestamp":"2026-06-19T23:55:29.472Z","tenantId":"authz-tenant","operation":"HandleToolRequest","auth":{"sub":"authz-user","scopes":["openid","email","profile","offline_access"],"clientId":"authz-client","tenantId":"authz-tenant","token":"[REDACTED]"},"originalErrorName":"McpError","originalMessage":"Insufficient permissions.","originalStack":"McpError: Insufficient permissions.\n at forbidden (file:///Users/casey/Developer/github/mcp-ts-core/dist/types-global/errors.js:84:54)\n at withRequiredScopes (file:///Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/transports/auth/lib/authUtils.js:68:15)\n at file:///Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/tools/utils/toolHandlerFactory.js:283:17\n at McpServer.executeToolHandler (file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:233:42)\n at file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:126:43\n at async wrappedHandler (file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/index.js:125:32)"},"stack":"McpError: Insufficient permissions.\n at ErrorHandler.handleError (file:///Users/casey/Developer/github/mcp-ts-core/dist/utils/internal/error-handler/errorHandler.js:170:19)\n at file:///Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/tools/utils/toolHandlerFactory.js:332:26\n at McpServer.executeToolHandler (file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:233:42)\n at file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:126:43\n at async wrappedHandler (file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/index.js:125:32)","msg":"Error in tool:scoped_echo: Insufficient permissions."}
5
- {"level":40,"time":1781913343027,"env":"testing","version":"0.10.8","pid":20630,"transport":"http","requestId":"GF046-IMNJH","timestamp":"2026-06-19T23:55:43.027Z","operation":"TransportManager.start","component":"HttpTransportSetup","msg":"MCP_ALLOWED_ORIGINS is not set — CORS is wildcard for CLI clients; browser Origin headers are restricted to loopback. Set MCP_ALLOWED_ORIGINS for production deployments accepting remote browser origins."}
6
- {"level":40,"time":1781913344790,"env":"testing","version":"0.10.8","pid":20630,"component":"HttpTransport","requestId":"Z5YGA-X0LTR","timestamp":"2026-06-19T23:55:44.790Z","operation":"HttpRpcRequest","sessionId":"not-a-real-session-1781913344790","msg":"Session validation failed - invalid or hijacked session"}
7
- {"level":50,"time":1781913345263,"env":"testing","version":"0.0.0-test","pid":20668,"requestId":"4BROD-WQSCR","timestamp":"2026-06-19T23:55:45.262Z","operation":"HandleToolRequest","critical":false,"errorCode":-32005,"originalErrorType":"McpError","finalErrorType":"McpError","sessionId":"25c684941147a157673abe23c7519112dbe02be9c0262c28478ff1fc436ebf1b","toolName":"scoped_echo","tenantId":"authz-tenant","auth":{"sub":"authz-user","scopes":["tool:other:read"],"clientId":"authz-client","tenantId":"authz-tenant","token":"[REDACTED]"},"errorData":{"sessionId":"25c684941147a157673abe23c7519112dbe02be9c0262c28478ff1fc436ebf1b","toolName":"scoped_echo","requestId":"4BROD-WQSCR","timestamp":"2026-06-19T23:55:45.262Z","tenantId":"authz-tenant","operation":"HandleToolRequest","auth":{"sub":"authz-user","scopes":["tool:other:read"],"clientId":"authz-client","tenantId":"authz-tenant","token":"[REDACTED]"},"originalErrorName":"McpError","originalMessage":"Insufficient permissions.","originalStack":"McpError: Insufficient permissions.\n at forbidden (/Users/casey/Developer/github/mcp-ts-core/dist/types-global/errors.js:84:58)\n at withRequiredScopes (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/transports/auth/lib/authUtils.js:68:15)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/tools/utils/toolHandlerFactory.js:283:17)\n at executeToolHandler (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:231:34)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:126:43)\n at processTicksAndRejections (native:7:39)"},"stack":"McpError: Insufficient permissions.\n at handleError (/Users/casey/Developer/github/mcp-ts-core/dist/utils/internal/error-handler/errorHandler.js:170:23)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/tools/utils/toolHandlerFactory.js:332:26)\n at executeToolHandler (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:231:34)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:126:43)\n at processTicksAndRejections (native:7:39)","msg":"Error in tool:scoped_echo: Insufficient permissions."}
8
- {"level":50,"time":1781913345270,"env":"testing","version":"0.0.0-test","pid":20668,"requestId":"3OCQP-0V3O2","timestamp":"2026-06-19T23:55:45.270Z","operation":"HandleToolRequest","critical":false,"errorCode":-32005,"originalErrorType":"McpError","finalErrorType":"McpError","sessionId":"10e3337a2b2dbc0eb5bf700bf8e875b1b829ebb783a65abcf06d9ffbf3006536","toolName":"scoped_echo","tenantId":"authz-tenant","auth":{"sub":"authz-user","scopes":["openid","email","profile","offline_access"],"clientId":"authz-client","tenantId":"authz-tenant","token":"[REDACTED]"},"errorData":{"sessionId":"10e3337a2b2dbc0eb5bf700bf8e875b1b829ebb783a65abcf06d9ffbf3006536","toolName":"scoped_echo","requestId":"3OCQP-0V3O2","timestamp":"2026-06-19T23:55:45.270Z","tenantId":"authz-tenant","operation":"HandleToolRequest","auth":{"sub":"authz-user","scopes":["openid","email","profile","offline_access"],"clientId":"authz-client","tenantId":"authz-tenant","token":"[REDACTED]"},"originalErrorName":"McpError","originalMessage":"Insufficient permissions.","originalStack":"McpError: Insufficient permissions.\n at forbidden (/Users/casey/Developer/github/mcp-ts-core/dist/types-global/errors.js:84:58)\n at withRequiredScopes (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/transports/auth/lib/authUtils.js:68:15)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/tools/utils/toolHandlerFactory.js:283:17)\n at executeToolHandler (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:231:34)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:126:43)\n at processTicksAndRejections (native:7:39)"},"stack":"McpError: Insufficient permissions.\n at handleError (/Users/casey/Developer/github/mcp-ts-core/dist/utils/internal/error-handler/errorHandler.js:170:23)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/tools/utils/toolHandlerFactory.js:332:26)\n at executeToolHandler (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:231:34)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:126:43)\n at processTicksAndRejections (native:7:39)","msg":"Error in tool:scoped_echo: Insufficient permissions."}
1
+ {"level":40,"time":1781941716382,"env":"testing","version":"0.10.9","pid":63392,"transport":"http","requestId":"2MPNT-BJ5A1","timestamp":"2026-06-20T07:48:36.381Z","operation":"TransportManager.start","component":"HttpTransportSetup","msg":"MCP_ALLOWED_ORIGINS is not set — CORS is wildcard for CLI clients; browser Origin headers are restricted to loopback. Set MCP_ALLOWED_ORIGINS for production deployments accepting remote browser origins."}
2
+ {"level":40,"time":1781941718200,"env":"testing","version":"0.10.9","pid":63392,"component":"HttpTransport","requestId":"IERKD-MLXU9","timestamp":"2026-06-20T07:48:38.200Z","operation":"HttpRpcRequest","sessionId":"not-a-real-session-1781941718198","msg":"Session validation failed - invalid or hijacked session"}
3
+ {"level":50,"time":1781941725554,"env":"testing","version":"0.0.0-test","pid":63571,"requestId":"PP1XS-CJ3YO","timestamp":"2026-06-20T07:48:45.554Z","operation":"HandleToolRequest","critical":false,"errorCode":-32005,"originalErrorType":"McpError","finalErrorType":"McpError","sessionId":"1f8f79dd7650efad787547e6d186503c524849b86f7028eb0a48f8dc6f0971e5","toolName":"scoped_echo","tenantId":"authz-tenant","auth":{"sub":"authz-user","scopes":["tool:other:read"],"clientId":"authz-client","tenantId":"authz-tenant","token":"[REDACTED]"},"errorData":{"sessionId":"1f8f79dd7650efad787547e6d186503c524849b86f7028eb0a48f8dc6f0971e5","toolName":"scoped_echo","requestId":"PP1XS-CJ3YO","timestamp":"2026-06-20T07:48:45.554Z","tenantId":"authz-tenant","operation":"HandleToolRequest","auth":{"sub":"authz-user","scopes":["tool:other:read"],"clientId":"authz-client","tenantId":"authz-tenant","token":"[REDACTED]"},"originalErrorName":"McpError","originalMessage":"Insufficient permissions.","originalStack":"McpError: Insufficient permissions.\n at forbidden (file:///Users/casey/Developer/github/mcp-ts-core/dist/types-global/errors.js:84:54)\n at withRequiredScopes (file:///Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/transports/auth/lib/authUtils.js:68:15)\n at file:///Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/tools/utils/toolHandlerFactory.js:283:17\n at McpServer.executeToolHandler (file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:233:42)\n at file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:126:43\n at async wrappedHandler (file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/index.js:125:32)"},"stack":"McpError: Insufficient permissions.\n at ErrorHandler.handleError (file:///Users/casey/Developer/github/mcp-ts-core/dist/utils/internal/error-handler/errorHandler.js:170:19)\n at file:///Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/tools/utils/toolHandlerFactory.js:332:26\n at McpServer.executeToolHandler (file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:233:42)\n at file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:126:43\n at async wrappedHandler (file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/index.js:125:32)","msg":"Error in tool:scoped_echo: Insufficient permissions."}
4
+ {"level":50,"time":1781941725565,"env":"testing","version":"0.0.0-test","pid":63571,"requestId":"8R56N-EA925","timestamp":"2026-06-20T07:48:45.565Z","operation":"HandleToolRequest","critical":false,"errorCode":-32005,"originalErrorType":"McpError","finalErrorType":"McpError","sessionId":"4ff9f61440a71ba0f9c889f48708530881f35b46ef14e342bebfd3a5d386648d","toolName":"scoped_echo","tenantId":"authz-tenant","auth":{"sub":"authz-user","scopes":["openid","email","profile","offline_access"],"clientId":"authz-client","tenantId":"authz-tenant","token":"[REDACTED]"},"errorData":{"sessionId":"4ff9f61440a71ba0f9c889f48708530881f35b46ef14e342bebfd3a5d386648d","toolName":"scoped_echo","requestId":"8R56N-EA925","timestamp":"2026-06-20T07:48:45.565Z","tenantId":"authz-tenant","operation":"HandleToolRequest","auth":{"sub":"authz-user","scopes":["openid","email","profile","offline_access"],"clientId":"authz-client","tenantId":"authz-tenant","token":"[REDACTED]"},"originalErrorName":"McpError","originalMessage":"Insufficient permissions.","originalStack":"McpError: Insufficient permissions.\n at forbidden (file:///Users/casey/Developer/github/mcp-ts-core/dist/types-global/errors.js:84:54)\n at withRequiredScopes (file:///Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/transports/auth/lib/authUtils.js:68:15)\n at file:///Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/tools/utils/toolHandlerFactory.js:283:17\n at McpServer.executeToolHandler (file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:233:42)\n at file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:126:43\n at async wrappedHandler (file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/index.js:125:32)"},"stack":"McpError: Insufficient permissions.\n at ErrorHandler.handleError (file:///Users/casey/Developer/github/mcp-ts-core/dist/utils/internal/error-handler/errorHandler.js:170:19)\n at file:///Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/tools/utils/toolHandlerFactory.js:332:26\n at McpServer.executeToolHandler (file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:233:42)\n at file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:126:43\n at async wrappedHandler (file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/index.js:125:32)","msg":"Error in tool:scoped_echo: Insufficient permissions."}
5
+ {"level":40,"time":1781941739460,"env":"testing","version":"0.10.9","pid":63828,"transport":"http","requestId":"1B8KU-RX0D2","timestamp":"2026-06-20T07:48:59.460Z","operation":"TransportManager.start","component":"HttpTransportSetup","msg":"MCP_ALLOWED_ORIGINS is not set — CORS is wildcard for CLI clients; browser Origin headers are restricted to loopback. Set MCP_ALLOWED_ORIGINS for production deployments accepting remote browser origins."}
6
+ {"level":50,"time":1781941769956,"env":"testing","version":"0.0.0-test","pid":64367,"requestId":"BXZXW-ITAUJ","timestamp":"2026-06-20T07:49:29.955Z","operation":"HandleToolRequest","critical":false,"errorCode":-32005,"originalErrorType":"McpError","finalErrorType":"McpError","sessionId":"d0084a4d9af8dde128d867a6ff54d073155e05898a72f6bf5971ae8834e267b4","toolName":"scoped_echo","tenantId":"authz-tenant","auth":{"sub":"authz-user","scopes":["tool:other:read"],"clientId":"authz-client","tenantId":"authz-tenant","token":"[REDACTED]"},"errorData":{"sessionId":"d0084a4d9af8dde128d867a6ff54d073155e05898a72f6bf5971ae8834e267b4","toolName":"scoped_echo","requestId":"BXZXW-ITAUJ","timestamp":"2026-06-20T07:49:29.955Z","tenantId":"authz-tenant","operation":"HandleToolRequest","auth":{"sub":"authz-user","scopes":["tool:other:read"],"clientId":"authz-client","tenantId":"authz-tenant","token":"[REDACTED]"},"originalErrorName":"McpError","originalMessage":"Insufficient permissions.","originalStack":"McpError: Insufficient permissions.\n at forbidden (/Users/casey/Developer/github/mcp-ts-core/dist/types-global/errors.js:84:58)\n at withRequiredScopes (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/transports/auth/lib/authUtils.js:68:15)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/tools/utils/toolHandlerFactory.js:283:17)\n at executeToolHandler (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:231:34)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:126:43)\n at processTicksAndRejections (native:7:39)"},"stack":"McpError: Insufficient permissions.\n at handleError (/Users/casey/Developer/github/mcp-ts-core/dist/utils/internal/error-handler/errorHandler.js:170:23)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/tools/utils/toolHandlerFactory.js:332:26)\n at executeToolHandler (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:231:34)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:126:43)\n at processTicksAndRejections (native:7:39)","msg":"Error in tool:scoped_echo: Insufficient permissions."}
7
+ {"level":50,"time":1781941769966,"env":"testing","version":"0.0.0-test","pid":64367,"requestId":"VFS62-PJ4HJ","timestamp":"2026-06-20T07:49:29.966Z","operation":"HandleToolRequest","critical":false,"errorCode":-32005,"originalErrorType":"McpError","finalErrorType":"McpError","sessionId":"faf86ac4e0fa052ce32c646aab8dbbc7621060afc517e7dcf6a4c102cf021ee2","toolName":"scoped_echo","tenantId":"authz-tenant","auth":{"sub":"authz-user","scopes":["openid","email","profile","offline_access"],"clientId":"authz-client","tenantId":"authz-tenant","token":"[REDACTED]"},"errorData":{"sessionId":"faf86ac4e0fa052ce32c646aab8dbbc7621060afc517e7dcf6a4c102cf021ee2","toolName":"scoped_echo","requestId":"VFS62-PJ4HJ","timestamp":"2026-06-20T07:49:29.966Z","tenantId":"authz-tenant","operation":"HandleToolRequest","auth":{"sub":"authz-user","scopes":["openid","email","profile","offline_access"],"clientId":"authz-client","tenantId":"authz-tenant","token":"[REDACTED]"},"originalErrorName":"McpError","originalMessage":"Insufficient permissions.","originalStack":"McpError: Insufficient permissions.\n at forbidden (/Users/casey/Developer/github/mcp-ts-core/dist/types-global/errors.js:84:58)\n at withRequiredScopes (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/transports/auth/lib/authUtils.js:68:15)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/tools/utils/toolHandlerFactory.js:283:17)\n at executeToolHandler (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:231:34)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:126:43)\n at processTicksAndRejections (native:7:39)"},"stack":"McpError: Insufficient permissions.\n at handleError (/Users/casey/Developer/github/mcp-ts-core/dist/utils/internal/error-handler/errorHandler.js:170:23)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/tools/utils/toolHandlerFactory.js:332:26)\n at executeToolHandler (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:231:34)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:126:43)\n at processTicksAndRejections (native:7:39)","msg":"Error in tool:scoped_echo: Insufficient permissions."}
8
+ {"level":40,"time":1781941790323,"env":"testing","version":"0.10.9","pid":64810,"transport":"http","requestId":"5WVSR-FFHLN","timestamp":"2026-06-20T07:49:50.322Z","operation":"TransportManager.start","component":"HttpTransportSetup","msg":"MCP_ALLOWED_ORIGINS is not set CORS is wildcard for CLI clients; browser Origin headers are restricted to loopback. Set MCP_ALLOWED_ORIGINS for production deployments accepting remote browser origins."}
9
+ {"level":40,"time":1781941792076,"env":"testing","version":"0.10.9","pid":64810,"component":"HttpTransport","requestId":"UOW2E-42D2F","timestamp":"2026-06-20T07:49:52.076Z","operation":"HttpRpcRequest","sessionId":"not-a-real-session-1781941792076","msg":"Session validation failed - invalid or hijacked session"}
10
+ {"level":50,"time":1781941796117,"env":"testing","version":"0.0.0-test","pid":64938,"requestId":"QE8W3-P4XQM","timestamp":"2026-06-20T07:49:56.116Z","operation":"HandleToolRequest","critical":false,"errorCode":-32005,"originalErrorType":"McpError","finalErrorType":"McpError","sessionId":"cd72d96dbf83183020b6d476224a4654587c8ce298a6cac2dce03c8a8eca5391","toolName":"scoped_echo","tenantId":"authz-tenant","auth":{"sub":"authz-user","scopes":["tool:other:read"],"clientId":"authz-client","tenantId":"authz-tenant","token":"[REDACTED]"},"errorData":{"sessionId":"cd72d96dbf83183020b6d476224a4654587c8ce298a6cac2dce03c8a8eca5391","toolName":"scoped_echo","requestId":"QE8W3-P4XQM","timestamp":"2026-06-20T07:49:56.116Z","tenantId":"authz-tenant","operation":"HandleToolRequest","auth":{"sub":"authz-user","scopes":["tool:other:read"],"clientId":"authz-client","tenantId":"authz-tenant","token":"[REDACTED]"},"originalErrorName":"McpError","originalMessage":"Insufficient permissions.","originalStack":"McpError: Insufficient permissions.\n at forbidden (/Users/casey/Developer/github/mcp-ts-core/dist/types-global/errors.js:84:58)\n at withRequiredScopes (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/transports/auth/lib/authUtils.js:68:15)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/tools/utils/toolHandlerFactory.js:283:17)\n at executeToolHandler (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:231:34)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:126:43)\n at processTicksAndRejections (native:7:39)"},"stack":"McpError: Insufficient permissions.\n at handleError (/Users/casey/Developer/github/mcp-ts-core/dist/utils/internal/error-handler/errorHandler.js:170:23)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/tools/utils/toolHandlerFactory.js:332:26)\n at executeToolHandler (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:231:34)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:126:43)\n at processTicksAndRejections (native:7:39)","msg":"Error in tool:scoped_echo: Insufficient permissions."}
11
+ {"level":50,"time":1781941796125,"env":"testing","version":"0.0.0-test","pid":64938,"requestId":"O5VM6-4511G","timestamp":"2026-06-20T07:49:56.125Z","operation":"HandleToolRequest","critical":false,"errorCode":-32005,"originalErrorType":"McpError","finalErrorType":"McpError","sessionId":"d8bd62ea8033d5f366561ebe1a7edeee06ea1fd415a0485a9c8e3e0405db7813","toolName":"scoped_echo","tenantId":"authz-tenant","auth":{"sub":"authz-user","scopes":["openid","email","profile","offline_access"],"clientId":"authz-client","tenantId":"authz-tenant","token":"[REDACTED]"},"errorData":{"sessionId":"d8bd62ea8033d5f366561ebe1a7edeee06ea1fd415a0485a9c8e3e0405db7813","toolName":"scoped_echo","requestId":"O5VM6-4511G","timestamp":"2026-06-20T07:49:56.125Z","tenantId":"authz-tenant","operation":"HandleToolRequest","auth":{"sub":"authz-user","scopes":["openid","email","profile","offline_access"],"clientId":"authz-client","tenantId":"authz-tenant","token":"[REDACTED]"},"originalErrorName":"McpError","originalMessage":"Insufficient permissions.","originalStack":"McpError: Insufficient permissions.\n at forbidden (/Users/casey/Developer/github/mcp-ts-core/dist/types-global/errors.js:84:58)\n at withRequiredScopes (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/transports/auth/lib/authUtils.js:68:15)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/tools/utils/toolHandlerFactory.js:283:17)\n at executeToolHandler (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:231:34)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:126:43)\n at processTicksAndRejections (native:7:39)"},"stack":"McpError: Insufficient permissions.\n at handleError (/Users/casey/Developer/github/mcp-ts-core/dist/utils/internal/error-handler/errorHandler.js:170:23)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/tools/utils/toolHandlerFactory.js:332:26)\n at executeToolHandler (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:231:34)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:126:43)\n at processTicksAndRejections (native:7:39)","msg":"Error in tool:scoped_echo: Insufficient permissions."}
12
+ {"level":40,"time":1781941850599,"env":"testing","version":"0.10.9","pid":66654,"transport":"http","requestId":"AVHC2-TQ4WB","timestamp":"2026-06-20T07:50:50.598Z","operation":"TransportManager.start","component":"HttpTransportSetup","msg":"MCP_ALLOWED_ORIGINS is not set — CORS is wildcard for CLI clients; browser Origin headers are restricted to loopback. Set MCP_ALLOWED_ORIGINS for production deployments accepting remote browser origins."}
13
+ {"level":40,"time":1781941852475,"env":"testing","version":"0.10.9","pid":66654,"component":"HttpTransport","requestId":"IWBB2-XM5RC","timestamp":"2026-06-20T07:50:52.475Z","operation":"HttpRpcRequest","sessionId":"not-a-real-session-1781941852473","msg":"Session validation failed - invalid or hijacked session"}
14
+ {"level":50,"time":1781941859690,"env":"testing","version":"0.0.0-test","pid":66848,"requestId":"AZFXD-PQ7DK","timestamp":"2026-06-20T07:50:59.689Z","operation":"HandleToolRequest","critical":false,"errorCode":-32005,"originalErrorType":"McpError","finalErrorType":"McpError","sessionId":"85e4333dbe697b7516d227521c97236ddd17f6ec81f2c9ee0196ce2645fb0dbd","toolName":"scoped_echo","tenantId":"authz-tenant","auth":{"sub":"authz-user","scopes":["tool:other:read"],"clientId":"authz-client","tenantId":"authz-tenant","token":"[REDACTED]"},"errorData":{"sessionId":"85e4333dbe697b7516d227521c97236ddd17f6ec81f2c9ee0196ce2645fb0dbd","toolName":"scoped_echo","requestId":"AZFXD-PQ7DK","timestamp":"2026-06-20T07:50:59.689Z","tenantId":"authz-tenant","operation":"HandleToolRequest","auth":{"sub":"authz-user","scopes":["tool:other:read"],"clientId":"authz-client","tenantId":"authz-tenant","token":"[REDACTED]"},"originalErrorName":"McpError","originalMessage":"Insufficient permissions.","originalStack":"McpError: Insufficient permissions.\n at forbidden (file:///Users/casey/Developer/github/mcp-ts-core/dist/types-global/errors.js:84:54)\n at withRequiredScopes (file:///Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/transports/auth/lib/authUtils.js:68:15)\n at file:///Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/tools/utils/toolHandlerFactory.js:283:17\n at McpServer.executeToolHandler (file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:233:42)\n at file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:126:43\n at async wrappedHandler (file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/index.js:125:32)"},"stack":"McpError: Insufficient permissions.\n at ErrorHandler.handleError (file:///Users/casey/Developer/github/mcp-ts-core/dist/utils/internal/error-handler/errorHandler.js:170:19)\n at file:///Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/tools/utils/toolHandlerFactory.js:332:26\n at McpServer.executeToolHandler (file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:233:42)\n at file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:126:43\n at async wrappedHandler (file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/index.js:125:32)","msg":"Error in tool:scoped_echo: Insufficient permissions."}
15
+ {"level":50,"time":1781941859700,"env":"testing","version":"0.0.0-test","pid":66848,"requestId":"SKS94-73A9N","timestamp":"2026-06-20T07:50:59.700Z","operation":"HandleToolRequest","critical":false,"errorCode":-32005,"originalErrorType":"McpError","finalErrorType":"McpError","sessionId":"d22d4188544ccf25509b8570e83d6d33c0603fd1cf90dccbcd46321b282ba941","toolName":"scoped_echo","tenantId":"authz-tenant","auth":{"sub":"authz-user","scopes":["openid","email","profile","offline_access"],"clientId":"authz-client","tenantId":"authz-tenant","token":"[REDACTED]"},"errorData":{"sessionId":"d22d4188544ccf25509b8570e83d6d33c0603fd1cf90dccbcd46321b282ba941","toolName":"scoped_echo","requestId":"SKS94-73A9N","timestamp":"2026-06-20T07:50:59.700Z","tenantId":"authz-tenant","operation":"HandleToolRequest","auth":{"sub":"authz-user","scopes":["openid","email","profile","offline_access"],"clientId":"authz-client","tenantId":"authz-tenant","token":"[REDACTED]"},"originalErrorName":"McpError","originalMessage":"Insufficient permissions.","originalStack":"McpError: Insufficient permissions.\n at forbidden (file:///Users/casey/Developer/github/mcp-ts-core/dist/types-global/errors.js:84:54)\n at withRequiredScopes (file:///Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/transports/auth/lib/authUtils.js:68:15)\n at file:///Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/tools/utils/toolHandlerFactory.js:283:17\n at McpServer.executeToolHandler (file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:233:42)\n at file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:126:43\n at async wrappedHandler (file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/index.js:125:32)"},"stack":"McpError: Insufficient permissions.\n at ErrorHandler.handleError (file:///Users/casey/Developer/github/mcp-ts-core/dist/utils/internal/error-handler/errorHandler.js:170:19)\n at file:///Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/tools/utils/toolHandlerFactory.js:332:26\n at McpServer.executeToolHandler (file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:233:42)\n at file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:126:43\n at async wrappedHandler (file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/index.js:125:32)","msg":"Error in tool:scoped_echo: Insufficient permissions."}
16
+ {"level":40,"time":1781941873566,"env":"testing","version":"0.10.9","pid":67154,"transport":"http","requestId":"P8B3O-4P9SU","timestamp":"2026-06-20T07:51:13.566Z","operation":"TransportManager.start","component":"HttpTransportSetup","msg":"MCP_ALLOWED_ORIGINS is not set — CORS is wildcard for CLI clients; browser Origin headers are restricted to loopback. Set MCP_ALLOWED_ORIGINS for production deployments accepting remote browser origins."}
17
+ {"level":40,"time":1781941875328,"env":"testing","version":"0.10.9","pid":67154,"component":"HttpTransport","requestId":"KI665-ND0RJ","timestamp":"2026-06-20T07:51:15.328Z","operation":"HttpRpcRequest","sessionId":"not-a-real-session-1781941875328","msg":"Session validation failed - invalid or hijacked session"}
18
+ {"level":50,"time":1781941875790,"env":"testing","version":"0.0.0-test","pid":67189,"requestId":"14TZ3-3ZCS0","timestamp":"2026-06-20T07:51:15.789Z","operation":"HandleToolRequest","critical":false,"errorCode":-32005,"originalErrorType":"McpError","finalErrorType":"McpError","sessionId":"ec0f8fbb4adfb0331f4128a3485b72a67a52d2875a3260079ddfb802757ac9ba","toolName":"scoped_echo","tenantId":"authz-tenant","auth":{"sub":"authz-user","scopes":["tool:other:read"],"clientId":"authz-client","tenantId":"authz-tenant","token":"[REDACTED]"},"errorData":{"sessionId":"ec0f8fbb4adfb0331f4128a3485b72a67a52d2875a3260079ddfb802757ac9ba","toolName":"scoped_echo","requestId":"14TZ3-3ZCS0","timestamp":"2026-06-20T07:51:15.789Z","tenantId":"authz-tenant","operation":"HandleToolRequest","auth":{"sub":"authz-user","scopes":["tool:other:read"],"clientId":"authz-client","tenantId":"authz-tenant","token":"[REDACTED]"},"originalErrorName":"McpError","originalMessage":"Insufficient permissions.","originalStack":"McpError: Insufficient permissions.\n at forbidden (/Users/casey/Developer/github/mcp-ts-core/dist/types-global/errors.js:84:58)\n at withRequiredScopes (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/transports/auth/lib/authUtils.js:68:15)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/tools/utils/toolHandlerFactory.js:283:17)\n at executeToolHandler (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:231:34)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:126:43)\n at processTicksAndRejections (native:7:39)"},"stack":"McpError: Insufficient permissions.\n at handleError (/Users/casey/Developer/github/mcp-ts-core/dist/utils/internal/error-handler/errorHandler.js:170:23)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/tools/utils/toolHandlerFactory.js:332:26)\n at executeToolHandler (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:231:34)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:126:43)\n at processTicksAndRejections (native:7:39)","msg":"Error in tool:scoped_echo: Insufficient permissions."}
19
+ {"level":50,"time":1781941875797,"env":"testing","version":"0.0.0-test","pid":67189,"requestId":"SOHUW-Y0E4B","timestamp":"2026-06-20T07:51:15.797Z","operation":"HandleToolRequest","critical":false,"errorCode":-32005,"originalErrorType":"McpError","finalErrorType":"McpError","sessionId":"2113a55565c3b427bbf85447bec3eb27975594598131a4bd4dba72532b7a88b9","toolName":"scoped_echo","tenantId":"authz-tenant","auth":{"sub":"authz-user","scopes":["openid","email","profile","offline_access"],"clientId":"authz-client","tenantId":"authz-tenant","token":"[REDACTED]"},"errorData":{"sessionId":"2113a55565c3b427bbf85447bec3eb27975594598131a4bd4dba72532b7a88b9","toolName":"scoped_echo","requestId":"SOHUW-Y0E4B","timestamp":"2026-06-20T07:51:15.797Z","tenantId":"authz-tenant","operation":"HandleToolRequest","auth":{"sub":"authz-user","scopes":["openid","email","profile","offline_access"],"clientId":"authz-client","tenantId":"authz-tenant","token":"[REDACTED]"},"originalErrorName":"McpError","originalMessage":"Insufficient permissions.","originalStack":"McpError: Insufficient permissions.\n at forbidden (/Users/casey/Developer/github/mcp-ts-core/dist/types-global/errors.js:84:58)\n at withRequiredScopes (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/transports/auth/lib/authUtils.js:68:15)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/tools/utils/toolHandlerFactory.js:283:17)\n at executeToolHandler (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:231:34)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:126:43)\n at processTicksAndRejections (native:7:39)"},"stack":"McpError: Insufficient permissions.\n at handleError (/Users/casey/Developer/github/mcp-ts-core/dist/utils/internal/error-handler/errorHandler.js:170:23)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/tools/utils/toolHandlerFactory.js:332:26)\n at executeToolHandler (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:231:34)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:126:43)\n at processTicksAndRejections (native:7:39)","msg":"Error in tool:scoped_echo: Insufficient permissions."}
@@ -1,4 +1,10 @@
1
- {"level":50,"time":1781913329461,"env":"testing","version":"0.0.0-test","pid":20387,"requestId":"5JUEU-0VDJE","timestamp":"2026-06-19T23:55:29.461Z","operation":"HandleToolRequest","critical":false,"errorCode":-32005,"originalErrorType":"McpError","finalErrorType":"McpError","sessionId":"da08fbd6c9656cf3f0b23b60935dfa84e7923c134e40b457be98bda811ed2efc","toolName":"scoped_echo","tenantId":"authz-tenant","auth":{"sub":"authz-user","scopes":["tool:other:read"],"clientId":"authz-client","tenantId":"authz-tenant","token":"[REDACTED]"},"errorData":{"sessionId":"da08fbd6c9656cf3f0b23b60935dfa84e7923c134e40b457be98bda811ed2efc","toolName":"scoped_echo","requestId":"5JUEU-0VDJE","timestamp":"2026-06-19T23:55:29.461Z","tenantId":"authz-tenant","operation":"HandleToolRequest","auth":{"sub":"authz-user","scopes":["tool:other:read"],"clientId":"authz-client","tenantId":"authz-tenant","token":"[REDACTED]"},"originalErrorName":"McpError","originalMessage":"Insufficient permissions.","originalStack":"McpError: Insufficient permissions.\n at forbidden (file:///Users/casey/Developer/github/mcp-ts-core/dist/types-global/errors.js:84:54)\n at withRequiredScopes (file:///Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/transports/auth/lib/authUtils.js:68:15)\n at file:///Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/tools/utils/toolHandlerFactory.js:283:17\n at McpServer.executeToolHandler (file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:233:42)\n at file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:126:43\n at async wrappedHandler (file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/index.js:125:32)"},"stack":"McpError: Insufficient permissions.\n at ErrorHandler.handleError (file:///Users/casey/Developer/github/mcp-ts-core/dist/utils/internal/error-handler/errorHandler.js:170:19)\n at file:///Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/tools/utils/toolHandlerFactory.js:332:26\n at McpServer.executeToolHandler (file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:233:42)\n at file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:126:43\n at async wrappedHandler (file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/index.js:125:32)","msg":"Error in tool:scoped_echo: Insufficient permissions."}
2
- {"level":50,"time":1781913329472,"env":"testing","version":"0.0.0-test","pid":20387,"requestId":"R7MGX-J7GDG","timestamp":"2026-06-19T23:55:29.472Z","operation":"HandleToolRequest","critical":false,"errorCode":-32005,"originalErrorType":"McpError","finalErrorType":"McpError","sessionId":"d784c7b4dd86d4f145dee03c30c3a68ae51a8606097461f46ebb719cfd85d619","toolName":"scoped_echo","tenantId":"authz-tenant","auth":{"sub":"authz-user","scopes":["openid","email","profile","offline_access"],"clientId":"authz-client","tenantId":"authz-tenant","token":"[REDACTED]"},"errorData":{"sessionId":"d784c7b4dd86d4f145dee03c30c3a68ae51a8606097461f46ebb719cfd85d619","toolName":"scoped_echo","requestId":"R7MGX-J7GDG","timestamp":"2026-06-19T23:55:29.472Z","tenantId":"authz-tenant","operation":"HandleToolRequest","auth":{"sub":"authz-user","scopes":["openid","email","profile","offline_access"],"clientId":"authz-client","tenantId":"authz-tenant","token":"[REDACTED]"},"originalErrorName":"McpError","originalMessage":"Insufficient permissions.","originalStack":"McpError: Insufficient permissions.\n at forbidden (file:///Users/casey/Developer/github/mcp-ts-core/dist/types-global/errors.js:84:54)\n at withRequiredScopes (file:///Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/transports/auth/lib/authUtils.js:68:15)\n at file:///Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/tools/utils/toolHandlerFactory.js:283:17\n at McpServer.executeToolHandler (file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:233:42)\n at file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:126:43\n at async wrappedHandler (file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/index.js:125:32)"},"stack":"McpError: Insufficient permissions.\n at ErrorHandler.handleError (file:///Users/casey/Developer/github/mcp-ts-core/dist/utils/internal/error-handler/errorHandler.js:170:19)\n at file:///Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/tools/utils/toolHandlerFactory.js:332:26\n at McpServer.executeToolHandler (file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:233:42)\n at file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:126:43\n at async wrappedHandler (file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/index.js:125:32)","msg":"Error in tool:scoped_echo: Insufficient permissions."}
3
- {"level":50,"time":1781913345263,"env":"testing","version":"0.0.0-test","pid":20668,"requestId":"4BROD-WQSCR","timestamp":"2026-06-19T23:55:45.262Z","operation":"HandleToolRequest","critical":false,"errorCode":-32005,"originalErrorType":"McpError","finalErrorType":"McpError","sessionId":"25c684941147a157673abe23c7519112dbe02be9c0262c28478ff1fc436ebf1b","toolName":"scoped_echo","tenantId":"authz-tenant","auth":{"sub":"authz-user","scopes":["tool:other:read"],"clientId":"authz-client","tenantId":"authz-tenant","token":"[REDACTED]"},"errorData":{"sessionId":"25c684941147a157673abe23c7519112dbe02be9c0262c28478ff1fc436ebf1b","toolName":"scoped_echo","requestId":"4BROD-WQSCR","timestamp":"2026-06-19T23:55:45.262Z","tenantId":"authz-tenant","operation":"HandleToolRequest","auth":{"sub":"authz-user","scopes":["tool:other:read"],"clientId":"authz-client","tenantId":"authz-tenant","token":"[REDACTED]"},"originalErrorName":"McpError","originalMessage":"Insufficient permissions.","originalStack":"McpError: Insufficient permissions.\n at forbidden (/Users/casey/Developer/github/mcp-ts-core/dist/types-global/errors.js:84:58)\n at withRequiredScopes (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/transports/auth/lib/authUtils.js:68:15)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/tools/utils/toolHandlerFactory.js:283:17)\n at executeToolHandler (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:231:34)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:126:43)\n at processTicksAndRejections (native:7:39)"},"stack":"McpError: Insufficient permissions.\n at handleError (/Users/casey/Developer/github/mcp-ts-core/dist/utils/internal/error-handler/errorHandler.js:170:23)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/tools/utils/toolHandlerFactory.js:332:26)\n at executeToolHandler (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:231:34)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:126:43)\n at processTicksAndRejections (native:7:39)","msg":"Error in tool:scoped_echo: Insufficient permissions."}
4
- {"level":50,"time":1781913345270,"env":"testing","version":"0.0.0-test","pid":20668,"requestId":"3OCQP-0V3O2","timestamp":"2026-06-19T23:55:45.270Z","operation":"HandleToolRequest","critical":false,"errorCode":-32005,"originalErrorType":"McpError","finalErrorType":"McpError","sessionId":"10e3337a2b2dbc0eb5bf700bf8e875b1b829ebb783a65abcf06d9ffbf3006536","toolName":"scoped_echo","tenantId":"authz-tenant","auth":{"sub":"authz-user","scopes":["openid","email","profile","offline_access"],"clientId":"authz-client","tenantId":"authz-tenant","token":"[REDACTED]"},"errorData":{"sessionId":"10e3337a2b2dbc0eb5bf700bf8e875b1b829ebb783a65abcf06d9ffbf3006536","toolName":"scoped_echo","requestId":"3OCQP-0V3O2","timestamp":"2026-06-19T23:55:45.270Z","tenantId":"authz-tenant","operation":"HandleToolRequest","auth":{"sub":"authz-user","scopes":["openid","email","profile","offline_access"],"clientId":"authz-client","tenantId":"authz-tenant","token":"[REDACTED]"},"originalErrorName":"McpError","originalMessage":"Insufficient permissions.","originalStack":"McpError: Insufficient permissions.\n at forbidden (/Users/casey/Developer/github/mcp-ts-core/dist/types-global/errors.js:84:58)\n at withRequiredScopes (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/transports/auth/lib/authUtils.js:68:15)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/tools/utils/toolHandlerFactory.js:283:17)\n at executeToolHandler (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:231:34)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:126:43)\n at processTicksAndRejections (native:7:39)"},"stack":"McpError: Insufficient permissions.\n at handleError (/Users/casey/Developer/github/mcp-ts-core/dist/utils/internal/error-handler/errorHandler.js:170:23)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/tools/utils/toolHandlerFactory.js:332:26)\n at executeToolHandler (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:231:34)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:126:43)\n at processTicksAndRejections (native:7:39)","msg":"Error in tool:scoped_echo: Insufficient permissions."}
1
+ {"level":50,"time":1781941725554,"env":"testing","version":"0.0.0-test","pid":63571,"requestId":"PP1XS-CJ3YO","timestamp":"2026-06-20T07:48:45.554Z","operation":"HandleToolRequest","critical":false,"errorCode":-32005,"originalErrorType":"McpError","finalErrorType":"McpError","sessionId":"1f8f79dd7650efad787547e6d186503c524849b86f7028eb0a48f8dc6f0971e5","toolName":"scoped_echo","tenantId":"authz-tenant","auth":{"sub":"authz-user","scopes":["tool:other:read"],"clientId":"authz-client","tenantId":"authz-tenant","token":"[REDACTED]"},"errorData":{"sessionId":"1f8f79dd7650efad787547e6d186503c524849b86f7028eb0a48f8dc6f0971e5","toolName":"scoped_echo","requestId":"PP1XS-CJ3YO","timestamp":"2026-06-20T07:48:45.554Z","tenantId":"authz-tenant","operation":"HandleToolRequest","auth":{"sub":"authz-user","scopes":["tool:other:read"],"clientId":"authz-client","tenantId":"authz-tenant","token":"[REDACTED]"},"originalErrorName":"McpError","originalMessage":"Insufficient permissions.","originalStack":"McpError: Insufficient permissions.\n at forbidden (file:///Users/casey/Developer/github/mcp-ts-core/dist/types-global/errors.js:84:54)\n at withRequiredScopes (file:///Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/transports/auth/lib/authUtils.js:68:15)\n at file:///Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/tools/utils/toolHandlerFactory.js:283:17\n at McpServer.executeToolHandler (file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:233:42)\n at file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:126:43\n at async wrappedHandler (file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/index.js:125:32)"},"stack":"McpError: Insufficient permissions.\n at ErrorHandler.handleError (file:///Users/casey/Developer/github/mcp-ts-core/dist/utils/internal/error-handler/errorHandler.js:170:19)\n at file:///Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/tools/utils/toolHandlerFactory.js:332:26\n at McpServer.executeToolHandler (file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:233:42)\n at file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:126:43\n at async wrappedHandler (file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/index.js:125:32)","msg":"Error in tool:scoped_echo: Insufficient permissions."}
2
+ {"level":50,"time":1781941725565,"env":"testing","version":"0.0.0-test","pid":63571,"requestId":"8R56N-EA925","timestamp":"2026-06-20T07:48:45.565Z","operation":"HandleToolRequest","critical":false,"errorCode":-32005,"originalErrorType":"McpError","finalErrorType":"McpError","sessionId":"4ff9f61440a71ba0f9c889f48708530881f35b46ef14e342bebfd3a5d386648d","toolName":"scoped_echo","tenantId":"authz-tenant","auth":{"sub":"authz-user","scopes":["openid","email","profile","offline_access"],"clientId":"authz-client","tenantId":"authz-tenant","token":"[REDACTED]"},"errorData":{"sessionId":"4ff9f61440a71ba0f9c889f48708530881f35b46ef14e342bebfd3a5d386648d","toolName":"scoped_echo","requestId":"8R56N-EA925","timestamp":"2026-06-20T07:48:45.565Z","tenantId":"authz-tenant","operation":"HandleToolRequest","auth":{"sub":"authz-user","scopes":["openid","email","profile","offline_access"],"clientId":"authz-client","tenantId":"authz-tenant","token":"[REDACTED]"},"originalErrorName":"McpError","originalMessage":"Insufficient permissions.","originalStack":"McpError: Insufficient permissions.\n at forbidden (file:///Users/casey/Developer/github/mcp-ts-core/dist/types-global/errors.js:84:54)\n at withRequiredScopes (file:///Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/transports/auth/lib/authUtils.js:68:15)\n at file:///Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/tools/utils/toolHandlerFactory.js:283:17\n at McpServer.executeToolHandler (file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:233:42)\n at file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:126:43\n at async wrappedHandler (file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/index.js:125:32)"},"stack":"McpError: Insufficient permissions.\n at ErrorHandler.handleError (file:///Users/casey/Developer/github/mcp-ts-core/dist/utils/internal/error-handler/errorHandler.js:170:19)\n at file:///Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/tools/utils/toolHandlerFactory.js:332:26\n at McpServer.executeToolHandler (file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:233:42)\n at file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:126:43\n at async wrappedHandler (file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/index.js:125:32)","msg":"Error in tool:scoped_echo: Insufficient permissions."}
3
+ {"level":50,"time":1781941769956,"env":"testing","version":"0.0.0-test","pid":64367,"requestId":"BXZXW-ITAUJ","timestamp":"2026-06-20T07:49:29.955Z","operation":"HandleToolRequest","critical":false,"errorCode":-32005,"originalErrorType":"McpError","finalErrorType":"McpError","sessionId":"d0084a4d9af8dde128d867a6ff54d073155e05898a72f6bf5971ae8834e267b4","toolName":"scoped_echo","tenantId":"authz-tenant","auth":{"sub":"authz-user","scopes":["tool:other:read"],"clientId":"authz-client","tenantId":"authz-tenant","token":"[REDACTED]"},"errorData":{"sessionId":"d0084a4d9af8dde128d867a6ff54d073155e05898a72f6bf5971ae8834e267b4","toolName":"scoped_echo","requestId":"BXZXW-ITAUJ","timestamp":"2026-06-20T07:49:29.955Z","tenantId":"authz-tenant","operation":"HandleToolRequest","auth":{"sub":"authz-user","scopes":["tool:other:read"],"clientId":"authz-client","tenantId":"authz-tenant","token":"[REDACTED]"},"originalErrorName":"McpError","originalMessage":"Insufficient permissions.","originalStack":"McpError: Insufficient permissions.\n at forbidden (/Users/casey/Developer/github/mcp-ts-core/dist/types-global/errors.js:84:58)\n at withRequiredScopes (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/transports/auth/lib/authUtils.js:68:15)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/tools/utils/toolHandlerFactory.js:283:17)\n at executeToolHandler (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:231:34)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:126:43)\n at processTicksAndRejections (native:7:39)"},"stack":"McpError: Insufficient permissions.\n at handleError (/Users/casey/Developer/github/mcp-ts-core/dist/utils/internal/error-handler/errorHandler.js:170:23)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/tools/utils/toolHandlerFactory.js:332:26)\n at executeToolHandler (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:231:34)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:126:43)\n at processTicksAndRejections (native:7:39)","msg":"Error in tool:scoped_echo: Insufficient permissions."}
4
+ {"level":50,"time":1781941769966,"env":"testing","version":"0.0.0-test","pid":64367,"requestId":"VFS62-PJ4HJ","timestamp":"2026-06-20T07:49:29.966Z","operation":"HandleToolRequest","critical":false,"errorCode":-32005,"originalErrorType":"McpError","finalErrorType":"McpError","sessionId":"faf86ac4e0fa052ce32c646aab8dbbc7621060afc517e7dcf6a4c102cf021ee2","toolName":"scoped_echo","tenantId":"authz-tenant","auth":{"sub":"authz-user","scopes":["openid","email","profile","offline_access"],"clientId":"authz-client","tenantId":"authz-tenant","token":"[REDACTED]"},"errorData":{"sessionId":"faf86ac4e0fa052ce32c646aab8dbbc7621060afc517e7dcf6a4c102cf021ee2","toolName":"scoped_echo","requestId":"VFS62-PJ4HJ","timestamp":"2026-06-20T07:49:29.966Z","tenantId":"authz-tenant","operation":"HandleToolRequest","auth":{"sub":"authz-user","scopes":["openid","email","profile","offline_access"],"clientId":"authz-client","tenantId":"authz-tenant","token":"[REDACTED]"},"originalErrorName":"McpError","originalMessage":"Insufficient permissions.","originalStack":"McpError: Insufficient permissions.\n at forbidden (/Users/casey/Developer/github/mcp-ts-core/dist/types-global/errors.js:84:58)\n at withRequiredScopes (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/transports/auth/lib/authUtils.js:68:15)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/tools/utils/toolHandlerFactory.js:283:17)\n at executeToolHandler (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:231:34)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:126:43)\n at processTicksAndRejections (native:7:39)"},"stack":"McpError: Insufficient permissions.\n at handleError (/Users/casey/Developer/github/mcp-ts-core/dist/utils/internal/error-handler/errorHandler.js:170:23)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/tools/utils/toolHandlerFactory.js:332:26)\n at executeToolHandler (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:231:34)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:126:43)\n at processTicksAndRejections (native:7:39)","msg":"Error in tool:scoped_echo: Insufficient permissions."}
5
+ {"level":50,"time":1781941796117,"env":"testing","version":"0.0.0-test","pid":64938,"requestId":"QE8W3-P4XQM","timestamp":"2026-06-20T07:49:56.116Z","operation":"HandleToolRequest","critical":false,"errorCode":-32005,"originalErrorType":"McpError","finalErrorType":"McpError","sessionId":"cd72d96dbf83183020b6d476224a4654587c8ce298a6cac2dce03c8a8eca5391","toolName":"scoped_echo","tenantId":"authz-tenant","auth":{"sub":"authz-user","scopes":["tool:other:read"],"clientId":"authz-client","tenantId":"authz-tenant","token":"[REDACTED]"},"errorData":{"sessionId":"cd72d96dbf83183020b6d476224a4654587c8ce298a6cac2dce03c8a8eca5391","toolName":"scoped_echo","requestId":"QE8W3-P4XQM","timestamp":"2026-06-20T07:49:56.116Z","tenantId":"authz-tenant","operation":"HandleToolRequest","auth":{"sub":"authz-user","scopes":["tool:other:read"],"clientId":"authz-client","tenantId":"authz-tenant","token":"[REDACTED]"},"originalErrorName":"McpError","originalMessage":"Insufficient permissions.","originalStack":"McpError: Insufficient permissions.\n at forbidden (/Users/casey/Developer/github/mcp-ts-core/dist/types-global/errors.js:84:58)\n at withRequiredScopes (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/transports/auth/lib/authUtils.js:68:15)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/tools/utils/toolHandlerFactory.js:283:17)\n at executeToolHandler (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:231:34)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:126:43)\n at processTicksAndRejections (native:7:39)"},"stack":"McpError: Insufficient permissions.\n at handleError (/Users/casey/Developer/github/mcp-ts-core/dist/utils/internal/error-handler/errorHandler.js:170:23)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/tools/utils/toolHandlerFactory.js:332:26)\n at executeToolHandler (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:231:34)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:126:43)\n at processTicksAndRejections (native:7:39)","msg":"Error in tool:scoped_echo: Insufficient permissions."}
6
+ {"level":50,"time":1781941796125,"env":"testing","version":"0.0.0-test","pid":64938,"requestId":"O5VM6-4511G","timestamp":"2026-06-20T07:49:56.125Z","operation":"HandleToolRequest","critical":false,"errorCode":-32005,"originalErrorType":"McpError","finalErrorType":"McpError","sessionId":"d8bd62ea8033d5f366561ebe1a7edeee06ea1fd415a0485a9c8e3e0405db7813","toolName":"scoped_echo","tenantId":"authz-tenant","auth":{"sub":"authz-user","scopes":["openid","email","profile","offline_access"],"clientId":"authz-client","tenantId":"authz-tenant","token":"[REDACTED]"},"errorData":{"sessionId":"d8bd62ea8033d5f366561ebe1a7edeee06ea1fd415a0485a9c8e3e0405db7813","toolName":"scoped_echo","requestId":"O5VM6-4511G","timestamp":"2026-06-20T07:49:56.125Z","tenantId":"authz-tenant","operation":"HandleToolRequest","auth":{"sub":"authz-user","scopes":["openid","email","profile","offline_access"],"clientId":"authz-client","tenantId":"authz-tenant","token":"[REDACTED]"},"originalErrorName":"McpError","originalMessage":"Insufficient permissions.","originalStack":"McpError: Insufficient permissions.\n at forbidden (/Users/casey/Developer/github/mcp-ts-core/dist/types-global/errors.js:84:58)\n at withRequiredScopes (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/transports/auth/lib/authUtils.js:68:15)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/tools/utils/toolHandlerFactory.js:283:17)\n at executeToolHandler (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:231:34)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:126:43)\n at processTicksAndRejections (native:7:39)"},"stack":"McpError: Insufficient permissions.\n at handleError (/Users/casey/Developer/github/mcp-ts-core/dist/utils/internal/error-handler/errorHandler.js:170:23)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/tools/utils/toolHandlerFactory.js:332:26)\n at executeToolHandler (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:231:34)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:126:43)\n at processTicksAndRejections (native:7:39)","msg":"Error in tool:scoped_echo: Insufficient permissions."}
7
+ {"level":50,"time":1781941859690,"env":"testing","version":"0.0.0-test","pid":66848,"requestId":"AZFXD-PQ7DK","timestamp":"2026-06-20T07:50:59.689Z","operation":"HandleToolRequest","critical":false,"errorCode":-32005,"originalErrorType":"McpError","finalErrorType":"McpError","sessionId":"85e4333dbe697b7516d227521c97236ddd17f6ec81f2c9ee0196ce2645fb0dbd","toolName":"scoped_echo","tenantId":"authz-tenant","auth":{"sub":"authz-user","scopes":["tool:other:read"],"clientId":"authz-client","tenantId":"authz-tenant","token":"[REDACTED]"},"errorData":{"sessionId":"85e4333dbe697b7516d227521c97236ddd17f6ec81f2c9ee0196ce2645fb0dbd","toolName":"scoped_echo","requestId":"AZFXD-PQ7DK","timestamp":"2026-06-20T07:50:59.689Z","tenantId":"authz-tenant","operation":"HandleToolRequest","auth":{"sub":"authz-user","scopes":["tool:other:read"],"clientId":"authz-client","tenantId":"authz-tenant","token":"[REDACTED]"},"originalErrorName":"McpError","originalMessage":"Insufficient permissions.","originalStack":"McpError: Insufficient permissions.\n at forbidden (file:///Users/casey/Developer/github/mcp-ts-core/dist/types-global/errors.js:84:54)\n at withRequiredScopes (file:///Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/transports/auth/lib/authUtils.js:68:15)\n at file:///Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/tools/utils/toolHandlerFactory.js:283:17\n at McpServer.executeToolHandler (file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:233:42)\n at file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:126:43\n at async wrappedHandler (file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/index.js:125:32)"},"stack":"McpError: Insufficient permissions.\n at ErrorHandler.handleError (file:///Users/casey/Developer/github/mcp-ts-core/dist/utils/internal/error-handler/errorHandler.js:170:19)\n at file:///Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/tools/utils/toolHandlerFactory.js:332:26\n at McpServer.executeToolHandler (file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:233:42)\n at file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:126:43\n at async wrappedHandler (file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/index.js:125:32)","msg":"Error in tool:scoped_echo: Insufficient permissions."}
8
+ {"level":50,"time":1781941859700,"env":"testing","version":"0.0.0-test","pid":66848,"requestId":"SKS94-73A9N","timestamp":"2026-06-20T07:50:59.700Z","operation":"HandleToolRequest","critical":false,"errorCode":-32005,"originalErrorType":"McpError","finalErrorType":"McpError","sessionId":"d22d4188544ccf25509b8570e83d6d33c0603fd1cf90dccbcd46321b282ba941","toolName":"scoped_echo","tenantId":"authz-tenant","auth":{"sub":"authz-user","scopes":["openid","email","profile","offline_access"],"clientId":"authz-client","tenantId":"authz-tenant","token":"[REDACTED]"},"errorData":{"sessionId":"d22d4188544ccf25509b8570e83d6d33c0603fd1cf90dccbcd46321b282ba941","toolName":"scoped_echo","requestId":"SKS94-73A9N","timestamp":"2026-06-20T07:50:59.700Z","tenantId":"authz-tenant","operation":"HandleToolRequest","auth":{"sub":"authz-user","scopes":["openid","email","profile","offline_access"],"clientId":"authz-client","tenantId":"authz-tenant","token":"[REDACTED]"},"originalErrorName":"McpError","originalMessage":"Insufficient permissions.","originalStack":"McpError: Insufficient permissions.\n at forbidden (file:///Users/casey/Developer/github/mcp-ts-core/dist/types-global/errors.js:84:54)\n at withRequiredScopes (file:///Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/transports/auth/lib/authUtils.js:68:15)\n at file:///Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/tools/utils/toolHandlerFactory.js:283:17\n at McpServer.executeToolHandler (file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:233:42)\n at file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:126:43\n at async wrappedHandler (file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/index.js:125:32)"},"stack":"McpError: Insufficient permissions.\n at ErrorHandler.handleError (file:///Users/casey/Developer/github/mcp-ts-core/dist/utils/internal/error-handler/errorHandler.js:170:19)\n at file:///Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/tools/utils/toolHandlerFactory.js:332:26\n at McpServer.executeToolHandler (file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:233:42)\n at file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:126:43\n at async wrappedHandler (file:///Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/index.js:125:32)","msg":"Error in tool:scoped_echo: Insufficient permissions."}
9
+ {"level":50,"time":1781941875790,"env":"testing","version":"0.0.0-test","pid":67189,"requestId":"14TZ3-3ZCS0","timestamp":"2026-06-20T07:51:15.789Z","operation":"HandleToolRequest","critical":false,"errorCode":-32005,"originalErrorType":"McpError","finalErrorType":"McpError","sessionId":"ec0f8fbb4adfb0331f4128a3485b72a67a52d2875a3260079ddfb802757ac9ba","toolName":"scoped_echo","tenantId":"authz-tenant","auth":{"sub":"authz-user","scopes":["tool:other:read"],"clientId":"authz-client","tenantId":"authz-tenant","token":"[REDACTED]"},"errorData":{"sessionId":"ec0f8fbb4adfb0331f4128a3485b72a67a52d2875a3260079ddfb802757ac9ba","toolName":"scoped_echo","requestId":"14TZ3-3ZCS0","timestamp":"2026-06-20T07:51:15.789Z","tenantId":"authz-tenant","operation":"HandleToolRequest","auth":{"sub":"authz-user","scopes":["tool:other:read"],"clientId":"authz-client","tenantId":"authz-tenant","token":"[REDACTED]"},"originalErrorName":"McpError","originalMessage":"Insufficient permissions.","originalStack":"McpError: Insufficient permissions.\n at forbidden (/Users/casey/Developer/github/mcp-ts-core/dist/types-global/errors.js:84:58)\n at withRequiredScopes (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/transports/auth/lib/authUtils.js:68:15)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/tools/utils/toolHandlerFactory.js:283:17)\n at executeToolHandler (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:231:34)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:126:43)\n at processTicksAndRejections (native:7:39)"},"stack":"McpError: Insufficient permissions.\n at handleError (/Users/casey/Developer/github/mcp-ts-core/dist/utils/internal/error-handler/errorHandler.js:170:23)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/tools/utils/toolHandlerFactory.js:332:26)\n at executeToolHandler (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:231:34)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:126:43)\n at processTicksAndRejections (native:7:39)","msg":"Error in tool:scoped_echo: Insufficient permissions."}
10
+ {"level":50,"time":1781941875797,"env":"testing","version":"0.0.0-test","pid":67189,"requestId":"SOHUW-Y0E4B","timestamp":"2026-06-20T07:51:15.797Z","operation":"HandleToolRequest","critical":false,"errorCode":-32005,"originalErrorType":"McpError","finalErrorType":"McpError","sessionId":"2113a55565c3b427bbf85447bec3eb27975594598131a4bd4dba72532b7a88b9","toolName":"scoped_echo","tenantId":"authz-tenant","auth":{"sub":"authz-user","scopes":["openid","email","profile","offline_access"],"clientId":"authz-client","tenantId":"authz-tenant","token":"[REDACTED]"},"errorData":{"sessionId":"2113a55565c3b427bbf85447bec3eb27975594598131a4bd4dba72532b7a88b9","toolName":"scoped_echo","requestId":"SOHUW-Y0E4B","timestamp":"2026-06-20T07:51:15.797Z","tenantId":"authz-tenant","operation":"HandleToolRequest","auth":{"sub":"authz-user","scopes":["openid","email","profile","offline_access"],"clientId":"authz-client","tenantId":"authz-tenant","token":"[REDACTED]"},"originalErrorName":"McpError","originalMessage":"Insufficient permissions.","originalStack":"McpError: Insufficient permissions.\n at forbidden (/Users/casey/Developer/github/mcp-ts-core/dist/types-global/errors.js:84:58)\n at withRequiredScopes (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/transports/auth/lib/authUtils.js:68:15)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/tools/utils/toolHandlerFactory.js:283:17)\n at executeToolHandler (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:231:34)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:126:43)\n at processTicksAndRejections (native:7:39)"},"stack":"McpError: Insufficient permissions.\n at handleError (/Users/casey/Developer/github/mcp-ts-core/dist/utils/internal/error-handler/errorHandler.js:170:23)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/tools/utils/toolHandlerFactory.js:332:26)\n at executeToolHandler (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:231:34)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:126:43)\n at processTicksAndRejections (native:7:39)","msg":"Error in tool:scoped_echo: Insufficient permissions."}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cyanheads/mcp-ts-core",
3
- "version": "0.10.8",
3
+ "version": "0.10.9",
4
4
  "mcpName": "io.github.cyanheads/mcp-ts-core",
5
5
  "description": "Agent-native TypeScript framework for building MCP servers. Declarative definitions with auth, multi-backend storage, OpenTelemetry, and first-class support for Bun/Node/Cloudflare Workers.",
6
6
  "main": "dist/core/index.js",
@@ -10,6 +10,7 @@
10
10
  "dist/",
11
11
  "scripts/build-changelog.ts",
12
12
  "scripts/build.ts",
13
+ "scripts/check-dependency-specifiers.ts",
13
14
  "scripts/check-docs-sync.ts",
14
15
  "scripts/check-framework-antipatterns.ts",
15
16
  "scripts/check-skill-versions.ts",
@@ -198,7 +199,7 @@
198
199
  "devDependencies": {
199
200
  "@biomejs/biome": "2.5.0",
200
201
  "@cloudflare/vitest-pool-workers": "^0.16.18",
201
- "@cloudflare/workers-types": "4.20260619.1",
202
+ "@cloudflare/workers-types": "4.20260620.1",
202
203
  "@duckdb/node-api": "^1.5.4-r.1",
203
204
  "@hono/otel": "^1.1.2",
204
205
  "@opentelemetry/exporter-metrics-otlp-http": "^0.219.0",
@@ -0,0 +1,190 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * @fileoverview Rejects floating dependency specifiers — `latest`, `*`, and
4
+ * pre-release dist-tags (`next`/`beta`/`canary`/`rc`) — in the manifests we
5
+ * control: `package.json`'s dependency sections and `bun.lock`'s `workspaces`
6
+ * specifier maps. `bun update --latest` bumps `package.json` to a caret range
7
+ * but writes the literal `latest` dist-tag into the lock's workspace map; the
8
+ * concrete resolution is correct at write time, so it clears every other gate
9
+ * and ships unnoticed, letting the next `bun install` re-resolve the dep past
10
+ * the `package.json` range and past any intentional version hold (#246).
11
+ *
12
+ * Section-specific rules — `peer`/`optional` may legitimately float to "any
13
+ * host version", so `*` and dist-tags are allowed there; `latest` never is:
14
+ *
15
+ * | specifier | dependencies / devDependencies | peer / optional |
16
+ * |---------------------------|:------------------------------:|:---------------:|
17
+ * | latest | fail | fail |
18
+ * | * | fail | allow |
19
+ * | next / beta / canary / rc | fail | allow |
20
+ *
21
+ * Only the `workspaces` section of `bun.lock` is inspected — the `packages`
22
+ * section records third-party packages' own nested declarations, which can
23
+ * legitimately be `latest`/`*` (e.g. a vendored `"@edge-runtime/vm": "*"`), so
24
+ * a naive whole-file grep false-positives on those. The lock is JSONC (trailing
25
+ * commas), so it is normalized before parsing.
26
+ *
27
+ * Shipped to consumers via `package.json` `files:` because `devcheck` invokes
28
+ * it. Runs standalone (`bun run scripts/check-dependency-specifiers.ts`) and as
29
+ * a devcheck step; no network, no git — runs in the default and `--fast` passes.
30
+ *
31
+ * @module scripts/check-dependency-specifiers
32
+ */
33
+ import { existsSync, readFileSync } from 'node:fs';
34
+ import { resolve } from 'node:path';
35
+ import process from 'node:process';
36
+
37
+ const ROOT = resolve('.');
38
+
39
+ const DEP_SECTIONS = [
40
+ 'dependencies',
41
+ 'devDependencies',
42
+ 'peerDependencies',
43
+ 'optionalDependencies',
44
+ ] as const;
45
+ type DepSection = (typeof DEP_SECTIONS)[number];
46
+
47
+ /** Sections where a host project legitimately accepts "any version" (`*`/dist-tag). */
48
+ const HOST_SECTIONS = new Set<DepSection>(['peerDependencies', 'optionalDependencies']);
49
+
50
+ /** Pre-release dist-tags that float like `latest`, narrower in reach. */
51
+ const FLOATING_DIST_TAGS = new Set(['next', 'beta', 'canary', 'rc']);
52
+
53
+ interface Offender {
54
+ location: string;
55
+ name: string;
56
+ specifier: string;
57
+ }
58
+
59
+ type DepMap = Record<string, string>;
60
+ type SectionedManifest = Partial<Record<DepSection, DepMap>>;
61
+
62
+ /** A specifier floats if it can re-resolve to a different version over time. */
63
+ function isFloating(specifier: string, section: DepSection): boolean {
64
+ const spec = specifier.trim();
65
+ if (spec === 'latest') return true; // never reproducible, in any section
66
+ if (HOST_SECTIONS.has(section)) return false; // `*` / dist-tags are legitimate here
67
+ return spec === '*' || FLOATING_DIST_TAGS.has(spec);
68
+ }
69
+
70
+ /** Scan the four dependency sections of one manifest object. */
71
+ function scanManifest(manifest: SectionedManifest, label: string): Offender[] {
72
+ const offenders: Offender[] = [];
73
+ for (const section of DEP_SECTIONS) {
74
+ const deps = manifest[section];
75
+ if (!deps || typeof deps !== 'object') continue;
76
+ for (const [name, specifier] of Object.entries(deps)) {
77
+ if (typeof specifier === 'string' && isFloating(specifier, section)) {
78
+ offenders.push({ name, specifier, location: `${label} ${section}` });
79
+ }
80
+ }
81
+ }
82
+ return offenders;
83
+ }
84
+
85
+ /**
86
+ * Minimal JSONC → object parse: strips `//` and block comments and trailing
87
+ * commas while preserving string contents verbatim, then `JSON.parse`s.
88
+ * `bun.lock` is emitted with trailing commas, which strict `JSON.parse` rejects.
89
+ */
90
+ function parseJsonc<T>(text: string): T {
91
+ let out = '';
92
+ let i = 0;
93
+ const n = text.length;
94
+ while (i < n) {
95
+ const ch = text[i] as string;
96
+ if (ch === '"') {
97
+ // Copy a string literal verbatim, honoring escapes.
98
+ out += ch;
99
+ i++;
100
+ while (i < n) {
101
+ const c = text[i] as string;
102
+ out += c;
103
+ if (c === '\\') {
104
+ out += text[i + 1] ?? '';
105
+ i += 2;
106
+ continue;
107
+ }
108
+ i++;
109
+ if (c === '"') break;
110
+ }
111
+ continue;
112
+ }
113
+ if (ch === '/' && text[i + 1] === '/') {
114
+ const nl = text.indexOf('\n', i);
115
+ if (nl === -1) break;
116
+ i = nl;
117
+ continue;
118
+ }
119
+ if (ch === '/' && text[i + 1] === '*') {
120
+ const end = text.indexOf('*/', i + 2);
121
+ i = end === -1 ? n : end + 2;
122
+ continue;
123
+ }
124
+ if (ch === ',') {
125
+ // Drop the comma when the next significant char closes an object/array.
126
+ let j = i + 1;
127
+ while (j < n && /\s/.test(text[j] as string)) j++;
128
+ if (text[j] === '}' || text[j] === ']') {
129
+ i++;
130
+ continue;
131
+ }
132
+ }
133
+ out += ch;
134
+ i++;
135
+ }
136
+ return JSON.parse(out) as T;
137
+ }
138
+
139
+ const offenders: Offender[] = [];
140
+
141
+ // ── package.json (all four dependency sections) ──
142
+ const pkgPath = resolve(ROOT, 'package.json');
143
+ if (existsSync(pkgPath)) {
144
+ try {
145
+ offenders.push(
146
+ ...scanManifest(
147
+ JSON.parse(readFileSync(pkgPath, 'utf-8')) as SectionedManifest,
148
+ 'package.json',
149
+ ),
150
+ );
151
+ } catch (err) {
152
+ console.error(`Failed to parse package.json: ${err instanceof Error ? err.message : err}`);
153
+ process.exit(2);
154
+ }
155
+ }
156
+
157
+ // ── bun.lock (workspaces specifier maps only — never the `packages` section) ──
158
+ const lockPath = resolve(ROOT, 'bun.lock');
159
+ if (existsSync(lockPath)) {
160
+ try {
161
+ const lock = parseJsonc<{ workspaces?: Record<string, SectionedManifest> }>(
162
+ readFileSync(lockPath, 'utf-8'),
163
+ );
164
+ for (const [ws, manifest] of Object.entries(lock.workspaces ?? {})) {
165
+ const label = ws === '' ? 'bun.lock workspaces[root]' : `bun.lock workspaces["${ws}"]`;
166
+ offenders.push(...scanManifest(manifest, label));
167
+ }
168
+ } catch (err) {
169
+ console.error(`Failed to parse bun.lock: ${err instanceof Error ? err.message : err}`);
170
+ process.exit(2);
171
+ }
172
+ }
173
+
174
+ if (offenders.length === 0) {
175
+ console.log('No floating dependency specifiers found.');
176
+ process.exit(0);
177
+ }
178
+
179
+ const lines = [
180
+ `${offenders.length} floating dependency specifier(s) found:`,
181
+ '',
182
+ ...offenders.map((o) => ` - ${o.name} → ${o.specifier} (${o.location})`),
183
+ '',
184
+ 'Fix: pin to a concrete semver range (e.g. ^1.2.3). A `latest`/`*`/dist-tag',
185
+ 'specifier lets `bun install` re-resolve the dep past the package.json range',
186
+ 'and past any intentional hold. After `bun update --latest`, run a plain',
187
+ '`bun install` to reconcile bun.lock to the package.json ranges.',
188
+ ];
189
+ console.error(lines.join('\n'));
190
+ process.exit(1);
@@ -437,10 +437,16 @@ const ALL_CHECKS: Check[] = [
437
437
  flag: '--no-packaging',
438
438
  canFix: false,
439
439
  // Validates env var alignment between manifest.json (MCPB bundle) and
440
- // server.json (MCP Registry). Skipped cleanly when manifest.json is absent
441
- // consumers who deleted it for an HTTP-only deploy are unaffected.
440
+ // server.json (MCP Registry), plus plugin marketplace manifests (#240).
441
+ // Runs when manifest.json OR any plugin manifest is present; skipped cleanly
442
+ // when none exist — consumers on an HTTP-only deploy are unaffected.
442
443
  getCommand: () => {
443
- if (!existsSync(path.join(ROOT_DIR, 'manifest.json'))) return null;
444
+ const hasManifest = existsSync(path.join(ROOT_DIR, 'manifest.json'));
445
+ const hasPluginManifest =
446
+ existsSync(path.join(ROOT_DIR, '.claude-plugin/plugin.json')) ||
447
+ existsSync(path.join(ROOT_DIR, '.codex-plugin/plugin.json')) ||
448
+ existsSync(path.join(ROOT_DIR, '.codex-plugin/mcp.json'));
449
+ if (!hasManifest && !hasPluginManifest) return null;
444
450
  return ['bun', 'run', 'scripts/lint-packaging.ts'];
445
451
  },
446
452
  tip: (c) =>
@@ -458,6 +464,18 @@ const ALL_CHECKS: Check[] = [
458
464
  tip: (c) =>
459
465
  `Remove the flagged SDK-coupling shortcut. See ${c.bold('scripts/check-framework-antipatterns.ts')} for rule rationale.`,
460
466
  },
467
+ {
468
+ name: 'Dependency Specifiers',
469
+ flag: '--no-dep-specifiers',
470
+ canFix: false,
471
+ // Rejects floating specifiers (latest/*/dist-tags) in package.json + the
472
+ // bun.lock workspaces map (#246). Static and local — no network, no git —
473
+ // so it runs in the default and --fast passes. Shipped to consumers via
474
+ // package.json `files:`; reads package.json/bun.lock directly, no guard.
475
+ getCommand: () => ['bun', 'run', 'scripts/check-dependency-specifiers.ts'],
476
+ tip: (c) =>
477
+ `Pin the flagged dep to a concrete range; after ${c.bold('bun update --latest')} run a plain ${c.bold('bun install')} to reconcile ${c.bold('bun.lock')}.`,
478
+ },
461
479
  {
462
480
  name: 'Open-Indexed Interfaces',
463
481
  flag: '--no-open-index',
@@ -32,6 +32,15 @@
32
32
  * `createWorkerHandler()` (src/index.ts, src/worker.ts) and manifest
33
33
  * `display_name` must equal the unscoped package name; a partial
34
34
  * `name`/`title` pair warns without failing (issue #231).
35
+ * 10. Plugin marketplace manifests (`.claude-plugin/plugin.json`,
36
+ * `.codex-plugin/plugin.json`, `.codex-plugin/mcp.json`): non-empty
37
+ * descriptions, and identity/install correctness — display fields
38
+ * (`name`, server key, `interface.displayName`) carry the unscoped machine
39
+ * name while the `npx -y` install arg carries the full `package.json`
40
+ * name (scoped if scoped). An unscoped install arg for a scoped package
41
+ * is a guaranteed install 404. Gated by `devcheck.config.json`
42
+ * `packaging.pluginManifests` (default on); each manifest is skipped
43
+ * cleanly when absent (issue #240).
35
44
  *
36
45
  * Every check skips cleanly when its input is absent — consumers who deleted
37
46
  * `manifest.json` for an HTTP-only deploy, or who haven't built a bundle,
@@ -374,6 +383,128 @@ export function checkManifestIdentity(manifest: Manifest, unscopedName: string):
374
383
  return [];
375
384
  }
376
385
 
386
+ /** Parsed plugin marketplace manifests; an absent manifest is `undefined`. */
387
+ export interface PluginManifestInputs {
388
+ claudePlugin?: unknown;
389
+ codexMcp?: unknown;
390
+ codexPlugin?: unknown;
391
+ }
392
+
393
+ const isRecord = (v: unknown): v is Record<string, unknown> => typeof v === 'object' && v !== null;
394
+ const isNonEmptyString = (v: unknown): boolean => typeof v === 'string' && v.trim().length > 0;
395
+
396
+ /** The `npx -y <pkg>` install target is the arg after the `-y` flag (args[1]). */
397
+ function installArg(entry: Record<string, unknown>): unknown {
398
+ return Array.isArray(entry.args) ? entry.args[1] : undefined;
399
+ }
400
+
401
+ /**
402
+ * Check 10: plugin marketplace manifests. Display fields (`name`, server key,
403
+ * `interface.displayName`) must equal the unscoped machine name; the install
404
+ * arg must equal the full `package.json` name (the real `npx` target). Empty
405
+ * descriptions ship blank marketplace cards. Each manifest is validated only
406
+ * when present, so HTTP-only and non-plugin consumers are unaffected. The
407
+ * caller gates the whole check on `packaging.pluginManifests`.
408
+ */
409
+ export function checkPluginManifests(
410
+ inputs: PluginManifestInputs,
411
+ unscopedName: string,
412
+ fullName: string,
413
+ ): string[] {
414
+ const errors: string[] = [];
415
+ const optOut =
416
+ '(or set "packaging": { "pluginManifests": false } in devcheck.config.json to opt out)';
417
+
418
+ // ── .claude-plugin/plugin.json ──
419
+ const claude = inputs.claudePlugin;
420
+ if (isRecord(claude)) {
421
+ const f = '.claude-plugin/plugin.json';
422
+ if (!isNonEmptyString(claude.description)) {
423
+ errors.push(`${f} "description" is empty — populate it ${optOut}`);
424
+ }
425
+ if (claude.name !== unscopedName) {
426
+ errors.push(
427
+ `${f} "name" is "${String(claude.name)}" — must equal the unscoped package name "${unscopedName}"`,
428
+ );
429
+ }
430
+ const servers = claude.mcpServers;
431
+ if (isRecord(servers)) {
432
+ if (!(unscopedName in servers)) {
433
+ errors.push(
434
+ `${f} mcpServers has no "${unscopedName}" entry — the server key must be the unscoped package name`,
435
+ );
436
+ }
437
+ const entry = servers[unscopedName];
438
+ if (isRecord(entry) && installArg(entry) !== fullName) {
439
+ errors.push(
440
+ `${f} mcpServers["${unscopedName}"] install arg is "${String(installArg(entry))}" — ` +
441
+ `must be the full package name "${fullName}" (the npx -y target; an unscoped arg for a scoped package 404s)`,
442
+ );
443
+ }
444
+ }
445
+ }
446
+
447
+ // ── .codex-plugin/plugin.json ──
448
+ const codex = inputs.codexPlugin;
449
+ if (isRecord(codex)) {
450
+ const f = '.codex-plugin/plugin.json';
451
+ if (!isNonEmptyString(codex.description)) {
452
+ errors.push(`${f} "description" is empty — populate it ${optOut}`);
453
+ }
454
+ if (codex.name !== unscopedName) {
455
+ errors.push(
456
+ `${f} "name" is "${String(codex.name)}" — must equal the unscoped package name "${unscopedName}"`,
457
+ );
458
+ }
459
+ const iface = codex.interface;
460
+ if (isRecord(iface)) {
461
+ if (iface.displayName !== unscopedName) {
462
+ errors.push(
463
+ `${f} interface.displayName is "${String(iface.displayName)}" — must equal the unscoped package name "${unscopedName}"`,
464
+ );
465
+ }
466
+ if (!isNonEmptyString(iface.shortDescription)) {
467
+ errors.push(`${f} interface.shortDescription is empty — populate it ${optOut}`);
468
+ }
469
+ if (!isNonEmptyString(iface.longDescription)) {
470
+ errors.push(`${f} interface.longDescription is empty — populate it ${optOut}`);
471
+ }
472
+ } else {
473
+ errors.push(
474
+ `${f} is missing the "interface" object (displayName / shortDescription / longDescription)`,
475
+ );
476
+ }
477
+ }
478
+
479
+ // ── .codex-plugin/mcp.json ──
480
+ const codexMcp = inputs.codexMcp;
481
+ if (isRecord(codexMcp)) {
482
+ const f = '.codex-plugin/mcp.json';
483
+ if (!(unscopedName in codexMcp)) {
484
+ errors.push(
485
+ `${f} has no "${unscopedName}" server entry — the server key must be the unscoped package name`,
486
+ );
487
+ }
488
+ const entry = codexMcp[unscopedName];
489
+ if (isRecord(entry) && installArg(entry) !== fullName) {
490
+ errors.push(
491
+ `${f} "${unscopedName}" install arg is "${String(installArg(entry))}" — ` +
492
+ `must be the full package name "${fullName}" (the npx -y target)`,
493
+ );
494
+ }
495
+ }
496
+
497
+ return errors;
498
+ }
499
+
500
+ /** Read `packaging.pluginManifests` from devcheck.config.json; default on. */
501
+ function pluginManifestsEnabled(): boolean {
502
+ const cfg = tryReadJson<{ packaging?: { pluginManifests?: boolean } }>(
503
+ resolve('devcheck.config.json'),
504
+ );
505
+ return cfg?.packaging?.pluginManifests ?? true;
506
+ }
507
+
377
508
  async function main(): Promise<void> {
378
509
  const errors: string[] = [];
379
510
  const warnings: string[] = [];
@@ -496,6 +627,27 @@ async function main(): Promise<void> {
496
627
  }
497
628
  }
498
629
 
630
+ // ── Plugin marketplace manifests (check 10) ──
631
+ if (unscopedName && pkg?.name) {
632
+ if (pluginManifestsEnabled()) {
633
+ errors.push(
634
+ ...checkPluginManifests(
635
+ {
636
+ claudePlugin: tryReadJson(resolve('.claude-plugin/plugin.json')),
637
+ codexPlugin: tryReadJson(resolve('.codex-plugin/plugin.json')),
638
+ codexMcp: tryReadJson(resolve('.codex-plugin/mcp.json')),
639
+ },
640
+ unscopedName,
641
+ pkg.name,
642
+ ),
643
+ );
644
+ } else {
645
+ notes.push(
646
+ 'Plugin-manifest checks disabled via devcheck.config.json packaging.pluginManifests.',
647
+ );
648
+ }
649
+ }
650
+
499
651
  for (const note of notes) console.log(note);
500
652
  for (const warning of warnings) console.warn(` ⚠ ${warning}`);
501
653
 
@@ -4,7 +4,7 @@ description: >
4
4
  Finalize documentation and project metadata for a ship-ready MCP server. Use after implementation is complete, tests pass, and devcheck is clean. Safe to run at any stage — each step checks current state and only acts on what still needs work.
5
5
  metadata:
6
6
  author: cyanheads
7
- version: "2.8"
7
+ version: "2.9"
8
8
  audience: external
9
9
  type: workflow
10
10
  ---
@@ -169,20 +169,22 @@ Never hand-edit `CHANGELOG.md` when using this pattern — it's a build artifact
169
169
 
170
170
  ### 10. Plugin Metadata (Codex / Claude Code)
171
171
 
172
+ `lint:packaging` (run by `devcheck`) now enforces the high-value subset automatically when these manifests are present: non-empty descriptions, and identity/install correctness — display fields (`name`, server key, `interface.displayName`) must be the **unscoped** machine name, while the `npx -y` install arg must be the full `package.json` `name` (scoped if scoped). Opt out per project with `"packaging": { "pluginManifests": false }` in `devcheck.config.json`. The checks below cover the fields the gate doesn't (version / repository / license sync, category, env vars).
173
+
172
174
  If `.codex-plugin/plugin.json` exists, verify it's populated and in sync with `package.json` and `server.json`:
173
175
 
174
- - `name` matches `package.json` `name`
176
+ - `name` is the unscoped `package.json` `name` (display identity is the machine name on every surface)
175
177
  - `version` matches `package.json` `version`
176
178
  - `description` matches `package.json` `description`
177
179
  - `repository` matches `package.json` `repository.url`
178
180
  - `license` matches `package.json` `license`
179
- - `interface.displayName` = `package.json` `name`
181
+ - `interface.displayName` is the unscoped `package.json` `name`
180
182
  - `interface.shortDescription` matches `package.json` `description`
181
183
  - `interface.category` is set to a meaningful category
182
184
 
183
- If `.codex-plugin/mcp.json` exists, verify the server name key matches `package.json` `name` and env vars include any required API keys from the server config schema.
185
+ If `.codex-plugin/mcp.json` exists, verify the server-name key is the unscoped `package.json` `name`, the `npx -y` install arg is the full `package.json` `name`, and env vars include any required API keys from the server config schema.
184
186
 
185
- If `.claude-plugin/plugin.json` exists, apply the same checks: `name`, `version`, `description`, `repository`, `license` from `package.json`. Verify the inline `mcpServers` entry key matches `package.json` `name` and env vars include any required API keys.
187
+ If `.claude-plugin/plugin.json` exists, apply the same checks: `name` (unscoped), `version`, `description`, `repository`, `license` from `package.json`. Verify the inline `mcpServers` entry key is the unscoped name, its `npx -y` install arg is the full `package.json` `name`, and env vars include any required API keys.
186
188
 
187
189
  ### 11. MCPB Bundling Artifacts
188
190
 
@@ -12,5 +12,8 @@
12
12
  },
13
13
  "outdated": {
14
14
  "allowlist": []
15
+ },
16
+ "packaging": {
17
+ "pluginManifests": true
15
18
  }
16
19
  }