iimon TECH BLOG

iimonエンジニアが得られた経験や知識を共有して世の中をイイモンにしていくためのブログです

駆け出しエンジニアはAI禁止!?使う前に身に着けてほしい2つの力〜RustもMCPも知らない中年エンジニアの奮闘から〜

はじめに

こんにちは!ダービーで失ったお金を安田記念で取り返そうとしたら返り討ちにあったiimonのエンジニアマネージャー松田です。

私はEMとして、CTOの森さんと一緒にエンジニア組織の生産性やメンバーの育成方針などを毎週議論させてもらっていますが、最近の内容としては、やはりAIとの付き合い方、みたいなところが多かったりします。

なんでもかんでもAIに聞いてしまって、果たして人は成長するのだろうか。 もし成長できたとしても、それは果たして正しい方向への成長なのだろうか。

自分がまだ若かったころの常識とつい比べてしまうけど、”現代の常識”と比べると果たしてどうなのだろうか。

その議論にはいったん答えを出しましたが、時の経過とともにおそらくその答えも変わっていくだろうと思っています。

今回は”来たるべきその日”に備えて、自分が新卒、またはジュニア・エンジニアになったと仮定してシミュレーションをすることで、どういう課題があるのかを発見してみたいと思います。

では早速、AIに頼って、「知らない言語を使って」「知らないものを作って勉強」してみます!

今回の題材

私が勉強したいと思っていて放置しているものの中に、「Rust」があります。

今回はその「Rust」を勉強しつつ、こちらもまだよくわかっていない「MCPサーバ」を作ってみたいと思います!

MCPサーバってなんですのん?

先日公開されるや否や、「めちゃわかりやすい」と大評判になったみのるんさんの資料

やさしいMCP入門 - Speaker Deck

を見ても、アラフィフの私の脳みそには3%くらいしか情報がキャッチアップされませんでした・・・。

AIに頼れば、私のように頭が硬くなったおっさんにもわかりやすく説明してくれるのでしょうか・・・。

さっそく質問してみると・・・

了解です!では、「MCPサーバってなんですのん?」という疑問に、45歳のちょっと頭が固い(でも真面目で頑張り屋さんな)中年男性にもわかるように、身近な例と平たい言葉で説明しますね。

めっちゃ気を遣ってくれますやん!笑 そう!真面目で頑張り屋さんなんです!・・・とまぁそれはいったん置いておいて、どんな身近な例を出してきてくれたんでしょうか。

ざっくり言うと、「AIと会話するための司会進行役」みたいなサーバです。

ほうほう。

今どき、AIっていっぱいあるじゃないですか。 ChatGPTもそうですし、画像を作るAIとか、ゲームの中のAIとか。 でも実は、それぞれのAIがバラバラなルールで動いてることが多くて、 どんなデータを送れば動くの? どうやって会話を続けるの? 返事の形式は? 文脈は覚えてるの? …っていうのが全部バラバラで、開発者もユーザーも「うーん、めんどい…」ってなってたんです。

ふむふむ!

いろんなAIと話すための共通ルール(プロトコル)を決めましょ! っていうのが「MCP」です。 で、「MCPサーバ」は、そういう共通ルールにしたがってAIとやりとりを中継してくれる役割のサーバです。

わかりよい〜!

📦 「宅配便の仕分けセンター」みたいなもん たとえば、あなたがいろんなお店から荷物を送ってもらうとして、 ヨドバシカメラの段ボール Amazonの箱 メルカリの袋 …って全部バラバラ。でも、宅配センターでルールに従って仕分けすればちゃんと届きますよね? MCPサーバは、その「仕分けセンター」みたいな存在。

この”身近な例”はよくわかんなかったけどまぁいいです笑

おっさん向けたとえ:ビデオデッキ時代 昔、ビデオの規格(VHSとβとか)で迷ったこと、ありますよね? MCPはそれを思い出させます。 つまり、「もう規格の違いで困らないようにしようぜ」という発想です。

うるさい!そこまでおっさんじゃないよ!(私の時代はもうVHS1強でした!笑)

それはともかく、これでMCPサーバって何かわかったぞー!となったはいいものの、私はこれまで、AIには散々ウソをつかれてきました。(ハルシネーション)

このgoogleの「AIによる概要」自体にもハルシネーションたくさんあるので要注意!

私がMCPサーバのことをよく知らないのをいいことに、平然とうそを説明されている可能性もあります。

