【Python】最低限の手順でMCPサーバーを構築するメモ

前回はTypescriptで最低限のMCPサーバーを構築する手順をまとめました

https://qiita.com/yonaka15/items/8a28c2bb59b4b2baf246

このメモでは、Python SDKを使用してMCPサーバーを最小限のステップで構築する手順をまとめます。

## 前提環境

- Python: v3.10.0以上
- MCP SDK: v0.2.0以上

## 1. プロジェクトセットアップ

新しいディレクトリを作成し、必要なパッケージをインストールします。公式ドキュメントでは、Pythonプロジェクト管理に[uv](https://docs.astral.sh/uv/)の使用を推奨しています。uvは高速でモダンなPythonパッケージマネージャーです。

### uvを使用する場合（推奨）

```bash
# uvがインストールされていない場合はインストール
# curl -sSf https://astral.sh/uv/install.sh | sh

# プロジェクトを初期化
uv init minimal-mcp-server-python
cd minimal-mcp-server-python

# MCPパッケージのインストール
uv add "mcp[cli]"
```

### pipを使用する場合（代替手段）

```bash
mkdir minimal-mcp-server-python
cd minimal-mcp-server-python

# 仮想環境の作成
python -m venv venv
source venv/bin/activate  # Linuxの場合
# venv\Scripts\activate   # Windowsの場合

# MCPパッケージのインストール
pip install "mcp[cli]"
```

パッケージの役割：
- `mcp`: MCP用Python SDK
- `[cli]`: コマンドラインツールを含むオプション

## 2. MCPサーバー実装

`server.py`ファイルを作成し、基本的なMCPサーバーを実装します。Pythonでは、関数のアノテーションを使用して型を指定します。

```python
"""
最小限のMCPサーバー実装
"""
from mcp.server.fastmcp import FastMCP

# サーバーインスタンス作成
mcp = FastMCP("minimal-mcp-server")

# エコーツール定義
@mcp.tool()
def echo(message: str) -> str:
    """入力されたメッセージをそのまま返す簡単なツール"""
    return f"Echo: {message}"

# 日時ツール追加
@mcp.tool()
def get_current_time() -> str:
    """現在の日時を取得するツール"""
    from datetime import datetime
    now = datetime.now()
    return f"現在の日時: {now.strftime('%Y-%m-%d %H:%M:%S')}"

# メイン実行部分（直接実行する場合）
if __name__ == "__main__":
    mcp.run()
```

サーバーの構造について:

1. `FastMCP`クラスインスタンスを作成し、サーバー名を指定します
2. `@mcp.tool()`デコレータを使って関数をツールとして登録します
3. 関数のドキュメント文字列はツールの説明として使用されます
4. 関数のパラメータと戻り値の型アノテーションは自動的にMCPの型情報に変換されます

## 3. リソースとプロンプトの追加

MCPサーバーをさらに拡張して、リソースやプロンプトを追加することができます。：

```python
# リソース定義の例
@mcp.resource("info://server")
def server_info() -> str:
    """サーバーに関する情報を提供するリソース"""
    return "これは最小限の設定で作られたMCPサーバーです。"

# 動的リソースの例
@mcp.resource("greeting://{name}")
def get_greeting(name: str) -> str:
    """名前に基づいた挨拶を返すリソース"""
    return f"こんにちは、{name}さん！"

# プロンプト定義の例
@mcp.prompt()
def simple_prompt(text: str) -> str:
    """単純なプロンプトテンプレート"""
    return f"以下のテキストについて考えてください: {text}"
```

リソースについて:
- `@mcp.resource()`デコレータで関数をリソースとして登録します
- URIテンプレートに変数を含めることができ、関数の引数として渡されます
- リソースはLLMの文脈に情報を提供するためのものです

プロンプトについて:
- `@mcp.prompt()`デコレータで関数をプロンプトテンプレートとして登録します
- ユーザーはこれらのテンプレートを呼び出してLLMとの対話を開始できます

## 5. テストと検証

MCP Inspectorを使ってサーバーをテストします。

```bash
# pipインストールの場合
mcp dev server.py

# uvを使用している場合
uv run mcp dev server.py
```

これにより、**インスペクタが起動してローカルホストのURLが表示されます。** ブラウザでアクセスすると開発用インターフェースが表示され、定義したツールやリソース、プロンプトが確認できます。各ツールを直接呼び出して結果を確認することもできます。

![Screenshot 2025-04-07 at 22.04.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79562/598145df-5318-4263-83b4-09eca0f7cf18.png)


:::note info
Typescriptに比べるとビルドが不要で手間が少なく、インスペクタの起動も簡単ですね
::: 

## 6. LLMクライアント接続

### Claude Desktop設定

MCP CLIツールを使用して簡単にサーバーをインストールできます：

```bash
# pipインストールの場合
mcp install server.py

# カスタム名でインストール
mcp install server.py --name "Python MCP サーバー"

# 環境変数を設定
mcp install server.py -v API_KEY=abc123 -v DB_URL=postgres://...
mcp install server.py -f .env

# uvを使用している場合
uv run mcp install server.py
```

設定ファイルに下記のような内容が追加されます：
- MacOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
- Windows: `%AppData%\Claude\claude_desktop_config.json`

```json
{
  "mcpServers": {
    "minimal-mcp-server": {
      "command": "uv",
      "args": [
        "run",
        "--with",
        "mcp[cli]",
        "mcp",
        "run",
        "/絶対パス/minimal-mcp-server-python/server.py"
      ]
    }
  }
}
```

### Cursorでの設定

1. Settings → MCPセクション → 「Add new MCP server」
2. 入力情報：
   - Name: minimal-mcp-python
   - Type: command
   - Command: `python /絶対パス/minimal-mcp-server-python/server.py`

### HTTP/SSEトランスポート

公式ドキュメントに基づき、FastMCPはSSEサーバーとしての機能も提供しています：

```python
from starlette.applications import Starlette
from starlette.routing import Mount
from mcp.server.fastmcp import FastMCP

# MCPサーバー作成
mcp = FastMCP("HTTP-MCP-Server")

# ツールやリソースの定義...

# Starletteアプリにマウント
app = Starlette(
    routes=[
        Mount('/', app=mcp.sse_app()),
    ]
)

# ASGIサーバーでStarletteアプリを実行する場合
if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=3000)
```

## まとめ

このガイドでは、Python SDKを使用してMCPサーバーを構築する基本的な手順を紹介しました。Python版MCPサーバーはデコレータを活用した直感的なAPIを提供しており、型ヒントを用いて入力値の型チェックを行います。

Typescriptよりもツールやドキュメントが充実していると感じました。個人的には型チェックのできるTypescriptのほうが好みですが（動作も安定する気がしています）、気軽に始めてみるにはPythonのほうがいいですね！

## 参考

- [Model Context Protocol 公式](https://modelcontextprotocol.io/)
- [MCP GitHub](https://github.com/modelcontextprotocol)
- [MCP Python SDK](https://github.com/modelcontextprotocol/python-sdk)
- [MCP 仕様書](https://spec.modelcontextprotocol.io/specification/2025-03-26/)
- [uv パッケージマネージャー](https://docs.astral.sh/uv/)