1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

型システムを信じるな、規約を信じろ。独立プローブによる「泥臭い」境界防御のすすめ

1
Last updated at Posted at 2026-04-04

Gemini_Generated_Image_lnevhblnevhblnev.png

TL;DR

  • 課題: サーバーとテストクライアントで型定義を共有する「内閉的な検証」は、規約(JSON等)の微細な不整合を見逃す死角を生む
  • 解決策: 実装(Rust)から物理的に遮断された別言語(Python/Node.js等)による、「冷酷な契約検証(Cold Contract Validation)」 を導入する
  • 結論: 単一エコシステムへの過信を捨て、外部規約(Spec)を唯一の正典として叩き続ける「意図的な不便さ」こそが、真に堅牢な境界防御を実現する

第1章:設計仮定の明示 — 「型の安全性」が招く思わぬ死角

プロセス間通信を伴うアプリケーションの設計において、Rust のような強力な型システムを持つ言語を採用することは、論理的な一貫性を保つ上で非常に有効な手段となります。しかし、外部インターフェース(特に stdio を介した MCP や JSON-RPC 等のプロトコル)を扱う際、この「型の強固さ」が、思わぬ死角を作り出すことがあります。

私たちは、内部のユニットテストがパスし、cargo test が正常に終了していれば、外部からの呼び出しも正しく動作すると信じがちです。しかし、実は「内部の整合性」と「外部との契約」は、全く別のレイヤーに属する問題です。

第2章:観測された不整合 — 「型は通るが規約に違反する」事象

この死角が最も顕著に現れるのが、JSON 上での「値の不在」の表現です。例えば、Rust の型定義で Option<T> を用いるケースを考えます。多くの MCP 規約では、オプションのフィールドについて「null を許容するのではなく、キー自体が存在しないこと」を厳密に要求する場合があります。

// 規約が求める形式 (フィールド欠落)
{ "id": 1, "method": "foo" }

// 実装が誤って出力する形式 (null)
{ "id": 1, "method": "foo", "params": null }

Rust 内部で Serde を用いてシリアライズする際、アトリビュートの設定(skip_serializing_if 等)を誤れば、上記のように null が出力されます。この時、テストコード側でも同じ型定義を用いてデシリアライズしていれば、どちらも None として正しく処理されてしまうため、この微細な規約違反を検知することはできません。

第3章:仮定 de 破綻 — 内部剛性と外部流動性の相克

多くの開発現場では、開発の効率化(DRY 原則)のために、サーバー実装とテストクライアントの間で 型定義(Struct や Enum 等)を共有 します。一見、これは生産性の高い手法に思えますが、実は「境界検証」という観点からは重大な脆さを孕んでいます。

内部テストは「自分たちの実装」を正解として参照してしまう。これが、単一言語・単一プロジェクトに閉じた検証の限界です。

型定義を共有すると、サーバーとテストが「同じ誤り」を共有してしまう。これが境界検証における最大の構造的リスクだ。

第4章:再定義 — 「冷酷な契約検証(Cold Contract Validation)」

この「型の甘え」を構造的に排除するためには、内部の実装から物理的に遮断された 「独立プローブ」 による検証が必要です。これを、私たちは 「冷酷な契約検証(Cold Contract Validation)」 と呼んでいます。

「モノカルチャー」の引力に抗う

現代の開発環境(Web サービスネイティブな環境)では、開発言語の統一による生産性の向上が重視されます。しかし、境界検証において言語の同一性は「論理の一致(Single Point of Logic Failure)」のリスクを高めます。異なるエコシステム(例:Python の Pydantic 等)を用いて、異なる視点からプロトコルの境界線を物理的に叩き、検証し続ける。この「不便さ」を選択することこそが、堅牢なシステムを維持するための構造的な必然性となります。

第5章:実装原理(核心のみ) — 独立プローブによる「物理的な遮断」

あえて Python や Node.js 等の別言語を用いて検証プローブを構築するのには、明確な構造上の理由があります。

  • 他言語であれば、Rust の内部型定義を import することは物理的に不可能である
  • 検証コードは、プロトコル規約(JSON Schema 等)を出発点として、ゼロから期待値を定義することを強制される
  • エコシステムを分断することで、暗黙の前提(Serde の既定値等)を共有するリスクを排除する

