MCPサーバーの最小実装 — FastMCPで最初のツールを作る
連載:AIに仕事を奪われる不安から始めるハーネス作成入門
全24回(週2回・12週間)|第8回 / 24
この連載は、AIに仕事を奪われるかもしれないという不安を「ハーネス(AIエージェント制御の仕組み)」を自分で作る行動に変えるシリーズです。
はじめに:この記事で扱う不安
「MCPサーバーを作ってみたいけど、何から書けばいいのかわからない」——前回(第7回)でMCPサーバーの分割設計を行い、MCP責務表まで作りました。しかし、設計図があっても「最初の1行目」が書けないと手が止まります。
今回は、その不安を解消するためにFastMCPを使った最小実装を体験します。「思ったより少ないコードで動く」という感覚を掴むことが目標です。
対象読者
- SE・プログラマ経験3年以上の方
- Pythonの基本構文(関数、デコレータ、型ヒント)を理解している方
- MCPサーバーを実際に作りたい方
- 前回までの連載を読んでいる方(未読でもOK)
結論
MCPサーバーの最小実装は、Pythonの関数にデコレータを付けるだけです。@mcp.tool() を付けた関数が、そのままAIエージェントから呼び出せるツールになります。SE経験者がAPI設計で培った「引数の型を決める」「戻り値の形式を統一する」スキルがそのまま活きます。
なぜ「最小実装」から始めるべきか
第7回で作ったMCP責務表には4つのMCPサーバーがありました。全部を一度に作ろうとすると、以下の問題が起きます。
- 設計の迷い: 最初から完璧なインターフェースを設計しようとして手が止まる
- 動作確認の遅れ: コードが増えるほど、最初の動作確認までの時間が長くなる
- モチベーションの低下: 成果が見えないまま設計だけが進む
SEなら「まずプロトタイプを作って動かしてから改善する」アプローチに馴染みがあるはずです。MCPサーバーでも同じです。まず1つのMCPサーバーに2つのツールを実装して動かすことから始めましょう。
既存のSE / プログラマ経験をどう活かせるか
| SE経験 | MCPサーバー実装への活用 |
|---|---|
| API設計(RESTful) | ツールの引数・戻り値設計 |
| インターフェース定義(型定義) | 型ヒントによるツールシグネチャ設計 |
| エラーハンドリング設計 | dictベースの統一エラー応答 |
| ドキュメント作成 | docstringによるツール説明 |
| 単体テスト設計 | ツール単位のテスタビリティ確保 |
FastMCPとは何か
FastMCPは、MCPサーバーをPythonで手軽に構築するためのフレームワークです。最小5行でMCPサーバーが動きます。
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("my-first-mcp")
@mcp.tool()
def hello() -> str:
"""最初のMCPツール"""
return "Hello from MCP!"
if __name__ == "__main__":
mcp.run()
これだけで、AIエージェントから hello ツールを呼び出せるMCPサーバーが完成します。
重要なポイント
-
FastMCP("サーバー名")でサーバーインスタンスを作る -
@mcp.tool()デコレータで関数をツールとして登録 -
mcp.run()でstdio(標準入出力)トランスポートとして起動 - HTTPサーバーを自分で立てる必要がない
最小MCPサーバーの実装(今回の主要成果物)
第7回で設計した article_mcp(記事の作成・管理)の最初のツールを実装します。
import os
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("article-mcp")
@mcp.tool()
def health_check() -> dict:
"""MCPサーバーの状態を確認する。"""
return {
"ok": True,
"data": {
"server_name": "article-mcp",
"version": "0.1.0",
"status": "running"
}
}
@mcp.tool()
def create_article_project(
platform: str,
title_working: str,
purpose: str = "",
language: str = "ja"
) -> dict:
"""記事プロジェクトを新規作成する。
Args:
platform: 投稿先プラットフォーム('qiita' または 'note')
title_working: 仮タイトル
purpose: 記事の目的(オプション)
language: 言語コード(デフォルト: 'ja')
"""
# バリデーション
valid_platforms = ["qiita", "note", "both"]
if platform not in valid_platforms:
return {
"ok": False,
"error": {
"message": f"platformは {valid_platforms} のいずれかを指定してください"
}
}
article_id = f"art_{platform}_{title_working[:10]}"
return {
"ok": True,
"tool": "create_article_project",
"article_id": article_id,
"data": {
"platform": platform,
"title_working": title_working,
"purpose": purpose,
"language": language
}
}
if __name__ == "__main__":
mcp.run()
コード解説
ツールのシグネチャ設計のポイント
MCPツールのシグネチャ(引数と戻り値)は、AIエージェントとの契約です。SE的にはAPIのインターフェース定義と同じです。
| 設計要素 | 役割 | SE的対応 |
|---|---|---|
| 関数名 | AIがツールを選ぶ手がかり | APIエンドポイント名 |
| docstring | AIがツールの用途を判断する | APIドキュメント |
| 型ヒント | AIが渡すべきデータ型を知る | リクエストスキーマ |
| デフォルト値 | AIが省略可能な引数を知る | オプショナルパラメータ |
| 戻り値のdict | AIが結果を解釈する | レスポンススキーマ |
注意すべき3つのルール
-
戻り値は常にdictで統一する:
{"ok": True/False, ...}の形式にすると、成功/失敗の判定がAIにもプログラムにも容易 - 例外を投げずにdictでエラーを返す: MCPではJSON-RPCの仕様上、Python例外よりもdictベースのエラー応答が安全
- docstringは必ず書く: AIエージェントはdocstringを読んでツールを選ぶ。空だと呼ばれない可能性がある
ローカルでの動作確認
stdioモードでの起動
# 仮想環境を有効化
python -m venv .venv
.venv\Scripts\activate # Windows
# source .venv/bin/activate # Mac/Linux
# 依存パッケージをインストール
pip install mcp
# サーバー起動テスト(起動後 Ctrl+C で停止)
python src/server.py
AI開発環境への接続
AI開発環境(Antigravity、Claude Desktopなど)にMCPサーバーを登録するには、設定ファイルにサーバー情報を追加します。
{
"mcpServers": {
"article-mcp": {
"command": "python",
"args": ["src/server.py"],
"cwd": "/path/to/your/project"
}
}
}
登録後、AIエージェントに「health_checkを呼んで」と指示すると、サーバーの状態が返ります。自分が書いたPython関数がAIから呼び出される——この体験が、ハーネス開発の第一歩です。
実装・設計時の注意点
| 注意点 | 理由 | 対策 |
|---|---|---|
| 最初のツールは2〜3個に絞る | ツールが多すぎるとAIが迷う | health_check + 業務ツール1〜2個 |
| 型ヒントを省略しない | AIが引数の型を推測できなくなる | 全引数にstr/int/bool/dictを明記 |
| docstringを省略しない | AIがツールの用途を判断できない | 1行でツールの目的を書く |
| グローバル変数に依存しない | テスト時にモックが困難 | 引数で必要な情報を受け取る |
| 非同期は後回し | asyncの複雑さで手が止まる | まず同期関数で動かす |
今回の小さな成果物(チェックリスト)
-
FastMCPで
health_checkツールを持つMCPサーバーを作る - もう1つ、自分の用途に合った業務ツールを追加する
- ローカルでstdioモード起動を確認する
- AI開発環境に接続し、ツールが呼び出されることを確認する
- (発展)第7回のMCP責務表の他のMCPサーバーも最小実装してみる
まとめ
今回は、FastMCPを使ったMCPサーバーの最小実装を体験しました。
キーポイント
- MCPサーバーの実装は「関数 + デコレータ」だけで始められる
- ツールのシグネチャ設計は、SE経験のAPI設計スキルがそのまま使える
- 戻り値はdictで統一、エラーもdictで返す
- docstringと型ヒントが、AIエージェントとの「契約」になる
- まず2〜3ツールで動かし、育てていくアプローチが現実的
次回予告
第9回「RAG / Knowledge MCPがSE経験者に向いている理由」 では、知識基盤の世界に踏み込みます。
扱う内容
- RAG(Retrieval-Augmented Generation)の基本概念
- Knowledge MCPがハーネスに果たす役割
- SE経験者が「DB設計」の知見でRAGを理解できる理由
得られる成果物
- 知識管理方針(何を、どう登録し、どう検索するか)
試しておくこと
- 今回作ったMCPサーバーを手元に残しておく(次回以降、knowledge_mcpを追加する際の参考にします)
- 「ドキュメントを検索する」経験を振り返る(社内Wiki、Confluence、Notionなど)
- 「あの情報どこだっけ」と困った経験をメモしておく
連載目次
| 回 | タイトル | 状態 |
|---|---|---|
| 第1回 | AIに仕事を奪われる不安から「ハーネス作成」を学ぶ理由 | ✅ |
| 第2回 | 最小構成のAIハーネスをMermaidで設計してみる | ✅ |
| 第3回 | AIにコードを書かせるだけでは足りない理由 | ✅ |
| 第4回 | task_request / task_resultでAIエージェントの仕事を契約化する | ✅ |
| 第5回 | SEの設計経験をAIエージェント制御に転用する | ✅ |
| 第6回 | ハーネス用のディレクトリ構成とREADMEを作る | ✅ |
| 第7回 | MCPサーバーを「道具箱」として分割する考え方 | ✅ |
| 第8回 | MCPサーバーの最小実装 — FastMCPで最初のツールを作る | 📖 |
| 第9回 | RAG / Knowledge MCPがSE経験者に向いている理由 | 次回 |
| 第10回 | 設計メモをKnowledge MCPへ登録する前提のMarkdownテンプレート | ─ |
| 第11回 | ローカルLLMを使うべき場面と外部LLMに任せる場面 | ─ |
| 第12〜24回 | (以降の回) | ─ |
連載:AIに仕事を奪われる不安から始めるハーネス作成入門
著者: @singula00991 | 週2回更新
次回は「RAG / Knowledge MCPがSE経験者に向いている理由」を予定しています。