なのでここでは「教えてくれたことが本当か確認したいので公式ソースを提示して」と言ってみました。

教えてくれた公式ページがこちら

Specification (Latest) – Model Context Protocol (MCP)

ふむ、確かに私の知りたい「MCP」の仕様について書かれているページのようです。

実はこの記事を書くために最初に試行錯誤していたときは、まったく別の「MなんとかCなんとかPなんとか(忘れちゃいました汗)」について教えてくれてたんですよね。

私が前述した資料を読んだり、「AI駆動開発カンファレンス」に行かせてもらったりしてMCPについてなんとなく知っていたから「MCP違い」に気づけましたが、まったくの初学者だった場合は違いに気付けない可能性もあります。

なので、AIが”なんのことを説明してくれているか”、公式ソースを示してもらうのは非常に重要ですね。

AIの助言を得て、自分で裏取りした最小限のMCPサーバに必要なこと

AIの説明を受けて、自分で公式ドキュメントを読んで確認して・・・と繰り返してなんとなく見えてきたMCPサーバに必要なことは下記の通りです。

  • MCPサーバとの通信は JSON-RPCを使って行う
  • MCPサーバへは下記のような通信が行われる
    • リソース探索
    • リソース読み取り
    • ツール呼び出し
  • 通信には標準入出力が使われる

たとえば、

{
  "jsonrpc": "2.0",
  "method": "echo",
  "params": {
    "message": "Hello, world!"
  },
  "id": 1
}

という「Hello, world!」をechoして!というリクエストを送れば、

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "message": "Echo: Hello, world!"
  }
}

という「Echo: 」が頭についた文字列がresultで返ってくるものなどが考えられます。

今回はこの最小限のサンプルを作ってみたいと思います。

ちなみに、リクエスト、レスポンスについては、ChatGPT君(なぜか1人称が「僕」だった。指示してないのに・・・)は

{
  "type": "request",
  "id": "abc123",
  "action": "call",
  "target": "tool:echo",
  "body": {
    "message": "Hello, world!"
  }
}
{
  "type": "response",
  "ref": "abc123",
  "body": {
    "message": "Echo: Hello, world!"
  },
  "content_type": "application/json"
}

という形だと教えてくれましたが、これについては公式ページで裏取りができずだったので、公式ドキュメントを信じることにしました。

公式ページのリクエストについての説明部分

Rustは知らない、でもTypeScriptやPHPは知っている

私は長年、サーバサイドエンジニアとしてPHPを書いてきました。そして今、iimonではTypeScriptを中心に使っています。

なのでRustについては、TypeScriptやPHPと比較して教えてもらいましょう。

そして今回は時間が限られているので、「最小限のMCPサーバを実装してみるのに必要なRustの知識」だけを教えてもらうことにします。

Rustで最小限のMCPサーバを作るための知識まとめ(TypeScript / PHPとの対比)

概念 Rust TypeScript/PHPとの対比 解説
型と変数定義 let name: String = "foo".to_string(); TS: let name: string = "foo";
PHP: $name = "foo";
Rustはすべて型安全。letで変数定義。TSに似てるが、String&strの違いに注意。
構造体(Struct) struct Tool { id: String, name: String } TS: interface Tool { id: string; name: string }
PHP: class Tool { public string $id; }
TSのinterfaceに似てるが、Rustは実体(値)も持つ。クラスより軽い。
HTTPサーバ axumwarp TS: Express
PHP: Laravel Slimなど
axumはExpressに近い書き心地。非同期/ルーティング/JSON対応が簡単。
非同期処理 async fn + .await TS: async/await
PHP: そもそも非同期ない
TSに近い書き方。tokioランタイムを使うことが多い。
シリアライズ/デシリアライズ serde TS: JSON.stringify/parse
PHP: json_encode/decode
#[derive(Serialize, Deserialize)]で自動化できる。MCPJSON-RPC処理に必須。
マッチング処理 match value { A => ..., B => ... } TS: switch
PHP: switch
matchはパターンマッチ。Rust特有だが慣れると強力。
エラーハンドリング Result<T, E>で返し、?で伝播 TS: try/catch
PHP: try/catch
Rustは例外じゃなく、値でエラーを返すスタイル。関数定義でResultを返すのが普通。
依存管理 Cargo.toml TS: package.json
PHP: composer.json
Cargoはnpm/composerに相当。非常に整っている。
分野 知識レベル 必須度
Rustの型、構造体、関数 TSに似てる。違いは所有権と参照 ★★★
async/awaitとtokio TSと近いが、ランタイムを意識する必要あり ★★★
serdeによるJSONの扱い TSでの型付きJSONと近い感覚 ★★★
Cargoと依存管理 package.jsonとほぼ同じ感覚 ★★☆
axumによるHTTPサーバ Expressに近い。TS経験者には親しみやすい ★★★

