diff --git a/.artifacts/ci-deps-update/REPORT.md b/.artifacts/ci-deps-update/REPORT.md new file mode 100644 index 0000000..52f4bfc --- /dev/null +++ b/.artifacts/ci-deps-update/REPORT.md @@ -0,0 +1,107 @@ +# ci-deps-update / CI近代化+依存更新(7日ルール)+脆弱性0化 + +Created: 2026-06-12 +Branch: feature/ci-deps-update +Status: Awaiting Review + +## 📦 依頼内容(これは何のアウトプット?) + +> 「CIのnodeの問題とnpmに脆弱生成がないか?古すぎないか?7日ルールで最新にするやつを1つのPRにして!」 + +→ ①CIのNode deprecated警告対応、②npm依存の脆弱性解消(**39件→0件**)、③**7日ルール**(公開から7日以上経過した最新版のみ採用=サプライチェーン対策)での依存更新、を1つのPRにまとめました。さらに検証中に**本番の /mcp が warm isolate で500になる既存バグ**を発見し、修正を同梱しています。 + +## 📌 Attention Required(今回の確認項目) + +| # | 確認ポイント | 前提・判断材料 | 質問 | +|---|------|---------------|------| +| 1 | **MCPの既存バグ修正を同梱した** | 検証中に発見:本番 `/mcp` へ連続リクエストすると3回目で500(`Already connected to a transport`)。単一McpServerに毎リクエストtransportをconnectする実装が原因で、**今の本番でも再現**(200/200/500を実測)。SDK 1.29ではこのエラーが確実に出るため、修正なしでは更新自体が成立しない | 同梱でOK?(分離するなら依存更新PRが先に進めない依存関係になる) | +| 2 | **zod 3→4 のメジャー更新を含む** | MCP SDK 1.29.0 / @hono/mcp 0.3.0 は `zod ^3.25 \|\| ^4.0` 対応を確認。実workerdで tools/list(JSONスキーマ変換)・tools/call(実GitHub取得)まで実打して成功 | OK? | +| 3 | **CIを npm install → pnpm + frozen-lockfile に変更** | リポジトリはpnpm管理なのにCIだけ `npm install`(ロックファイル無視)だった。前PRでlockfileを同期済みなので、CIもlockfile通りに入れる方が7日ルールの固定が効く | OK? | +| 4 | **CIのNodeを22→24(LTS)に更新** | actionsのdeprecation対応と同時に実施。ローカルは26で動作確認済み | OK? | + +## 🛡 脆弱性: 39件 → 0件 + +| | Before | After | +|---|--------|-------| +| **pnpm audit** | 🔴 **39件**(high 8 / moderate 28 / low 3) | 🟢 **0件**(No known vulnerabilities found) | +| 主な原因 | hono 4.7.5(JWT等の既知脆弱性)、MCP SDK 1.17.4配下の古いexpress系 | 直接依存の更新+transitive 2件(path-to-regexp 8.4.0 / qs 6.15.2)はpnpm overridesで強制 | + +## 📅 依存更新(7日ルール: 2026-06-05以前に公開された最新版のみ採用) + +| パッケージ | Before | After | 公開日 | 最新版を見送った理由 | +|---|---|---|---|---| +| hono | 4.7.5 | **4.12.23** | 2026-05-25 | 4.12.25は06-09公開=7日未満 | +| zod | 3.25.76 | **4.4.3** | 2026-05-04 | (4.4.3が最新) | +| @modelcontextprotocol/sdk | 1.17.4 | **1.29.0** | 2026-03-30 | (1.29.0が最新) | +| @hono/mcp | 0.1.1 | **0.3.0** | 2026-05-16 | (0.3.0が最新) | +| @cloudflare/workers-types | 4.20250405.0 | **4.20260605.1** | 2026-06-05 | 4.20260612.1は当日公開 | +| @typescript/native-preview | dev.20260326.1 | **dev.20260604.1** | 2026-06-04 | dev.20260611.2は7日未満 | +| path-to-regexp (transitive) | 8.2.x | **8.4.0** (override) | 2026-03-26 | DoS脆弱性パッチ版 | +| qs (transitive) | 6.13.x | **6.15.2** (override) | 2026-05-16 | DoS脆弱性パッチ版 | +| wrangler / vite / vitest / typescript / @cloudflare/vite-plugin / jszip | — | **据え置き** | — | 既に「7日ルール内の最新」(より新しい版は7日未満 or 存在せず) | + +## ⚙️ CI workflow の変更(Node 20 deprecated 対応) + +| 項目 | Before | After | 7日ルール確認 | +|---|---|---|---| +| actions/checkout | v4(Node20系・deprecated) | **v6** | v6.0.3 公開 2026-06-02 ✓ | +| actions/setup-node | v4(同上) | **v6** | v6.4.0 公開 2026-04-20 ✓ | +| actions/github-script | v7(同上) | **v9** | v9.0.0 公開 2026-04-09 ✓ | +| pnpm/action-setup | (なし) | **v6** 新規 | v6.0.8 公開 2026-05-12 ✓ | +| Node.js | 22 | **24(LTS)** | — | +| インストール | `npm install`(lockfile無視😱) | `pnpm install --frozen-lockfile` | — | + +## 🐛 同梱バグ修正: /mcp が warm isolate で500 + +```mermaid +flowchart LR + subgraph Before["Before(本番で実測: 200/200/500)"] + A1[リクエスト1] --> S1[単一のmcpServer
connect 1回目 OK] + A2[リクエスト2
同じisolate] --> S2["connect 2回目
💥 Already connected"] + end + subgraph After["After(実測: 200/200/200)"] + B1[リクエスト1] --> C1[createMcpServer()
毎回新インスタンス] + B2[リクエスト2] --> C2[createMcpServer()
毎回新インスタンス] + end +``` + +- `src/mcp.ts`: `export const mcpServer` → `export function createMcpServer()` ファクトリ化 +- `src/index.ts`: `/mcp` ルートでリクエスト毎に生成 +- `tests/integration/http.spec.ts`: **Test 6b** として連続initialize×3が全部200になるregressionテストを追加 + +## ✅ Evidence(検証ログ) + +### テスト・ビルド・監査 +```bash +pnpm install --frozen-lockfile # CIと同条件 → OK +pnpm typecheck # エラーなし +pnpm test # Test Files 3 passed / Tests 43 passed(regression含む) +pnpm build # ✓ built +pnpm audit # No known vulnerabilities found +node tests/e2e/extension.e2e.mjs # E2E ALL GREEN(拡張も無事) +``` + +### 実workerd(wrangler dev)での実打 +```bash +# tools/list → zod4のJSONスキーマ変換成功(inputSchema が正しく出力される) +# tools/call → 実GitHubから File Tree 取得成功 +# 連続initialize×3 → try1: 200 / try2: 200 / try3: 200 +# (比較: 現在の本番 https://pera1.kazu-san.workers.dev/mcp は try3 で 500) +``` + +### Verification Checklist +- [x] 脆弱性 39件→0件(pnpm audit実測) +- [x] 全更新パッケージの公開日を npm registry で実測し7日ルール適合を確認 +- [x] vitest 43件パス(regressionテスト追加込み)/ tsc クリーン / build成功 +- [x] 実workerdでMCPフルフロー(initialize→tools/list→tools/call)実打成功 +- [x] 本番の /mcp 500バグを実測で確認した上で修正・regressionテスト追加 +- [x] CIと同条件の frozen-lockfile インストール成功 + +
+⚠️ 備考・スコープ外 + +- マージ後、deploy.yml が本番デプロイするので `/mcp` バグ修正も自動で本番反映される +- gist対応やhono 4.12系の新機能追従はスコープ外 +- 今後 `pnpm audit` をCIに組み込む案もあり(今回は入れていない。希望あれば追加) + +
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b16caf9..8cb7eeb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,41 +10,54 @@ jobs: test: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - - uses: actions/setup-node@v4 + - uses: pnpm/action-setup@v6 with: - node-version: "22" + version: 10 + + - uses: actions/setup-node@v6 + with: + node-version: "24" + cache: pnpm - name: Install dependencies - run: npm install + run: pnpm install --frozen-lockfile - name: Type check - run: npx tsc --noEmit + run: pnpm exec tsc --noEmit - name: Run tests - run: npx vitest run + run: pnpm exec vitest run preview: if: github.event_name == 'pull_request' needs: test runs-on: ubuntu-latest permissions: + # permissionsを明示すると未指定スコープはnoneになる。 + # 現状publicリポジトリなのでcheckoutは通るが、private化に備えて明示する + contents: read pull-requests: write steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 + + - uses: pnpm/action-setup@v6 + with: + version: 10 - - uses: actions/setup-node@v4 + - uses: actions/setup-node@v6 with: - node-version: "22" + node-version: "24" + cache: pnpm - name: Install dependencies - run: npm install + run: pnpm install --frozen-lockfile - name: Deploy to preview id: deploy run: | - OUTPUT=$(npx wrangler deploy --env preview --minify 2>&1) + OUTPUT=$(pnpm exec wrangler deploy --env preview --minify 2>&1) echo "$OUTPUT" PREVIEW_URL=$(echo "$OUTPUT" | grep -oP 'https://[^\s]+\.workers\.dev' | head -1) echo "preview_url=$PREVIEW_URL" >> "$GITHUB_OUTPUT" @@ -53,7 +66,7 @@ jobs: CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} - name: Comment preview URL on PR - uses: actions/github-script@v7 + uses: actions/github-script@v9 with: script: | const previewUrl = '${{ steps.deploy.outputs.preview_url }}' || 'https://pera1-preview..workers.dev'; diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index e8b1713..69110e4 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -8,17 +8,22 @@ jobs: deploy: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - - uses: actions/setup-node@v4 + - uses: pnpm/action-setup@v6 with: - node-version: "22" + version: 10 + + - uses: actions/setup-node@v6 + with: + node-version: "24" + cache: pnpm - name: Install dependencies - run: npm install + run: pnpm install --frozen-lockfile - name: Deploy to Cloudflare Workers (production) - run: npx wrangler deploy --minify + run: pnpm exec wrangler deploy --minify env: CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} diff --git a/package.json b/package.json index 2d5877a..bd553c7 100644 --- a/package.json +++ b/package.json @@ -16,19 +16,25 @@ "test:watch": "vitest" }, "dependencies": { - "@hono/mcp": "^0.1.1", - "@modelcontextprotocol/sdk": "^1.17.4", - "hono": "^4.7.5", + "@hono/mcp": "^0.3.0", + "@modelcontextprotocol/sdk": "^1.29.0", + "hono": "^4.12.23", "jszip": "^3.10.1", - "zod": "^3.24.1" + "zod": "^4.4.3" }, "devDependencies": { "@cloudflare/vite-plugin": "^1.30.1", - "@cloudflare/workers-types": "^4.20250405.0", - "@typescript/native-preview": "7.0.0-dev.20260326.1", + "@cloudflare/workers-types": "^4.20260605.1", + "@typescript/native-preview": "7.0.0-dev.20260604.1", "typescript": "^6.0.2", "vite": "^8.0.3", "vitest": "^4.1.2", "wrangler": "^4.98.0" + }, + "pnpm": { + "overrides": { + "path-to-regexp@>=8.0.0 <8.4.0": "8.4.0", + "qs@<6.15.2": "6.15.2" + } } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1379d18..8c7764d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4,35 +4,39 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false +overrides: + path-to-regexp@>=8.0.0 <8.4.0: 8.4.0 + qs@<6.15.2: 6.15.2 + importers: .: dependencies: '@hono/mcp': - specifier: ^0.1.1 - version: 0.1.1(@modelcontextprotocol/sdk@1.17.4)(hono@4.7.5) + specifier: ^0.3.0 + version: 0.3.0(@modelcontextprotocol/sdk@1.29.0(zod@4.4.3))(hono-rate-limiter@0.5.3(hono@4.12.23))(hono@4.12.23)(zod@4.4.3) '@modelcontextprotocol/sdk': - specifier: ^1.17.4 - version: 1.17.4 + specifier: ^1.29.0 + version: 1.29.0(zod@4.4.3) hono: - specifier: ^4.7.5 - version: 4.7.5 + specifier: ^4.12.23 + version: 4.12.23 jszip: specifier: ^3.10.1 version: 3.10.1 zod: - specifier: ^3.24.1 - version: 3.25.76 + specifier: ^4.4.3 + version: 4.4.3 devDependencies: '@cloudflare/vite-plugin': specifier: ^1.30.1 - version: 1.40.0(vite@8.0.16(esbuild@0.27.3))(workerd@1.20260603.1)(wrangler@4.98.0(@cloudflare/workers-types@4.20250405.0)) + version: 1.40.0(vite@8.0.16(esbuild@0.27.3))(workerd@1.20260603.1)(wrangler@4.98.0(@cloudflare/workers-types@4.20260605.1)) '@cloudflare/workers-types': - specifier: ^4.20250405.0 - version: 4.20250405.0 + specifier: ^4.20260605.1 + version: 4.20260605.1 '@typescript/native-preview': - specifier: 7.0.0-dev.20260326.1 - version: 7.0.0-dev.20260326.1 + specifier: 7.0.0-dev.20260604.1 + version: 7.0.0-dev.20260604.1 typescript: specifier: ^6.0.2 version: 6.0.3 @@ -44,7 +48,7 @@ importers: version: 4.1.8(vite@8.0.16(esbuild@0.27.3)) wrangler: specifier: ^4.98.0 - version: 4.98.0(@cloudflare/workers-types@4.20250405.0) + version: 4.98.0(@cloudflare/workers-types@4.20260605.1) packages: @@ -98,8 +102,8 @@ packages: cpu: [x64] os: [win32] - '@cloudflare/workers-types@4.20250405.0': - resolution: {integrity: sha512-rE7LQirsEorBir5hymXpi0D+G01lZ65GZTKBjmkbWLNHRQyyG964wqlMzxFuFTndKttLTlJjZyZHHg5scBi4Kg==} + '@cloudflare/workers-types@4.20260605.1': + resolution: {integrity: sha512-9YJaGPQwuQYFHoElVhJP40ZmUO/Z2OiBon58sKpHjgwq5btC/B2BZLC45AQ14k+1I+hjcY2z2t2R6uUxU9AqwQ==} '@cspotcode/source-map-support@0.8.1': resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} @@ -270,11 +274,19 @@ packages: cpu: [x64] os: [win32] - '@hono/mcp@0.1.1': - resolution: {integrity: sha512-2iQ4xBKfQdBBJP3V1/XCVyxQZeWWnxJG+5ytu9/Xuwwje3D70fm9ws0VV536rZ3CKWrnZZ/X+xeJ7FwR3ErVbw==} + '@hono/mcp@0.3.0': + resolution: {integrity: sha512-UhSWFbZwRxHBdptOn2r1HyB8Vt6gU+BL3AbTis2t8TBW69ZhG4soJQ09yEL/t/ymxszJnWp5Rq6tOXXOjuK1qg==} + peerDependencies: + '@modelcontextprotocol/sdk': ^1.25.1 + hono: '*' + hono-rate-limiter: ^0.5.3 + zod: ^3.25.0 || ^4.0.0 + + '@hono/node-server@1.19.14': + resolution: {integrity: sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw==} + engines: {node: '>=18.14.1'} peerDependencies: - '@modelcontextprotocol/sdk': ^1.12.0 - hono: '>=4.0.0' + hono: ^4 '@img/colour@1.1.0': resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} @@ -442,9 +454,15 @@ packages: '@jridgewell/trace-mapping@0.3.9': resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} - '@modelcontextprotocol/sdk@1.17.4': - resolution: {integrity: sha512-zq24hfuAmmlNZvik0FLI58uE5sriN0WWsQzIlYnzSuKDAHFqJtBFrl/LfB1NLgJT5Y7dEBzaX4yAKqOPrcetaw==} + '@modelcontextprotocol/sdk@1.29.0': + resolution: {integrity: sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ==} engines: {node: '>=18'} + peerDependencies: + '@cfworker/json-schema': ^4.1.1 + zod: ^3.25 || ^4.0 + peerDependenciesMeta: + '@cfworker/json-schema': + optional: true '@napi-rs/wasm-runtime@1.1.4': resolution: {integrity: sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==} @@ -584,43 +602,51 @@ packages: '@types/estree@1.0.9': resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} - '@typescript/native-preview-darwin-arm64@7.0.0-dev.20260326.1': - resolution: {integrity: sha512-eEMQnArhP/9cLOR3kkShEmT2y1dUs/kHLpwOdEHFmkXwJ477V7P0eZEtabsF5xefU9GwF+cMw4cw60ANVGPgeA==} + '@typescript/native-preview-darwin-arm64@7.0.0-dev.20260604.1': + resolution: {integrity: sha512-zs616um9UuaODLsNlCu5Aw95rFcTV4u3hVt090r6k0lVvTxfaJOv8HKA6BpIotcEYlZlMQowrMSYCCdedo7iyA==} + engines: {node: '>=16.20.0'} cpu: [arm64] os: [darwin] - '@typescript/native-preview-darwin-x64@7.0.0-dev.20260326.1': - resolution: {integrity: sha512-lUjpUTe95X4pmxIJb354UY/+1/+0Zh3z0J9ekNSWhhWgZpqQQi5rS1C5BfSJbg2aH8OXYVaEFWzxddXc8qeILg==} + '@typescript/native-preview-darwin-x64@7.0.0-dev.20260604.1': + resolution: {integrity: sha512-pOdNAf2pwc9JBjo8gUsvLs5uqg7d0AhYXfE8/3zvPKBlIZG+mTcvEWW1hPawlWxXzf/vxnP4dgYwUHAMDghhKA==} + engines: {node: '>=16.20.0'} cpu: [x64] os: [darwin] - '@typescript/native-preview-linux-arm64@7.0.0-dev.20260326.1': - resolution: {integrity: sha512-rhqnrDAeC1FhXuXDPQlcMULIvdlzerCc0cXJ16i18waLpZ1nr5ntvzhzzRx7+DvugemTGf2ximX6r/N9HRt+Ow==} + '@typescript/native-preview-linux-arm64@7.0.0-dev.20260604.1': + resolution: {integrity: sha512-GjIrt6YHP3bbOWBCCE08SlBSDf84Lnjn3Td822/lOX9nm6ODlA/HI7rtGh7KzS/fxehep2Vy4dXU4Il12X1s5A==} + engines: {node: '>=16.20.0'} cpu: [arm64] os: [linux] - '@typescript/native-preview-linux-arm@7.0.0-dev.20260326.1': - resolution: {integrity: sha512-w6jrOrAw9kDoFDToECXMEkYByxjK67FNXM96SzpoX0JRB0BwkdvVclKsYeZtiP9naaW0u7lzZdfh/h0Hw6euYw==} + '@typescript/native-preview-linux-arm@7.0.0-dev.20260604.1': + resolution: {integrity: sha512-IKaZL3i5HKmKqwb2IZEXW1j68fVg1HsvAaXkbrkOIG/J5Eyksu5tEnTzucrIY1oPdzgHT+y2HpDIYp2sGeHFvw==} + engines: {node: '>=16.20.0'} cpu: [arm] os: [linux] - '@typescript/native-preview-linux-x64@7.0.0-dev.20260326.1': - resolution: {integrity: sha512-F8aWt0EH8YBE3Xo2KwIcDwA0iiNq9CdV+z5/+tca70CU5HcfGJlY/c6u6UIM9ZYa1IFcykq0HMHv2FE1NAXdcw==} + '@typescript/native-preview-linux-x64@7.0.0-dev.20260604.1': + resolution: {integrity: sha512-twQ7XDjsmaHIevN1MjeRYIVLUPL0fBm8A0jg1FhGYPckhTxEBiHIpJf9E//eFidAdrEHjeTSBP1jJw3GNAensg==} + engines: {node: '>=16.20.0'} cpu: [x64] os: [linux] - '@typescript/native-preview-win32-arm64@7.0.0-dev.20260326.1': - resolution: {integrity: sha512-OQt93BgZbvkqHVYXH56gjQv2ZOchT4FvLwkwS6jei8t5zB2P4EXmnXA/WxMWwjpYNl4HGfEF/yRkPTfhmbODig==} + '@typescript/native-preview-win32-arm64@7.0.0-dev.20260604.1': + resolution: {integrity: sha512-QBRxaVT3SFiNfOhwYb/56ddpHWPMFdfiJ4zkFJIjaAXeZ/ssWNHM9lH7yR++GrE9VTsUZ4eVSZfOmQbzRERhgw==} + engines: {node: '>=16.20.0'} cpu: [arm64] os: [win32] - '@typescript/native-preview-win32-x64@7.0.0-dev.20260326.1': - resolution: {integrity: sha512-hfK3cA8+TtFICHwIo898QHd5VjbixEpdL5QcPkq3GtxuRQl7ZJvQj5Fb64fejIpxI3QicwIKgJW1jJDFCPSGsw==} + '@typescript/native-preview-win32-x64@7.0.0-dev.20260604.1': + resolution: {integrity: sha512-hR7YHoRpm88Q86gK6/IMayWUA+ROdHGzOPKK8EBp1xD/Cg2Bh5AXbut8HcyUDx/bcGQvnuht/XsW47bT3to9mg==} + engines: {node: '>=16.20.0'} cpu: [x64] os: [win32] - '@typescript/native-preview@7.0.0-dev.20260326.1': - resolution: {integrity: sha512-oq2UShxAa+CS4aalhQjntuxuzTv/ud54So3lqfYcJDiQabmpGk/95rGvW5PXi28JIBlZ6AbUL6gEj0gRvIDJcQ==} + '@typescript/native-preview@7.0.0-dev.20260604.1': + resolution: {integrity: sha512-A3/9yZTt2V5NlDURcVJ4mN2YjfeQTXCRyLuENKrNdGhO+y59mC/2UDr7UvpB3Li+83TRAuhDN8SBoM+7gkHdzQ==} + engines: {node: '>=16.20.0'} hasBin: true '@vitest/expect@4.1.8': @@ -656,8 +682,16 @@ packages: resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} engines: {node: '>= 0.6'} - ajv@6.12.6: - resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + ajv-formats@3.0.1: + resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + + ajv@8.20.0: + resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==} assertion-error@2.0.1: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} @@ -666,8 +700,8 @@ packages: blake3-wasm@2.1.5: resolution: {integrity: sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==} - body-parser@2.2.0: - resolution: {integrity: sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==} + body-parser@2.2.2: + resolution: {integrity: sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==} engines: {node: '>=18'} bytes@3.1.2: @@ -729,6 +763,15 @@ packages: supports-color: optional: true + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + depd@2.0.0: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} @@ -797,21 +840,21 @@ packages: resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} engines: {node: '>=12.0.0'} - express-rate-limit@7.5.1: - resolution: {integrity: sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw==} + express-rate-limit@8.5.2: + resolution: {integrity: sha512-5Kb34ipNX694DH48vN9irak1Qx30nb0PLYHXfJgw4YEjiC3ZEmZJhwOp+VfiCYwFzvFTdB9QkArYS5kXa2cx2A==} engines: {node: '>= 16'} peerDependencies: express: '>= 4.11' - express@5.1.0: - resolution: {integrity: sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==} + express@5.2.1: + resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} engines: {node: '>= 18'} fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - fast-json-stable-stringify@2.1.0: - resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + fast-uri@3.1.2: + resolution: {integrity: sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==} fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} @@ -862,24 +905,45 @@ packages: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} - hono@4.7.5: - resolution: {integrity: sha512-fDOK5W2C1vZACsgLONigdZTRZxuBqFtcKh7bUQ5cVSbwI2RWjloJDcgFOVzbQrlI6pCmhlTsVYZ7zpLj4m4qMQ==} + hono-rate-limiter@0.5.3: + resolution: {integrity: sha512-M0DxbVMpPELEzLi0AJg1XyBHLGJXz7GySjsPoK+gc5YeeBsdGDGe+2RvVuCAv8ydINiwlbxqYMNxUEyYfRji/A==} + peerDependencies: + hono: ^4.10.8 + unstorage: ^1.17.3 + peerDependenciesMeta: + unstorage: + optional: true + + hono@4.12.23: + resolution: {integrity: sha512-eIaZ9qDgu7XV0pxOCrg7/WhnQ6Ivm22UcxhXx/A3dcbqbbYgBEkc6e/J/s7j2tS96zoB0S9VBdLwQNCWwUo4LA==} engines: {node: '>=16.9.0'} http-errors@2.0.0: resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} engines: {node: '>= 0.8'} + http-errors@2.0.1: + resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} + engines: {node: '>= 0.8'} + iconv-lite@0.6.3: resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} engines: {node: '>=0.10.0'} + iconv-lite@0.7.2: + resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} + engines: {node: '>=0.10.0'} + immediate@3.0.6: resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + ip-address@10.2.0: + resolution: {integrity: sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==} + engines: {node: '>= 12'} + ipaddr.js@1.9.1: resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} engines: {node: '>= 0.10'} @@ -893,8 +957,14 @@ packages: isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - json-schema-traverse@0.4.1: - resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + jose@6.2.3: + resolution: {integrity: sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw==} + + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + + json-schema-typed@8.0.2: + resolution: {integrity: sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==} jszip@3.10.1: resolution: {integrity: sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==} @@ -1053,9 +1123,8 @@ packages: path-to-regexp@6.3.0: resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==} - path-to-regexp@8.2.0: - resolution: {integrity: sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==} - engines: {node: '>=16'} + path-to-regexp@8.4.0: + resolution: {integrity: sha512-PuseHIvAnz3bjrM2rGJtSgo1zjgxapTLZ7x2pjhzWwlp4SJQgK3f3iZIQwkpEnBaKz6seKBADpM4B4ySkuYypg==} pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} @@ -1082,12 +1151,8 @@ packages: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} - punycode@2.3.1: - resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} - engines: {node: '>=6'} - - qs@6.14.0: - resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} + qs@6.15.2: + resolution: {integrity: sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==} engines: {node: '>=0.6'} range-parser@1.2.1: @@ -1098,9 +1163,17 @@ packages: resolution: {integrity: sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==} engines: {node: '>= 0.8'} + raw-body@3.0.2: + resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} + engines: {node: '>= 0.10'} + readable-stream@2.3.8: resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + rolldown@1.0.3: resolution: {integrity: sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1236,9 +1309,6 @@ packages: resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} engines: {node: '>= 0.8'} - uri-js@4.4.1: - resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} @@ -1376,13 +1446,13 @@ packages: youch@4.1.0-beta.10: resolution: {integrity: sha512-rLfVLB4FgQneDr0dv1oddCVZmKjcJ6yX6mS4pU82Mq/Dt9a3cLZQ62pDBL4AUO+uVrCvtWz3ZFUL2HFAFJ/BXQ==} - zod-to-json-schema@3.24.6: - resolution: {integrity: sha512-h/z3PKvcTcTetyjl1fkj79MHNEjm+HpD6NXheWjzOekY7kV+lwDYnHw+ivHkijnCSMz1yJaWBD9vu/Fcmk+vEg==} + zod-to-json-schema@3.25.2: + resolution: {integrity: sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==} peerDependencies: - zod: ^3.24.1 + zod: ^3.25.28 || ^4 - zod@3.25.76: - resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} + zod@4.4.3: + resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==} snapshots: @@ -1394,13 +1464,13 @@ snapshots: optionalDependencies: workerd: 1.20260603.1 - '@cloudflare/vite-plugin@1.40.0(vite@8.0.16(esbuild@0.27.3))(workerd@1.20260603.1)(wrangler@4.98.0(@cloudflare/workers-types@4.20250405.0))': + '@cloudflare/vite-plugin@1.40.0(vite@8.0.16(esbuild@0.27.3))(workerd@1.20260603.1)(wrangler@4.98.0(@cloudflare/workers-types@4.20260605.1))': dependencies: '@cloudflare/unenv-preset': 2.16.1(unenv@2.0.0-rc.24)(workerd@1.20260603.1) miniflare: 4.20260603.0 unenv: 2.0.0-rc.24 vite: 8.0.16(esbuild@0.27.3) - wrangler: 4.98.0(@cloudflare/workers-types@4.20250405.0) + wrangler: 4.98.0(@cloudflare/workers-types@4.20260605.1) ws: 8.20.1 transitivePeerDependencies: - bufferutil @@ -1422,7 +1492,7 @@ snapshots: '@cloudflare/workerd-windows-64@1.20260603.1': optional: true - '@cloudflare/workers-types@4.20250405.0': {} + '@cloudflare/workers-types@4.20260605.1': {} '@cspotcode/source-map-support@0.8.1': dependencies: @@ -1522,10 +1592,17 @@ snapshots: '@esbuild/win32-x64@0.27.3': optional: true - '@hono/mcp@0.1.1(@modelcontextprotocol/sdk@1.17.4)(hono@4.7.5)': + '@hono/mcp@0.3.0(@modelcontextprotocol/sdk@1.29.0(zod@4.4.3))(hono-rate-limiter@0.5.3(hono@4.12.23))(hono@4.12.23)(zod@4.4.3)': + dependencies: + '@modelcontextprotocol/sdk': 1.29.0(zod@4.4.3) + hono: 4.12.23 + hono-rate-limiter: 0.5.3(hono@4.12.23) + pkce-challenge: 5.0.0 + zod: 4.4.3 + + '@hono/node-server@1.19.14(hono@4.12.23)': dependencies: - '@modelcontextprotocol/sdk': 1.17.4 - hono: 4.7.5 + hono: 4.12.23 '@img/colour@1.1.0': {} @@ -1634,20 +1711,25 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.0 - '@modelcontextprotocol/sdk@1.17.4': + '@modelcontextprotocol/sdk@1.29.0(zod@4.4.3)': dependencies: - ajv: 6.12.6 + '@hono/node-server': 1.19.14(hono@4.12.23) + ajv: 8.20.0 + ajv-formats: 3.0.1(ajv@8.20.0) content-type: 1.0.5 cors: 2.8.5 cross-spawn: 7.0.6 eventsource: 3.0.7 eventsource-parser: 3.0.5 - express: 5.1.0 - express-rate-limit: 7.5.1(express@5.1.0) + express: 5.2.1 + express-rate-limit: 8.5.2(express@5.2.1) + hono: 4.12.23 + jose: 6.2.3 + json-schema-typed: 8.0.2 pkce-challenge: 5.0.0 raw-body: 3.0.0 - zod: 3.25.76 - zod-to-json-schema: 3.24.6(zod@3.25.76) + zod: 4.4.3 + zod-to-json-schema: 3.25.2(zod@4.4.3) transitivePeerDependencies: - supports-color @@ -1743,36 +1825,36 @@ snapshots: '@types/estree@1.0.9': {} - '@typescript/native-preview-darwin-arm64@7.0.0-dev.20260326.1': + '@typescript/native-preview-darwin-arm64@7.0.0-dev.20260604.1': optional: true - '@typescript/native-preview-darwin-x64@7.0.0-dev.20260326.1': + '@typescript/native-preview-darwin-x64@7.0.0-dev.20260604.1': optional: true - '@typescript/native-preview-linux-arm64@7.0.0-dev.20260326.1': + '@typescript/native-preview-linux-arm64@7.0.0-dev.20260604.1': optional: true - '@typescript/native-preview-linux-arm@7.0.0-dev.20260326.1': + '@typescript/native-preview-linux-arm@7.0.0-dev.20260604.1': optional: true - '@typescript/native-preview-linux-x64@7.0.0-dev.20260326.1': + '@typescript/native-preview-linux-x64@7.0.0-dev.20260604.1': optional: true - '@typescript/native-preview-win32-arm64@7.0.0-dev.20260326.1': + '@typescript/native-preview-win32-arm64@7.0.0-dev.20260604.1': optional: true - '@typescript/native-preview-win32-x64@7.0.0-dev.20260326.1': + '@typescript/native-preview-win32-x64@7.0.0-dev.20260604.1': optional: true - '@typescript/native-preview@7.0.0-dev.20260326.1': + '@typescript/native-preview@7.0.0-dev.20260604.1': optionalDependencies: - '@typescript/native-preview-darwin-arm64': 7.0.0-dev.20260326.1 - '@typescript/native-preview-darwin-x64': 7.0.0-dev.20260326.1 - '@typescript/native-preview-linux-arm': 7.0.0-dev.20260326.1 - '@typescript/native-preview-linux-arm64': 7.0.0-dev.20260326.1 - '@typescript/native-preview-linux-x64': 7.0.0-dev.20260326.1 - '@typescript/native-preview-win32-arm64': 7.0.0-dev.20260326.1 - '@typescript/native-preview-win32-x64': 7.0.0-dev.20260326.1 + '@typescript/native-preview-darwin-arm64': 7.0.0-dev.20260604.1 + '@typescript/native-preview-darwin-x64': 7.0.0-dev.20260604.1 + '@typescript/native-preview-linux-arm': 7.0.0-dev.20260604.1 + '@typescript/native-preview-linux-arm64': 7.0.0-dev.20260604.1 + '@typescript/native-preview-linux-x64': 7.0.0-dev.20260604.1 + '@typescript/native-preview-win32-arm64': 7.0.0-dev.20260604.1 + '@typescript/native-preview-win32-x64': 7.0.0-dev.20260604.1 '@vitest/expect@4.1.8': dependencies: @@ -1820,27 +1902,31 @@ snapshots: mime-types: 3.0.1 negotiator: 1.0.0 - ajv@6.12.6: + ajv-formats@3.0.1(ajv@8.20.0): + optionalDependencies: + ajv: 8.20.0 + + ajv@8.20.0: dependencies: fast-deep-equal: 3.1.3 - fast-json-stable-stringify: 2.1.0 - json-schema-traverse: 0.4.1 - uri-js: 4.4.1 + fast-uri: 3.1.2 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 assertion-error@2.0.1: {} blake3-wasm@2.1.5: {} - body-parser@2.2.0: + body-parser@2.2.2: dependencies: bytes: 3.1.2 content-type: 1.0.5 - debug: 4.4.1 + debug: 4.4.3 http-errors: 2.0.0 - iconv-lite: 0.6.3 + iconv-lite: 0.7.2 on-finished: 2.4.1 - qs: 6.14.0 - raw-body: 3.0.0 + qs: 6.15.2 + raw-body: 3.0.2 type-is: 2.0.1 transitivePeerDependencies: - supports-color @@ -1890,6 +1976,10 @@ snapshots: dependencies: ms: 2.1.3 + debug@4.4.3: + dependencies: + ms: 2.1.3 + depd@2.0.0: {} detect-libc@2.0.3: {} @@ -1963,19 +2053,21 @@ snapshots: expect-type@1.3.0: {} - express-rate-limit@7.5.1(express@5.1.0): + express-rate-limit@8.5.2(express@5.2.1): dependencies: - express: 5.1.0 + express: 5.2.1 + ip-address: 10.2.0 - express@5.1.0: + express@5.2.1: dependencies: accepts: 2.0.0 - body-parser: 2.2.0 + body-parser: 2.2.2 content-disposition: 1.0.0 content-type: 1.0.5 cookie: 0.7.2 cookie-signature: 1.2.2 debug: 4.4.1 + depd: 2.0.0 encodeurl: 2.0.0 escape-html: 1.0.3 etag: 1.8.1 @@ -1988,7 +2080,7 @@ snapshots: once: 1.4.0 parseurl: 1.3.3 proxy-addr: 2.0.7 - qs: 6.14.0 + qs: 6.15.2 range-parser: 1.2.1 router: 2.2.0 send: 1.2.0 @@ -2001,7 +2093,7 @@ snapshots: fast-deep-equal@3.1.3: {} - fast-json-stable-stringify@2.1.0: {} + fast-uri@3.1.2: {} fdir@6.5.0(picomatch@4.0.4): optionalDependencies: @@ -2053,7 +2145,11 @@ snapshots: dependencies: function-bind: 1.1.2 - hono@4.7.5: {} + hono-rate-limiter@0.5.3(hono@4.12.23): + dependencies: + hono: 4.12.23 + + hono@4.12.23: {} http-errors@2.0.0: dependencies: @@ -2063,14 +2159,28 @@ snapshots: statuses: 2.0.1 toidentifier: 1.0.1 + http-errors@2.0.1: + dependencies: + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.2 + toidentifier: 1.0.1 + iconv-lite@0.6.3: dependencies: safer-buffer: 2.1.2 + iconv-lite@0.7.2: + dependencies: + safer-buffer: 2.1.2 + immediate@3.0.6: {} inherits@2.0.4: {} + ip-address@10.2.0: {} + ipaddr.js@1.9.1: {} is-promise@4.0.0: {} @@ -2079,7 +2189,11 @@ snapshots: isexe@2.0.0: {} - json-schema-traverse@0.4.1: {} + jose@6.2.3: {} + + json-schema-traverse@1.0.0: {} + + json-schema-typed@8.0.2: {} jszip@3.10.1: dependencies: @@ -2199,7 +2313,7 @@ snapshots: path-to-regexp@6.3.0: {} - path-to-regexp@8.2.0: {} + path-to-regexp@8.4.0: {} pathe@2.0.3: {} @@ -2222,9 +2336,7 @@ snapshots: forwarded: 0.2.0 ipaddr.js: 1.9.1 - punycode@2.3.1: {} - - qs@6.14.0: + qs@6.15.2: dependencies: side-channel: 1.1.0 @@ -2237,6 +2349,13 @@ snapshots: iconv-lite: 0.6.3 unpipe: 1.0.0 + raw-body@3.0.2: + dependencies: + bytes: 3.1.2 + http-errors: 2.0.1 + iconv-lite: 0.7.2 + unpipe: 1.0.0 + readable-stream@2.3.8: dependencies: core-util-is: 1.0.3 @@ -2247,6 +2366,8 @@ snapshots: string_decoder: 1.1.1 util-deprecate: 1.0.2 + require-from-string@2.0.2: {} + rolldown@1.0.3: dependencies: '@oxc-project/types': 0.133.0 @@ -2274,7 +2395,7 @@ snapshots: depd: 2.0.0 is-promise: 4.0.0 parseurl: 1.3.3 - path-to-regexp: 8.2.0 + path-to-regexp: 8.4.0 transitivePeerDependencies: - supports-color @@ -2430,10 +2551,6 @@ snapshots: unpipe@1.0.0: {} - uri-js@4.4.1: - dependencies: - punycode: 2.3.1 - util-deprecate@1.0.2: {} vary@1.1.2: {} @@ -2491,7 +2608,7 @@ snapshots: '@cloudflare/workerd-linux-arm64': 1.20260603.1 '@cloudflare/workerd-windows-64': 1.20260603.1 - wrangler@4.98.0(@cloudflare/workers-types@4.20250405.0): + wrangler@4.98.0(@cloudflare/workers-types@4.20260605.1): dependencies: '@cloudflare/kv-asset-handler': 0.5.0 '@cloudflare/unenv-preset': 2.16.1(unenv@2.0.0-rc.24)(workerd@1.20260603.1) @@ -2502,7 +2619,7 @@ snapshots: unenv: 2.0.0-rc.24 workerd: 1.20260603.1 optionalDependencies: - '@cloudflare/workers-types': 4.20250405.0 + '@cloudflare/workers-types': 4.20260605.1 fsevents: 2.3.3 transitivePeerDependencies: - bufferutil @@ -2525,8 +2642,8 @@ snapshots: cookie: 1.1.1 youch-core: 0.3.3 - zod-to-json-schema@3.24.6(zod@3.25.76): + zod-to-json-schema@3.25.2(zod@4.4.3): dependencies: - zod: 3.25.76 + zod: 4.4.3 - zod@3.25.76: {} + zod@4.4.3: {} diff --git a/src/index.ts b/src/index.ts index e7ab22d..7937ac9 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,7 +2,7 @@ import { Hono } from "hono"; import { StreamableHTTPTransport } from "@hono/mcp"; import { CACHE_ERROR_MAX_AGE, CACHE_MAX_AGE } from "./constants"; import { handleGitHubRequest } from "./github"; -import { mcpServer } from "./mcp"; +import { createMcpServer } from "./mcp"; import { resolveRequest } from "./resolver"; import { createErrorPage, createLandingPage } from "./ui"; @@ -11,6 +11,7 @@ const app = new Hono(); // MCP endpoint app.all("/mcp", async (c) => { const transport = new StreamableHTTPTransport(); + const mcpServer = createMcpServer(); await mcpServer.connect(transport); return transport.handleRequest(c); }); diff --git a/src/mcp.ts b/src/mcp.ts index c99cd68..aff785d 100644 --- a/src/mcp.ts +++ b/src/mcp.ts @@ -3,39 +3,46 @@ import { z } from "zod"; import { APP_VERSION } from "./constants"; import { processGitHubRepository } from "./github"; -export const mcpServer = new McpServer({ - name: "github-pera1-mcp-server", - version: APP_VERSION, -}); +// SDKはProtocolインスタンスごとに1つのtransportしか許可しないため、 +// リクエスト毎に新しいサーバーを生成する(warm isolateで2回目以降の +// リクエストが "Already connected to a transport" で500になる既存バグの修正) +export function createMcpServer(): McpServer { + const mcpServer = new McpServer({ + name: "github-pera1-mcp-server", + version: APP_VERSION, + }); -mcpServer.registerTool( - "fetch_github_code", - { - title: "GitHub Code Fetcher", - description: "Fetch code from GitHub repositories with flexible filtering options", - inputSchema: { - url: z.string().describe("GitHub repository URL (e.g., https://github.com/owner/repo)"), - dir: z.string().optional().describe("Filter by directory path (comma-separated)"), - ext: z.string().optional().describe("Filter by file extensions (comma-separated)"), - branch: z.string().optional().describe("Git branch name"), - file: z.string().optional().describe("Specific file path to fetch"), - mode: z.enum(["tree", "full"]).optional().describe("Display mode: tree (structure only) or full"), + mcpServer.registerTool( + "fetch_github_code", + { + title: "GitHub Code Fetcher", + description: "Fetch code from GitHub repositories with flexible filtering options", + inputSchema: { + url: z.string().describe("GitHub repository URL (e.g., https://github.com/owner/repo)"), + dir: z.string().optional().describe("Filter by directory path (comma-separated)"), + ext: z.string().optional().describe("Filter by file extensions (comma-separated)"), + branch: z.string().optional().describe("Git branch name"), + file: z.string().optional().describe("Specific file path to fetch"), + mode: z.enum(["tree", "full"]).optional().describe("Display mode: tree (structure only) or full"), + }, }, - }, - async (args) => { - if (!args?.url || typeof args.url !== "string" || args.url.trim() === "") { - throw new Error("URL parameter is required. Provide a GitHub repository URL."); - } + async (args) => { + if (!args?.url || typeof args.url !== "string" || args.url.trim() === "") { + throw new Error("URL parameter is required. Provide a GitHub repository URL."); + } - const result = await processGitHubRepository({ - url: args.url, - dir: args.dir, - ext: args.ext, - branch: args.branch, - file: args.file, - mode: args.mode, - }); + const result = await processGitHubRepository({ + url: args.url, + dir: args.dir, + ext: args.ext, + branch: args.branch, + file: args.file, + mode: args.mode, + }); - return { content: [{ type: "text" as const, text: result }] }; - }, -); + return { content: [{ type: "text" as const, text: result }] }; + }, + ); + + return mcpServer; +} diff --git a/tests/integration/http.spec.ts b/tests/integration/http.spec.ts index 3cea2ae..2abbbd1 100644 --- a/tests/integration/http.spec.ts +++ b/tests/integration/http.spec.ts @@ -147,6 +147,40 @@ describe("HTTP Integration Tests", () => { expect(res.status).not.toBe(404); }); + // ------------------------------------------------------------------ + // Test 6b: MCP — 連続リクエストのregressionテスト + // 単一のMcpServerインスタンスへ複数transportをconnectすると + // "Already connected to a transport" で2回目以降が500になるバグの再発防止 + // ------------------------------------------------------------------ + it("Test 6b: MCP endpoint survives multiple sequential initialize requests", async () => { + const initializePayload = JSON.stringify({ + jsonrpc: "2.0", + id: 1, + method: "initialize", + params: { + protocolVersion: "2025-03-26", + capabilities: {}, + clientInfo: { name: "integration-test", version: "1.0" }, + }, + }); + + for (let i = 0; i < 3; i++) { + const res = (await app.fetch( + new Request("http://localhost/mcp", { + method: "POST", + headers: { + "Content-Type": "application/json", + Accept: "application/json, text/event-stream", + }, + body: initializePayload, + }), + )) as Response; + expect(res.status, `request #${i + 1} should succeed`).toBe(200); + const text = await res.text(); + expect(text).toContain("github-pera1-mcp-server"); + } + }); + // ------------------------------------------------------------------ // Test 7: SSH URL — GET /git@github.com:owner/repo.git // ------------------------------------------------------------------