|
| 1 | +# 日報 — 2026-08-12 |
| 2 | + |
| 3 | +**作業者**: hideyukiMORI |
| 4 | +**バージョン**: v1.8.168(セッション終了時点) |
| 5 | + |
| 6 | +--- |
| 7 | + |
| 8 | +## 本日の作業サマリー |
| 9 | + |
| 10 | +2026-05-30 を最後に約 2 ヶ月半コミットが無く、その間 CI も一度も走っていなかった。 |
| 11 | +**コードは 1 行も変わっていないのに、上流の advisory データのほうが動いて CI が赤になっていた。** |
| 12 | + |
| 13 | +本日はその赤を閉じ、待たされていた PR をマージし、次に来る mcp 2.0 移行の実測調査を行った。 |
| 14 | + |
| 15 | +### 完了した PR(2 本) |
| 16 | + |
| 17 | +| PR | 内容 | 種別 | |
| 18 | +|---|---|---| |
| 19 | +| #769 | chore(deps): 依存の既知脆弱性 22 件を解消し CI を緑に戻す(v1.8.167) | security | |
| 20 | +| #767 | chore(deps): bump nanoid to 3.3.18 in lockfile(GHSA-2v37-7h3g-55p8) | security | |
| 21 | + |
| 22 | +`#767` は 2ヶ月半前から存在した pip-audit の既存赤に阻まれて open のままだった。 |
| 23 | +`#769` で赤を閉じてから rebase して通した。 |
| 24 | + |
| 25 | +--- |
| 26 | + |
| 27 | +## 1. 依存の既知脆弱性 22 件(v1.8.167) |
| 28 | + |
| 29 | +`pip-audit` の出力は **27 行**だが、`pip` / `pyjwt` / `starlette` に重複行があり |
| 30 | +**ユニークでは 22 件 / 8 パッケージ**。 |
| 31 | + |
| 32 | +| パッケージ | 変更 | 解消した ID | 件数 | |
| 33 | +|---|---|---|---| |
| 34 | +| pyjwt | 2.12.1 → 2.13.0 | PYSEC-2026-175 / 176 / 177 / 178 / 179 | 5 | |
| 35 | +| cryptography | 48.0.0 → 50.0.0 | PYSEC-2026-3552 / 3553 / 3554・GHSA-537c-gmf6-5ccf | 4 | |
| 36 | +| starlette | 1.0.1 → 1.6.0 | PYSEC-2026-248 / 249 / 2280 / 2281 | 4 | |
| 37 | +| mcp | 1.27.1 → 1.29.0 | PYSEC-2026-3481 / 3482 / 3483 | 3 | |
| 38 | +| python-multipart | 0.0.29 → 0.0.32 | PYSEC-2026-3036 / 3037 / 3040 | 3 | |
| 39 | +| msgpack | 1.1.2 → 1.2.1 | PYSEC-2026-3625 | 1 | |
| 40 | +| pydantic-settings | 2.14.1 → 2.15.0 | GHSA-4xgf-cpjx-pc3j | 1 | |
| 41 | +| pip | 26.1.1 → 26.2.1 | PYSEC-2026-196 | 1 | |
| 42 | + |
| 43 | +- **`uv.lock` の更新のみで全件解消**。依存宣言はすべて下限のみだったため `pyproject.toml` の |
| 44 | + 依存宣言は無変更(変更は `version` のみ)= **PyPI 配布物の依存要件は変わっていない**。 |
| 45 | +- **新規の `--ignore-vuln` はゼロ。** 除外は既存の `PYSEC-2025-183` 1 件のみ据え置き。 |
| 46 | +- 段階更新(①低リスク 5 点 → ②cryptography → ③starlette → ④mcp)で進め、 |
| 47 | + 各段で `pytest` を実行。**④で実際に落ちた**ので、そこで止めて原因を切り分けた(§2)。 |
| 48 | + |
| 49 | +### 根本原因 |
| 50 | + |
| 51 | +コードは 2026-05-30 以降変更されていない。**変わったのは上流の advisory データのほう。** |
| 52 | +`uv.lock` を据え置いたまま CI が一度も走らなかったので、脆弱性だけが静かに積み上がった。 |
| 53 | + |
| 54 | +**凍結中のプロジェクトほど静かに腐る。** これは「コードを変えない限り安全」という |
| 55 | +直感が成り立たない領域で、定期再検査の装置が無いことの帰結である。 |
| 56 | +再発防止は `docs/todo/current.md` の優先タスクに起票した。 |
| 57 | + |
| 58 | +--- |
| 59 | + |
| 60 | +## 2. mcp 2.0 移行の実測調査 |
| 61 | + |
| 62 | +`uv lock --upgrade-package mcp` は **2.0.0(メジャー跨ぎ)** まで上げるが、テストが落ちる。 |
| 63 | +advisory の要求は 1.28.1 以上なので **1.29.0 で停止**し、移行は別タスクへ分離した。 |
| 64 | + |
| 65 | +> 🔴 **見積もりの訂正 — 測らずに出した数字を記録として残す** |
| 66 | +> |
| 67 | +> 当初この移行を **「`src/nene2/mcp/` と `src/example/mcp.py` の全面書き換えが必要」** と |
| 68 | +> 見積もった。**これは過大評価であり、誤りだった。** |
| 69 | +> |
| 70 | +> そう書いた根拠は「`uv sync` 後に 4 本のテストが収集エラーになった」ことだけで、 |
| 71 | +> **依存の実体を測っていなかった**。`grep` 2 発で確かめられることを確かめずに重い見積もりを |
| 72 | +> 出すと、その見積もり自体が着手を止める装置になる。 |
| 73 | +> |
| 74 | +> 実測すると `src/` 側の fastmcp 依存は **`server.py` の 1 行のみ**。 |
| 75 | +> 4 本が落ちたのは `nene2/mcp/__init__.py` が `server.py` を import するカスケードであって、 |
| 76 | +> 4 本それぞれが fastmcp を使っているからではない。 |
| 77 | +> **実際の移行規模は概算 11 行。** |
| 78 | +> |
| 79 | +> 訂正後の数字(11 行)は着手判断に使う。訂正前の失敗(測らずに見積もった)は |
| 80 | +> 次に見積もりを立てるときに使う。**両方を残す。** |
| 81 | +
|
| 82 | +### 2-1. 依存の実体 |
| 83 | + |
| 84 | +``` |
| 85 | +$ grep -rn 'fastmcp' src/ tests/ |
| 86 | +src/nene2/mcp/server.py:10: from mcp.server.fastmcp import FastMCP |
| 87 | +tests/example/test_http_mcp_parity.py:23: from mcp.server.fastmcp.exceptions import ToolError |
| 88 | +``` |
| 89 | + |
| 90 | +| ファイル | 行数 | fastmcp 依存 | |
| 91 | +|---|---|---| |
| 92 | +| `src/nene2/mcp/__init__.py` | 12 | なし(re-export のみ) | |
| 93 | +| `src/nene2/mcp/server.py` | 48 | 🔴 **唯一の依存点** | |
| 94 | +| `src/nene2/mcp/http_client.py` | 119 | なし(httpx のみ) | |
| 95 | +| `src/example/mcp.py` | 147 | なし(`LocalMcpServer` 越し・15 ツール登録) | |
| 96 | + |
| 97 | +**`LocalMcpServer`(48 行)がアンチコラプションレイヤーとして機能している。** |
| 98 | +`example/mcp.py` の 15 ツールも、MCP 系テスト 22 本も、すべてこの 48 行の裏側に守られており、 |
| 99 | +**メジャー更新の衝撃が 1 ファイルに閉じている。** 元の設計が正しかったことの実証データである。 |
| 100 | + |
| 101 | +### 2-2. 2.0.0 で実際に変わったもの(隔離 venv で実測・Python 3.14 / uv 0.11.15) |
| 102 | + |
| 103 | +| 1.x | 2.0.0 | |
| 104 | +|---|---| |
| 105 | +| `mcp.server.fastmcp` | **削除** → `mcp.server.mcpserver`(パッケージごと改名) | |
| 106 | +| `FastMCP` | `MCPServer` | |
| 107 | +| `mcp.server.fastmcp.exceptions.ToolError` | `mcp.server.mcpserver.exceptions.ToolError`(クラス名は同一) | |
| 108 | + |
| 109 | +`LocalMcpServer` が使っている 4 機能の移行可否: |
| 110 | + |
| 111 | +| 使用箇所 | 2.0.0 での状況 | 判定 | |
| 112 | +|---|---|---| |
| 113 | +| `FastMCP(name, instructions=, host=, port=)` | `MCPServer(...)`。**`host` / `port` はコンストラクタから `run()` へ移動**(消滅ではない) | 🟡 要追随 | |
| 114 | +| `.tool(description=...)` | キーワード互換 | 🟢 | |
| 115 | +| `._tool_manager.list_tools()` | **同名・同挙動で残存** | 🟢(ただし私有 API) | |
| 116 | +| `.run(transport=...)` | `transport` ごとの overload。`sse` / `streamable-http` が `host=` `port=` を受ける | 🟡 | |
| 117 | + |
| 118 | +### 2-3. 唯一の実質的な破壊点 — `call_tool()` の戻り値 |
| 119 | + |
| 120 | +| | 1.x | 2.0.0 | |
| 121 | +|---|---|---| |
| 122 | +| 戻り値 | content block の列(tuple のことがある) | **`CallToolResult`** | |
| 123 | +| フィールド | — | `meta` / `content` / `structured_content` / `is_error` / `result_type` | |
| 124 | +| 本文の取り出し | `raw[0] if isinstance(raw, tuple) else raw` | `result.content` | |
| 125 | + |
| 126 | +- **「1 要素 1 content block」という性質は 2.0 でも成立**(実測)。 |
| 127 | +- **ツール内例外は 2.0 でも `ToolError` で送出される**(`is_error` フラグに落ちるのではない)。 |
| 128 | + 実測: `ToolError: Error executing tool boom: bad input` |
| 129 | +- = パリティテストの異常系アサーションは **import パスの変更だけで生き残る**。 |
| 130 | + |
| 131 | +### 2-4. 落ちた 4 本が守っていた保証 |
| 132 | + |
| 133 | +| テスト | 件数 | 守っている保証 | 移行後 | |
| 134 | +|---|---|---|---| |
| 135 | +| `tests/nene2/mcp/test_server.py` | 5 | `LocalMcpServer` の公開契約(登録したツールが `list_tools()` に名前で現れる・デコレータ付き関数が素の関数としても呼べる) | **変更不要**。移行の合否判定器になる | |
| 136 | +| `tests/example/test_mcp.py` | 3 | Note の作成→取得→更新→削除ライフサイクル | **変更不要** | |
| 137 | +| `tests/nene2/mcp/test_http_client.py` | 14 | `HttpxMcpClient` の HTTP 挙動 | **変更不要**(fastmcp と無関係・巻き添えで落ちただけ) | |
| 138 | +| `tests/example/test_http_mcp_parity.py` | 5 | 🔴 **差別化そのもの**(同一ストア上での両サーフェス等価性・巨大 title / 空 body が両方で拒否される) | **要修正 3 行** | |
| 139 | + |
| 140 | +パリティテストが守る不変条件は **UseCase の Input DTO 側にあって MCP ライブラリ側には無い** |
| 141 | +(v1.8.166)。だから mcp のメジャー更新で保証が揺らがない。移行が小さく済む理由もここにある。 |
| 142 | + |
| 143 | +### 2-5. 依存の増分 |
| 144 | + |
| 145 | +2.0.0 は **`httpx2` へ乗り換える**。1.29.0 → 2.0.0 で: |
| 146 | + |
| 147 | +- **追加**: `httpx2` / `httpx2-jsfetch` / `mcp-types==2.0.0`(完全一致ピン)/ `opentelemetry-api` / `truststore` |
| 148 | +- **削除**: `httpx-sse` |
| 149 | +- `requires-python` は `>=3.10` のまま = **3.12 / 3.14 サポートに影響なし** |
| 150 | + |
| 151 | +自艦は `httpx>=0.27` を直接依存に持つため、2.0 を入れると **httpx と httpx2 が同居する** |
| 152 | +(競合はしない)。「httpx2 へ寄せるか」は本移行とは**別軸の判断**として記録しておく。 |
| 153 | + |
| 154 | +### 2-6. 移行方針(案と推し) |
| 155 | + |
| 156 | +| 案 | 内容 | 代償 | |
| 157 | +|---|---|---| |
| 158 | +| A | import パスと host/port だけ直す(約 11 行) | `_tool_manager` 私有 API 依存が残る | |
| 159 | +| **B-2**(**推し**) | A + ツール名を自前で保持し私有 API 依存を外す | デコレータのラップ数行 | |
| 160 | +| B-1 | `list_tools()` を 2.0 の async 公開 API に寄せる | **公開 API の破壊的変更**。得られるのは体裁だけ | |
| 161 | +| C | `lowlevel` に降りて fastmcp 相当を自前実装 | 🔴 スキーマ生成・引数検証・content 変換を全部抱える。**「薄く包む」方針の変更** | |
| 162 | +| D | 移行せず 1.x に留まる | 上流の 1.x サポート終了まで先送り | |
| 163 | + |
| 164 | +**推しは B-2。** `_tool_manager` は 2.0 でたまたま同名で生き残っただけで契約されていない。 |
| 165 | +パッケージ名ごと作り替える上流である以上、次も残る保証がない。 |
| 166 | +**同じ移行を 2 回やらないために、今回のついでに外す。** |
| 167 | + |
| 168 | +見積もり: `server.py` 約 15 行 + パリティテスト 3 行 = **半日以内**。 |
| 169 | +既存 27 本のテストがそのまま合否判定器になる。 |
| 170 | + |
| 171 | +### 2-7. 着手条件 |
| 172 | + |
| 173 | +🔴 **`pyproject.toml` の `mcp` バージョン境界をどうするかの決定が先。** |
| 174 | +`mcp>=2` に上げるのか、`[tool.uv] constraint-dependencies` で 1.x に留めるのかで、 |
| 175 | +**この移行の着手是非そのものが決まる。** |
| 176 | + |
| 177 | +1.x に固定するなら、本移行は**上流の 1.x サポート終了まで塩漬けが正しい** |
| 178 | +(advisory は 1.29.0 で全て閉じているので急ぐ理由がない)。 |
| 179 | + |
| 180 | +なお本移行も `mcp` 下限の引き上げも、**[ADR-0011](../adr/0011-mcp-as-core-dependency.md) |
| 181 | +(MCP をコア依存として含める)の決定とは矛盾しない** — 動くのはバージョン境界であって、 |
| 182 | +コア依存かどうかではない。着手時の ADR は ADR-0011 を上書きするのではなく、その上に積む形になる。 |
| 183 | + |
| 184 | +### 2-8. 測定の再現手順(次に読む人へ) |
| 185 | + |
| 186 | +```bash |
| 187 | +mkdir /tmp/mcp20 && cd /tmp/mcp20 |
| 188 | +uv venv -p 3.14 && uv pip install "mcp==2.0.0" |
| 189 | +ls .venv/lib/python3.14/site-packages/mcp/server/ # fastmcp が無いことを確認 |
| 190 | +``` |
| 191 | + |
| 192 | +`mcp.server.mcpserver` から `MCPServer` を import し、`.tool()` で 2 本登録して |
| 193 | +`_tool_manager.list_tools()` が名前を返すこと、`call_tool()` が `CallToolResult` を返すこと、 |
| 194 | +ツール内例外が `ToolError` になることを確認する。 |
| 195 | + |
| 196 | +⚠️ **本節の数値は 2026-08-12 時点の `mcp==2.0.0` の実測。** 着手時には版が進んでいる |
| 197 | +可能性があるので、`mcp.server.mcpserver` の存在と `call_tool()` の戻り値型だけは |
| 198 | +**測り直してから**書き始めること。 |
| 199 | + |
| 200 | +--- |
| 201 | + |
| 202 | +## 3. リポジトリの整理 |
| 203 | + |
| 204 | +- **マージ済みリモートブランチ 4 本**(`docs/translate-{de,fr,pt-br,zh}`)を削除。 |
| 205 | +- **locked worktree 4 本**(`.claude/worktrees/agent-*`)を削除。未コミット成果物が無いことを |
| 206 | + `git status --porcelain --ignored` で確認してから外した。 |
| 207 | +- **ローカルブランチ 20 本**を削除。リモート・ローカルとも `main` のみになった。 |
| 208 | + |
| 209 | +> **測り方の教訓**: 当初 `git diff origin/main...<branch>` でマージ済み判定を行い、 |
| 210 | +> 「10 本は差分が残っていて消せない」と誤判定した。三点 diff は**マージベース以降に |
| 211 | +> ブランチ側で入った変更**を出すので、main が squash merge で同じ内容を持っていても |
| 212 | +> 差分として見える。`git cherry`(patch-id 照合)と内容比較で測り直したところ、 |
| 213 | +> **未取り込みは実際にはゼロ**だった。 |
| 214 | +> **マージ済み判定に三点 diff を使わない。`git branch --merged` も squash merge を |
| 215 | +> 未マージと報告するので同様。** 使うのは `git cherry` か内容比較。 |
| 216 | +
|
| 217 | +--- |
| 218 | + |
| 219 | +## 4. 明日以降の方針 |
| 220 | + |
| 221 | +| 優先度 | タスク | |
| 222 | +|---|---| |
| 223 | +| 中 | **mcp 2.0 移行**(本日の調査 §2 が設計ノート。バージョン境界の決定が着手条件) | |
| 224 | +| 中 | **依存の定期再検査を仕組み化**(`schedule:` トリガー CI か月次 `uv lock --upgrade` 運用) | |
| 225 | +| 判断待ち | `pyproject.toml` の `mcp` / `python-multipart` / `pydantic-settings` の下限引き上げ(利用者影響あり) | |
| 226 | +| 低 | PyJWT 推移的 CVE(PYSEC-2025-183)— mcp 修正待ち | |
| 227 | + |
| 228 | +オープン Issue / PR: ゼロ。main クリーン。**CI グリーン**(3.12 / 3.14・実 DB 統合テスト含む)。 |
0 commit comments