Skip to content

chore: back-merge main into v2/main so the first milestone merge is clean - #1868

Closed
cliffhall wants to merge 224 commits into
v2/mainfrom
v2/docs/backmerge-main-into-v2main
Closed

chore: back-merge main into v2/main so the first milestone merge is clean#1868
cliffhall wants to merge 224 commits into
v2/mainfrom
v2/docs/backmerge-main-into-v2main

Conversation

@cliffhall

Copy link
Copy Markdown
Member

Closes #1821

Task 1 of #1821"Merges from v2/main into main enabled for milestone development release workflow". Analysis in this comment; this is the mechanical half.

Why

v2/main and main already share history — merge base 4d30d1cd, established by the go-live merge (#1830) — so milestone merges work without any graft. But the two had diverged on README.md, so the first v2/mainmain merge would have conflicted:

Copying main's text onto v2/main would not have fixed this — both sides would still show overlapping edits to the same region and conflict again. Recording main as merged is what fixes it: main's tip becomes an ancestor of v2/main, so the release side contributes nothing to reconcile.

Verified

$ git merge-base --is-ancestor origin/main HEAD   →  yes

# dry-run of the next milestone merge, into a scratch worktree off origin/main:
$ git merge --no-commit --no-ff v2/docs/backmerge-main-into-v2main
Automatic merge went well; stopped before committing as requested
conflicts: (none)          SECURITY.md: present

What it brings from main

README conflict resolution

Took main's restructured section and carried v2/main's #1846 correction into it. main's copy still claimed:

Mcp-Param-* mirroring is skipped by the SDK in the browser … So calling get_weather from the web client omits Mcp-Param-City and the strict server answers -32020.

That stopped being true when the Inspector took over building the mirrored headers itself. The callout now says mirroring works on every client, web included, since the web client's upstream request is issued by the Node backend rather than the browser.

This is not a docs-only change

It lands on v2/main the rc-series bumps that had only ever reached main:

Package v2/main after
@hono/node-server ^1.19.14 ^2.0.12 (major)
vite ^8.0.0 / ^8.0.16 ^8.1.5
@modelcontextprotocol/sdk 1.29.0 1.30.0

The lockfiles auto-merged consistently — a subsequent npm install produced no changes. npm run ci passes (validate → coverage → verify:build-gate → smoke → Storybook), which is what gives confidence in the major @hono/node-server bump against the web backend.

Sequencing with #1867

#1867 (SECURITY.md on v2/main) overlaps this PR — the back-merge necessarily brings that file across. Merging #1867 first is cleanest: the file is then identical on both sides and this PR's diff simply no longer contains it. Alternatively #1867 can be closed as subsumed. Either order works; there's no conflict.

🤖 Generated with Claude Code

https://claude.ai/code/session_01YAt8rqxysNbhYWLhoRm3fU

howardjohn and others added 30 commits October 13, 2025 08:22
When failing to connect to an MCP server, its very hard to understand
why. There is only an opaque "Connection Error" message with no
additional info. This also doesn't change at all on repeated attempts,
so there is no indication we attempted again and failed.

This change introduces a `toast` to visualize the error, and adds the
`cause` into the error message for further debugging
Guard against calling controller.close() when the stream has already
been closed by an external cancellation. This can happen when the SDK
cancels the stream before the underlying Node stream emits its 'end'
event.

- Add `closed` flag to track controller state
- Guard all controller operations with closed check
- Add `cancel()` callback to handle external cancellation
- Properly destroy the Node stream on cancellation
1. createWebReadableStream: Add closed flag and cancel() callback to
   prevent double-close crashes when SSE streams end. This fixes the
   "Controller is already closed" error that occurs when the SDK calls
   response.body.cancel() on 202 responses.

2. DELETE handler: Call serverTransport.close() after terminateSession()
   to properly cleanup the transport and cancel pending reconnections.
   - terminateSession() notifies the server (sends DELETE request)
   - close() cleans up client-side resources (abort controller, timeouts)
   - Both are needed for a complete disconnect
…eam-double-close

Fix ReadableStream controller double-close crash
…-debug

fix: proper stream cleanup and transport close on disconnect
mcp: add icon + website for testing SEP-973
In DynamicJsonForm.tsx,
  - Support all five enum shapes used by MCP SDK:
    - Titled single-select via `oneOf`/`anyOf` with `{ const, title }`
    - Untitled single-select via `enum`
    - Titled legacy single-select with optional `enumNames` for labels
    - Titled multi-select via `items.anyOf`/`oneOf`
    - Untitled multi-select via `items.enum`
  - Show field descriptions for string select fields and boolean checkboxes (consistent help text above inputs).
  - Prefer schema property `title` for object field labels; fall back to the JSON key when missing.
  - Allow top‑level form rendering for objects with properties, arrays with items, and primitive types (was overly strict before).
  - Multi-select UI: sensible list size and `minItems`/`maxItems` helper text when present.
  - JSON editor fallback, copy/format controls, and debounced parsing preserved.
  - apply defaults for optional fields during form init

In schemaUtils.ts
  - `generateDefaultValue` now includes optional properties that declare a `default`, ensuring fields like strings show their defaults on first render.

In jsonUtils.ts
  - Add legacy `enumNames?: string[]` and array constraints `minItems?`/`maxItems?`.
- Align tests with new form-first rendering and UI behavior:
  - Labels prefer schema `title` over property key.
  - Descriptions shown for boolean checkboxes and select fields.
  - Explicit mode switching between Form/JSON when needed.
- Add comprehensive coverage for enum schema variants:
  - Titled single-select via `oneOf`/`anyOf` with `{ const, title }`.
  - Untitled single-select via `enum` (with legacy `enumNames` labels).
  - Untitled multi-select via `items.enum` with `minItems`/`maxItems` helper text.
  - Titled multi-select via `items.anyOf`/`oneOf` with `{ const, title }`.
- Adjust complex/JSON-mode tests to click “Switch to JSON” before asserting textarea and clipboard interactions.
- Fix debounced JSON update expectations to assert parsed objects rather than raw text.

Files updated:
- `client/src/components/__tests__/DynamicJsonForm.test.tsx`
- `client/src/components/__tests__/DynamicJsonForm.array.test.tsx`
cliffhall and others added 19 commits July 17, 2026 20:00
Bumps shell-quote from ^1.8.3 to ^1.8.4 in the root and server
packages to resolve a critical security advisory. Adds an npm
override so concurrency's pinned shell-quote@1.8.3 also resolves to
a patched version, leaving no vulnerable copy in the tree.


Claude-Session: https://claude.ai/code/session_01HiccCEh9mwCfVzE8qYcop1

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Resolves Dependabot alerts #126, #128, #127, #125, #124 (transitive via
@modelcontextprotocol/sdk). Part of #1706.


