はじめに
公式 npm パッケージ @modelcontextprotocol/server-postgres を MCP サーバーとして使った検証(Track A)では、watsonx Orchestrate(wxO) エージェントから PostgreSQL を自然言語で 参照 できることを確認しました。
ただし @modelcontextprotocol/server-postgres はすでにアーカイブ済みのパッケージであり、機能も SELECT 専用です。独自のユースケースや社内 API に対応するには、MCP サーバーを自作できるようになることが重要です。
本記事はその続編 Track B として、FastMCP を使って Python で MCP サーバーを自作し、INSERT / UPDATE / DELETE まで含めた CRUD 操作を wxO エージェントから呼び出せることを確認します。
コードと手順は GitHub に公開しています。
やったこと
- 広く使われている Python MCP フレームワーク FastMCP で MCP サーバーを自作(4 ツール)
- MCP Inspector でローカル動作確認(デプロイ前の検証)
- wxO の
--package-root機能でローカルの Python ファイルをクラウドにアップロード - wxO エージェントから商品データの一覧取得・追加・価格変更・削除を自然言語で操作
結果
wxO のチャット画面から自然言語で CRUD 操作が完結しました。
商品一覧を見せて
→ products テーブルの全件が表示される
PC の商品だけ見せて
→ category = 'PC' で絞り込んで返ってくる
テスト商品を 500 円、カテゴリ test、在庫 1 で追加して
→ INSERT 実行、新しい ID が返ってくる
追加したテスト商品の価格を 999 円にして
→ UPDATE 実行、変更が反映される
追加したテスト商品を削除して
→ DELETE 実行
ポイント① FastMCP のツール定義は驚くほど簡単
FastMCP は Python で MCP サーバーを書くための広く使われているフレームワークです。
@mcp.tool() デコレータをつけた Python 関数が、そのまま MCP ツールとして公開されます。
from fastmcp import FastMCP
mcp = FastMCP("postgres-rw")
@mcp.tool()
def list_products(category: str = None) -> str:
"""商品一覧を返す。category を指定すると絞り込む。"""
# ... psycopg2 で SELECT 実行
型ヒントと docstring がそのままツールの引数定義・説明として自動生成されます。
エージェントはこの定義を読んで「いつどのツールを呼ぶか」を判断するので、docstring は重要です。
今回実装した 4 ツールはこちら:
| ツール名 | SQL | 引数 |
|---|---|---|
list_products |
SELECT | category(省略可) |
add_product |
INSERT | name, category, price, stock |
update_product_price |
UPDATE | product_id, new_price |
delete_product |
DELETE | product_id |
ツールを「4本の個別関数」として定義することには、機能面以外の意味もあります。「任意の SQL を実行する」汎用ツールにしてしまうと、エージェントが意図しない SELECT や DELETE を発行するリスクが生まれます。操作ごとに関数を分けることで エージェントが実行できる操作の範囲を明示的に制限でき、本番環境でも使いやすい設計になります。
ポイント② MCP Inspector でデプロイ前に動作確認できる
FastMCP には MCP Inspector というブラウザ UI が付属しています。
wxO にデプロイする前に「ツールが正しく定義されているか」をローカルで目視確認・実行テストできます。
DATABASE_URL="postgresql://..." fastmcp dev mcp_server/server.py
ターミナルに表示される URL をブラウザで開くと、Tools タブに 4 ツールが並びます。
ここで引数・説明・実行結果を確認できれば、FastMCP サーバーとして正しく実装されています。
ポイント③ --package-root でローカルファイルがクラウドに上がる
Track A で説明したとおり、wxO の MCP Toolkit は STDIO トランスポートで動作します。wxO エージェント(MCP クライアント)がサーバープロセスを子プロセスとして起動し、標準入出力で JSON-RPC メッセージをやり取りする方式です。FastMCP サーバーもこの仕組みをそのまま使います。
Track A では command: に npx コマンドを書いて npm パッケージを直接実行しました。
Track B では package_root: にローカルのディレクトリを指定します。
# toolkits/m-postgres-rw.yaml
spec_version: v1
kind: mcp
name: m-postgres-rw
description: FastMCP Python による PostgreSQL R/W ツールキット
package_root: ../mcp_server # このディレクトリが zip 化されてアップロードされる
command: python server.py
connections:
- m-postgres-conn
tools:
- "*"
orchestrate toolkits import -f toolkits/m-postgres-rw.yaml を実行すると、
mcp_server/ フォルダが zip に圧縮されて wxO クラウドにアップロードされます。
wxO はアップロードされたファイルを展開し、requirements.txt をもとに依存パッケージを
インストールしてから python server.py を起動します。
Track A と同様、MCP サーバーは wxO クラウド上で動くため、手元の PC に Python 環境は不要です。
構成
track-b/
├── mcp_server/
│ ├── server.py # FastMCP サーバー(4 ツール)
│ └── requirements.txt # fastmcp / psycopg2-binary
├── connections/
│ └── m-postgres-conn.yaml
├── toolkits/
│ └── m-postgres-rw.yaml
├── agents/
│ └── M-postgres-rw-agent.yaml
└── import-all.sh
Connection は Track A と共用できます。Supabase のセットアップも Track A と同じです。
おわりに
FastMCP を使うと、Python 関数に @mcp.tool() をつけるだけで MCP サーバーが完成します。
--package-root でそのままクラウドにデプロイできるので、npm パッケージが存在しない独自のデータソースや社内 API でも同じ構成が使えます。
シリーズ
(本記事は、執筆にあたりAnthropic Claudeを利用し、その出力を参考にしています。)