Skip to content

Upgrade MCP infrastructure to SDK v2 + 2026-07-28 protocol - #409

Merged
runyourempire merged 1 commit into
mainfrom
worktree-mcp-sdk-v2-upgrade
Aug 11, 2026
Merged

Upgrade MCP infrastructure to SDK v2 + 2026-07-28 protocol#409
runyourempire merged 1 commit into
mainfrom
worktree-mcp-sdk-v2-upgrade

Conversation

@runyourempire

Copy link
Copy Markdown
Collaborator

What

Migrates all three MCP servers off the discontinued @modelcontextprotocol/sdk v1 line (frozen at 1.30.0, 2026-07-27) onto the stable SDK v2 packages, and adopts the v2 serving entries so every endpoint speaks both protocol eras — the classic 2025 initialize handshake AND the new stateless 2026-07-28 revision (server/discover).

Package Before After
@4da/mcp-server (published) 4.6.7, sdk ^1.29.0 5.0.0, @modelcontextprotocol/server + /node ^2.0.0
mcp-memory-server (private) 1.0.0, sdk ^1.29.0 2.0.0, @modelcontextprotocol/server ^2.0.0
@4da/mcp-streets-server (unpublished) 1.0.0, sdk ^1.10.0 2.0.0, @modelcontextprotocol/server ^2.0.0

How

  • Official codemod (@modelcontextprotocol/codemod v1-to-v2) first, then restructure per the official migration guide: each server's handlers now live in a buildServer() factory.
  • stdioserveStdio(buildServer): era negotiated per connection; one pinned instance per connection (identical to prior behavior for 2025 hosts).
  • --http (4da server) → createMcpHandler(buildServer) + toNodeHandler: stateless serving for both eras; the hand-rolled per-request transport + body parsing is gone. Health endpoint, localhost bind, Origin-header DNS-rebinding protection, and the optional JWT auth gate are unchanged.
  • Handler registration moved to method strings ('tools/list', 'tools/call', 'resources/list', 'resources/read'); dispatchTool return typed as spec CallToolResult; memory server's ToolResponse.content[].type narrowed to the "text" literal (SDK v2 types handler returns from the spec).
  • semver-major for the published package: SDK v2 requires Node >= 20 (Node 18 EOL since Apr 2025). Bumped engines, README badge, and the .mcpb manifest runtime floor; server.json (MCP registry) bumped to 5.0.0. CI already runs Node 22 — no workflow changes needed.
  • Fixed a real drift bug: the stdio startup log hardcoded "v4.6.3"; it now derives from package.json.