なるほど・・・やっぱりRustの肝である「所有権」についての知識は必須ですか・・・。

その辺は必要になったら詳しく教えてもらうとして、まずは文字列を渡したらそれの頭に「Echo:」をつけて返すだけの「echo」という関数を作ってみましょう。

TDDでやってくぞ!

先日の記事にもあったように、私はTDD信者?なのでまずはテストから書いていきます!

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_echo_returns_input_text() {
        let output = echo("Hello, world!");
        assert_eq!(output, "Echo: Hello, world!");
    }
}

ここではまず、テストコードをAIで作ってもらって、わからない部分を少しずつ質問しながら作っていきました。

「#[cfg(test)]」や「use super::*;」はTypeScriptやPHPを知っているだけでは意味がわからない部分ですからね〜

テストを実行すると、予定通りRedになりました。

TDDはまずRedにしてから最低限の実装を満たすコードを書き、リファクタして、RedになったらまたGreenにして、リファクタして・・・を繰り返す開発手法です。早速まずはGreenにする実装を書いてみます。

pub fn echo(input: &str) -> String {
    format!("Echo: {}", input)
}

OK、グリーンになりました。

早速、借用された文字列(&str)が出てきたので、焦らずに所有権や借用についても公式ドキュメントプログラミングRust第2版などで裏取りをしつつ勉強していきます。

1つ、一番小さな単位のプログラムを作り終わったら、このあと作っていく工程を確認しましょう。

  • 標準入力からJSONを受け取る
  • JSONを構造体にデシリアライズ
  • "method": "echo"のリクエストに対応する
  • パラメータからmessageを取り出す
  • messageの頭に「Echo: 」をつけて返す(最初に実装済み)
  • レスポンスを構造体にシリアライズ
  • 標準出力にJSONで返す

工程が見えたらあとは粛々とテスト作成→Red→単純な実装→Green→リファクタを繰り返すだけですね!

格闘すること約6時間あまり・・・

やっと完成!

JSONの細かいスキーマがちょっと予定から変わっているのは格闘の証?として見逃してもらうとして、送ったメッセージの頭に「Echo: 」という文字列を追加して返す echoというツールを持ったMCPサーバが作れました。

Clineで実行してみてもOK

やってみてどうだった?

MCPサーバ」に関しても「Rust」に関しても知識ゼロのところから(Rustは練習帳をちょっと試したことあったけど・・・汗)最小限のサンプルを作ることができました。

AIがとっかかりとなる情報をくれるので、何も知らない状態でも「あ、こうすればいいんだな」というロードマップが見えてめちゃくちゃすごいスピードで開発できました。

ただ、AIに頼りきりだとバグ修正の無限ループが起きてしまったり、ウソ(?)の仕様を教えられたりと、いくつもの罠が待っていたことも確かです。

そんな時に生きたのは、やはりこれまで苦労して公式ドキュメントと向き合ってきたり、エラー修正をしてきた経験値だったのかなぁとも思います。

  • 公式ドキュメント(1次情報)を読んで裏取りを行う力
  • エラー文や状況を読み解き、AIに「こうやれば直るんじゃない?」と指示する力

AI駆動開発の時代になっても、やはりこの2つを身につけることは大変重要だと感じたトライアルとなりました。

もし私にこれらが備わっていなければ・・・AIが言うことをすべて信じるしかなく、バグ修正の無限ループが起きてもイライラしながら「まだバグってるよ!直して!」を連呼するしかなかったでしょう。 そんな状態では、今回のサンプルも最後まで作りきれていなかった、と実際やってみたからこそ断言できます。

EMとして、これからの時代を作っていくエンジニアを育てるためにも貴重な経験となりましたね。

おわりに

最後になりますが、現在弊社ではエンジニアを募集しています。

この記事を読んで少しでも興味を持ってくださった方は、ぜひカジュアル面談でお話ししましょう!

 iimon採用サイト / Wantedly / Green

最後まで読んでいただきありがとうございました!

参考

やさしいMCP入門 - Speaker Deck

Specification - Model Context Protocol

The Rust Programming Language - The Rust Programming Language