$shibayu36->blog;

クラスター株式会社のソフトウェアエンジニアです。エンジニアリングや読書などについて書いています。

MySQLのスキーマ情報を返すMCPサーバーをVibe Codingで作った具体的な流れ

前回紹介したMySQLのスキーマ情報を圧縮して提供するMCPサーバーは、かなりの部分をVibe Codingで作った。その時にVibe Codingのやり方を調べていたのだが、Tipsは色々出てくるものの、具体的にどうAIと会話していったかなどはあまり分からず困っていた。

そこで今回の記事では、このツールの実装時に具体的にどのようにVibe Codingをしたかを紹介する。同じように具体的なやり方が分からず困っている人の参考になれば嬉しい。

今回のMCPサーバーを作った時、全体としては以下のようにVibe Codingをした。

  • 機能要件が大体動く部分までは、ほぼコードレビューすらせずに動作確認だけするようなVibe Codingで作る
  • テストの最初の構造作りはVibe Codingがうまくいかなかったため、この辺りを自分で用意
  • それ以降もここまで、テスト作り・リファクタ・text/template利用などの変更を加えた。Vibe Codingをメインとしながら、うまくいかない部分をちょっとだけ手で更新しつつ実装した

この中で一部の実装の実例を紹介していきたいと思う。今回のレポジトリではこのcommitのtreeまでは、.cursor/配下やdocs/配下も積極的にcomitしているので、その辺りも一緒に見ると分かりやすいと思う。

基本の流れ

  • 作り始める前に、チャットで要件を壁打ちしてもらいながらrequirements.mdというファイルを作る
  • 何かを実装するときは、まずチャットで設計をしてもらう => それを実現するためのTODOリストも含めてdocsに書き出しをしておく => そのdocsを再度読み込ませてコーディングしてもらうという流れで行う
    • ただし複雑な設計じゃなくコンテキスト長の制限を超えないケースならdocsに書き出さずにそのまま実装しても良い
  • 作りながら仕様変更や設計変更をしたら、docsに書き出ししておく

今回はCursorのAgentを活用し、modelはGemini 2.5 Proを使っていることが多かった。たまにo4-miniやClaude 3.5 Sonnetを使うこともあった。またmemory bankやMCPサーバーは使わなかった。

実例

requirements.mdの壁打ち

まずは要件定義を壁打ちしてもらった実例から。以下のような質問から開始して要件定義に付き合ってもらった。

その後もかなり雑にチャットを続けていて

やりたい事としては、環境変数でどのデータベースに接続するかを設定した後に、tool callで
- テーブル一覧を出力
- テーブル詳細を出力
の2つを出したい
どんな名前のツールにするといいかな?

あたりを質問続けて会話しながら、それっぽいのできたなと思った段階で、「今までの会話をrequirements.mdに反映させてください」と言って書き出してもらった。

その時にできたものがこちら。眺めるとわかるが、実はこの時点ではAIがMCPサーバーの概念を理解していない。

そこで続いてMCPサーバーの概念を理解させながらrequirements.mdを更新することにした。MCPサーバーを実装する時の参考資料である https://modelcontextprotocol.io/quickstart/server が使えると思ったため、ChatGPTで以下のような質問をしてまずサマリー資料を作ってもらった。

MCP Serverを実装するときにAIに参考のために読み込ませる資料を用意したい。
https://modelcontextprotocol.io/quickstart/server の資料を読み込み、
AIに読ませるmarkdownの情報を作って

作った資料をdocs/に配置した後、読み込ませてもう一度requirements.mdを作ったcommitがこちら。MCPサーバーのtoolの概念を理解したようなrequirements.mdができた。

ここまでのdiffも参照してほしい。

list_tablesの実装

続いてlist_tablesという、特定データベースのテーブル一覧のサマリー情報を出力するtool機能を実装した時の実例を紹介する。全体像はこちら

この時はlist_tablesの実装のためのTODOリストを自分の頭の中に持っていたので、1つずつVibe Codingで実装した。

まずはテーブル名とテーブルコメントだけ出力する部分を作った。これを作るときは次のようにCursorの@参照を使ってdocs/配下を読み込んでまずコード書かずに設計してねと伝えて設計から始めた。大体のチャットの流れ的には

@main.go ではlist_tablesを作っていきたい。まずはコードを書かずにどのような設計にするか考えてみてほしい @docs 
とりあえずテーブル名とテーブルコメントを一覧表示するのはどうだろうか
@https://github.com/mark3labs/mcp-go/blob/main/README.md の情報を読み込み、listTablesHandlerが返す内容をもう少し精査して

その後どんどんチャットを繰り返し、それっぽく設計できたなと思ったタイミングで次のように一気にコード生成した。

良いですね。main.goにこの実装を反映して

このような流れで同様にPK,UK,FKの出力部分も作っていった。

text/templateを利用するリファクタリングをした時の実装

これまでに説明したやり方で、全部の機能要件は作っていった。続いてtext/templateを使うようにするリファクタリングの実例も紹介する。

最初にVibe Codingで作ったコードは、テキストの組み立てを文字列結合でひたすらやっていくという実装になっていた。見通しをよくするためにtext/templateを使えないかなと考えたため、Vibe Codingで実現していった。全体像はこれ

やり方自体はこれまで紹介したのと同様で、まずチャットで設計をしてもらう => それを実現するためのTODOリストも含めてdocsに書き出しをしておく => そのdocsを再度読み込ませてコーディングしてもらうという流れだ。最初はこういう質問から始めて

さらにチャットをどんどん繰り返す。たとえば以下のような質問をしたりしながら繰り返した。