Claude-Session: https://claude.ai/code/session_01HiccCEh9mwCfVzE8qYcop1

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Resolves Dependabot alert #130. Part of #1706.


Claude-Session: https://claude.ai/code/session_01HiccCEh9mwCfVzE8qYcop1

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Resolves Dependabot alert #132. Uses a version-targeted override
(@babel/core@<=7.29.0) so all copies of the vulnerable range are bumped.
Part of #1706.


Claude-Session: https://claude.ai/code/session_01HiccCEh9mwCfVzE8qYcop1

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
npm does not reliably apply these transitive overrides to an existing
lockfile (bare and targeted overrides via install/update leave residual
vulnerable copies). This regenerates the lockfile from scratch with
version-targeted overrides so every copy of the affected packages
resolves to a patched version.

Resolves Dependabot alerts:
- esbuild #121 (-> 0.28.1)
- minimatch #69, #66, #61 (3.x -> 3.1.5)
- @babel/core #132 (-> 7.29.7; completes the partial fix from #1712)
Also pins js-yaml overrides (3.15.0 / 4.2.0) to prevent regression.

Supersedes #1713, #1714, #1715. Part of #1706.

Verified: 0 vulnerable copies across all advisories; build + client (535)
+ cli tests pass; lockfile internally consistent.


