Skip to content

Typecheck the three test workspace packages, and fix the registerPrompt typing defect they were hiding - #2841

Open
sharziki wants to merge 4 commits into
modelcontextprotocol:mainfrom
sharziki:fix/typecheck-test-packages
Open

sharziki wants to merge 4 commits into
modelcontextprotocol:mainfrom
sharziki:fix/typecheck-test-packages

Conversation

@sharziki

Copy link
Copy Markdown

Fixes #2840

What

pnpm -r typecheck silently skips test/conformance, test/helpers, and test/integration because none of them defines a typecheck script. All three define check as npm run typecheck && npm run lint, so the intent was there; the script simply did not exist, and a missing script in a recursive run is a no-op rather than an error.

35 type errors were sitting in the repo with CI green.

Three commits, deliberately separable

1. build: run typecheck on the three test workspace packages
Adds the missing typecheck script and the @typescript/native-preview devDependency it needs. This is the commit that makes the problem visible.

2. test: fix the type errors hidden by the missing typecheck scripts
The 34 in test/integration and 1 in test/conformance. Test-side type drift; no runtime behavior changes.

3. fix(server): type the context-only registerPrompt callback
The one real API defect among them, described below. Includes a changeset since it changes public types.

If you would rather take 1+2 now and discuss 3 separately, dropping the last commit is clean.

The API defect

When registerPrompt gets a config with no argsSchema, createPromptHandler takes its else branch and calls callback(ctx) — the server context is the only argument. Neither public overload describes that: both constrain Args to a schema type, so the argument-less form resolves to the deprecated raw-shape signature and types the first parameter as the arguments record.

So this fails to compile while working correctly at runtime:

server.registerPrompt('ping', { description: 'no args' }, ctx => {
    ctx.mcpReq; // error: property does not exist on the arguments record
    return { messages: [] };
});

An explicit PromptCallback annotation does not help either, since it matches neither overload.

The fix adds an argsSchema?: undefined overload typing the callback as PromptCallback, and widens the implementation signature to accept it. Callbacks that declare no parameters already compiled and are unaffected, as is every schema-bearing form.

This stayed invisible because the only caller of that form lives in test/integration — the package that was never typechecked. Commit 1 and commit 3 are the same bug at two levels.

Verification

$ pnpm -r typecheck
# main:   exits 0, never visits the three test packages
# branch: every package typechecks, all clean

$ pnpm -r --filter '!test-e2e' test
4256 tests passed, 0 failed

test/conformance alone had 1 error, test/integration 34, test/helpers 0 (it was clean, but should still be guarded).

I could not run pnpm test:conformance:server on my machine; it fails at browser launch there, and the identical failure reproduces on a clean checkout, so it is unrelated to this change.

`test/helpers`, `test/conformance` and `test/integration` each define
`check` as `npm run typecheck && npm run lint`, but none of them defines a
`typecheck` script. `pnpm -r typecheck` skips a package that lacks the
script rather than failing, so `pnpm check:all` — the CI gate in
`.github/workflows/main.yml` — silently typechecked 52 of 53 workspace
projects and these three were never covered. Running `npm run check` in any
of them fails outright with `Missing script: "typecheck"`, so the per-package
entry point was broken too.

Add the script, matching the `tsgo -p tsconfig.json --noEmit` form every
`packages/*` project already uses, and the `@typescript/native-preview`
devDependency that provides `tsgo`. Each package already has a `tsconfig.json`,
so nothing else was needed to make them checkable.

Enabling the check surfaces 35 pre-existing type errors that the gap had been
hiding; they are fixed in the following commit so this one stays reviewable.

Signed-off-by: Sharvil Saxena <sharvil.saxena@gmail.com>
Enabling `typecheck` on `test/conformance` and `test/integration` surfaces 35
type errors that CI had never seen. Each is a fault in the test code, not in
the SDK, and none changes what a test asserts:

- `noUncheckedIndexedAccess` violations: `tools[0].x` and `registered[2].x`
  now use `?.`/`!`, matching how `packages/*/test` already writes these.
- `everythingServer.ts` casts the `x-mcp-header` property to
  `Record<string, unknown>`, as `mcpParamValidation.test.ts` and
  `scopeChallengeModern.test.ts` do — the annotation is not in the
  `JSONSchema` property type.
- `dualEraStdio.test.ts` wrapped `onmessage`/`send` with a second parameter.
  `StdioClientTransport` declares neither, so the extra arguments were
  inert; the wrappers now match the real signatures.
- `mcp.test.ts` called `registerResource`/`registerPrompt` without the
  required `config` argument, and built a flat `ServerContext` that no
  longer matches the type.
- elicitation content values are `string | number | boolean | string[]`, so
  `server.test.ts` omits an absent `username` instead of passing `undefined`,
  and `elicitation.test.ts` annotates the handler return as `ElicitResult` so
  each branch widens to the shared type.
- `client.test.ts`'s `roots/list` handler returns `{ roots: [] }`; the
  assertion is that registration throws, so the value is never produced.

`pnpm -r typecheck` and `pnpm check:all` now pass across the whole workspace,
and `test/integration` stays at 371/371.

Signed-off-by: Sharvil Saxena <sharvil.saxena@gmail.com>
When `registerPrompt` is given a config with no `argsSchema`,
`createPromptHandler` takes its `else` branch and invokes the callback as
`callback(ctx)` — the server context is the only argument. Neither public
overload describes that: both constrain `Args` to a schema type, so the
argument-less form fell through to the deprecated raw-shape signature and
typed the first parameter as the arguments record. A callback that reads
`ctx.mcpReq` therefore failed to compile against behaviour that works at
runtime, and there was no annotation that fixed it, since an explicit
`PromptCallback` also failed to match either overload.

