@cyanheads/mcp-ts-core 0.8.5 → 0.8.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +3 -5
- package/README.md +1 -1
- package/changelog/0.8.x/0.8.6.md +22 -0
- package/changelog/0.8.x/0.8.7.md +16 -0
- package/dist/logs/combined.log +4 -4
- package/dist/logs/error.log +4 -4
- package/package.json +1 -4
- package/skills/add-app-tool/SKILL.md +2 -2
- package/skills/add-resource/SKILL.md +2 -2
- package/skills/add-tool/SKILL.md +2 -2
- package/skills/field-test/SKILL.md +26 -22
- package/skills/polish-docs-meta/references/readme.md +1 -8
- package/skills/report-issue-framework/SKILL.md +1 -1
- package/skills/report-issue-local/SKILL.md +1 -1
- package/templates/AGENTS.md +0 -2
- package/templates/CLAUDE.md +0 -2
- package/templates/package.json +0 -2
package/CLAUDE.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Agent Protocol
|
|
2
2
|
|
|
3
|
-
**Package:** `@cyanheads/mcp-ts-core` · **Version:** 0.8.
|
|
3
|
+
**Package:** `@cyanheads/mcp-ts-core` · **Version:** 0.8.7
|
|
4
4
|
**npm:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) · **Docker:** [ghcr.io/cyanheads/mcp-ts-core](https://ghcr.io/cyanheads/mcp-ts-core)
|
|
5
5
|
|
|
6
6
|
> **Developer note:** Never assume. Read related files and docs before making changes. Read full file content for context. Never edit a file before reading it.
|
|
@@ -193,7 +193,7 @@ export const myTool = tool('my_tool', {
|
|
|
193
193
|
});
|
|
194
194
|
```
|
|
195
195
|
|
|
196
|
-
**Steps:** Create `src/mcp-server/tools/definitions/[name].tool.ts` (kebab-case) → use `tool('snake_case', {...})` with Zod `.describe()` on all fields → implement `handler(input, ctx)` (pure, throws on failure) → add `auth`/`format` if needed → register in `definitions/index.ts` → `bun run devcheck` → smoke-test with `
|
|
196
|
+
**Steps:** Create `src/mcp-server/tools/definitions/[name].tool.ts` (kebab-case) → use `tool('snake_case', {...})` with Zod `.describe()` on all fields → implement `handler(input, ctx)` (pure, throws on failure) → add `auth`/`format` if needed → register in `definitions/index.ts` → `bun run devcheck` → smoke-test with `bun run rebuild && bun run start:stdio` (or `start:http`).
|
|
197
197
|
|
|
198
198
|
**Schema constraint:** Input/output schemas must use JSON-Schema-serializable Zod types only. The MCP SDK converts schemas to JSON Schema for `tools/list` — non-serializable types (`z.custom()`, `z.date()`, `z.transform()`, `z.bigint()`, `z.symbol()`, `z.void()`, `z.map()`, `z.set()`, `z.function()`, `z.nan()`) cause a hard runtime failure. Use structural equivalents instead (e.g., `z.string()` with `.describe('ISO 8601 date')` instead of `z.date()`). The linter validates this at startup.
|
|
199
199
|
|
|
@@ -532,7 +532,7 @@ Detailed method signatures, options, and examples live in skill files. Read the
|
|
|
532
532
|
- **Registration:** definitions exported in `definitions/index.ts` barrel
|
|
533
533
|
- **Tests:** `createMockContext()`, `.handler()` tested directly
|
|
534
534
|
- **Gate:** `bun run devcheck` passes (includes MCP definition linting)
|
|
535
|
-
- **Smoke-test:**
|
|
535
|
+
- **Smoke-test:** `bun run rebuild && bun run start:stdio` (or `start:http`)
|
|
536
536
|
|
|
537
537
|
---
|
|
538
538
|
|
|
@@ -554,8 +554,6 @@ Detailed method signatures, options, and examples live in skill files. Read the
|
|
|
554
554
|
| `bun run lint:mcp` | Validate MCP definitions against spec |
|
|
555
555
|
| `bun run format` | Auto-fix Biome lint/format issues |
|
|
556
556
|
| `bun run test` | Unit/integration tests |
|
|
557
|
-
| `bun run dev:stdio` | Development mode (stdio) |
|
|
558
|
-
| `bun run dev:http` | Development mode (HTTP) |
|
|
559
557
|
| `bun run start:stdio` | Production mode (stdio, after build) |
|
|
560
558
|
| `bun run start:http` | Production mode (HTTP, after build) |
|
|
561
559
|
| `bun run changelog:build` | Regenerate `CHANGELOG.md` from `changelog/*.md` |
|
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
<div align="center">
|
|
7
7
|
|
|
8
|
-
[](./CHANGELOG.md) [](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/2025-11-25/changelog.mdx) [](https://modelcontextprotocol.io/) [](./LICENSE)
|
|
9
9
|
|
|
10
10
|
[](https://www.typescriptlang.org/) [](https://bun.sh/)
|
|
11
11
|
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "Remove `dev:stdio`/`dev:http` watch scripts from framework and template `package.json`; smoke-test path standardized to `bun run rebuild && bun run start:stdio` across docs and skills."
|
|
3
|
+
breaking: false
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 0.8.6 — 2026-04-29
|
|
7
|
+
|
|
8
|
+
Workflow cleanup. The `dev:stdio` / `dev:http` watch scripts overlapped with `dev` (already a `bun --watch` runner) and produced a dev-vs-prod split where smoke-tests ran against an unbuilt source tree. Standardizing on `bun run rebuild && bun run start:stdio` (or `start:http`) gives every smoke-test path the same execution surface as production.
|
|
9
|
+
|
|
10
|
+
## Removed
|
|
11
|
+
|
|
12
|
+
- **`package.json`** — `dev:stdio` and `dev:http` scripts. Use `bun run dev` for watch mode (transport via `MCP_TRANSPORT_TYPE`); use `bun run rebuild && bun run start:stdio` (or `start:http`) for production-shape smoke tests.
|
|
13
|
+
- **`templates/package.json`** — same removal in the scaffold so fresh projects don't carry the stale scripts.
|
|
14
|
+
|
|
15
|
+
## Changed
|
|
16
|
+
|
|
17
|
+
- **`AGENTS.md` / `CLAUDE.md`** — Adding a Tool steps and the Code Style & Checklist now reference `bun run rebuild && bun run start:stdio`. Commands table drops the two `dev:*` rows.
|
|
18
|
+
- **`templates/AGENTS.md` / `templates/CLAUDE.md`** — same Commands-table cleanup for scaffolded projects.
|
|
19
|
+
- **`skills/field-test/SKILL.md`** — Transport coverage section reframed: stdio is now a **boot check only** (`bun run rebuild && bun run start:stdio`, confirm clean banner + expected counts, kill it). HTTP remains the primary harness for handler behavior. Stdio inspector / mcp-cli fallbacks dropped — the boot check covers what stdio coverage was actually verifying.
|
|
20
|
+
- **`skills/add-tool/SKILL.md`** / **`skills/add-resource/SKILL.md`** / **`skills/add-app-tool/SKILL.md`** — smoke-test step and final checklist item updated to the rebuild + start path.
|
|
21
|
+
- **`skills/polish-docs-meta/references/readme.md`** — README scaffold drops the "Hot-reload dev mode" subsection; "Build and run" replaces "Build and run the production version".
|
|
22
|
+
- **`skills/report-issue-framework/SKILL.md`** / **`skills/report-issue-local/SKILL.md`** — log-attach example uses `bun run rebuild && bun run start:stdio 2>&1 | head -N` so captured logs come from the same path the bug report reproduces against.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "Remove `dev` watch script (finishes 0.8.6 dev-vs-prod cleanup); fix field-test helper state collision when concurrent sessions run from different project directories."
|
|
3
|
+
breaking: false
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 0.8.7 — 2026-04-29
|
|
7
|
+
|
|
8
|
+
Follow-up to 0.8.6 plus a field-test helper bug fix. The `dev` script was the last watch-mode entry point producing the same dev-vs-prod split 0.8.6 closed for `dev:stdio`/`dev:http`; removing it standardizes every developer and smoke-test path on `bun run rebuild && bun run start:stdio` (or `start:http`).
|
|
9
|
+
|
|
10
|
+
## Removed
|
|
11
|
+
|
|
12
|
+
- **`package.json`** — `dev` script (`bun --watch src/index.ts`). Use `bun run rebuild && bun run start:stdio` (or `start:http`) instead.
|
|
13
|
+
|
|
14
|
+
## Fixed
|
|
15
|
+
|
|
16
|
+
- **`skills/field-test/SKILL.md` v2.2 → v2.3** ([#90](https://github.com/cyanheads/mcp-ts-core/issues/90)) — Helper state and logs lived at fixed `/tmp/mcp-field-test.{env,build.log,server.log,init-*,call-body}` paths. Concurrent field-tests across different project trees silently overwrote each other's state, causing `mcp_call` to route JSON-RPC traffic to the wrong server and return another project's tool output. Helper now namespaces every per-session file under `/tmp/mcp-field-test-<8charPWDhash>` (state file, build log, server log, init/call scratch files), so parallel sessions in different directories no longer collide. Helper file path itself stays singleton (content is identical across projects).
|
package/dist/logs/combined.log
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
{"level":50,"time":
|
|
2
|
-
{"level":50,"time":
|
|
3
|
-
{"level":50,"time":
|
|
4
|
-
{"level":50,"time":
|
|
1
|
+
{"level":50,"time":1777509241429,"env":"testing","version":"0.0.0-test","pid":42732,"requestId":"95RR8-CCDL5","timestamp":"2026-04-30T00:34:01.428Z","operation":"HandleToolRequest","critical":false,"errorCode":-32005,"originalErrorType":"McpError","finalErrorType":"McpError","sessionId":"cf1e0b94b52d79d440a36946bd597ba0ff7fe2d3dfb4fdd949b5c82c5aad683d","toolName":"scoped_echo","tenantId":"authz-tenant","auth":{"sub":"authz-user","scopes":["tool:other:read"],"clientId":"authz-client","tenantId":"authz-tenant"},"errorData":{"sessionId":"cf1e0b94b52d79d440a36946bd597ba0ff7fe2d3dfb4fdd949b5c82c5aad683d","toolName":"scoped_echo","requestId":"95RR8-CCDL5","timestamp":"2026-04-30T00:34:01.428Z","tenantId":"authz-tenant","operation":"HandleToolRequest","auth":{"sub":"authz-user","scopes":["tool:other:read"],"clientId":"authz-client","tenantId":"authz-tenant"},"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:61:15)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/tools/utils/toolHandlerFactory.js:133: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:169:23)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/tools/utils/toolHandlerFactory.js:168: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."}
|
|
2
|
+
{"level":50,"time":1777509242077,"env":"testing","version":"0.8.7","pid":42736,"requestId":"UMJV2-0KT5A","timestamp":"2026-04-30T00:34:02.077Z","operation":"httpErrorHandler","critical":false,"errorCode":-32006,"originalErrorType":"McpError","finalErrorType":"McpError","path":"/mcp","method":"POST","errorData":{"path":"/mcp","method":"POST","requestId":"UMJV2-0KT5A","timestamp":"2026-04-30T00:34:02.077Z","operation":"httpErrorHandler","originalErrorName":"McpError","originalMessage":"Missing or invalid Authorization header. Bearer scheme required.","originalStack":"McpError: Missing or invalid Authorization header. Bearer scheme required.\n at unauthorized (/Users/casey/Developer/github/mcp-ts-core/dist/types-global/errors.js:86:61)\n at authMiddleware (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/transports/auth/authMiddleware.js:64:19)\n at dispatch (/Users/casey/Developer/github/mcp-ts-core/node_modules/hono/dist/compose.js:22:23)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/transports/http/httpTransport.js:232:22)\n at dispatch (/Users/casey/Developer/github/mcp-ts-core/node_modules/hono/dist/compose.js:22:23)\n at cors2 (/Users/casey/Developer/github/mcp-ts-core/node_modules/hono/dist/middleware/cors/index.js:82:11)\n at processTicksAndRejections (native:7:39)"},"stack":"McpError: Missing or invalid Authorization header. Bearer scheme required.\n at handleError (/Users/casey/Developer/github/mcp-ts-core/dist/utils/internal/error-handler/errorHandler.js:169:23)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/transports/http/httpErrorHandler.js:59:39)\n at dispatch (/Users/casey/Developer/github/mcp-ts-core/node_modules/hono/dist/compose.js:26:25)\n at processTicksAndRejections (native:7:39)","msg":"Error in httpTransport: Missing or invalid Authorization header. Bearer scheme required."}
|
|
3
|
+
{"level":50,"time":1777509242091,"env":"testing","version":"0.8.7","pid":42736,"requestId":"H705O-NGS51","timestamp":"2026-04-30T00:34:02.090Z","operation":"httpErrorHandler","critical":false,"errorCode":-32006,"originalErrorType":"McpError","finalErrorType":"McpError","path":"/mcp","method":"POST","errorData":{"path":"/mcp","method":"POST","requestId":"H705O-NGS51","timestamp":"2026-04-30T00:34:02.090Z","operation":"httpErrorHandler","originalErrorName":"McpError","originalMessage":"Token has expired.","originalStack":"McpError: Token has expired.\n at unauthorized (/Users/casey/Developer/github/mcp-ts-core/dist/types-global/errors.js:86:61)\n at handleJoseVerifyError (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/transports/auth/lib/claimParser.js:56:11)\n at verify (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/transports/auth/strategies/jwtStrategy.js:91:13)\n at processTicksAndRejections (native:7:39)"},"stack":"McpError: Token has expired.\n at handleError (/Users/casey/Developer/github/mcp-ts-core/dist/utils/internal/error-handler/errorHandler.js:169:23)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/transports/http/httpErrorHandler.js:59:39)\n at dispatch (/Users/casey/Developer/github/mcp-ts-core/node_modules/hono/dist/compose.js:26:25)\n at processTicksAndRejections (native:7:39)","msg":"Error in httpTransport: Token has expired."}
|
|
4
|
+
{"level":50,"time":1777509242094,"env":"testing","version":"0.8.7","pid":42736,"requestId":"C7EUG-OQZOM","timestamp":"2026-04-30T00:34:02.094Z","operation":"httpErrorHandler","critical":false,"errorCode":-32006,"originalErrorType":"McpError","finalErrorType":"McpError","path":"/mcp","method":"GET","errorData":{"path":"/mcp","method":"GET","requestId":"C7EUG-OQZOM","timestamp":"2026-04-30T00:34:02.094Z","operation":"httpErrorHandler","originalErrorName":"McpError","originalMessage":"Missing or invalid Authorization header. Bearer scheme required.","originalStack":"McpError: Missing or invalid Authorization header. Bearer scheme required.\n at unauthorized (/Users/casey/Developer/github/mcp-ts-core/dist/types-global/errors.js:86:61)\n at authMiddleware (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/transports/auth/authMiddleware.js:64:19)\n at dispatch (/Users/casey/Developer/github/mcp-ts-core/node_modules/hono/dist/compose.js:22:23)\n at dispatch (/Users/casey/Developer/github/mcp-ts-core/node_modules/hono/dist/compose.js:22:23)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/transports/http/httpTransport.js:232:22)\n at dispatch (/Users/casey/Developer/github/mcp-ts-core/node_modules/hono/dist/compose.js:22:23)\n at cors2 (/Users/casey/Developer/github/mcp-ts-core/node_modules/hono/dist/middleware/cors/index.js:82:11)\n at processTicksAndRejections (native:7:39)"},"stack":"McpError: Missing or invalid Authorization header. Bearer scheme required.\n at handleError (/Users/casey/Developer/github/mcp-ts-core/dist/utils/internal/error-handler/errorHandler.js:169:23)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/transports/http/httpErrorHandler.js:59:39)\n at dispatch (/Users/casey/Developer/github/mcp-ts-core/node_modules/hono/dist/compose.js:26:25)\n at processTicksAndRejections (native:7:39)","msg":"Error in httpTransport: Missing or invalid Authorization header. Bearer scheme required."}
|
package/dist/logs/error.log
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
{"level":50,"time":
|
|
2
|
-
{"level":50,"time":
|
|
3
|
-
{"level":50,"time":
|
|
4
|
-
{"level":50,"time":
|
|
1
|
+
{"level":50,"time":1777509241429,"env":"testing","version":"0.0.0-test","pid":42732,"requestId":"95RR8-CCDL5","timestamp":"2026-04-30T00:34:01.428Z","operation":"HandleToolRequest","critical":false,"errorCode":-32005,"originalErrorType":"McpError","finalErrorType":"McpError","sessionId":"cf1e0b94b52d79d440a36946bd597ba0ff7fe2d3dfb4fdd949b5c82c5aad683d","toolName":"scoped_echo","tenantId":"authz-tenant","auth":{"sub":"authz-user","scopes":["tool:other:read"],"clientId":"authz-client","tenantId":"authz-tenant"},"errorData":{"sessionId":"cf1e0b94b52d79d440a36946bd597ba0ff7fe2d3dfb4fdd949b5c82c5aad683d","toolName":"scoped_echo","requestId":"95RR8-CCDL5","timestamp":"2026-04-30T00:34:01.428Z","tenantId":"authz-tenant","operation":"HandleToolRequest","auth":{"sub":"authz-user","scopes":["tool:other:read"],"clientId":"authz-client","tenantId":"authz-tenant"},"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:61:15)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/tools/utils/toolHandlerFactory.js:133: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:169:23)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/tools/utils/toolHandlerFactory.js:168: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."}
|
|
2
|
+
{"level":50,"time":1777509242077,"env":"testing","version":"0.8.7","pid":42736,"requestId":"UMJV2-0KT5A","timestamp":"2026-04-30T00:34:02.077Z","operation":"httpErrorHandler","critical":false,"errorCode":-32006,"originalErrorType":"McpError","finalErrorType":"McpError","path":"/mcp","method":"POST","errorData":{"path":"/mcp","method":"POST","requestId":"UMJV2-0KT5A","timestamp":"2026-04-30T00:34:02.077Z","operation":"httpErrorHandler","originalErrorName":"McpError","originalMessage":"Missing or invalid Authorization header. Bearer scheme required.","originalStack":"McpError: Missing or invalid Authorization header. Bearer scheme required.\n at unauthorized (/Users/casey/Developer/github/mcp-ts-core/dist/types-global/errors.js:86:61)\n at authMiddleware (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/transports/auth/authMiddleware.js:64:19)\n at dispatch (/Users/casey/Developer/github/mcp-ts-core/node_modules/hono/dist/compose.js:22:23)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/transports/http/httpTransport.js:232:22)\n at dispatch (/Users/casey/Developer/github/mcp-ts-core/node_modules/hono/dist/compose.js:22:23)\n at cors2 (/Users/casey/Developer/github/mcp-ts-core/node_modules/hono/dist/middleware/cors/index.js:82:11)\n at processTicksAndRejections (native:7:39)"},"stack":"McpError: Missing or invalid Authorization header. Bearer scheme required.\n at handleError (/Users/casey/Developer/github/mcp-ts-core/dist/utils/internal/error-handler/errorHandler.js:169:23)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/transports/http/httpErrorHandler.js:59:39)\n at dispatch (/Users/casey/Developer/github/mcp-ts-core/node_modules/hono/dist/compose.js:26:25)\n at processTicksAndRejections (native:7:39)","msg":"Error in httpTransport: Missing or invalid Authorization header. Bearer scheme required."}
|
|
3
|
+
{"level":50,"time":1777509242091,"env":"testing","version":"0.8.7","pid":42736,"requestId":"H705O-NGS51","timestamp":"2026-04-30T00:34:02.090Z","operation":"httpErrorHandler","critical":false,"errorCode":-32006,"originalErrorType":"McpError","finalErrorType":"McpError","path":"/mcp","method":"POST","errorData":{"path":"/mcp","method":"POST","requestId":"H705O-NGS51","timestamp":"2026-04-30T00:34:02.090Z","operation":"httpErrorHandler","originalErrorName":"McpError","originalMessage":"Token has expired.","originalStack":"McpError: Token has expired.\n at unauthorized (/Users/casey/Developer/github/mcp-ts-core/dist/types-global/errors.js:86:61)\n at handleJoseVerifyError (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/transports/auth/lib/claimParser.js:56:11)\n at verify (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/transports/auth/strategies/jwtStrategy.js:91:13)\n at processTicksAndRejections (native:7:39)"},"stack":"McpError: Token has expired.\n at handleError (/Users/casey/Developer/github/mcp-ts-core/dist/utils/internal/error-handler/errorHandler.js:169:23)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/transports/http/httpErrorHandler.js:59:39)\n at dispatch (/Users/casey/Developer/github/mcp-ts-core/node_modules/hono/dist/compose.js:26:25)\n at processTicksAndRejections (native:7:39)","msg":"Error in httpTransport: Token has expired."}
|
|
4
|
+
{"level":50,"time":1777509242094,"env":"testing","version":"0.8.7","pid":42736,"requestId":"C7EUG-OQZOM","timestamp":"2026-04-30T00:34:02.094Z","operation":"httpErrorHandler","critical":false,"errorCode":-32006,"originalErrorType":"McpError","finalErrorType":"McpError","path":"/mcp","method":"GET","errorData":{"path":"/mcp","method":"GET","requestId":"C7EUG-OQZOM","timestamp":"2026-04-30T00:34:02.094Z","operation":"httpErrorHandler","originalErrorName":"McpError","originalMessage":"Missing or invalid Authorization header. Bearer scheme required.","originalStack":"McpError: Missing or invalid Authorization header. Bearer scheme required.\n at unauthorized (/Users/casey/Developer/github/mcp-ts-core/dist/types-global/errors.js:86:61)\n at authMiddleware (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/transports/auth/authMiddleware.js:64:19)\n at dispatch (/Users/casey/Developer/github/mcp-ts-core/node_modules/hono/dist/compose.js:22:23)\n at dispatch (/Users/casey/Developer/github/mcp-ts-core/node_modules/hono/dist/compose.js:22:23)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/transports/http/httpTransport.js:232:22)\n at dispatch (/Users/casey/Developer/github/mcp-ts-core/node_modules/hono/dist/compose.js:22:23)\n at cors2 (/Users/casey/Developer/github/mcp-ts-core/node_modules/hono/dist/middleware/cors/index.js:82:11)\n at processTicksAndRejections (native:7:39)"},"stack":"McpError: Missing or invalid Authorization header. Bearer scheme required.\n at handleError (/Users/casey/Developer/github/mcp-ts-core/dist/utils/internal/error-handler/errorHandler.js:169:23)\n at <anonymous> (/Users/casey/Developer/github/mcp-ts-core/dist/mcp-server/transports/http/httpErrorHandler.js:59:39)\n at dispatch (/Users/casey/Developer/github/mcp-ts-core/node_modules/hono/dist/compose.js:26:25)\n at processTicksAndRejections (native:7:39)","msg":"Error in httpTransport: Missing or invalid Authorization header. Bearer scheme required."}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cyanheads/mcp-ts-core",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.7",
|
|
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",
|
|
@@ -121,9 +121,6 @@
|
|
|
121
121
|
"start": "bun ./dist/index.js",
|
|
122
122
|
"start:stdio": "MCP_TRANSPORT_TYPE=stdio bun ./dist/index.js",
|
|
123
123
|
"start:http": "MCP_TRANSPORT_TYPE=http bun ./dist/index.js",
|
|
124
|
-
"dev": "bun --watch src/index.ts",
|
|
125
|
-
"dev:stdio": "MCP_LOG_LEVEL=debug MCP_TRANSPORT_TYPE=stdio bun --watch src/index.ts",
|
|
126
|
-
"dev:http": "MCP_LOG_LEVEL=debug MCP_TRANSPORT_TYPE=http bun --watch src/index.ts",
|
|
127
124
|
"devdocs": "bun run scripts/devdocs.ts",
|
|
128
125
|
"devcheck": "bun run scripts/devcheck.ts",
|
|
129
126
|
"rebuild": "bun run scripts/clean.ts && bun run build",
|
|
@@ -40,7 +40,7 @@ For the full API, Context interface, and error codes, read `node_modules/@cyanhe
|
|
|
40
40
|
4. **Create the app resource** at `src/mcp-server/resources/definitions/{{tool-name}}-ui.app-resource.ts`
|
|
41
41
|
5. **Register both** in the project's existing `createApp()` arrays (directly in `src/index.ts` for fresh scaffolds, or via barrels if the repo already has them)
|
|
42
42
|
6. **Run `bun run devcheck`** — the linter validates `_meta.ui` and cross-checks tool/resource pairing
|
|
43
|
-
7. **Smoke-test** with `bun run
|
|
43
|
+
7. **Smoke-test** with `bun run rebuild && bun run start:stdio` (or `start:http`)
|
|
44
44
|
|
|
45
45
|
## App Tool Template
|
|
46
46
|
|
|
@@ -239,4 +239,4 @@ If the repo already uses `definitions/index.ts` barrels, update those instead of
|
|
|
239
239
|
- [ ] UI applies host context updates via `app.onhostcontextchanged`
|
|
240
240
|
- [ ] Both registered in the project's existing `createApp()` arrays (directly or via barrels)
|
|
241
241
|
- [ ] `bun run devcheck` passes (linter validates `_meta.ui` and tool/resource pairing)
|
|
242
|
-
- [ ] Smoke-tested with `bun run
|
|
242
|
+
- [ ] Smoke-tested with `bun run rebuild && bun run start:stdio` (or `start:http`)
|
|
@@ -24,7 +24,7 @@ For the full `resource()` API, pagination utilities, and `Context` interface, re
|
|
|
24
24
|
3. **Create the file** at `src/mcp-server/resources/definitions/{{resource-name}}.resource.ts`
|
|
25
25
|
4. **Register** the resource in the project's existing `createApp()` resource list (directly in `src/index.ts` for fresh scaffolds, or via a barrel if the repo already has one)
|
|
26
26
|
5. **Run `bun run devcheck`** to verify
|
|
27
|
-
6. **Smoke-test** with `bun run
|
|
27
|
+
6. **Smoke-test** with `bun run rebuild && bun run start:stdio` (or `start:http`)
|
|
28
28
|
|
|
29
29
|
## Template
|
|
30
30
|
|
|
@@ -159,4 +159,4 @@ Beyond `description`, `params`, `handler`, and `list`, the builder also supports
|
|
|
159
159
|
- [ ] Pagination used for large result sets (`extractCursor`/`paginateArray`)
|
|
160
160
|
- [ ] Registered in the project's existing `createApp()` resource list (directly or via barrel)
|
|
161
161
|
- [ ] `bun run devcheck` passes
|
|
162
|
-
- [ ] Smoke-tested with `bun run
|
|
162
|
+
- [ ] Smoke-tested with `bun run rebuild && bun run start:stdio` (or `start:http`)
|
package/skills/add-tool/SKILL.md
CHANGED
|
@@ -23,7 +23,7 @@ For the full `tool()` API, `Context` interface, and error codes, read `node_modu
|
|
|
23
23
|
3. **Create the file** at `src/mcp-server/tools/definitions/{{tool-name}}.tool.ts`
|
|
24
24
|
4. **Register** the tool in the project's existing `createApp()` tool list (directly in `src/index.ts` for fresh scaffolds, or via a barrel if the repo already has one)
|
|
25
25
|
5. **Run `bun run devcheck`** to verify
|
|
26
|
-
6. **Smoke-test** with `bun run
|
|
26
|
+
6. **Smoke-test** with `bun run rebuild && bun run start:stdio` (or `start:http`)
|
|
27
27
|
|
|
28
28
|
## Naming
|
|
29
29
|
|
|
@@ -481,4 +481,4 @@ Large payloads burn the agent's context window. Default to curated summaries; of
|
|
|
481
481
|
- [ ] `task: true` added if the tool is long-running
|
|
482
482
|
- [ ] Registered in the project's existing `createApp()` tool list (directly or via barrel)
|
|
483
483
|
- [ ] `bun run devcheck` passes
|
|
484
|
-
- [ ] Smoke-tested with `bun run
|
|
484
|
+
- [ ] Smoke-tested with `bun run rebuild && bun run start:stdio` (or `start:http`)
|
|
@@ -4,7 +4,7 @@ description: >
|
|
|
4
4
|
Exercise tools, resources, and prompts against a live HTTP server via MCP JSON-RPC over curl. Starts the server, surfaces the catalog, runs real and adversarial inputs, and produces a tight report with concrete findings and numbered follow-up options. Use after adding or modifying definitions, or when the user asks to test, try out, or verify their MCP surface.
|
|
5
5
|
metadata:
|
|
6
6
|
author: cyanheads
|
|
7
|
-
version: "2.
|
|
7
|
+
version: "2.3"
|
|
8
8
|
audience: external
|
|
9
9
|
type: debug
|
|
10
10
|
---
|
|
@@ -17,12 +17,9 @@ Unit tests (`add-test` skill) verify handler logic with mocked context. Field te
|
|
|
17
17
|
|
|
18
18
|
### Transport coverage
|
|
19
19
|
|
|
20
|
-
This skill drives an HTTP server because curl + JSON-RPC is the most reliable harness for shell-based agents.
|
|
20
|
+
This skill drives an HTTP server because curl + JSON-RPC is the most reliable harness for shell-based agents. The same handlers run on both transports — only the framing differs — so HTTP exercises the full functional surface.
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
- **mcp-cli** (`uvx mcp-cli --stdio bun run dev:stdio`) — scriptable JSON-RPC client; best for batch/agentic testing
|
|
24
|
-
|
|
25
|
-
Adapt the test plan below the same way — universal battery on every definition, situational categories only when triggered, same error-contract verification — but call the tools through the inspector / mcp-cli rather than `mcp_call`. Pino startup + handler logs land on stderr in stdio mode (stdout is reserved for JSON-RPC), so tail with `2>/tmp/mcp-server.log` if you start the server yourself.
|
|
22
|
+
**Stdio coverage is a boot check only.** Run `bun run rebuild && bun run start:stdio`, confirm the startup logs look clean (banner, expected tool/resource counts, no errors/warnings, no missing-config gripes), then kill it. Pino logs go to stderr in stdio mode (stdout is reserved for JSON-RPC), so they print straight to the terminal when you run interactively. No need to call tools over stdio — the HTTP pass already covered handler behavior.
|
|
26
23
|
|
|
27
24
|
---
|
|
28
25
|
|
|
@@ -30,7 +27,7 @@ Adapt the test plan below the same way — universal battery on every definition
|
|
|
30
27
|
|
|
31
28
|
### 1. Start the server
|
|
32
29
|
|
|
33
|
-
Write the helper to `/tmp/mcp-field-test.sh` once, then source it in every subsequent Bash call. Helper keeps PID / URL / session id in `/tmp/mcp-field-test
|
|
30
|
+
Write the helper to `/tmp/mcp-field-test.sh` once, then source it in every subsequent Bash call. Helper keeps PID / URL / session id in a per-`$PWD` state file (`/tmp/mcp-field-test-<hash>.env`) so state survives across tool invocations and concurrent field-tests in different project trees don't clobber each other.
|
|
34
31
|
|
|
35
32
|
```bash
|
|
36
33
|
cat > /tmp/mcp-field-test.sh <<'HELPER_EOF'
|
|
@@ -39,29 +36,36 @@ cat > /tmp/mcp-field-test.sh <<'HELPER_EOF'
|
|
|
39
36
|
# Surfaces failures aggressively — field test is for finding things that fail,
|
|
40
37
|
# so the helper auto-tails logs and prints HTTP status/body on errors instead
|
|
41
38
|
# of swallowing them.
|
|
42
|
-
|
|
39
|
+
#
|
|
40
|
+
# State and log paths are namespaced by an 8-char hash of $PWD so concurrent
|
|
41
|
+
# field-tests across different project trees don't clobber each other (see
|
|
42
|
+
# https://github.com/cyanheads/mcp-ts-core/issues/90).
|
|
43
|
+
PREFIX="/tmp/mcp-field-test-$(printf '%s' "$PWD" | shasum | cut -c1-8)"
|
|
44
|
+
STATE_FILE="${PREFIX}.env"
|
|
45
|
+
BUILD_LOG="${PREFIX}-build.log"
|
|
46
|
+
SERVER_LOG="${PREFIX}-server.log"
|
|
43
47
|
[ -f "$STATE_FILE" ] && . "$STATE_FILE"
|
|
44
48
|
|
|
45
49
|
mcp_start() {
|
|
46
50
|
local dir="${1:-$PWD}"
|
|
47
51
|
echo "building $dir ..."
|
|
48
|
-
if ! (cd "$dir" && bun run rebuild)
|
|
49
|
-
echo "BUILD FAILED — last 30 lines of
|
|
50
|
-
tail -30
|
|
52
|
+
if ! (cd "$dir" && bun run rebuild) >"$BUILD_LOG" 2>&1; then
|
|
53
|
+
echo "BUILD FAILED — last 30 lines of $BUILD_LOG:"
|
|
54
|
+
tail -30 "$BUILD_LOG"
|
|
51
55
|
return 1
|
|
52
56
|
fi
|
|
53
57
|
echo "starting server ..."
|
|
54
|
-
(cd "$dir" && bun run start:http)
|
|
58
|
+
(cd "$dir" && bun run start:http) >"$SERVER_LOG" 2>&1 &
|
|
55
59
|
local pid=$!
|
|
56
60
|
local line=""
|
|
57
61
|
for _ in $(seq 1 40); do
|
|
58
|
-
line=$(grep -Eo 'listening at http://[^" ]+/mcp'
|
|
62
|
+
line=$(grep -Eo 'listening at http://[^" ]+/mcp' "$SERVER_LOG" | head -1)
|
|
59
63
|
[ -n "$line" ] && break
|
|
60
64
|
sleep 0.25
|
|
61
65
|
done
|
|
62
66
|
if [ -z "$line" ]; then
|
|
63
|
-
echo "server failed to start within 10s — last 30 lines of
|
|
64
|
-
tail -30
|
|
67
|
+
echo "server failed to start within 10s — last 30 lines of $SERVER_LOG:"
|
|
68
|
+
tail -30 "$SERVER_LOG"
|
|
65
69
|
kill "$pid" 2>/dev/null
|
|
66
70
|
return 1
|
|
67
71
|
fi
|
|
@@ -78,13 +82,13 @@ EOF
|
|
|
78
82
|
|
|
79
83
|
mcp_init() {
|
|
80
84
|
[ -z "$MCP_URL" ] && { echo "run mcp_start first"; return 1; }
|
|
81
|
-
local hdr="
|
|
82
|
-
local body_file="
|
|
85
|
+
local hdr="${PREFIX}-init-headers.txt"
|
|
86
|
+
local body_file="${PREFIX}-init-body.txt"
|
|
83
87
|
local status
|
|
84
88
|
status=$(curl -sS -D "$hdr" -o "$body_file" -w '%{http_code}' -X POST "$MCP_URL" \
|
|
85
89
|
-H "Content-Type: application/json" \
|
|
86
90
|
-H "Accept: application/json, text/event-stream" \
|
|
87
|
-
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"field-test","version":"2.
|
|
91
|
+
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"field-test","version":"2.3"}}}')
|
|
88
92
|
local sid; sid=$(grep -i '^mcp-session-id:' "$hdr" | awk '{print $2}' | tr -d '\r\n')
|
|
89
93
|
if [ -z "$sid" ]; then
|
|
90
94
|
echo "init failed — HTTP $status, no Mcp-Session-Id header returned"
|
|
@@ -122,7 +126,7 @@ mcp_call() {
|
|
|
122
126
|
else
|
|
123
127
|
body=$(printf '{"jsonrpc":"2.0","id":%d,"method":"%s","params":%s}' "$RANDOM" "$method" "$params")
|
|
124
128
|
fi
|
|
125
|
-
local resp_file="
|
|
129
|
+
local resp_file="${PREFIX}-call-body.txt"
|
|
126
130
|
local status
|
|
127
131
|
status=$(curl -sS -o "$resp_file" -w '%{http_code}' -X POST "$MCP_URL" \
|
|
128
132
|
-H "Content-Type: application/json" \
|
|
@@ -144,11 +148,11 @@ mcp_call() {
|
|
|
144
148
|
|
|
145
149
|
# Tail the server log. Useful when a call surprises you — pino startup banner,
|
|
146
150
|
# definition lint diagnostics, request handler errors, upstream calls, and
|
|
147
|
-
# rate-limit warnings live in
|
|
151
|
+
# rate-limit warnings live in the per-session server log.
|
|
148
152
|
# Usage: mcp_log [N] (default: 50 lines)
|
|
149
153
|
mcp_log() {
|
|
150
154
|
local n="${1:-50}"
|
|
151
|
-
tail -n "$n"
|
|
155
|
+
tail -n "$n" "$SERVER_LOG"
|
|
152
156
|
}
|
|
153
157
|
|
|
154
158
|
mcp_stop() {
|
|
@@ -257,7 +261,7 @@ Use `TaskCreate` — one task per definition. Mark complete as you go. Don't bat
|
|
|
257
261
|
|
|
258
262
|
For each call, capture: input sent, response (trim huge payloads to files), whether `isError: true` appeared, anything surprising (slow response, parity drift, unhelpful text, crash).
|
|
259
263
|
|
|
260
|
-
When a call surprises you — slow, hangs, returns terse output, surfaces an unhelpful error — run `. /tmp/mcp-field-test.sh && mcp_log` to tail the server log. The pino startup banner, request handler errors, upstream API call traces, and rate-limit warnings all land in
|
|
264
|
+
When a call surprises you — slow, hangs, returns terse output, surfaces an unhelpful error — run `. /tmp/mcp-field-test.sh && mcp_log` to tail the server log. The pino startup banner, request handler errors, upstream API call traces, and rate-limit warnings all land in the per-session server log (read via `mcp_log`) rather than coming back through `mcp_call`. Don't guess at runtime behavior from response text alone.
|
|
261
265
|
|
|
262
266
|
**Interpreting responses**
|
|
263
267
|
|
|
@@ -363,14 +363,7 @@ Separate from Getting Started. Show dev, build + run, and Workers/Docker deploym
|
|
|
363
363
|
|
|
364
364
|
### Local development
|
|
365
365
|
|
|
366
|
-
- **
|
|
367
|
-
|
|
368
|
-
\`\`\`sh
|
|
369
|
-
bun run dev:stdio
|
|
370
|
-
bun run dev:http
|
|
371
|
-
\`\`\`
|
|
372
|
-
|
|
373
|
-
- **Build and run the production version:**
|
|
366
|
+
- **Build and run:**
|
|
374
367
|
|
|
375
368
|
\`\`\`sh
|
|
376
369
|
# One-time build
|
|
@@ -180,7 +180,7 @@ Combine labels: `--label "bug" --label "regression"`.
|
|
|
180
180
|
For long output, write to a file and attach:
|
|
181
181
|
|
|
182
182
|
```bash
|
|
183
|
-
bun run
|
|
183
|
+
bun run rebuild && bun run start:stdio 2>&1 | head -100 > /tmp/mcp-error.log
|
|
184
184
|
|
|
185
185
|
# As part of a new issue
|
|
186
186
|
gh issue create -R cyanheads/mcp-ts-core \
|
|
@@ -173,7 +173,7 @@ gh label create breaking-change --color d93f0b --description "Change will break
|
|
|
173
173
|
### Attaching logs or large output
|
|
174
174
|
|
|
175
175
|
```bash
|
|
176
|
-
bun run
|
|
176
|
+
bun run rebuild && bun run start:stdio 2>&1 | head -200 > /tmp/server-error.log
|
|
177
177
|
|
|
178
178
|
# As part of a new issue
|
|
179
179
|
gh issue create \
|
package/templates/AGENTS.md
CHANGED
|
@@ -288,8 +288,6 @@ When you complete a skill's checklist, check the boxes and add a completion time
|
|
|
288
288
|
| `npm run tree` | Generate directory structure doc |
|
|
289
289
|
| `npm run format` | Auto-fix formatting |
|
|
290
290
|
| `npm test` | Run tests |
|
|
291
|
-
| `npm run dev:stdio` | Dev mode (stdio) |
|
|
292
|
-
| `npm run dev:http` | Dev mode (HTTP) |
|
|
293
291
|
| `npm run start:stdio` | Production mode (stdio) |
|
|
294
292
|
| `npm run start:http` | Production mode (HTTP) |
|
|
295
293
|
| `npm run changelog:build` | Regenerate `CHANGELOG.md` from `changelog/*.md` |
|
package/templates/CLAUDE.md
CHANGED
|
@@ -288,8 +288,6 @@ When you complete a skill's checklist, check the boxes and add a completion time
|
|
|
288
288
|
| `npm run tree` | Generate directory structure doc |
|
|
289
289
|
| `npm run format` | Auto-fix formatting |
|
|
290
290
|
| `npm test` | Run tests |
|
|
291
|
-
| `npm run dev:stdio` | Dev mode (stdio) |
|
|
292
|
-
| `npm run dev:http` | Dev mode (HTTP) |
|
|
293
291
|
| `npm run start:stdio` | Production mode (stdio) |
|
|
294
292
|
| `npm run start:http` | Production mode (HTTP) |
|
|
295
293
|
| `npm run changelog:build` | Regenerate `CHANGELOG.md` from `changelog/*.md` |
|
package/templates/package.json
CHANGED
|
@@ -29,8 +29,6 @@
|
|
|
29
29
|
"changelog:build": "tsx scripts/build-changelog.ts",
|
|
30
30
|
"changelog:check": "tsx scripts/build-changelog.ts --check",
|
|
31
31
|
"test": "vitest run",
|
|
32
|
-
"dev:stdio": "MCP_TRANSPORT_TYPE=stdio tsx --watch src/index.ts",
|
|
33
|
-
"dev:http": "MCP_TRANSPORT_TYPE=http tsx --watch src/index.ts",
|
|
34
32
|
"start": "node dist/index.js",
|
|
35
33
|
"start:stdio": "MCP_TRANSPORT_TYPE=stdio node dist/index.js",
|
|
36
34
|
"start:http": "MCP_TRANSPORT_TYPE=http node dist/index.js"
|