Skip to content

Commit 89cd75c

Browse files
committed
ci: gate MCP releases on transport and runtime checks
Run frozen installs, type checking, both builds and protocol tests across Node 20, 22, 24 and 26. Update release actions and use Node 24; validate before atomically pushing a new release commit and tag without rewriting history. Document the dependency baseline and reproducible verification command. Actionlint and package dry-run pass.
1 parent 8a393d0 commit 89cd75c

4 files changed

Lines changed: 84 additions & 38 deletions

File tree

.github/workflows/check.yml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
name: Check
2+
3+
on:
4+
push:
5+
pull_request:
6+
7+
permissions:
8+
contents: read
9+
10+
jobs:
11+
check:
12+
runs-on: ubuntu-latest
13+
strategy:
14+
fail-fast: false
15+
matrix:
16+
node: [20, 22, 24, 26]
17+
steps:
18+
- uses: actions/checkout@v7
19+
- uses: actions/setup-node@v7
20+
with:
21+
node-version: ${{ matrix.node }}
22+
- uses: oven-sh/setup-bun@v2
23+
with:
24+
bun-version: '1.4.2'
25+
- name: Install locked dependencies
26+
run: bun install --frozen-lockfile
27+
- name: Check types, build and test both transports
28+
run: bun run check
29+
- name: Verify package contents
30+
run: npm pack --dry-run --ignore-scripts

.github/workflows/release-publish.yml

Lines changed: 27 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ on:
2626
default: 'latest'
2727
type: string
2828

29+
concurrency:
30+
group: release-${{ github.ref }}
31+
cancel-in-progress: false
32+
2933
jobs:
3034
release-and-publish:
3135
runs-on: ubuntu-latest
@@ -35,24 +39,24 @@ jobs:
3539
id-token: write
3640
steps:
3741
- name: Checkout code
38-
uses: actions/checkout@v4
42+
uses: actions/checkout@v7
3943
with:
4044
fetch-depth: 0
4145
token: ${{ secrets.PAT_GITHUB }}
4246

4347
- name: Setup Node.js
44-
uses: actions/setup-node@v4
48+
uses: actions/setup-node@v7
4549
with:
46-
node-version: '18.x'
50+
node-version: '24.x'
4751
registry-url: 'https://registry.npmjs.org'
4852

4953
- name: Setup Bun
50-
uses: oven-sh/setup-bun@v1
54+
uses: oven-sh/setup-bun@v2
5155
with:
52-
bun-version: latest
56+
bun-version: '1.4.2'
5357

5458
- name: Install dependencies
55-
run: bun install
59+
run: bun install --frozen-lockfile
5660

5761
- name: Configure Git
5862
run: |
@@ -62,42 +66,32 @@ jobs:
6266
6367
- name: Bump version
6468
id: bump_version
69+
env:
70+
CUSTOM_VERSION: ${{ inputs.custom_version }}
71+
VERSION_TYPE: ${{ inputs.version_type }}
6572
run: |
66-
if [ -n "${{ github.event.inputs.custom_version }}" ]; then
67-
echo "Using custom version ${{ github.event.inputs.custom_version }}"
68-
npm version ${{ github.event.inputs.custom_version }} --no-git-tag-version
69-
echo "VERSION=${{ github.event.inputs.custom_version }}" >> $GITHUB_ENV
70-
else
71-
echo "Bumping ${{ github.event.inputs.version_type }} version"
72-
NEW_VERSION=$(npm version ${{ github.event.inputs.version_type }} --no-git-tag-version)
73-
echo "VERSION=${NEW_VERSION:1}" >> $GITHUB_ENV
74-
fi
75-
echo "New version: ${{ env.VERSION }}"
73+
npm version "${CUSTOM_VERSION:-$VERSION_TYPE}" --no-git-tag-version
74+
VERSION=$(node -p "JSON.parse(require('fs').readFileSync('package.json', 'utf8')).version")
75+
echo "VERSION=$VERSION" >> "$GITHUB_ENV"
76+
bun install --lockfile-only
7677
7778
- name: Generate Changelog
7879
run: |
7980
npm run changelog
8081
npm run changelog:latest
8182
82-
- name: Build project
83-
run: bun run build && bun run build:http
84-
85-
- name: Commit and push changes
86-
run: |
87-
git pull origin main --no-edit
88-
git add package.json CHANGELOG.md
89-
git commit -m "Bump version to v${{ env.VERSION }}"
90-
git push --force-with-lease
83+
- name: Check types, build and test before release
84+
run: bun run check
9185