Verification (13/13 live runs, not just unit tests)

  • v1-SDK client (1.30.0) — what today's hosts run — against each migrated server over stdio: connect → listToolscallTool all pass. Old hosts are unaffected; this was tested, not assumed.
  • v2 client, legacy mode: era=legacy, all pass.
  • v2 client, versionNegotiation: auto: negotiates era=modern on all three servers — the 2026-07-28 revision is genuinely served.
  • HTTP (--http): health 200 @ 5.0.0, v1 client, v2-legacy, and v2-auto (era=modern) with live get_context calls.
  • Unit suite: 135/135 (mcp-4da-server vitest). pnpm install --frozen-lockfile + build verified for both pnpm packages (CI job's exact steps). File-size, doc-location, sync, ESLint, tsc, and secrets gates all pass.

Deliberately NOT done (operator calls)

  • No npm publish / no mcp-v* tag — publishing 5.0.0 is registry-irreversible; the tag-triggered workflow is ready when you are. Note: npm currently has 4.6.6 while the repo said 4.6.7 (4.6.7 was never published) — 5.0.0 supersedes.
  • mcp-streets-server: upgraded for consistency, but it is unpublished, unregistered in .mcp.json, and STREETS content moved to 4da.ai — flagging it as a deletion candidate under doctrine rule 8 (your call).
  • Victauri's embedded MCP (separate crate/repo) is out of scope; a peer terminal is already upgrading Verax's MCP to dual-era.

🤖 Generated with Claude Code

https://claude.ai/code/session_017dYrVvSZ1NpsteZUbzsjsc

Migrate all three MCP servers off the discontinued @modelcontextprotocol/sdk
v1 line (frozen at 1.30.0) onto the stable v2 packages, and adopt the v2
serving entries so every endpoint speaks both protocol eras:

- mcp-4da-server 5.0.0: @modelcontextprotocol/server + /node. stdio via
  serveStdio (era negotiated per connection), --http via createMcpHandler +
  toNodeHandler (stateless, both eras; health/auth/origin guards unchanged).
  Handlers restructured into a buildServer() factory; method-string
  registration; dispatchTool typed as CallToolResult. Fixes the hardcoded
  v4.6.3 startup-log version drift. Node >=20 (SDK v2 floor) in engines,
  README badge, and the .mcpb manifest; server.json bumped.
- mcp-memory-server 2.0.0: same factory + serveStdio pattern; Tool type from
  the server package; ToolResponse narrowed to the "text" literal.
- mcp-streets-server 2.0.0: same pattern, from SDK ^1.10.0.

Verified live, 13/13: each server against a real v1-SDK (1.30.0) client —
today's hosts, classic initialize handshake — plus a v2 client in legacy and
auto modes (auto negotiates era=modern, proving 2026-07-28 is served), and
the HTTP endpoint with health + v1 + v2-legacy + v2-auto. Unit suite: 135/135.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017dYrVvSZ1NpsteZUbzsjsc
@vercel

vercel Bot commented Aug 11, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
4da-home Ready Ready Preview Aug 11, 2026 2:53am

@runyourempire
runyourempire enabled auto-merge (squash) August 11, 2026 02:54
@runyourempire
runyourempire merged commit d5df9e3 into main Aug 11, 2026
10 checks passed
@runyourempire
runyourempire deleted the worktree-mcp-sdk-v2-upgrade branch August 11, 2026 03:04
runyourempire added a commit that referenced this pull request Aug 11, 2026
…rface (#411)

## What & why

Removes `mcp-streets-server` entirely. STREETS is 4da.ai website
content; it should not have an MCP server (operator direction,
consistent with the 2026-06-12 doctrine decision that retired the in-app
STREETS tab).

## Verification performed before deletion

- **What it did**: served the 7-module STREETS playbook markdown from
`docs/streets/` (which **stays** — the website is its home), "revenue
engine" project analysis, and personal lesson progress in a local SQLite
DB.
- **Zero consumers**: never published to npm (`@4da/mcp-streets-server`
→ E404), not registered in `.mcp.json` or `.claude/settings.json`, no
site/docs/course prose instructs installing it, no workspace includes
it, git history shows only dependency-hygiene sweeps.
- **Complete blast radius handled in the same commit**: nightly-audit
lockfile matrix (`.github/workflows/nightly-audit.yml`), `.gitignore`
artifact patterns, and `scripts/add-spdx-headers.cjs` roots no longer
reference the directory. `git grep` confirms no other tracked references
remain.

Follows #409 (which upgraded it along with the other servers before this
deletion was decided — history preserves everything).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

https://claude.ai/code/session_017dYrVvSZ1NpsteZUbzsjsc

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
runyourempire added a commit that referenced this pull request Aug 11, 2026
…hono/node-server 2.1.0 (#417)

`@4da/mcp-server` is published to npm, so its **runtime** dependencies
ship to users. Eight of the repo's nine `runtime`-scope Dependabot
alerts live here — all in the hono stack, pulled in transitively by the
MCP SDK v2 packages.

```
hono               4.12.25 -> 4.13.1    7 advisories (patched at 4.12.27 / 4.12.34)
@hono/node-server  1.19.14 -> 2.1.0     1 advisory  (patched at 2.0.5)
```

Context: of the repo's 44 open alerts, **36 are `development` scope and
every `high` is dev tooling.** These 8 plus `serde_with` (#305, merged)
were the entire shipped-code surface. This closes it.

## Why Dependabot never raised these

Neither package was a **direct** dependency — which is exactly why hono
PRs exist for `mcp-memory-server` but never for this one. `hono` is now
declared explicitly, which pins the version *and* makes it visible to
Dependabot going forward, so the blind spot doesn't recur.

## A pnpm override alone would have shipped a false fix

`hono` is an **optional peer** of `@modelcontextprotocol/node`. Adding
it to `pnpm.overrides` rewrote the peer *range* while resolution stayed
on **4.12.25** — confirmed on disk after `pnpm install --force`. The
explicit dependency is what actually moves it. The `@hono/node-server`
override does work, because that one is a real dependency of the SDK
rather than a peer.

## The major bump was tested, not assumed

`@hono/node-server` 1.x → 2.x is a major bump of a package the SDK owns,
so:

- `pnpm run build` — clean
- **135/135 tests pass**
- clean `--frozen-lockfile` install resolves **only** `hono@4.13.1` and
`@hono/node-server@2.1.0` — no vulnerable copy anywhere in the lockfile
- **stdio transport** (the default): real `initialize` + `tools/list`
handshake, 14 tools returned
- **HTTP transport** (`--http`): server listens, `tools/list` returns
the full tool set — this is the path `@hono/node-server` actually serves

## One pre-existing thing, explicitly not a regression

`server/discover` (the 2026-07-28 era entry point) answers `-32601
Method not found`. I built a control worktree at unmodified `main` and
got **identical** behaviour there, so it predates this change. Flagging
it because the SDK v2 upgrade (#409) advertised dual-era support — worth
a separate look, not a blocker here.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

https://claude.ai/code/session_01WR8YdADiaw1p8pD8CddncD

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
runyourempire added a commit that referenced this pull request Aug 17, 2026
…ME (#478)

## The residual this closes

npm is the **last surface anywhere still serving retired AD-030 copy**.
Timeline: 5.0.1 was published to npm manually at 2026-08-16 **11:01Z** —
thirteen minutes before #469 merged the corrected README at **11:14Z**.
So the live npm page still carries:

- `| Compound intelligence (learns over time) | -- | Yes |` (comparison
table)
- "…scored content from 20+ sources that **compounds over time**." (FAQ)

The repo README has been clean since #469 (`check-retired-claims`
verifies it — `mcp-4da-server/README.md` is in the gate's scan set).
Publishing current repo state fixes the npm surface. Tracked as item 2/3
of the AD-030 residuals in `.claude/plans/PENDING-DECISION.md`.

## Change (version metadata only, no code)

- `package.json` 5.0.1 → **5.0.2**
- `server.json` both version fields → 5.0.2
- `.claude-plugin/plugin.json` → 5.0.2 (had been left stale at 5.0.0)
- `CHANGELOG.md`: 5.0.1 marked released (it is live on npm), 5.0.2 entry
records why this release exists
- `src/index.ts` untouched — `SERVER_VERSION` reads package.json at
runtime (#409)

## Release plan after merge

Tag `mcp-v5.0.2` on the squash commit → `publish-mcp-server.yml`
publishes to npm (`NPM_TOKEN`, last exercised successfully on
4.6.5/4.6.6) + MCP Registry via OIDC. The workflow's version-matches-tag
check requires exactly this bump.

## Verification

- `pnpm run build` clean, `pnpm test` **185/185**
- `node scripts/check-mcp-server-sync.cjs` — in sync
- `node scripts/check-retired-claims.cjs` — OK (repo README clean)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

https://claude.ai/code/session_01LBY5q2MskiKMkTm6NmB49L

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
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.

1 participant