Skip to content

v2: Add left-hook pre-push#1003

Merged
felixweinberger merged 23 commits intomodelcontextprotocol:mainfrom
KKonstantinov:feature/ts-sdk-hooks
Mar 25, 2026
Merged

v2: Add left-hook pre-push#1003
felixweinberger merged 23 commits intomodelcontextprotocol:mainfrom
KKonstantinov:feature/ts-sdk-hooks

Conversation

@KKonstantinov
Copy link
Contributor

@KKonstantinov KKonstantinov commented Oct 3, 2025

This is a follow-up to #976 with a goal of improving DX and reducing contributor friction by ensuring linting, formatting, and builds are validated before pushing.

It introduces the following git hooks via Lefthook:

Default Hooks (lefthook.yml)

  • Pre-push (runs in parallel):

    • Typecheck (pnpm typecheck:all)
    • Lint (pnpm lint:all)
    • Build (pnpm build:all)
    • Each failed check includes a hint to enable optional pre-commit hooks for earlier feedback
  • Post-checkout & Post-merge:

    • Auto-runs pnpm install to keep dependencies in sync

Optional Pre-commit Hooks (lefthook-local.example.yml)

For contributors who prefer earlier feedback, an optional pre-commit configuration is provided:

cp lefthook-local.example.yml lefthook-local.yml

This enables:

  • Typecheck (pnpm typecheck:all)
  • Lint Fix & Format (pnpm lint:fix:all) with stage_fixed: true

Motivation and Context

PRs could get slowed down by failing CI when there is an accidental omission by the contributor to run lint/typecheck/build before pushing.

Using pre-push as the default (rather than pre-commit) balances catching issues early while not slowing down the commit workflow. Contributors who want faster feedback can opt into the pre-commit hooks.

How Has This Been Tested?

  • Tested pre-push hooks: npx lefthook run pre-push
  • Tested optional pre-commit hooks by copying lefthook-local.example.yml to lefthook-local.yml

Breaking Changes

No breaking changes, a pure DX improvement.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

@KKonstantinov KKonstantinov requested review from a team and ihrpr October 3, 2025 11:05
@chipgpt
Copy link
Contributor

chipgpt commented Oct 3, 2025

What happens if the test(s) fail? I once had a colleague tell me they don't like putting things like tests in a pre-commit script because you should never stop a developer from committing their code. To be fair, this was in the context of employees working on a commercial software stack, not an open source SDK. Still, it has stuck with me and I think there is something to it.

Example might be if a developer is going out of town for a week and wants to commit their work in progress on a feature. If it is failing a test and can't be committed, then no one else can pick it up while they are out.

@KKonstantinov
Copy link
Contributor Author

What happens if the test(s) fail? I once had a colleague tell me they don't like putting things like tests in a pre-commit script because you should never stop a developer from committing their code. To be fair, this was in the context of employees working on a commercial software stack, not an open source SDK. Still, it has stuck with me and I think there is something to it.

Example might be if a developer is going out of town for a week and wants to commit their work in progress on a feature. If it is failing a test and can't be committed, then no one else can pick it up while they are out.

They can still do git commit --no-verify and skip the check on-demand - should not be a reason to skip a full step in the checks.

@domdomegg
Copy link
Member

Appreciate the PR! Maybe we should discuss this in an in issue/discussion to figure out what we want to agree on?

fwiw my view is that if you want to run things locally you always can, and if not CI will be there to catch this. I've personally found pre-commit/other hooks burn more of my time than they save, or are frustrating when trying to commit a WIP or draft piece of work (appreciate can use --no-verify, but then it's extra stuff to do and doesn't work with GUI git tools, AI agents get confused etc.). Although will flag that I'm not a TypeScript SDK maintainer, and of course there are reasonable differences of opinion here.

@pcarleton
Copy link
Member

could we do pre-push by default, and make pre-commit optional?

@KKonstantinov KKonstantinov requested a review from a team as a code owner October 8, 2025 05:53
@KKonstantinov
Copy link
Contributor Author

could we do pre-push by default, and make pre-commit optional?

This is a great idea and alleviates a lot of the concerns.

Done and pushed.

cc @pcarleton

@KKonstantinov
Copy link
Contributor Author

Following up on this.

We could observe a lot of PRs having a "prettier fix" commit quite often - this on top of a "test fix" commit.

Having some hooks would resolve that.

@changeset-bot
Copy link

changeset-bot bot commented Feb 3, 2026

⚠️ No Changeset found

Latest commit: 52abc57

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

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

