Go製MCPサーバー開発は軽量バイナリと高並列で魅力的ですが、つまづきポイントに引っかかると「動かない」「つながらない」で時間を溶かしてしまいます。本記事では 私のGitHub の実験リポジトリと公開 Issue を読み解き、典型的なつまずきを 1,500 字程度で整理しました。
go‑mcpとは?
Model Context Protocol(MCP)は LLM アプリと外部ツール・データを橋渡しする新興プロトコルです。Go 版 SDK は mark3labs/mcp-go など複数あり、型安全な API と単一バイナリ配布を売りに急速にスターを伸ばしています。しかし仕様も実装も日進月歩で、安定運用には罠を踏み抜かない工夫が必須です。*4
失敗ポイント1 go runとgo.modの位置
実験リポジトリ go-mcp-abc では「go run /path/to/main.go だと go.mod が見つからず解決失敗」という報告が最初の壁に挙がっています。go run -C /path/to のように作業ディレクトリを切り替えるか、ビルド済みバイナリを呼び出すことで回避できます。
-
NG 例:go run /path/to/main.go
-
OK 例:go -C /path/to run main.go
-
OK 例:ビルドして絶対パス実行
プロジェクトルートとサーバープロセスを切り離すと依存解決が破綻する典型例です。
失敗ポイント2 — 標準出力の「余計なおしゃべり」
MCP は JSON‑RPC 2.0 を stdio でやり取りします。fmt.Println(“Starting server…”) といったログが最初に出るとクライアントは JSON 解析に失敗し、Unexpected token ‘S’ で即終了します。README でも「余計な出力はエラーになる」と強調されており、実際に同様の Issue が多数報告されています。
ワンポイント対策
-
ログは log パッケージで SetOutput(io.Discard) しておき、デバッグ時だけ環境変数で切り替える
-
専用フラグ –verbose を付けたときだけ人間向けログを出す
回避策とベストプラクティス
-
固定タグ運用
-
SDK は commit hash か semver タグで pin する
-
-
CI に JSON スモークテストを追加
-
echo ‘{}’ | your‑server | jq で JSON 妥当性を確認
-
-
エディタ拡張のバージョンも合わせる
-
VS Code / Claude CLI / Cursor などクライアントごとに検証
-
-
ServeStdio ラッパを自作
-
プリ/ポストフックでログ抑制やパニックリカバリを統一
-
まとめ
go‑mcp は Go の強みを活かせる一方、「モジュールパスの解決」「人間向けログの混入」「仕様日付のズレ」「SDK の揺れ」という 4 大失敗ポイントを知らないと開発初日にハマります。本稿で紹介した原因と対策を事前に押さえ、最小構成で E2E スモークテストを組んだうえで本格実装に進むのが安全です。アップデートは慎重に、タグ固定と自動テストで“動く状態”を守りましょう。
出典一覧
*1 https://github.com/kazuki-oshino/go-mcp-abc
*2 https://github.com/AgentDeskAI/browser-tools-mcp/issues/103
*3 https://github.com/anthropics/claude-code/issues/768
*4 https://github.com/mark3labs/mcp-go