DoD:境界防御における「完了」の定義

私たちは、以下の 3 条件をすべて満たした時のみ、その境界は「守られている」と定義(Definition of Done)します。

  1. 物理遮断の完遂: 検証コードが, サーバー実装の内部型定義(Serde 等)を 1 行も import していないこと
  2. 異言語プローブパス: 実装とは異なるランタイム(Python/Node.js 等)からの要求に対し、プロトコル規約通りの挙動が確認されていること
  3. ゼロ・トラスト検証: オプションフィールドの不在や null の扱いなど、実装側の「既定値」に依存しない厳格な契約検証がパスしていること

第6章:結果と帰結 — 「泥臭さ」という名の高級な設計

今の時代、AIがコードを書き、強力な型システムがバグを未然に防ぐのが「当たり前」とされる中で、このアプローチは間違いなく**「時代に逆行した、かつ意図的に泥臭い」**手法です。

なぜこれが「今時」の逆を行く泥臭さなのか、そしてなぜ今それが価値を持つのか。

ここからは、効率化の波に飲まれがちな現代の開発現場に対して、あえて逆張りする “老エンジニアの視点” を整理してみます。

1. 「効率」という甘い罠への反逆

今のトレンドは「生産性」です。

今時の正論: 「同じ型定義を共有(DRY)して、サーバーもクライアントも自動生成しよう。そうすれば修正は一箇所で済む。速いし, ミスもない。」

この記事の泥臭さ: 「いや、あえて共有しない。同じことを二度書け。別々の言語で、別々の苦労をしろ。」

これは、効率化のために「検証の独立性」を犠牲にしている現代への警告です。同じ金型(型定義)から作った製品同士をぶつけて「ほら、ぴったり合う(テスト成功)」と喜んでいる若手に、「金型そのものが歪んでいたらどうする?」と問いかける泥臭さです。

2. 「型システム」という聖域からの脱却

Rustのような言語を使っていると、「コンパイラは神」になります。

今時の正論: 「型さえ合っていれば、論理的に正しいことが保証される。」

この記事の泥臭さ: 「型なんてものは, バイナリの外に出ればただの言い訳だ。Pythonという『型に無論着な余所者』に, 生データ(JSON)を冷酷に突き刺させろ。」

最強の武器(Rust)を持ちながら、あえてそれを使わずに「素手(生データ検証)」で挑む。この「過信を捨てるときのストイックさ」が、最高に泥臭いんです。

3. 「境界防御」という名の保険料

今時の正論: 「テストコードは最小限に。保守コストを下げよう。」

この記事の泥臭さ: 「二重管理のコスト? 構造的な不便さ? ああ、全部受け入れよう。それが『境界を守る』ための保険料だ。」

動けばいい、納期が、効率が……。そんな言い訳を「リスクの非対称性」という言葉で一蹴し、あえて面倒な道を選ぶ。この姿勢は、スピード重視の現代では非常に「重たい(泥臭い)」決断です。

まとめ:内部は「型」で守り、境界は「独立した目」で疑う

この「泥臭さ」こそが「高級な設計」です。今の時代、誰でも「動くもの」は作れます。しかし、**「壊れないもの」**を作るには、こうした意図的な不便さが不可欠です。

自動生成されたテストは、鏡に映った自分とジャンケンをしているだけ。独立プローブは、本物の敵(外部仕様)を連れてくる作業。

この記事が提示しているのは、単なる古い手法への回帰ではなく、**「便利さに溺れて視力を失った現代のエンジニアに対する, 外科手術のようなアプローチ」**です。

「泥臭い」と言われたら、ニヤリと笑って「そうさ。泥の中でしか見えない真実(バグ)ってのがあってね」と返せるような, そんな深みのある設計を目指すべきではないでしょうか。

型システムの恩恵を享受しつつ、その限界を知り、境界線を冷酷に守り抜く。この二重の防御責任こそが、複雑な MCP エコシステムにおいて真に安定したサービスを提供するための鍵となるでしょう。

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?