92-
- name: Create and push tag
86+
- name: Commit and tag the verified release
9387
run: |
94-
git tag -d "v${{ env.VERSION }}" 2>/dev/null || true
95-
git push origin --delete "v${{ env.VERSION }}" 2>/dev/null || true
96-
git tag -a "v${{ env.VERSION }}" -m "Release v${{ env.VERSION }}"
97-
git push origin "v${{ env.VERSION }}"
88+
git add package.json bun.lock CHANGELOG.md
89+
git commit -m "chore: release v$VERSION"
90+
git tag -a "v$VERSION" -m "Release v$VERSION"
91+
git push --atomic origin "HEAD:refs/heads/$GITHUB_REF_NAME" "refs/tags/v$VERSION"
9892
9993
- name: Create GitHub Release
100-
uses: softprops/action-gh-release@v1
94+
uses: softprops/action-gh-release@v3
10195
with:
10296
tag_name: v${{ env.VERSION }}
10397
name: Release v${{ env.VERSION }}
@@ -107,7 +101,8 @@ jobs:
107101
GITHUB_TOKEN: ${{ secrets.PAT_GITHUB }}
108102

109103
- name: Publish to npm
110-
run: npm publish --access public --provenance --tag ${{ github.event.inputs.dist_tag || 'latest' }}
104+
run: npm publish --ignore-scripts --access public --provenance --tag "$DIST_TAG"
111105
env:
106+
DIST_TAG: ${{ inputs.dist_tag || 'latest' }}
112107
# Restored the token here to ensure it works
113108
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

README.md

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ All services are exposed through a consistent interface of MCP tools, resources,
175175

176176
## 🛠️ Prerequisites
177177