Claude-Session: https://claude.ai/code/session_01HiccCEh9mwCfVzE8qYcop1

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ta (#53) (#1717)

* fix(server): guard the /fetch proxy against SSRF to link-local/metadata

The /fetch proxy forwarded any user-supplied http/https URL straight into
fetch(), so a malicious remote MCP server could advertise OAuth metadata
pointing at the cloud metadata endpoint (169.254.169.254) and have the proxy
exfiltrate instance credentials (CodeQL js/request-forgery, alert #53).

Add a targeted SSRF guard: resolve the target host and reject link-local /
cloud-metadata addresses (169.254.0.0/16, IPv6 link-local, AWS IPv6 IMDS).
Loopback and RFC1918/private LAN targets stay reachable, since connecting to
local and self-hosted MCP servers is a core Inspector use case. Redirects are
now followed manually so every hop is re-validated, closing the
redirect-to-internal bypass. Returns 403 on a blocked target.

Adds endpoint tests for a direct metadata target, a redirect into a blocked
address, and normal redirects between allowed hosts.

Resolves code-scanning alert #53. Part of #1706.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HiccCEh9mwCfVzE8qYcop1

* fix(server): block IPv4-mapped IPv6 form of metadata IP in /fetch guard

The IPv4-mapped IPv6 branch of isBlockedProxyAddress only matched the
dotted-decimal form (::ffff:169.254.169.254), but the WHATWG URL parser
serializes IPv4-mapped addresses in hex (::ffff:a9fe:a9fe), so
http://[::ffff:169.254.169.254]/ resolved past the guard and still reached
the cloud metadata service on dual-stack hosts — the exact vector this guard
targets.

Extract the embedded IPv4 from both the hex and dotted forms and re-check it.
Adds a regression test for the IPv4-mapped IPv6 metadata address.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HiccCEh9mwCfVzE8qYcop1

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Phase 4 of the v2 go-live runbook (#1804 §5). `main` becomes the v2 tree while
keeping its own history: this is a true merge recording `v2/main` as a second
parent, not a reset, so no force-push is needed and the default branch's
history and PR trail survive intact.

Mechanically: `-s ours` to take no tree from the merge, then the index is
replaced wholesale with `v2/main`'s. `git diff HEAD origin/v2/main` is empty
afterwards.

Note the runbook's command needed one addition — `main` and `v2/main` have
genuinely unrelated histories (different root commits, no merge base), so
`--allow-unrelated-histories` is required or the merge refuses outright.

All 125 open PRs previously targeting `main` were re-pointed at `v1/main`
first, so none of them are stranded against a tree that no longer exists.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Txmv2qqv3yeKgRzoqXytzD
CodeQL alert #64 (`actions/missing-workflow-permissions`, medium) on
`.github/workflows/main.yml`: no `permissions` block, so every job inherits the
repository's default GITHUB_TOKEN scope, which is broader than anything here
needs.

It matters more than the severity suggests because this is the workflow that
publishes to npm under OIDC — an over-permissioned token in a job that mints
publish credentials is worth tightening before 2.0.0 ships (#1818).

Adds a workflow-level `permissions: contents: read`. The `publish` and
`publish-github-container-registry` jobs already declare their own blocks
(`id-token: write` and friends) and are unaffected: job-level permissions
override the workflow-level default outright rather than merging with it. The
comment records that, since it means each publish job must keep listing every
scope it needs — including `contents: read` — and a future edit that trims one
"because it's inherited" would break the publish.

Surfaced by the v2 tree swap (#1817): `main` had never scanned this workflow
before. Pre-existing on `v2/main`, not introduced by that merge.


Claude-Session: https://claude.ai/code/session_01Txmv2qqv3yeKgRzoqXytzD

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* ci: set a least-privilege default GITHUB_TOKEN scope

CodeQL alert #64 (`actions/missing-workflow-permissions`, medium) on
`.github/workflows/main.yml`: no `permissions` block, so every job inherits the
repository's default GITHUB_TOKEN scope, which is broader than anything here
needs.

It matters more than the severity suggests because this is the workflow that
publishes to npm under OIDC — an over-permissioned token in a job that mints
publish credentials is worth tightening before 2.0.0 ships (#1818).

Adds a workflow-level `permissions: contents: read`. The `publish` and
`publish-github-container-registry` jobs already declare their own blocks
(`id-token: write` and friends) and are unaffected: job-level permissions
override the workflow-level default outright rather than merging with it. The
comment records that, since it means each publish job must keep listing every
scope it needs — including `contents: read` — and a future edit that trims one
"because it's inherited" would break the publish.

Surfaced by the v2 tree swap (#1817): `main` had never scanned this workflow
before. Pre-existing on `v2/main`, not introduced by that merge.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Txmv2qqv3yeKgRzoqXytzD

* chore(deps): upgrade @hono/node-server to 2.0.12

Clears GHSA-frvp-7c67-39w9 (2 Dependabot alerts): path traversal in
`serve-static` on Windows via an encoded backslash, affecting < 2.0.5. The
Inspector's prod web server calls the flagged function directly
(`clients/web/server/server.ts` mounts `serveStatic` at `/*`).

Worth being precise about the actual exposure, since the summary line reads
worse than the flaw is: `..` escapes remain blocked, so it only reaches files
*inside* the configured root, by slipping past prefix-mounted middleware. Here
`root` is the built SPA — everything in it is public by design — and the only
prefix middleware (`/api/*`) is a separate route, not a subdirectory of that
root. So there was no auth bypass and no arbitrary file read to fix; this is
hygiene, not an incident.

The 1.x → 2.x majors turn out to be a non-event for this codebase: v2 drops
Node 18 (the repo already requires >=22.19.0) and removes the Vercel adapter
(unused). `serve`, `serveStatic`, and `ServerType` — the entire import surface
here, across the prod server and ~15 integration tests — are unchanged.

`npm run validate` passes on all four clients.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Txmv2qqv3yeKgRzoqXytzD

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
… latest (#1834)

`npm publish` defaults to `--tag latest` regardless of semver prerelease
status, and the publish step passed no `--tag`. So cutting the `2.0.0-rc.1`
release that #1818 calls for would have published the release candidate to
`latest` — pointing every `npx @modelcontextprotocol/inspector` at an RC. That
is the same class of failure #1816 fixed for v1, except triggered deliberately
by following the runbook.

Derives the tag from the version: a hyphen after the patch component means a
prerelease (`2.0.0-rc.1` → `next`), anything else is a release (`2.0.0` →
`latest`). Build metadata (`2.0.0+build.5`) is correctly not a prerelease.

Implemented as a shell `case` rather than with `semver`, which is only a
transitive dependency here and should not be relied on in CI.

Also makes the RC step of #1818 possible at all — there was previously no way
to pass a dist-tag through a release-triggered publish.


Claude-Session: https://claude.ai/code/session_01Txmv2qqv3yeKgRzoqXytzD

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Release candidate for the 2.0.0 go-live (#1818, §6). Publishes under the `next`
dist-tag via the derivation added in #1834 — verified: `2.0.0-rc.1` contains a
hyphen after the patch component, so it resolves to `next`, leaving `latest` on
1.0.1 untouched.

The RC exists to exercise what only exists against the live registry: the
`next`-tag publish path itself (newly written in #1834), provenance/OIDC
minting, the `files` allowlist as npm actually packs it, and the postinstall
cascade's early-exit under a real dependency install on a clean machine.


Claude-Session: https://claude.ai/code/session_01Txmv2qqv3yeKgRzoqXytzD

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…TOKEN (#1836)

* fix(ci): publish via OIDC trusted publishing, not a non-existent NPM_TOKEN

The 2.0.0-rc.1 publish failed with `npm error code ENEEDAUTH`. Two causes, both
in the v2 publish job, which had never actually executed before — every prior
release was cut from the v1 workflow.

1. `NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}` pointed at a secret that does
   not exist (the repo has no secrets at repo or environment level — publishing
   moved to OIDC trusted publishing). `setup-node` therefore wrote an *empty*
   `_authToken` into its generated `.npmrc`, and npm failed ENEEDAUTH before
   OIDC was ever attempted. Removed, with a comment saying why it must not be
   "restored".

2. The job never upgraded the npm CLI. Trusted publishing requires npm
   >= 11.5.1 and Node 22 bundles 10.x, so this would have failed even with the
   token line gone. The v1 workflow has this step; v2 was missing it.

The RC did its job: it caught both against the real registry, and consumed
nothing — the run failed before `npm publish` wrote anything, so no version was
burned and the dist-tags are untouched.

Also confirms #1834 works: the log shows `Publishing 2.0.0-rc.1 under dist-tag
'next'` before the auth failure.

README corrected — it documented `NPM_TOKEN` as part of the publish setup.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Txmv2qqv3yeKgRzoqXytzD

* docs: restructure the test-servers section into navigable subsections

The section had grown into eight undifferentiated paragraphs, the longest 1,965
characters, each describing one or two showcase configs. The content is good
reference material — the problem was purely that you could not find anything in
it or tell where one config's description ended and the next began.

Restructured, not rewritten. No facts removed:

- A summary table of all nine showcase configs, with what each demonstrates and
  its tracking issue, so the set is visible at a glance.
- One `####` subsection per config family, so each is linkable and skimmable.
- Enumerations that were buried in prose are now tables: the six MRTR presets,
  the four `trigger_*` spec-error tools and their status/code pairs.
- Step sequences (advertised extensions) and era contrasts (logging,
  subscriptions, tasks) are now bullets rather than run-on sentences.
- Two caveats that were parenthetical asides — browser `Mcp-Param-*` skipping,
  and `collect_elicitation` erroring on the modern leg — are now blockquotes,
  since both are things you hit and then have to go hunting for.

Longest line drops 1,965 → 620 characters. Verified every previously-documented
config and all technical identifiers survive.

Noted while auditing: `demo.json`, `oauth-step-up-demo.json`,
`url-elicitation-form.json` and `xaa-ema-http.json` exist in
`test-servers/configs/` but have never been documented here. Left alone —
that is a pre-existing gap, not a regression from this change.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Txmv2qqv3yeKgRzoqXytzD

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sweeps every Dependabot alert that reaches users, then bumps to rc.2 so the
swept tree gets the same live-registry validation rc.1 got. Deliberate: rc.1
validated a specific dependency tree, and changing it invalidates that proof.

Result: **zero prod-scope high/critical vulnerabilities** across all five
manifests (root + four clients).

Achieved with lockfile changes ONLY — no package.json touched, no declared
range widened, no major upgrade. Every one of these was a stale lockfile pin
sitting inside an existing caret range:

  hono             → 4.12.32  (needed 4.12.27)
  fast-uri         → 3.1.4    (needed 3.1.3)
  postcss          → 8.5.23   (needed 8.5.18)
  brace-expansion  → 1.1.16   (needed 1.1.16)
  js-yaml          → 4.3.0    (needed 4.3.0)
  ws               → 8.21.0/1 (needed 8.21.0)
  flatted          → 3.4.3    (needed 3.4.2)

Two dev-scope clusters remain, both deliberately untouched — neither ships (the
`files` allowlist is `clients/*/build`, `clients/web/dist`, and
`scripts/install-clients.mjs`), and both need real work that does not belong
immediately before a release:

- eslint (5 alerts × 5 lockfiles): a `brace-expansion` DoS via `minimatch`,
  fixable only by eslint@10 — a major bump across every package, likely
  requiring rule migration. The glob patterns involved come from the repo's own
  config, never attacker-controlled.
- vitest (3 critical, clients/web): a circular exact-pin knot —
  `@vitest/browser-playwright@4.1.0` requires `@vitest/browser@"4.1.0"` exactly,
  `vitest@4.1.0` requires `@vitest/browser-playwright@"4.1.0"` exactly, and
  `@storybook/addon-vitest` constrains the set further. `npm i` fails ERESOLVE;
  untangling means moving Storybook too.

`npm run ci` passes on the swept tree — full chain including the coverage gate,
build gate, smokes, and 462 Storybook tests.


Claude-Session: https://claude.ai/code/session_01Txmv2qqv3yeKgRzoqXytzD

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…visories; 2.0.0-rc.3 (#1841)

The #1837 sweep moved vite to 8.0.16 in the root and tui manifests but left
`clients/web` pinned at **8.0.0** — `npm update` reported "up to date" and only
an explicit install would move it. That left five open advisories, three high:

  GHSA-fx2h-pf6j-xcff  high    `server.fs.deny` bypass via Windows ADS
  GHSA-v2wj-q39q-566r  high    `server.fs.deny` bypassed with queries
  GHSA-p9ff-h696-f583  high    arbitrary file read via the dev server
  GHSA-v6wh-96g9-6wx3  medium  launch-editor NTLMv2 hash disclosure
  GHSA-4w7w-66w2-5vf9  medium  path traversal in optimized deps

These are worth fixing rather than dismissing as "dev-only". Unlike the other
remaining dev-scope alerts, `server.fs.deny` bypass is *remotely triggerable*: a
malicious page can read arbitrary files from anyone running `npm run dev`.
Published-package users are unaffected — they get the built `dist` and never
run vite — but contributors are.

Also raises the declared floor to `^8.1.5` in all three manifests that declare
vite. The root previously declared `^8.0.0`, which still *permitted* the
vulnerable 8.0.0 on a fresh resolve, so pinning the lockfile alone would have
left a regression path open.

Bumped to rc.3 rather than folding this into 2.0.0: vite builds the shipped
bundle, so changing it changes the artifact, and the tree that ships should be
the tree that was validated against the live registry. rc.2 validated a
different tree.

`npm run ci` passes — full chain including the coverage gate, build gate,
smokes, and 462 Storybook tests.


Claude-Session: https://claude.ai/code/session_01Txmv2qqv3yeKgRzoqXytzD

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
The v2 go-live release (#1818, phase 5 of #1804).

This is byte-identical to 2.0.0-rc.3 apart from dropping the prerelease suffix,
which is what makes rc.3's validation meaningful: the tree that ships is the
tree that was validated against the live registry.

`2.0.0` has no hyphen, so the derivation added in #1834 resolves it to `latest`
— this is the release that takes the tag from 1.0.1.

Validated across three release candidates:

- rc.1 caught two publish-path defects invisible to every local check —
  `NODE_AUTH_TOKEN` pointing at a non-existent secret (shadowing OIDC trusted
  publishing) and a missing npm CLI upgrade (trusted publishing needs
  >= 11.5.1; Node 22 bundles 10.x). Both fixed in #1836.
- rc.2 validated the dependency sweep (#1837) that cleared every prod-scope
  advisory using lockfile-only changes.
- rc.3 validated the vite 8.1.5 bump (#1841) closing three high-severity
  dev-server file-read advisories.

Each RC was verified with a cold `node:22` container install driving the
published tarball end to end — install, `--help`, and a real `--cli tools/list`
against a live stdio server. `latest` remained on 1.0.1 throughout, proving the
`--tag` derivation.

Zero open Dependabot alerts at time of release.


Claude-Session: https://claude.ai/code/session_01Txmv2qqv3yeKgRzoqXytzD

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
`SECURITY.md` existed on the pre-swap `main` (ac3c1a1) and still exists on
`v1/main`, but the v2 tree never had one — so #1817 silently removed the
security policy from the default branch.

That is the wrong file to be missing right now: it is where private
vulnerability reporting is advertised, and it disappeared in the same window as
2.0.0 shipping and external pull requests being turned off (#1820). Losing the
PR path and the security-report path together would leave an outside reporter
with no documented route at all.

Restored from `v1/main` with the additions #1820 asks for:

- A supported-versions table covering all four package names — v2 supported, the
  v1 line security-fixes-only under the `v1-latest` dist-tag, anything below
  1.0.0 unsupported. The three sub-packages are named explicitly since they
  exist only on v1 and are deprecated.
- A note that the repository does not accept outside pull requests, but that
  this explicitly does NOT apply to security reports, which must go through the
  advisory process rather than any public channel. Without that, the new
  issues-only policy reads as "no way to reach us".
- "Whether it affects v2, v1, or both" added to the report checklist, now that
  two lines are live.

Verified private vulnerability reporting is enabled on the repo, so the advisory
link is a working route rather than an aspiration.


Claude-Session: https://claude.ai/code/session_01Txmv2qqv3yeKgRzoqXytzD

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ture)

Prepares the milestone-merge workflow (#1821, task 1). `v2/main` and `main`
already share history — the merge base is 4d30d1c, established by the go-live
merge (#1830) — but the two had diverged on README.md, so the first
v2/main -> main milestone merge would have conflicted.

Recording main as merged here means that merge is now a clean fast-forward:
main's tip becomes an ancestor of v2/main, so the release side contributes no
changes to reconcile.

Brings from main: the README restructure (#1836), SECURITY.md (#1843), the
2.0.0 release/version commits, the workflow dist-tag change (#1834), and the
dependency bumps that shipped with the rc series.

README.md conflict resolution: took main's restructured "Test servers" section
(headings + config table + per-config subsections) and carried v2/main's #1846
correction into it. main's copy still claimed `Mcp-Param-*` mirroring is
skipped in the browser so a web `get_weather` call answers -32020; that stopped
being true when the Inspector took over building the mirrored headers itself,
so the callout now says mirroring works on every client, web included.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YAt8rqxysNbhYWLhoRm3fU
@cliffhall cliffhall added the v2 Issues and PRs for v2 label Jul 31, 2026
@cliffhall cliffhall closed this Jul 31, 2026
@cliffhall
cliffhall deleted the v2/docs/backmerge-main-into-v2main branch July 31, 2026 23:22
cliffhall added a commit that referenced this pull request Aug 2, 2026
…#1904)

main's copy of .github/workflows/main.yml carried three release fixes
v2/main never took -- #1831 (least-privilege default GITHUB_TOKEN
scope), #1834 (derive the npm dist-tag from the version) and #1836
(publish via npm OIDC trusted publishing).

Diffing the file both directions shows v2/main has NOTHING main lacks:
its only unique content is the superseded publish step,

    run: npm publish --access public --provenance
    env:
      NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

which is exactly what #1836 replaced. Every other line already matched.
So this is a verbatim copy of main's file rather than a hunk-by-hunk
forward-port -- fewer ways to get it wrong, and it leaves the two
branches byte-identical (`git diff origin/main -- .github/workflows`
is now empty).

Not a back-merge: only this one file is taken, so none of main's
pre-swap v1 lineage enters v2/main's ancestry (see #1868).


Claude-Session: https://claude.ai/code/session_01YAt8rqxysNbhYWLhoRm3fU

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

v2 Issues and PRs for v2

Projects

None yet

Development

Successfully merging this pull request may close these issues.