Add an `argsSchema?: undefined` overload typing the callback as
`PromptCallback`, and widen the implementation signature to accept it.
Callbacks that declare no parameters already compiled and are unaffected, as
is every schema-bearing form.

This was invisible because the only caller in the repo lives in
`test/integration`, which was not typechecked until the preceding commits.

Signed-off-by: Sharvil Saxena <sharvil.saxena@gmail.com>
@sharziki
sharziki requested a review from a team as a code owner September 21, 2026 18:52
@changeset-bot

changeset-bot Bot commented Sep 21, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 5a74dc9

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 6 packages
Name Type
@modelcontextprotocol/server Patch
@modelcontextprotocol/client Patch
@modelcontextprotocol/codemod Patch
@modelcontextprotocol/core Patch
@modelcontextprotocol/server-legacy Patch
@modelcontextprotocol/core-internal Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@pkg-pr-new

pkg-pr-new Bot commented Sep 21, 2026

Copy link
Copy Markdown

Open in StackBlitz

@modelcontextprotocol/client

npm i https://pkg.pr.new/@modelcontextprotocol/client@2841

@modelcontextprotocol/codemod

npm i https://pkg.pr.new/@modelcontextprotocol/codemod@2841

@modelcontextprotocol/core

npm i https://pkg.pr.new/@modelcontextprotocol/core@2841

@modelcontextprotocol/server

npm i https://pkg.pr.new/@modelcontextprotocol/server@2841

@modelcontextprotocol/server-legacy

npm i https://pkg.pr.new/@modelcontextprotocol/server-legacy@2841

@modelcontextprotocol/express

npm i https://pkg.pr.new/@modelcontextprotocol/express@2841

@modelcontextprotocol/fastify

npm i https://pkg.pr.new/@modelcontextprotocol/fastify@2841

@modelcontextprotocol/hono

npm i https://pkg.pr.new/@modelcontextprotocol/hono@2841

@modelcontextprotocol/node

npm i https://pkg.pr.new/@modelcontextprotocol/node@2841

commit: 5a74dc9

Enabling `typecheck` on `test/conformance` passes against a tree that has
already been built, but fails from a clean checkout:

    ../../packages/client/src/client/auth.ts(1,34): error TS2307:
      Cannot find module '@modelcontextprotocol/client/_shims'
      or its corresponding type declarations.

(and the same for four more files across `client` and `server`).

`test/conformance/tsconfig.json` redirects `@modelcontextprotocol/client` and
`@modelcontextprotocol/server` to their `src/index.ts` so the conformance suite
typechecks against sources rather than build output. Those sources import the
`/_shims` subpath, which is only resolvable through the package's `exports`
map, and every target there is under `dist/`. With no `paths` entry for the
subpath, resolution falls through to `exports` and needs a build to exist.

CI runs `pnpm run check:all` before `pnpm run build:all`, so `dist/` is absent
and the typecheck fails. It passed locally only because a previous build had
left `dist/` behind.

Map the subpath to `src/shimsNode.ts`, which is what every other project that
redirects these packages to source already does: `test/e2e`,
`test/integration`, `examples/*` and all four `packages/middleware/*`
tsconfigs. `test/conformance` was the only one missing it.

Verified by removing every `packages/*/dist` directory to reproduce a clean
checkout: the five errors above appear before this change and none after.

Signed-off-by: Sharvil Saxena <sharvil.saxena@gmail.com>
@sharziki

Copy link
Copy Markdown
Author

The build job was failing on my previous push and I've fixed it in 5a74dc9. Writing up what it was, since the failure mode is a nice illustration of why the missing typecheck scripts went unnoticed for so long.

Enabling typecheck on test/conformance passed on my machine but failed in CI with:

../../packages/client/src/client/auth.ts(1,34): error TS2307: Cannot find module
  '@modelcontextprotocol/client/_shims' or its corresponding type declarations.

plus the same for four more files across client and server.

Cause. test/conformance/tsconfig.json redirects @modelcontextprotocol/client and @modelcontextprotocol/server to their src/index.ts, so the suite typechecks against sources rather than build output. Those sources import the /_shims subpath, which is only resolvable through the package's exports map, and every target there lives under dist/. With no paths entry for the subpath, resolution falls through to exports and therefore needs a build to exist.

main.yml runs pnpm run check:all before pnpm run build:all, so in CI dist/ is absent and it fails. It passed locally only because an earlier build had left dist/ behind — the same class of "green because of state that CI doesn't have" problem as the original gap this PR is about.

Fix. Map the subpath to src/shimsNode.ts. This isn't a new convention: test/e2e, test/integration, examples/* and all four packages/middleware/* tsconfigs already carry exactly this entry alongside their src/index.ts redirect. test/conformance was the only project redirecting these packages to source without it, which is consistent with it being the one that was never typechecked.

Verification. I reproduced CI's clean checkout by deleting every packages/*/dist directory. Before the change, the five errors above; after it, tsgo -p tsconfig.json --noEmit is clean, and a full pnpm run check:all on that dist-free tree exits 0.

Happy to split the tsconfig change into the first commit (build: run typecheck on the three test workspace packages) if you'd rather the series be bisect-clean, rather than having it as a follow-up fix. Let me know which you prefer.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

pnpm -r typecheck silently skips the three test packages, hiding 35 type errors and one registerPrompt typing defect

1 participant