【Go】古いコードからの卒業を支えるMCPサーバー
はじめに
本記事の要旨
Claude Code などの LLM を活用したコーディングエージェント(以下、エージェントと呼びます)の利用が急速に進んでいますね。私も機会があるごとに利用してみてはいますが、エージェントが学習データに引っ張られて、新しい言語機能や標準パッケージを使ってくれないことがあるという挙動には歯痒い思いをしていました。(そして結局自分で書き直す)
こちらのスライドにもあるように、エージェントには最新知識をインプットしてあげることが必要ですね。
あるいは静的解析からのLint&Formatが市民権を得ている言語の場合は、古い言語機能や標準パッケージの利用を検出して警告することも有用でしょう。(以下のスライドは直近でイイね!と感じた参考資料です)
本記事では前者のアプローチを採用し、エージェントが自律的にGoの最新情報を取得可能にするMCPサーバーの作成について紹介します。筆者の趣味でGoを選んでいますが、他の言語でも同様のことが可能です。
MCPサーバーの実装はGo言語で行いました。実装の大半をエージェントに任せてみたところ、予想通りやや古いGoで書かれたのですが、作成したMCPを使って知識をアップデートし、リファクタを実行したところ、狙い通りに新しい標準パッケージ等を使ってくれました✨
作成したMCPサーバーのコードはこちらです。
本記事の対象読者
- エージェントが最新の言語機能やパッケージを使ってくれないことを解消したい人
- MCPサーバーの作成に興味がある人
本記事で扱わないこと
- 各LLMモデル、エージェントの使いこなし
- MCPサーバーの基本
結び
次の章から本題に入って参ります。以下の順序で説明します。
- 最新情報インプットになぜMCPサーバーを選んだのか
- MCPサーバーの実装手順
- 作成したMCPサーバーを利用する
最新情報インプットになぜMCPサーバーを選んだのか
最新情報をエージェントにインプットする方法はいろいろ考えられます。CLAUDE.md
やcopilot-instructions.md
のような各エージェントが参照するルールファイルに最新情報を記載しておくのも良いですよね。
Goの場合、異なるバージョンの利用が非常に気軽に行えることもあり、プロジェクトによって利用するGoバージョンが変わることは想像に容易いです。Go1.22を使っているプロジェクトにとってはGo1.23~1.24(執筆時点最新)の情報は逆にノイズになるため、適切なフィルタリングが必要と考えました。
そこでMCPサーバーを作成することにします。以下の順序で動作することを狙います。
- エージェントが
go.mod
ファイルまたはgo version
コマンドから、使用するGoのバージョンを確認する。 - MCPサーバーにGoのバージョンを入力して、そのバージョンまでに実施されたGoの言語機能および標準パッケージのアップデート情報を返してもらう。
- コンテキスト節約のため、パッケージ名によるフィルタリングも可能にしておく。
これにより、ノイズを取り除いて、必要なだけの最新情報をエージェントが利用できるようにしてみようと思います。
MCPサーバーの実装手順
実装を進めていきます。
今回はエージェント(Claude Code with Claude Sonnet 4)を使って実装を進めていこうと思います。おそらく、現在のペインである「新しくはない機能を使って実装する」ことになると思いますが、完成したMCPサーバーを使ってリファクタすれば動作確認もできて一石二鳥です ✌️
アップデート情報の保持
Goのアップデート情報を、各マイナーバージョンごとにリポジトリ内に保持しておくことにします。リリースノートを解析し、構造化してJSON形式で保存しておくことにしました。このファイルは最終的にはembed
で実行ファイルに埋め込み、シングルバイナリファイルで配布可能にします。
リリースノートからの情報抽出もせっかくならエージェントにお願いします。今後のバージョンアップにも対応可能なようにプロンプトも整備しておきたいところ。このプロンプト作成もお願いしちゃいましょう。「抽出手順などを計画し、再現性が高いプロンプトを作ってね」と依頼。私の存在意義とは…。
作成したプロンプトを使ってGo1.24のリリースノートを解析し、結果を確認します…。ひとまずOK。
少しずつ作業を進め、いったんGo1.13程度までの情報を保管しました。
サーバーの実装
MCPサーバーの実装を進めます。
GoのMCPサーバー公式SDKは無いので(執筆時点)、github.com/mark3labs/mcp-go
を使って実装したいと思います。
エージェントにMCPサーバーを実装してもらう場合、こちらのチュートリアルにそって進めると高速道路に乗れて良いです。MCPについて記述したllms-full.txt
と各SDKのドキュメントをエージェントに読み込ませ、作りたいMCPサーバー仕様を指示していきます。
今回は以下の仕様にします。
- MCPサーバーとして
Resource
を提供するかTool
を提供するか迷いますが、MCPサーバー側で情報をフィルタリングして渡すという処理を行いたいため、ひとまずTool
にしておく。 - 引数1(必須):
1.21
のようにどのバージョンまでのアップデート情報を取得したいかを指定する。 - 引数2(任意):
os
のようにどのパッケージについてのアップデート情報を取得したいかを指定する。バージョンとのAND条件でフィルタリングする。 - 返却する情報は、LLMが理解しやすい形式でよろしく(乱暴)。
- 結果的に以下の内容をフォーマットして返す形式を提案されました。
{
"version": "1.XX",
"release_date": "YYYY-MM-DDTHH:MM:SSZ",
"summary": "One-sentence compelling summary highlighting revolutionary/major features",
"changes": [
{
"category": "language|runtime|toolchain|platform",
"description": "Specific technical description with concrete details",
"impact": "new|enhancement|performance|breaking|deprecation"
}
],
"packages": {
"package/name": [
{
"function": "FunctionName (optional)",
"description": "Detailed function/feature description",
"impact": "new|enhancement|performance|breaking|deprecation",
"example": "Practical code example (optional)"
}
]
}
}
方針が決まったところでエージェントにごりごりと実装を進めてもらいます。今回は以下の条件で作業しました。
- Claude Code (LLM: Claude Sonnet 4)
- Go1.24
驚くほどスムーズに作成は進みましたが、保守性・拡張性の観点で納得がいかないところがあったので、何度かの修正は必要でした。
-
main
関数に処理をベタ書き、バージョンごとに分けてあるJSONファイルをグローバルな変数にそれぞれembedして読み込みなど、結構辛いコードからスタート。テストなし。 - SOLID原則やtestabilityの観点で改善よろしく、と依頼して大分改善。ただしこの時点では便利な新しい標準パッケージなどを使っていない。
なにはともあれ、欲しかった機能は完成です!
作成したMCPサーバーを利用する
MCPホストによって登録形式は異なりますが、go run github.com/tenkoh/recent-go-mcp@latest
を実行するように登録することで利用可能です。
MCPサーバーの実装を進める間もワクワクしていたのですが、せっかく作ったこのMCPサーバーを使って、MCPサーバーのコード自体も最新のGoに追従させてみたいですよね?
ということでrecent-go-mcpツールを使って、現在のコードを最新のGoの機能・標準パッケージによって改善できる点を探し、適切に修正せよ
というようにエージェントに依頼してみます。
ちょっと想定外の修正もありますが、凄まじい勢いでコードが置き換えられていきます!気持ちいい! (カスタムエラーを用意するとか、context
を使うとか、ベストプラクティスに基づく修正も一緒に行われていますね。なんでだろう。)
狙い通りに新しいGoの言語機能や標準パッケージをエージェントに使わせることができそうですね!
おわりに
週末に家事育児をする傍らClaude Codeに指示を与えて作成していたのですが、今後自分では継続して使ってみようかなと思えるMCPサーバーが誕生しました🐣。
冒頭にも書きましたが、一番大事なバージョンアップ情報をまとめたデータの精査ができていないので、それは私自身がコツコツと行おうと思います…。もしよろしければフィードバックを頂けると大変助かります。
Discussion
MCPホストによってはMCPツールに許可する最大ペイロードを超える場合があるのでページングの仕組みを入れます…。
APIが変わったところは以下の情報も使えるかもしれません。
リリースノートにもHTML見るとその機能に対応するプロポーザル等のissueのリンクが貼られているので、文脈を補足するのに使えるかもしれません。
ちなみにGo1.25でgo fixに変更が加わり、go fixで対応できる部分も増えそうです。
modernizeのREADMEに書いてある内容も参考になるかもですね。
tenntennさんありがとうございます!
情報を拡充する際の参考にさせて下さい!
(Go1.25までに間に合わせたい…!)