H-6752: Remove the Linear and Notion MCP servers and ban install scripts - #9183
Conversation
Delete `apps/mcp` (the `@apps/linear-mcp` and `@apps/notion-mcp` workspaces) and retire the `postinstall` mechanism, of which they were the only consumers. - remove the root `package.json` `postinstall` script, which ran `turbo run postinstall` on every `yarn install` - remove the `postinstall` task from the root `turbo.json` - drop the two workspaces, their dependencies and the transitive packages that become unreferenced from `yarn.lock` - drop the reference to the bundled servers from `.config/_examples/README.md` `turbo run postinstall` now resolves no task at all, and a plain `yarn install` no longer triggers a turbo pass.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #9183 +/- ##
=======================================
Coverage 59.58% 59.58%
=======================================
Files 1419 1419
Lines 138220 138220
Branches 6549 6549
=======================================
+ Hits 82355 82356 +1
+ Misses 54801 54800 -1
Partials 1064 1064
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Removing the `postinstall` mechanism only cleared the existing scripts; this stops new ones being introduced. Add `enforceNoInstallScripts` to `yarn.config.cjs`, rejecting `preinstall`, `install`, `postinstall` and `prepare` in every workspace (the root included). These run on `yarn install` and so allow arbitrary code execution on a plain checkout-and-install. The constraint already gates manifests in CI (`lint.yml`, `yarn lint:constraints`) and on staged `package.json` via lefthook, so no new tooling is needed. It `unset`s rather than `error`s, matching the surrounding convention, so `yarn fix:constraints` autofixes a violation. Publish lifecycle scripts (`prepack`, `prepublishOnly`, `postpublish`, ...) are deliberately out of scope: 17 of them across 11 published packages are needed by `yarn changeset:publish`. Delete the only two pre-existing violations: - `apps/hash-ai-worker-ts` `prepare` — the package is private, so no publish path invoked it. Its output (`@local/hash-isomorphic-utils/src/chart-config-schema.ts`) is committed, and `generate:chart-config-schema` remains for manual regeneration. - `@hashintel/ds-components` `prepare` — redundant with `prepublishOnly: turbo run build`, whose `build` task depends on `codegen`, running the same `codegen:colors && codegen:tokens && codegen:panda` chain.
PR SummaryLow Risk Overview Install scripts are now blocked repo-wide:
Reviewed by Cursor Bugbot for commit 7558cb2. Bugbot is set up for automated code reviews on this repo. Configure here. |
Benchmark results
|
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| resolve_policies_for_actor | user: empty, selectivity: high, policies: 2002 | Flame Graph | |
| resolve_policies_for_actor | user: empty, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: empty, selectivity: medium, policies: 1002 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: high, policies: 3314 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: medium, policies: 1527 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: high, policies: 2078 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: medium, policies: 1033 | Flame Graph |
policy_resolution_medium
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| resolve_policies_for_actor | user: empty, selectivity: high, policies: 102 | Flame Graph | |
| resolve_policies_for_actor | user: empty, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: empty, selectivity: medium, policies: 52 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: high, policies: 269 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: medium, policies: 108 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: high, policies: 133 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: medium, policies: 63 | Flame Graph |
policy_resolution_none
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| resolve_policies_for_actor | user: empty, selectivity: high, policies: 2 | Flame Graph | |
| resolve_policies_for_actor | user: empty, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: empty, selectivity: medium, policies: 2 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: high, policies: 8 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: medium, policies: 3 | Flame Graph |
policy_resolution_small
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| resolve_policies_for_actor | user: empty, selectivity: high, policies: 52 | Flame Graph | |
| resolve_policies_for_actor | user: empty, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: empty, selectivity: medium, policies: 26 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: high, policies: 94 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: medium, policies: 27 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: high, policies: 66 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: medium, policies: 29 | Flame Graph |
read_scaling_complete
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| entity_by_id;one_depth | 1 entities | Flame Graph | |
| entity_by_id;one_depth | 10 entities | Flame Graph | |
| entity_by_id;one_depth | 25 entities | Flame Graph | |
| entity_by_id;one_depth | 5 entities | Flame Graph | |
| entity_by_id;one_depth | 50 entities | Flame Graph | |
| entity_by_id;two_depth | 1 entities | Flame Graph | |
| entity_by_id;two_depth | 10 entities | Flame Graph | |
| entity_by_id;two_depth | 25 entities | Flame Graph | |
| entity_by_id;two_depth | 5 entities | Flame Graph | |
| entity_by_id;two_depth | 50 entities | Flame Graph | |
| entity_by_id;zero_depth | 1 entities | Flame Graph | |
| entity_by_id;zero_depth | 10 entities | Flame Graph | |
| entity_by_id;zero_depth | 25 entities | Flame Graph | |
| entity_by_id;zero_depth | 5 entities | Flame Graph | |
| entity_by_id;zero_depth | 50 entities | Flame Graph |
read_scaling_linkless
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| entity_by_id | 1 entities | Flame Graph | |
| entity_by_id | 10 entities | Flame Graph | |
| entity_by_id | 100 entities | Flame Graph | |
| entity_by_id | 1000 entities | Flame Graph | |
| entity_by_id | 10000 entities | Flame Graph |
representative_read_entity
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/block/v/1
|
Flame Graph | |
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/book/v/1
|
Flame Graph | |
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/building/v/1
|
Flame Graph | |
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/organization/v/1
|
Flame Graph | |
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/page/v/2
|
Flame Graph | |
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/person/v/1
|
Flame Graph | |
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/playlist/v/1
|
Flame Graph | |
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/song/v/1
|
Flame Graph | |
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/uk-address/v/1
|
Flame Graph |
representative_read_entity_type
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| get_entity_type_by_id | Account ID: bf5a9ef5-dc3b-43cf-a291-6210c0321eba
|
Flame Graph |
representative_read_multiple_entities
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| entity_by_property | traversal_paths=0 | 0 | |
| entity_by_property | traversal_paths=255 | 1,resolve_depths=inherit:1;values:255;properties:255;links:127;link_dests:126;type:true | |
| entity_by_property | traversal_paths=2 | 1,resolve_depths=inherit:0;values:0;properties:0;links:0;link_dests:0;type:false | |
| entity_by_property | traversal_paths=2 | 1,resolve_depths=inherit:0;values:0;properties:0;links:1;link_dests:0;type:true | |
| entity_by_property | traversal_paths=2 | 1,resolve_depths=inherit:0;values:0;properties:2;links:1;link_dests:0;type:true | |
| entity_by_property | traversal_paths=2 | 1,resolve_depths=inherit:0;values:2;properties:2;links:1;link_dests:0;type:true | |
| link_by_source_by_property | traversal_paths=0 | 0 | |
| link_by_source_by_property | traversal_paths=255 | 1,resolve_depths=inherit:1;values:255;properties:255;links:127;link_dests:126;type:true | |
| link_by_source_by_property | traversal_paths=2 | 1,resolve_depths=inherit:0;values:0;properties:0;links:0;link_dests:0;type:false | |
| link_by_source_by_property | traversal_paths=2 | 1,resolve_depths=inherit:0;values:0;properties:0;links:1;link_dests:0;type:true | |
| link_by_source_by_property | traversal_paths=2 | 1,resolve_depths=inherit:0;values:0;properties:2;links:1;link_dests:0;type:true | |
| link_by_source_by_property | traversal_paths=2 | 1,resolve_depths=inherit:0;values:2;properties:2;links:1;link_dests:0;type:true |
scenarios
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| full_test | query-limited | Flame Graph | |
| full_test | query-unlimited | Flame Graph | |
| linked_queries | query-limited | Flame Graph | |
| linked_queries | query-unlimited | Flame Graph |
Requested via Slack thread
🌟 What is the purpose of this PR?
Removes the two in-repo MCP servers (Linear and Notion), retires the
postinstallmechanism, and then bans install scripts outright so it cannot come back.Before: a plain
yarn installended by runningturbo run postinstall, a pass over 87 task nodes whose only real work was building two MCP servers that nothing in the monorepo consumes. (Each server also declared its ownpostinstall, so Yarn built them once directly and the root turbo pass built them again.) Nothing prevented a new install script being added tomorrow.After: install does no turbo work, the servers are gone, and any workspace that declares
preinstall,install,postinstallorpreparenow failsyarn lint:constraints. Removing the scripts was the cleanup; the constraint is what makes it stick.🔗 Related links
🔍 What does this change?
Removing the servers and the mechanism
apps/mcp/—@apps/linear-mcpand@apps/notion-mcp, plus the folder READMEpostinstallscript from the rootpackage.jsonpostinstalltask (and the now-empty// Install commandsgroup) from the rootturbo.jsonyarn.lock— drops the two workspace entries, their dependencies (@modelcontextprotocol/sdk,@notionhq/client,notion-to-md,chokidar-cli,shx) and the transitive packages that become unreferenced.config/_examples/README.mdBanning install scripts
enforceNoInstallScriptstoyarn.config.cjs, rejectingpreinstall,install,postinstallandpreparein every workspace, the root included.yarn.config.cjsis already the repo's manifest gate — it runs in CI vialint.yml(yarn lint:constraints) and on stagedpackage.jsonvia lefthook — so this needs no new tooling or CI step. Itunsets rather thanerrors, matching the file's convention, soyarn fix:constraintsautofixes a violation.prepareinapps/hash-ai-worker-ts/package.jsonand inlibs/@hashintel/ds-components/package.jsonPublish lifecycle scripts (
prepack,prepublishOnly,postpublish, ...) are deliberately not covered — 17 of them across 11 published packages are needed byyarn changeset:publish.The
node.postinstall = "corepack enable"hook in.config/mise/config.tomlis an unrelated mise tool hook and is untouched."install": "0.13.0"inapps/hash-api/package.jsonis a dependency namedinstall, not a script; amanifest.scripts-based constraint correctly ignores it.Pre-Merge Checklist 🚀
🚢 Has this modified a publishable library?
This PR:
📜 Does this require a change to the docs?
The changes in this PR:
🕸️ Does this require a change to the Turbo Graph?
The changes in this PR:
turbo.json's have been updated to reflect thisServerwithsetRequestHandler, rather thanMcpServer/registerTool— and were stdio-only (StdioServerTransport). Both Linear and Notion now ship their own MCP servers, so anyone who had these wired in locally should point their client at those instead.hydrateLinearIssue(libs/@local/hash-backend-utils/src/linear.ts) was imported by the Linear server, but it is not orphaned by this change:libs/@local/repo-chores/node/scripts/ai-pr-review/get-pr-info.tsstill uses it. No follow-up needed.preparefromapps/hash-ai-worker-tsis safe: the package is private, so no publish path invoked it, its generated output (@local/hash-isomorphic-utils/src/chart-config-schema.ts) is committed, andgenerate:chart-config-schemaremains for manual regeneration. Dropping it from@hashintel/ds-componentsis safe becauseprepublishOnly: turbo run buildalready runs the same codegen chain viabuild'sdependsOn: ["codegen"].🐾 Next steps
None.
🛡 What tests cover this?
No test covered the deleted packages; nothing imported them. The constraint is itself the regression test for the ban, and it runs in CI on every PR.
❓ How to test this?
yarn lint:constraintspasses with zero violations."postinstall"to the rootpackage.jsonandyarn lint:constraintsfails withhash@workspace:. → Extraneous field scripts["postinstall"]; the same happens for a non-root workspace.yarn fix:constraintsremoves it again.turbo run postinstall --dry=jsonfails withCould not find task 'postinstall' in project(it previously resolved 87 nodes, 2 of them real).turbo run build --dry=jsonandturbo run lint:tsc --dry=jsonstill resolve, with the workspace count down from 87 to 85 and only@apps/linear-mcp/@apps/notion-mcpdropped.yarn install --immutablesucceeds and completes without invoking turbo.