テンプレート系の処理はview.goにすると良いですかね?他に良いファイル名あります?

大体設計ができたなと思ったらdocsに書き出してもらった。その時できたのがこれ(ただしこのdocsをcommitせずに進行したのでdescribe_tablesのtext/template化のものも混ざっている)

そういう方向でいきましょう。今までの設計をdocs/onetime/20250427-use-template.mdに書き出してもらっていいですか?

そのあと実装フェーズに移った。先ほどのドキュメントを読ませた上でさらにTODOリストを作らせて

ステップバイステップでいきましょう。まず何からやるべきですか?

その後1つずつコード生成をして、都度gitのstageに載せ、次のステップを実装という流れを繰り返した。最終的にlist_tablesのtext/template化が完成したタイミングでcommitした。

あとは同様の流れでdescribe_tables側も作成してリファクタが完了した。

Vibe Codingを試して感じたこと

  • 今回はいろんなmodelを試した中で、Gemini 2.5 Proがかなり良かった。コンテキスト長が長いからなのかなぜなのかはよく分からない
    • ただしGeminiは無駄にコードコメントを書きまくってしまうという特性があり、その部分は非常に面倒だった
  • .cursor/rules/配下を整えるのは大前提
  • 新しめの技術仕様やライブラリの使い方は別でdocsを用意して必要な時に読み込ませると良い
  • 今回はVibe Codingを理解するために縛りプレイでエージェントにお任せしたが、書き捨てコードや自分だけでメンテするようなツールでない限り、Vibe CodingでPoCしつつ、その後は自分でコードを調整したり書き直したりした方が良さそう

まとめ

今回は、MySQLのスキーマ情報を返すMCPサーバーをVibe Codingで作った具体的な流れを紹介した。Vibe Codingに関するいろんな記事が出ているが具体的な例があまり無く困っていたので、同じような悩みを持っている人の参考になれば嬉しい。

クロマ・サブサンプリングについて調べた

複数のpngを全部pdfに結合する処理を書いていて、その中でJPEG圧縮について興味が湧いた。JPEG圧縮全体はまだ全く理解出来てなかったけど、その工程の中のクロマ・サブサンプリングについて調べたのでメモしておく。間違ってる可能性も高いので、ツッコミあれば教えてください。

そもそもJPEGの圧縮の流れ

ChatGPTに聞いたら次の流れのようだ。逆順をたどれば復元できるが、量子化で捨てた分は戻らない。

  1. 色を人間の感じ方に合わせて変換(RGB → YCbCr)
  2. 色差成分を間引き(サブサンプリング)
  3. 画像を 8×8 ピクセルの小さなブロックに分割
  4. 各ブロックに離散コサイン変換(DCT)をかけて「周波数成分」に分解
  5. 高い周波数ほど粗く丸める(量子化)=ここが“劣化”ポイント
  6. ゼロが並びやすい順に並べ直し(ジグザグスキャン)
  7. ゼロの連続を短い記号で表現し、ハフマン符号でさらに圧縮

これの2でクロマ・サブサンプリングをしている。

YCbCr

RGBからの可逆変換で、RGBと違い色の情報だけサンプリングしやすい。人間は輝度に対して色差の変化を感じにくいことを利用して情報を圧縮することができる。

雑に言うとYは輝度(グレースケール)、Cbは青っぽさ、Crは赤っぽさを表す数字になっていて、この3つを使うことで色を表現する。

クロマ・サブサンプリング

YCbCrでCbCrだけをサンプリングする。imagemagickなどで -sampling-factor 4:2:0 と指定しているが、この情報はクロマ・サブサンプリングに使われている。

クロマ・サブサンプリング - Wikipediaの図がわかりやすい。4:2:0をJ:a:bと表した時

  • J:水平サンプリング基準(概念的な領域の幅)。通常は4。
  • a:Jピクセルの最初の行のクロマサンプル(Cr、Cb)の数。
  • b:Jピクセルの最初の行と次の行のクロマサンプル(Cr、Cb)の変化量。

と表現される。それぞれのsampling-factorの変換のイメージはWikipediaの画像がわかりやすい。

サンプリングした後のフォーマット

データ構造的にサンプリングしただけでデータ量が減るんだっけ?と疑問に思ったが、これはYUVフォーマットという形式を調べるとデータ量が減ることがわかる。参考: YUVフォーマットの違いを世界一分かりやすく解説 #OpenCV - Qiita

視覚的にはこの図を見るとわかりやすい。

mysql-schema-explorer-mcpを英語化した

MySQLのスキーマ情報を圧縮して提供するMCPサーバーを作ったの記事で紹介したmysql-schema-explorer-mcpを英語化してみた。

https://github.com/shibayu36/mysql-schema-explorer-mcp/pull/1

機能としてはtool callの説明文や出力を英語にしたとしても、普通に日本語でチャットで扱えた。とくに何も考えず英語化できたので良かった。

今回の英語化もVibe Codingでやってみた。たとえばこういうチャットから始めて

*.goのファイルの中のコードコメントやエラーメッセージを英語化して
ただし、英語非母語話者でもすぐに分かるように、平易な英語に翻訳してください。

その後AIが修正したものを軽く眺めてcommitを繰り返していった。「ただし、英語非母語話者でもすぐにわかるように、平易な英語に翻訳してください。」のプロンプトを毎回入れていて、OSSなので読みやすい英語を大事にした。commitメッセージはOSS向けに英語を書くためにChatGPTのProjectsを活用しているの記事で紹介したやり方を活用した。

こういうチャットをひたすら繰り返していったら、大体1時間かからないくらいですべての英語化が終わった。最近は便利ですね。