@KKonstantinov KKonstantinov changed the title MCP SDK: Add pre-commit/post-checkout/post-merge hooks MCP SDK: Add left-hook pre-push Feb 3, 2026
@KKonstantinov KKonstantinov changed the title MCP SDK: Add left-hook pre-push `v2: Add left-hook pre-push Feb 3, 2026
@pkg-pr-new
Copy link

pkg-pr-new bot commented Feb 3, 2026

Open in StackBlitz

@modelcontextprotocol/client

npm i https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/client@1003

@modelcontextprotocol/server

npm i https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/server@1003

@modelcontextprotocol/express

npm i https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/express@1003

@modelcontextprotocol/hono

npm i https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/hono@1003

@modelcontextprotocol/node

npm i https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/node@1003

commit: 52abc57

@KKonstantinov KKonstantinov changed the title `v2: Add left-hook pre-push v2: Add left-hook pre-push Mar 5, 2026
@KKonstantinov KKonstantinov added the v2 Ideas, requests and plans for v2 of the SDK which will incorporate major changes and fixes label Mar 5, 2026
Copy link
Contributor

@felixweinberger felixweinberger left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pre-push LGTM and seems useful to encourage better submissions.

The post-checkout/post-merge pnpm install feels a bit aggro though - I wouldn't want every branch switch to fire pnpm install tbh.

Could we stick to the pre-push hook only? We can still keep the others optional.

@KKonstantinov
Copy link
Contributor Author

@felixweinberger done, addressed the comment

@felixweinberger
Copy link
Contributor

@claude review

@felixweinberger
Copy link
Contributor

@claude review

Comment on lines +33 to +37
- name: 'Build'
run: pnpm run build:all
fail_text: |
💡 To catch build issues earlier, enable the pre-commit hook:
cp lefthook-local.example.yml lefthook-local.yml
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 The Build job fail_text (lines 35-37) suggests enabling the pre-commit hook to catch build issues earlier, but lefthook-local.example.yml only defines Typecheck and Lint Fix & Format pre-commit jobs -- there is no build step. A contributor following this advice would still only get build feedback at pre-push time.

Extended reasoning...

What the bug is

The Build job in lefthook.yml (lines 33-37) has a fail_text that reads:

To catch build issues earlier, enable the pre-commit hook:
cp lefthook-local.example.yml lefthook-local.yml

This suggests that enabling the optional pre-commit hooks will catch build failures earlier. However, lefthook-local.example.yml only defines two pre-commit jobs: Typecheck (pnpm typecheck:all) and Lint Fix & Format (pnpm lint:fix:all). There is no build step in the pre-commit configuration.

Step-by-step proof

  1. A contributor pushes code and the pre-push Build job (pnpm run build:all) fails.
  2. They see the fail_text suggesting they copy lefthook-local.example.yml to lefthook-local.yml.
  3. They follow the advice: cp lefthook-local.example.yml lefthook-local.yml.
  4. Now on their next commit, the pre-commit hook runs -- but it only executes Typecheck and Lint Fix & Format.
  5. No build step runs at pre-commit time.
  6. The contributor pushes again and the build still fails at pre-push time, exactly as before.
  7. The advice was misleading -- enabling the pre-commit hook did nothing to catch build issues earlier.

Why existing code does not prevent this

The Typecheck and Lint jobs have similar fail_text messages, which are at least partially justified -- the pre-commit config does include pnpm typecheck:all and pnpm lint:fix:all. It appears the Build job fail_text was copied from one of the other jobs without adjusting for the fact that no corresponding build step exists in the pre-commit example.

Impact

This is a misleading hint that could confuse contributors. Someone who follows the advice expecting their build issues to be caught at commit time will be frustrated when they still only see build failures at push time. It erodes trust in the developer tooling suggestions.

How to fix

Either:

  1. Remove the fail_text hint from the Build job (or replace it with a message that does not reference pre-commit hooks), or
  2. Add a build step (pnpm build:all) to the pre-commit jobs in lefthook-local.example.yml.

Option 1 is likely preferable since running a full build on every commit would be slow and counterproductive for the DX goals of this PR.

@felixweinberger felixweinberger merged commit 40174d2 into modelcontextprotocol:main Mar 25, 2026
12 checks passed
felixweinberger added a commit that referenced this pull request Mar 26, 2026
The nightly update-spec-types workflow is failing because lefthook's
pre-push hook (added in #1003) runs `pnpm run lint:all`, which rejects
the freshly-fetched spec.types.ts for not matching prettier style.

Format the output via prettier's Node API using the project config
before writing it to disk. This also reduces nightly PR diffs to only
semantic changes, not formatting noise.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

v2 Ideas, requests and plans for v2 of the SDK which will incorporate major changes and fixes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants