本記事のゴール
FastMCPでリモートMCPサーバー(Streamable HTTPトランスポート利用)を構築し、Claude DesktopからMCPサーバーを経由して外部APIからデータを取得する
外部APIにはjsonplacejsonplaceholderを利用する
全体像
https://modelcontextprotocol.io/introduction より引用
- MCPホスト
- Claude Desktop、ChatGPT Desktop、CursorなどのMCP経由でデータにアクセスできるAIアシスタント
- MCP サーバー
- MCP プロトコルを介してツールなどの特定の機能を提供するローカルまたはリモートのサーバー
事前準備
Claude Desktopの入手
Claude for Desktopの設定を変更して作成したMCPサーバーを使うように設定してみます。
環境
- Python3.13
- 3.13未満の方は本記事下部のインストール手順を参照ください
- Mac
目次
- MCPとは
- ローカルMCPサーバーの構築
- リモートMCPサーバーの構築
- リモートMCPサーバー経由で外部APIからデータを取得する
MCPとは
- Model Context Protocol の略
- ClaudeなどのAIアシスタントとアプリケーションを接続するための規格
- 2024年にAnthropicが提唱。2025年にはOpenAIとGoogleもMCPへの参加を表明し、標準化の流れが加速
ローカルMCPサーバーの構築
プロジェクト作成
uvのインストール
uvはRust製の高速でモダンなPythonパッケージマネージャー
https://docs.astral.sh/uv/getting-started/installation/#installation-methods
curl -LsSf https://astral.sh/uv/install.sh | sh
インストール後、バージョン確認。uvコマンドが認識されていなければ、ターミナルを再起動。
uv -V
uv 0.7.16 (b6b7409d1 2025-06-27)
プロジェクト初期化
uv init mcp-server-sample
以下のようなファイルが生成される
- .gitignore
- .python-version
- main.py
- pyproject.toml
- README.md
仮想環境の構築
venvを使って仮想環境を作成
uv venv
仮想環境を有効化
source .venv/bin/activate
MCP関連のモジュール追加
MCPサーバーを構築するための必要なモジュールが含まれているmodelcontextprotocol公式のライブラリを追加する
https://github.com/modelcontextprotocol/python-sdk
(FastAPIやUVicornと統合された開発サーバーも含まれている
# コマンドラインツールを含むオプションを指定して追加
uv add "mcp[cli]"
uv.lockが生成され、pyproject.toml, uv.lockに依存関係として追加される
MCPサーバーの実装
プロジェクトのルートにあるmain.pyをserver.pyに名称変更し、クイックスタートの内容を貼り付ける
- デコレーター@mcp.tool()を付けた関数がMCPのツールとして登録され、そのまま関数名がツール名になる
- 2つの値を足し算するtoolを登録。後ほどClaude Desktopなどから実行する
- リソース、ツール、プロンプトについて
# server.py
from mcp.server.fastmcp import FastMCP
# Create an MCP server
mcp = FastMCP("Demo")
# Add an addition tool
@mcp.tool()
def add(a: int, b: int) -> int:
"""Add two numbers"""
return a + b
# Add a dynamic greeting resource
@mcp.resource("greeting://{name}")
def get_greeting(name: str) -> str:
"""Get a personalized greeting"""
return f"Hello, {name}!"
if __name__ == "__main__":
mcp.run()
FastMCPについて
- TypescriptやPythonなど言語に対応
- バックグラウンドでFastAPIが起動する
動作検証
まずは、作成したMCPサーバをローカルで起動。
uvicornによりhttp://localhost:8000でサーバーが立ち上がる
uv run server.py
REST APIではないため、Postmanなどでは検証が難しい。jsonrpc形式でデータをMCPサーバーに送る必要がある
MCP Inspectorから検証
MCP Inspectorを使用して検証する
mcp dev server.py
以下のようなトークン付きのURLが表示されるので、ここにアクセスすると検証ツールの画面が表示される
http://localhost:6274/?MCP_PROXY_AUTH_TOKEN=XXXXXXXXXXX
「接続」ボタンをクリック。成功した場合、Connected
と表示される

次に、画面上部のToolsからList Toolsをクリックして利用可能なツール(この場合は add
)を確認し、加算する2つの数値を指定して実行
レスポンスがSuccessとなり、結果が返却されていれば成功

Claude Desktopから検証
以下を実行すると、Claud Desktopの構成にMCPサーバーが追加される(Claude Desktopを完全に終了した状態で実行
uv run mcp install server.py
INFO Added server 'Demo' to Claude config
INFO Successfully installed Demo in Claude app
Claude Desktopを起動し、設定を選択

開発者を選択すると先ほど追加したMCPサーバー(MCPインスタンス名)が表示されていることがわかる

構成を編集というボタンをクリックすると
~/Library/Application Support/Claude/claude_desktop_config.json
が確認でき、その中に追加したMCPサーバーの項目が存在する
注意点として、commandのパスは、実行ファイルへのフルパス(絶対パス)を入力する必要がある
{
"mcpServers": {
"Demo": {
# これは、uvコマンドの絶対パス
"command": "/Users/<username>/.local/bin/uv",
"args": [
"run",
"--with",
"mcp[cli]",
"mcp",
"run",
# これは、実装したserver.pyの絶対パス
"/Users/<username>/git/mcp-server-sample/server.py"
]
}
}
}
Claudeのチャット画面に戻ると、追加したツールが表示されていることがわかる

このツールを選択し実行することで、MCPサーバーに定義したClaude Desktopからツールを実行することができる(実行前に確認画面が表示される


ちなみに、引数が2つしかないので3つ数を渡すと、199と10を一度足してから、追加の指示なしに結果を再度3つめの数字を加算して結果を返してくれる
公式ドキュメントによると、このとき以下のようなことが行われている
https://modelcontextprotocol.io/quickstart/server#what%E2%80%99s-happening-under-the-hood
リモートMCPサーバーの構築
ローカルに構築したMCPサーバーをStreamable HTTPトランスポートを活用してリモート環境にデプロイして、Claude Desktopから実行する
デプロイ先のサービスとしては、Herokuの後継として利用可能なRenderを利用する
ローカルのMCPサーバー実装時との変更箇所は主に以下
- PORTを環境変数で設定できるようにしておく
- FastMCPインスタンス生成時にhostとportを指定する
- このモジュールが直接呼ばれた時に、MCPサーバーを実行し、そのトランスポート指定をstreamable-httpに変更
# server.py
from mcp.server.fastmcp import FastMCP
import os
PORT = os.environ.get("PORT", 10000)
mcp = FastMCP("Demo", host="0.0.0.0", port=PORT)
# Add an addition tool
@mcp.tool()
def add(a: int, b: int) -> int:
"""Add two numbers"""
return a + b
# Add a dynamic greeting resource
@mcp.resource("greeting://{name}")
def get_greeting(name: str) -> str:
"""Get a personalized greeting"""
return f"Hello, {name}!"
if __name__ == "__main__":
mcp.run(transport="streamable-http")
事前にGitHubリポジトリを作成し、ソースコードをpushしておくこと
Renderのサービス作成
アカウントを作成し、Web Serviceを追加、ソースコードをGitHubリポジトリと接続する

Build Commandeをuv sync

Start Commandをuv run server.py

MCP Inspectorから検証
サーバーをデプロイできたらMCP InspectorからリモートのMCPサーバーを検証する
Inspectorを起動
mcp dev server.py
ローカルでの検証時とは異なり、URLをリモートのMCPサーバーのURLを指定する必要がある。(URLはデプロイ完了後にRenderの管理画面で確認できるのでそちらを指定

ローカルでの検証時と同様に、実装したツールが呼び出せるか確認する
Claude Desktopから検証
すでに追加したDemoのMCPサーバーのurlをリモートのMCPサーバーのURLに指定する
"Demo": {
"command": "/Users/<username>/.volta/bin/npx",
"args": ["-y", "mcp-remote", "https://xxxxxxxxxxxx.com/mcp/"]
}
Claude Desktopから実行し、ローカルでの挙動と同じようにできれば成功
リモートMCPサーバー経由で外部APIからデータを取得
server2.pyを作成し、jsonplaceholderからデータフェッチするget_postsツールを作成
参考:https://github.com/modelcontextprotocol/python-sdk#tools
from typing import Any, Dict, List
from mcp.server.fastmcp import FastMCP
import httpx
import os
# FastMCPサーバーのインスタンスを作成
PORT = os.environ.get("PORT", 10000)
mcp = FastMCP("Demo2", host="0.0.0.0", port=PORT)
@mcp.tool()
async def get_posts() -> List[Dict[str, Any]]:
"""JSONPlaceholderから全ての投稿を取得する"""
async with httpx.AsyncClient() as client:
response = await client.get("https://jsonplaceholder.typicode.com/posts")
response.raise_for_status()
return response.json()
if __name__ == "__main__":
mcp.run(transport="streamable-http")
MCPサーバーをローカルで起動
uv run server2.py
Inspectorを起動し、Toolからget_postsを実行し、jsonplaceholderから投稿データを取得できれば成功
mcp dev server2.py

リモートで検証するため、ソースコードをpush。Renderで別のサービスを作成しデプロイ
Start Commandをuv run server2.pyで指定してサービスを作成
Claude Desktopからツールを実行し「記事を取得して」、とプロンプトを入力し取得できれば成功
