Reported issues for mcp-ts-template
Pod holds 24 of 329 problems reported by people outside the maintainer team. Issues filed by the project's own owners, members and collaborators are excluded entirely — a maintainer's release checklist is not a warning to a prospective user.
Back to mcp-ts-template.
Most discussed
bug(tool): error structuredContent fails strict SDK clients' output-schema validation on isError
When a tool declares an output schema, an isError: true response carrying structuredContent: { error: … } makes a validating MCP client throw -32602 "Structured content does not match the tool's output schema" instead of returning the isError result. The client validates the error envelope against the success schema, which it can never satisfy.
Exposure is every tool on every consuming server: output is required on ToolDefinition, so every tool advertises an outputSchema, an
Read the thread · 2026-06-18 · closed · 11 comments
feat(sdk): TypeScript SDK v2 / protocol 2026-07-28 — adoption impact audit
The framework pins @modelcontextprotocol/sdk ^1.29.0 (v1, current latest). Upstream has split v2 into @modelcontextprotocol/server / client / node (GA — 2.0.0, published 2026-07-27) and published the migration path for the 2026-07-28 protocol revision: support-2026-07-28.md (prerequisite: [upgrade-to-v2.md](https://gi
Read the thread · 2026-07-27 · closed · 7 comments
feat(canvas): prevent auth-none enumeration and capacity starvation
Use case
Related: #225, #275, #305
Under MCP_AUTH_MODE=none, every request intentionally resolves to the default tenant. A stateful HTTP session ID is not an authentication or tenant boundary, and two serving modes carry no session ID at all: stateless legacy HTTP, and every request under the per-request 2026-07-28 protocol revision. Session-derived tenancy therefore cannot promise confidentiality.
The collapsed tenant still creates two framework-level problems:
- **Ambient enumerat
Read the thread · 2026-07-02 · open · 7 comments
bug(transport): HTTP per-request McpServer cleanup leaks ~30 KB/req on heap
mcp-ts-core version
0.6.10 (reproduced against 0.6.16 — src/mcp-server/transports/http/httpTransport.ts cleanup path is unchanged between the two)
Runtime
Bun
Runtime version
Bun 1.3.2 (oven/bun:1 production image)
Transport
http (Streamable HTTP)
OS
Debian 13 (Docker container)
Description
The HTTP transport's per-request cleanup path — a fire-and-forget queueMicrotask calling transport.close() and server.close() after non-SSE responses — leaves ~30
Read the thread · 2026-04-24 · closed · 7 comments
Error-path parity: auto-mirror data.recovery.hint into error content[] text
Problem
The framework enforces parity on success responses via the format-parity linter rule: every field in output must appear in format()'s rendered content[], so structuredContent-readers and content[]-readers see the same data.
Errors have no equivalent guarantee. Handler-thrown errors are converted at src/mcp-server/tools/utils/toolHandlerFactory.ts:196–205:
return {
isError: true,
content: [{ type: 'text', text: `Error: ${mcpError.message}` }],
_meta: {
[Read the thread](https://github.com/cyanheads/mcp-ts-core/issues/84) · 2026-04-29 · closed · 6 comments
### feat(tool): flatten SDK input-validation error text and move issues to error.data (follow-up to #55)
> **Status: resolved by SDK v2 — verify and close at the v2 migration (#305 Phase 1). Nothing ships in this framework.**
> The v2 `tools/call` input validator formats failures as flat `path: message` sentences joined by commas (`formatIssue` in `packages/core-internal/src/util/standardSchema.ts`), so the serialized `ZodIssue[]` blob in `content[0].text` that this issue targets is gone on v2. The structured half of the original proposal (surfacing raw issues under `_meta.error.data.issues`) is **
[Read the thread](https://github.com/cyanheads/mcp-ts-core/issues/66) · 2026-04-24 · closed · 6 comments
### bug(telemetry): every tool call in a process shares one traceId — tool spans parent to a leaked boot span
### mcp-ts-core version
0.10.15
### Runtime
Bun
### Runtime version
Bun 1.3
### Transport
HTTP (Streamable HTTP)
### OS
Linux / any
### Description
Under HTTP transport with telemetry enabled, tool spans could inherit the startup span's async context and share its trace ID across process lifetime.
### Reproduction
Start an HTTP server with telemetry enabled, invoke a tool from multiple sessions, and compare emitted trace IDs.
### Actual behavior
Tool calls could be parented to a l
[Read the thread](https://github.com/cyanheads/mcp-ts-core/issues/294) · 2026-07-26 · closed · 5 comments
### feat(linter): flag handler-local ctx.fail sites that omit declared recovery
### Use case
An `errors[]` contract can declare a required recovery hint while a directly visible `ctx.fail('reason', ...)` call omits `ctx.recoveryFor('reason')`. The definition passes `lint:mcp`, but the client-visible error has no `data.recovery.hint` because recovery forwarding is deliberately opt-in.
This drift has recurred across downstream servers. The linter already checks handler-local error-contract conformance, so it should warn about the subset of missing recovery forwarding it can
[Read the thread](https://github.com/cyanheads/mcp-ts-core/issues/255) · 2026-07-02 · open · 5 comments
## Most recent
### feat(exports): advertisedOutputSchema is unreachable from any export subpath, so consumers cannot snapshot advertised wire shapes
Related: #241, #232
### Use case
[0.12.0](https://github.com/cyanheads/mcp-ts-core/blob/main/changelog/0.12.x/0.12.0.md) changed the bytes a tool advertises: `inputSchema` gained `additionalProperties: false`, the dialect moved to JSON Schema 2020-12, and `outputSchema` now declares the error envelope with success fields widened to optional. Its `agent-notes` tells downstream servers that "wire-shape snapshots need re-recording" as step 7 of the upgrade.
A consumer cannot actually do that. `a
[Read the thread](https://github.com/cyanheads/mcp-ts-core/issues/396) · 2026-08-25 · open · 0 comments
### bug(landing): connect card's curl snippet returns 400 — modern protocol header paired with a legacy initialize body
The landing page's `curl` tab publishes a request that fails on first paste. `connect.js` interpolates `manifest.protocol.latestVersion` into **both** the `MCP-Protocol-Version` header and the `initialize` body's `protocolVersion`. Now that `latestVersion` is `2026-07-28`, that pairs a modern header with a legacy handshake — a combination the transport explicitly rejects.
There is a second, independent defect in the same snippet: it omits `Accept`.
## Reproduction
Verified against a stock HTT
[Read the thread](https://github.com/cyanheads/mcp-ts-core/issues/395) · 2026-08-25 · open · 0 comments
### bug(tool): strictening a default-mode input silently discards its .meta(), dropping anyOf from the advertised inputSchema
### mcp-ts-core version
0.12.3
### Runtime
Bun
### Runtime version
1.4.0
### Transport
http
### Description
Related: #232
`tool()` applies `.strict()` to a default-mode input. Zod's `.strict()` returns a **fresh schema instance**, and that instance is not in the metadata registry, so anything attached with `.meta()` is silently lost. The advertised `inputSchema` loses the metadata with no error, no warning, and no lint finding.
The failure is invisible in the obvious place. Registrati
[Read the thread](https://github.com/cyanheads/mcp-ts-core/issues/394) · 2026-08-25 · open · 0 comments
### bug(skills): git-wrapup's version-sync list omits .claude-plugin/.codex-plugin plugin.json, so releases silently leave them behind
### mcp-ts-core version
0.12.3
### Runtime
Bun
### Runtime version
Bun 1.4.0
### Transport
N/A (release tooling)
### OS
macOS 15 (darwin arm64)
### Description
`skills/git-wrapup/SKILL.md` enumerates the files a release must re-version, and the list omits `.claude-plugin/plugin.json` and `.codex-plugin/plugin.json` — both of which declare a `version` that is expected to track `package.json`.
The list appears three times, consistently incomplete:
- the version-sync section names `pac
[Read the thread](https://github.com/cyanheads/mcp-ts-core/issues/393) · 2026-08-25 · open · 0 comments
### bug(templates): multi-arch Docker build fails on linux/amd64 under Bun 1.4.0
### Description
`templates/Dockerfile` runs its build stage on the target platform. Since the template moved to `oven/bun:1.4.0`, the `linux/amd64` leg of a multi-arch `docker buildx build` on an arm64 host aborts partway through `bun run build`: Bun's JavaScriptCore runs out of memory under QEMU x86_64 emulation and dies with SIGABRT.
The same Dockerfile shape built cleanly on `oven/bun:1.3.14`, so adopting the 1.4.0 pin is what exposes it. Any server that takes the template pin and publishes
[Read the thread](https://github.com/cyanheads/mcp-ts-core/issues/392) · 2026-08-25 · open · 1 comment
### bug(skills): field-test helper aborts on a stateless server — a missing Mcp-Session-Id is read as init failure
### mcp-ts-core version
0.12.3
### Runtime
Bun
### Runtime version
Bun 1.4.0
### Transport
http
### OS
macOS 15 (darwin arm64)
### Description
`skills/field-test/SKILL.md`'s `mcp_start` treats a missing `Mcp-Session-Id` response header as a fatal init failure:
```bash
local sid; sid=$(grep -i '^mcp-session-id:' "$hdr" | awk '{print $2}' | tr -d '\r\n')
if [ -z "$sid" ]; then
echo "init failed — HTTP $code, no Mcp-Session-Id header returned" >&2
A server running `MCP_SESSION_MO
Read the thread · 2026-08-25 · open · 0 comments
bug(devcheck): audit classifier splits paths on U+203A, but Bun 1.4 emits ASCII '>' — every transitive advisory reads as direct
mcp-ts-core version
0.12.3
Runtime
Bun
Runtime version
Bun 1.4.0
Transport
N/A (build tooling)
OS
macOS 15 (darwin arm64)
Description
classifyAuditVulns in scripts/devcheck.ts decides direct-vs-transitive by looking for › (U+203A) in each dependency path:
const isDirect = DIRECT_DEPS.has(pkgName) || paths.some((p) => !p.includes('›'));
Bun 1.4.0 emits ASCII > as the path separator, not ›. Every path therefore fails the includes check, `i
Read the thread · 2026-08-25 · open · 2 comments
bug(tool): generated error.data.reason description runs contract entries together
mcp-ts-core version
0.12.3
Runtime
Bun
Runtime version
1.4.0
Transport
stdio
OS
macOS 26.1
Description
toolErrorEnvelopeSchema in src/mcp-server/tools/utils/toolHandlerFactory.ts builds the advertised description for error.data.reason by joining each declared contract entry with a single space and then appending a trailing sentence with no separator:
.describe(`Machine-readable failure mode. Declared by this tool: ${contract
.map((entry) => `\`${
[Read the thread](https://github.com/cyanheads/mcp-ts-core/issues/389) · 2026-08-25 · open · 0 comments
### feat(linter): read truncationAllowlist from devcheck.config.json
`validateDefinitions()` accepts `LintInput.truncationAllowlist`, but `templates/scripts/lint-mcp.ts` never passes it. A consumer server that needs a legitimate `capped-list-no-truncation` exemption is therefore left with only the `MCP_LINT_TRUNCATION_ALLOWLIST` env var — and because `devcheck` spawns the linter as a child process, the var has to be duplicated across two `package.json` script entries:
```json
"devcheck": "MCP_LINT_TRUNCATION_ALLOWLIST=<tool> bun run scripts/devcheck.ts",
"lint:m
[Read the thread](https://github.com/cyanheads/mcp-ts-core/issues/388) · 2026-08-25 · open · 0 comments
### bug(http): server card omits transport.sessionMode, contrary to #357's acceptance criteria
Related: #357
### Description
`buildServerCard()` never emits `sessionMode`. The SEP-1649 discovery document served at `/.well-known/mcp.json` carries `mcp_version`, `server_name`, `server_version`, `server_description`, `endpoints`, `capabilities`, `authentication`, `extensions`, `documentation`, and `generated_at` — and nothing from `manifest.transport` beyond the endpoint URL it builds from `endpointPath`.
#357 closed with an acceptance criterion that reads "the landing page **and server c
[Read the thread](https://github.com/cyanheads/mcp-ts-core/issues/387) · 2026-08-25 · open · 0 comments
### bug(errors): client disconnect mid-call is reported as -32603 InternalError (FetchAborted + SdkError "Connection closed")
### mcp-ts-core version
0.12.3
### Runtime
Bun
### Runtime version
Bun 1.4.x
### Transport
HTTP (Streamable HTTP)
### OS
Linux (Docker)
### Description
When a client drops its HTTP connection while a tool call is in flight, the failure is reported as `-32603 InternalError` and logged at error level with a full stack, on two separate paths:
| Path | Where | What it produces |
|:---|:---|:---|
| Upstream fetch in progress | `fetchWithTimeout` → `abortedFailure()` (`src/utils/network/fe
[Read the thread](https://github.com/cyanheads/mcp-ts-core/issues/386) · 2026-08-25 · open · 0 comments
### bug(testing): zodToArbitrary ignores .regex(), so pattern-validated inputs never reach the handler under fuzz
### Description
`arbitraryForZodString` in `src/testing/fuzz.ts` derives a string arbitrary from `format`, `minLength`, and `maxLength` only. A `.regex()` constraint is ignored, so every generated sample for a pattern-validated string field is rejected at `input.parse` before the handler runs. `fuzzTool` still reports a clean run — `crashes: []`, `leaks: []` — but the handler was never reached, so the report attests to nothing.
This is the same class as #319 and #320: a constraint `zodToArbitr
[Read the thread](https://github.com/cyanheads/mcp-ts-core/issues/385) · 2026-08-25 · open · 0 comments
### bug(templates): .env.example documents MCP_SESSION_MODE default as stateful and omits auto
### mcp-ts-core version
0.12.3
### Runtime
Bun
### Description
`templates/.env.example:17` documents `MCP_SESSION_MODE` as:
MCP_SESSION_MODE=stateful # stateful | stateless (default: stateful)
Both halves are wrong. The enum has three members, not two, and the default is `auto`:
```ts
// src/config/index.ts:156
mcpSessionMode: z.preprocess(
emptyStringAsUndefined,
z.enum(['stateless', 'stateful', 'auto']).default('auto'),
),
auto resolves to stateful at rea
Read the thread · 2026-08-25 · open · 0 comments
bug(templates): templates/bunfig.toml is missing from the published tarball, so init scaffolds without the supply-chain guard
templates/bunfig.toml (added in 114edd03, tracked, under files: ["templates/"]) is not in the published @cyanheads/mcp-ts-core@0.12.3 tarball, so bunx @cyanheads/mcp-ts-core init <name> produces a project with no bunfig.toml — no minimumReleaseAge, no Socket install scanner. Every other templates/ file ships; only this one is dropped.
Repro
npm pack @cyanheads/mcp-ts-core@0.12.3
tar tzf cyanheads-mcp-ts-core-0.12.3.tgz | grep templates/bunfig # → nothing
npm pack --dr
[Read the thread](https://github.com/cyanheads/mcp-ts-core/issues/383) · 2026-08-22 · open · 0 comments
### bug(templates): CLAUDE.md/AGENTS.md checklist says plugin displayName = package name, which lint:packaging rejects for scoped packages
The scaffolded agent-protocol checklist tells an agent to set the plugin manifests' display fields from the **package name**, while `lint-packaging.ts` check 10 requires the **unscoped** machine name in exactly those fields. For a scoped package the two disagree, so an agent that follows the checklist writes a manifest that then fails `devcheck`.
## Where
`templates/CLAUDE.md` and `templates/AGENTS.md`, both at lines 411–412 (identical text):
-
.codex-plugin/plugin.jsonpopulated —
Read the thread · 2026-08-22 · open · 0 comments
bug(core): logger drops every record emitted from a server's setup() hook
composeServices awaits the consumer's setup(coreServices) hook at src/core/app.ts:395, but logger.initialize(...) does not run until src/core/app.ts:634. Logger.log returns early while !this.initialized (src/utils/internal/logger.ts:617), so every core.logger.* call made inside a server's setup() is silently discarded — no sink, at any log level, on either transport, with no warning that a record was dropped.
Not a regression: v0.11.0 has the same ordering (setup at
Read the thread · 2026-08-22 · open · 0 comments
The remaining reports are on the project's issue tracker.