178-
- [Bun](https://bun.sh/) 1.0.0 or higher (recommended)
178+
- [Bun](https://bun.sh/) 1.4.2 (the version used by CI)
179179
- Node.js 20.0.0 or higher (if not using Bun)
180180
- Optional: [Etherscan API key](https://etherscan.io/apis) for ABI fetching
181181

@@ -187,7 +187,7 @@ git clone https://github.com/mcpdotdirect/evm-mcp-server.git
187187
cd evm-mcp-server
188188

189189
# Install dependencies with Bun
190-
bun install
190+
bun install --frozen-lockfile
191191

192192
# Or with npm
193193
npm install
@@ -747,6 +747,15 @@ evm-mcp-server/
747747

748748
## 🛠️ Development
749749

750+
Run the complete migration checks before committing or publishing:
751+
752+
```bash
753+
bun install --frozen-lockfile
754+
bun run check
755+
```
756+
757+
This type-checks source and tests, builds both Node entry points, and runs the HTTP, OAuth, and modern/legacy stdio integration tests. Tests use local fixtures and do not submit blockchain transactions. CI runs the checks across Node 20, 22, 24, and 26. See [the migration notes](docs/mcp-2026-07-28-upgrade.md) for protocol decisions and dependency versions.
758+
750759
To modify or extend the server:
751760

752761
1. Add new services in the appropriate file under `src/core/services/`

docs/mcp-2026-07-28-upgrade.md

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ This repository targets the final MCP `2026-07-28` specification through the rel
99
- SDK v1-to-v2 migration: https://github.com/modelcontextprotocol/typescript-sdk/blob/main/docs/migration/upgrade-to-v2.md
1010
- SDK `2026-07-28` support: https://github.com/modelcontextprotocol/typescript-sdk/blob/main/docs/migration/support-2026-07-28.md
1111

12+
## Dependency Baseline
13+
14+
Verified against the registry on September 13, 2026: the server, Node, Express, and test-client MCP packages are on stable `2.0.0`. Runtime dependencies include Express `5.2.1`, viem `2.56.5`, and Zod `4.6.4`; `bun.lock` pins the complete dependency graph. TypeScript `5.9.3` is a development dependency, not a peer requirement for consumers of the compiled CLI. Node types stay on the existing 22.x line rather than introducing Node 26-only APIs. The migration does not require the TypeScript 7 major upgrade.
15+
1216
## Final Alignment
1317

1418
- Replaced `@modelcontextprotocol/sdk` v1 with:
@@ -29,6 +33,9 @@ This repository targets the final MCP `2026-07-28` specification through the rel
2933
- `Mcp-Method`
3034
- `Mcp-Name`
3135
- Added Host and Origin validation before the HTTP MCP handler.
36+
- Added application-level enforcement of the protocol-version header and both accepted response types, including `q=0` exclusions. These supplement SDK v2.0.0's header value validation.
37+
- Return JSON-RPC parse errors for malformed JSON and a JSON error for the 1 MB request limit; syntactically valid non-RPC JSON remains the SDK's responsibility.
38+
- Verified Base64 sentinel decoding for `Mcp-Name` and `x-mcp-header` parameter validation. Current EVM tools do not declare routing headers; an annotated test tool verifies missing, malformed, mismatched, and correctly encoded headers before handler execution.
3239
- Added MCP OAuth resource-server support for HTTP:
3340
- localhost can run without authorization
3441
- non-local binds fail closed unless OAuth is configured
@@ -52,6 +59,7 @@ This repository targets the final MCP `2026-07-28` specification through the rel
5259
- rejects tampering, argument changes, cross-token use, and replay
5360
- Bounded `wait_for_transaction` with `timeoutSeconds` from 1 through 90, defaulting to 90 seconds so it returns before the 120-second HTTP transport timeout.
5461
- Kept process diagnostics on `stderr`, including the npm CLI startup line, so stdio `stdout` contains protocol messages only.
62+
- The CLI uses its parent Node executable and propagates child startup failures. Server identity reads the package version at build time so version bumps update both entry points.
5563

5664
## Final-Spec Differences from the RC
5765

@@ -108,17 +116,21 @@ The automated MCP integration tests cover:
108116
- cache hints on discovery, list, and resource results
109117
- resource reads and a read-only tool call
110118
- final `HeaderMismatch` and `UnsupportedProtocolVersion` error codes
119+
- real Express HTTP requests covering media types, required headers, Host/Origin rejection, parser errors, removed methods, and the SDK client
120+
- packaged Node CLI clients exercising tools, resource reads, and prompts over modern and legacy stdio, plus startup exit-code propagation
111121
- local authorization opt-out, remote fail-closed behavior, OAuth metadata validation, RFC 7662 introspection, audience checks, and scopes
112122

113123
Release checks:
114124

115125
```bash
116-
bunx tsc --noEmit
117-
bun run test:mcp
118-
bun run build
119-
bun run build:http
126+
bun install --frozen-lockfile
127+
bun run check
128+
bun audit
129+
npm pack --dry-run --ignore-scripts
120130
```
121131

132+
`bun run check` type-checks source and tests, builds both entry points, then runs the complete test suite (including the built CLI). `bun run test:mcp` runs the suite against existing build output. Tests use localhost listeners and fixture credentials; they do not submit blockchain transactions. CI runs the checks with Node 20, 22, 24, and 26 and Bun 1.4.2. The manual release workflow uses Node 24, verifies the bumped package before committing, and pushes the commit and new tag atomically without rewriting existing tags or branches. No npm release is triggered by a normal branch push.
133+
122134
## Follow-up Work
123135

124136
These are enhancements, not compliance blockers:

0 commit comments

Comments
 (0)