Summary
Under Deno, every .js-suffixed subpath import of the SDK fails type resolution with TS2307, because the ./* export pattern maps types to ./dist/esm/*.d.ts. For the specifier @modelcontextprotocol/sdk/server/mcp.js, * captures server/mcp.js, so the types path resolves to dist/esm/server/mcp.js.d.ts — which does not exist. The real declaration file is dist/esm/server/mcp.d.ts.
tsc resolves this fine (it strips the .js before matching), so the problem is invisible to Node-only users. Deno applies the substitution literally and fails.
This affects the import style used throughout the SDK's own README and examples, so it hits essentially any MCP server that tries to type-check under Deno or publish to JSR.
Reproduction
Clean directory, no tsconfig:
mkdir repro && cd repro
echo '{"name":"repro","type":"module","dependencies":{"@modelcontextprotocol/sdk":"1.30.0"}}' > package.json
npm install
echo '{"nodeModulesDir":"manual"}' > deno.json
printf 'import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";\nexport const s: McpServer | null = null;\n' > mod.ts
deno check mod.ts
Result:
Check mod.ts
TS2307 [ERROR]: Cannot find module '@modelcontextprotocol/sdk/server/mcp.js'.
at file:///.../repro/mod.ts:1:27
error: Type checking failed.
The identical file under tsc 5.9.3 exits 0:
tsc --noEmit --module nodenext --moduleResolution nodenext --strict mod.ts # exit 0
Why it's worse than one error
Once McpServer is unresolved, the zod-inferred parameter types on every server.tool(...) callback collapse to any. In a real server this cascades: a file of mine with 3 SDK imports produced 1 × TS2307 plus 19 × TS7031 ("Binding element 'sessionId' implicitly has an 'any' type"), all downstream of the single resolution failure. The error output makes it look like a codebase problem rather than a one-line packaging one.
Versions
@modelcontextprotocol/sdk 1.30.0
- Deno 2.9.0 (stable, x86_64-unknown-linux-gnu)
- TypeScript 5.9.3
- Node 24
Suggested fix
Add a ./*.js pattern alongside the existing ./*. Node's exports resolution prefers the more specific pattern, so ordering doesn't matter and existing consumers are unaffected:
"./*.js": {
"types": "./dist/esm/*.d.ts",
"import": "./dist/esm/*.js",
"require": "./dist/cjs/*.js"
},
"./*": {
"types": "./dist/esm/*.d.ts",
"import": "./dist/esm/*",
"require": "./dist/cjs/*"
}
I verified this against 1.30.0 by patching node_modules:
deno check mod.ts → exit 0
node --input-type=module -e 'import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; ...' → still resolves, typeof McpServer === "function"
So it fixes Deno without regressing Node.
Note on prior art
#1269 ("Non-Node environment support (Bun, Deno, React Native)") was closed as completed in March, but this type-resolution path appears not to be covered by it — runtime import works under Deno, only type-checking fails. Happy to open a PR if the suggested shape looks right.
Summary
Under Deno, every
.js-suffixed subpath import of the SDK fails type resolution withTS2307, because the./*export pattern maps types to./dist/esm/*.d.ts. For the specifier@modelcontextprotocol/sdk/server/mcp.js,*capturesserver/mcp.js, so the types path resolves todist/esm/server/mcp.js.d.ts— which does not exist. The real declaration file isdist/esm/server/mcp.d.ts.tscresolves this fine (it strips the.jsbefore matching), so the problem is invisible to Node-only users. Deno applies the substitution literally and fails.This affects the import style used throughout the SDK's own README and examples, so it hits essentially any MCP server that tries to type-check under Deno or publish to JSR.
Reproduction
Clean directory, no tsconfig:
Result:
The identical file under
tsc5.9.3 exits 0:tsc --noEmit --module nodenext --moduleResolution nodenext --strict mod.ts # exit 0Why it's worse than one error
Once
McpServeris unresolved, the zod-inferred parameter types on everyserver.tool(...)callback collapse toany. In a real server this cascades: a file of mine with 3 SDK imports produced 1 ×TS2307plus 19 ×TS7031("Binding element 'sessionId' implicitly has an 'any' type"), all downstream of the single resolution failure. The error output makes it look like a codebase problem rather than a one-line packaging one.Versions
@modelcontextprotocol/sdk1.30.0Suggested fix
Add a
./*.jspattern alongside the existing./*. Node's exports resolution prefers the more specific pattern, so ordering doesn't matter and existing consumers are unaffected:I verified this against 1.30.0 by patching
node_modules:deno check mod.ts→ exit 0node --input-type=module -e 'import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; ...'→ still resolves,typeof McpServer === "function"So it fixes Deno without regressing Node.
Note on prior art
#1269 ("Non-Node environment support (Bun, Deno, React Native)") was closed as completed in March, but this type-resolution path appears not to be covered by it — runtime import works under Deno, only type-checking fails. Happy to open a PR if the suggested shape looks right.