MCPサーバーを立ててAIがPostgreSQLを参照できるようにしてみた話
はじめに
こんにちは。マーケティングオートメーションツール「ListFinder」開発チームのはちです。
普段はデータ加工や外部システムとのデータ連携処理などをGo言語で書いています。
弊社では生成AIの活用を推進しており、AIエージェントの Devin
や AIエディタの Cursor
、 AIレビュアーの CodeRabbit
などを利用しています。
この記事は、データベースを使うプログラムを書くことが多い私が開発効率向上のためにgithub copilotがコンテナ上のPostgreSQLを直接参照できるようにした話です。
実行環境
この記事の内容は以下の環境で行なったものです。構成の違いによって違う結果になる可能性があります
- mac os Sequoia 15.6
- Orbstack 2.0.1
- Visual Studio Code 1.103.2
- github copilot chat
- PostgreSQL13.8 コンテナイメージ ※PostgreSQLはDockerコンテナ上で動作するように設定しています
- MCP Go SDK Github v0.5.0
要約
- 公式SDKを使って簡単なプログラムを書くことでVSCodeからgithub copilot chatがコンテナ上のPostgreSQLにアクセスできるようになった
- AIがテーブル構造を理解した上でコードを生成できるようになったのでデータベース周りの実装が楽になった
- 作成したMCPサーバーのソースコードを公開します
- 公式Go言語SDKを使ったローカルMCPサーバー開発の流れ
- VSCodeでローカルMCPサーバーを使う設定の流れ
やろうと思ったきっかけ
GoでORMを使う場合はテーブル構造に沿った構造体型を定義する必要があります。
ListFinderではデータベースのマイグレーションはWebサービスに使用するLaravelで行うので、Go側はマイグレーション結果を見て実装する必要があります。
テーブルに変更を反映する必要が出てきた際など とても面倒くさい(※怠惰はプログラマーの3大美徳の一つです) 。
github copilotを導入した結果エディタ上でAIの支援を受けられるようになりましたが、データベース定義はAIの手が届かないところにあるので手作業が必要でした。
MCPサーバーを使ってAIがデータベースにアクセスできたら楽になるかと考えチャレンジしてみました。
効率化のた目の面倒くさいことは積極的に行いましょう 。
最初は公式の リファレンスサーバーを使って実現した
という内容を予定していたのですが、気づいたらアーカイブされていたので 自分で実装してみた
という内容に変更しました。
参考にしたWebサイト
- Model Context Protocol 公式
-
MCP Go SDK Github v0.5.0
- 破壊的変更も含め頻繁に更新されます。この記事のソースコードでは
v0.5.0
を使用しています。
- 破壊的変更も含め頻繁に更新されます。この記事のソースコードでは
- MCP inspector
-
VSCode公式 MCPサーバーの使い方
-
Add an MCP server to your workspace
の手順に従いました
-
作成したソースコード
作成したソースコードはこちらです。
作成したMCPサーバーのソースコード
package main
import (
"context"
"encoding/json"
"flag"
"fmt"
"log"
"time"
"github.com/jackc/pgx/v5"
"github.com/modelcontextprotocol/go-sdk/mcp"
)
// DSN パラメータで受け取る
var (
dsn string
)
// Input MCPクライアントから受け取るパラメータ構造体
type Input struct {
Query string `json:"query" jsonschema:"実行するSQLクエリ"`
}
// Output MCPクライアントに返すパラメータ構造体
type Output struct {
QueryResult string `json:"query_result" jsonschema:"SQLクエリの結果(JSON形式)"`
}
// runQuery クエリを実行し、結果をJSON形式で返すハンドラ
func runQuery(ctx context.Context, request *mcp.CallToolRequest, input *Input) (*mcp.CallToolResult, *Output, error) {
// クエリが空の場合はエラーメッセージを返す
if input.Query == "" {
return nil, &Output{QueryResult: "No query provided"}, nil
}
// タイムアウト設定
ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
defer cancel()
// PostgreSQLに接続
// 都度接続するので、トランザクションは使えない
db, err := pgx.Connect(ctx, dsn)
if err != nil {
log.Fatalf("Unable to connect to database: %v\n", err)
}
defer db.Close(ctx)
// クエリを実行
rows, err := db.Query(ctx, input.Query)
if err != nil {
return nil, nil, fmt.Errorf("failed to execute query: %w", err)
}
defer rows.Close()
// フィールド情報を取得
// 結果が同じ場合、毎回呼び出すのは非効率なので変数に代入
cols := rows.FieldDescriptions()
// 結果をマップのスライスとして収集
var results []map[string]string
for rows.Next() {
row := make(map[string]string, len(cols))
vals, err := rows.Values()
if err != nil {
return nil, nil, fmt.Errorf("failed to scan row: %w", err)
}
for i, c := range cols {
// 型がバラバラなのでstringに変換する
row[c.Name] = fmt.Sprint(vals[i])
}
results = append(results, row)
}
// 結果をJSONに変換して返す
jr, err := json.Marshal(results)
if err != nil {
return nil, nil, fmt.Errorf("failed to marshal results: %w", err)
}
return nil, &Output{QueryResult: string(jr)}, nil
}
func main() {
// DSN(接続URL)をコマンドライン引数から取得
flag.StringVar(&dsn, "dsn", "postgresql://username:password@hostname:5432/database", "DSN to database")
flag.Parse()
ctx := context.Background()
// サーバーの初期化
server := mcp.NewServer(&mcp.Implementation{Name: "PostgreSQL", Version: "v1.0.0"}, nil)
// ツールの登録
mcp.AddTool(server, &mcp.Tool{Name: "RunQuery", Description: "run query"}, runQuery)
// サーバーの起動
if err := server.Run(ctx, &mcp.StdioTransport{}); err != nil {
log.Fatalf("Failed to run server: %v\n", err)
}
}
実装のポイント
ほぼ公式のサンプル通りです。
今回は標準入力を介してパラメータを受け取ります。
頻繁に更新されるのでタグを指定してパッケージの取得を行うと安全です。
このソースコードでは v0.5.0
を使用しているので、次のコマンドを実行します。
$ go get -u github.com/modelcontextprotocol/go-sdk@v0.5.0
動作確認方法
MCP公式のinspector
を使用するとMCPクライアントなしでもMCPサーバーの動作確認ができます。
npx
コマンドをインストールした状態で次のコマンドを実行します。
$ npx @modelcontextprotocol/inspector
コマンドを実行するとURLが表示されるので、ブラウザで開くとこんな画面が表示されます。
inspector起動時の画面
Command
と Arguments
を入力して Connect
ボタンをクリックすると右側にツールリストが表示されます。
go run main.go
がなぜか動かなかったので、ビルドして実行ファイルを指定しました。
inspector Connect後
List Tools
をクリックすると登録されているツールの一覧が表示され、MCPサーバーへリクエストを送信することができます。
このように incpector
から自作MCPサーバーを通してSQLを実行することができました。
inspector リクエスト送信後
どうやら思惑通りに動作しているようです。
MCPサーバーの実装は以上です。
VSCodeで自作MCPサーバーを使う設定
VSCodeのワークスペースに .vscode/mcp.json
ファイルを作成します。
スクリーンショットを貼り付けたら見づらくなったので表示は省略します。
mcp.json
ファイルの内容を空のjson
{}
に変更すると、エディタの下に サーバーの追加
ボタンが現れるのでクリックします。
サーバーの追加
今回は コマンド(stdio) ... 手動インストール
を選択します。
手動インストール
inspector
で指定した実行モジュールとパラメータを入力してEnter。
サーバーIDは考えなくても自動的につけてくれます。名前をつけてEnter。
コマンド指定
もちろん 信頼する
をクリック。
信頼する
.vscode/mcp.json
にこんな内容が保存されます。
サーバーIDの上に 起動
と薄く表示されるのでクリックするとMCPサーバーが起動します。
MCPサーバー起動
{
"servers": {
"my-mcp-server-82d0e78e": {
"type": "stdio",
"command": "./mcp",
"args": [
"-dsn",
"postgresql://xxxxx:xxxxx@localhost:5432/dbname"
]
}
},
"inputs": []
}
Copilotの入力欄の ツールの構成
ボタンをクリックしてCopilotが使用するMCPサーバーを選択します。
ツールの構成
これでCopilotからMCPサーバーを使う準備ができました。
試しに、適当なエンティティ構造体を作成してCopilotに構造体定義の妥当性を検証してもらいます。
使ってみる
動きました!
これでモデル構造体の記述はGithub Copilot Chat Agentに任せられるようになりました。
まとめ
公式ドキュメント記載のサンプルコードに独自のハンドラを追加した程度でMCPサーバーが動きました。
簡単に実装できるので夢が広がりますね。
SDKも日々改善が行われておりどんどん使いやすくなっています(たまに壊れていますが)。
皆さんもオリジナルMCPサーバーを作って快適なAIコーディングライフ、快適なGoライフをお送りください。

業界最大級の法人向けIT製品比較サービス「ITトレンド」の運営会社、イノベーション開発チームの公式Tech Blogです! 各記事の内容は個人の意見であり、企業を代表するものではございません。 note にも投稿しています! note.com/inno_tech/m/me0da0dc94db9
Discussion