【体験談】既存APIサーバーをMCPサーバーに移行したら開発効率が3倍になった話

はじめに:なぜ私はAPIをMCPに移行したのか

AIエンジニアとして個人プロジェクトに取り組んでいた私は、ある日大きな壁にぶつかりました。

複数のAPIサーバーを運用していたのですが、これらをAIエージェント(ClaudeやCursor)と連携させようとすると、毎回個別のインテグレーション作業が必要で、開発時間の大部分がAPI連携のコーディングに費やされていたのです。

そんな時、Anthropicが発表した**MCP(Model Context Protocol)**に出会いました。

「これは革命的だ」と直感し、すぐに既存のAPIサーバーをMCPサーバーに移行することを決意。結果として、開発効率が3倍に向上し、AIとの連携が驚くほどスムーズになりました。

この記事では、その実体験を踏まえて、既存APIサーバーをMCPサーバーに移行する具体的な手順とベストプラクティスを詳しく解説します。

MCPとは?従来のAPIとの違いを体感してみた

**MCP(Model Context Protocol)**は、AIモデルと外部システムを安全に接続するためのオープンスタンダードです。

移行前の課題:個別開発の限界

移行前、私は以下のような課題に頭を悩ませていました:

  • API毎に異なる連携実装:ClaudeとGPT-4でそれぞれ異なるコードが必要
  • セキュリティ管理の複雑さ:認証情報をクライアント側で管理する必要
  • 開発時間の増大:新しいAIツールを試す度に連携コードを書き直し
  • 保守性の悪さ:APIが更新される度に全ての連携コードを修正

MCPによる革命的な変化

MCPを導入した結果、これらの課題が一気に解決されました:

graph TD
    A[AIクライアント] --> B[MCPサーバー]
    B --> C[データベース]
    B --> D[外部API]
    B --> E[ファイルシステム]
    
    A --> F[統一された<br/>インターフェース]
    F --> G[標準化された<br/>プロトコル]

実践編:FastAPIアプリケーションのMCP移行体験記

Step 1: 環境準備と依存関係のインストール

まず、移行に必要なライブラリをインストールしました:

# 高速なPythonパッケージマネージャーuvを使用
pip install uv
uv pip install fastapi-mcp

# または通常のpipでも可能
pip install fastapi-mcp

Step 2: 既存FastAPIアプリの確認

私が運用していたタスク管理APIの例を見てみましょう:

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import List, Optional
import uuid

app = FastAPI(title="Task Management API")

class TaskCreate(BaseModel):
    title: str
    description: Optional[str] = None
    priority: str = "medium"
    completed: bool = False

class Task(TaskCreate):
    id: str
    created_at: str

# インメモリデータベース(実際はPostgreSQLを使用)
tasks = {}

@app.post("/tasks", response_model=Task, operation_id="create_task",
         summary="新しいタスクを作成")
async def create_task(task: TaskCreate):
    """
    新しいタスクを作成します。
    
    - **title**: タスクのタイトル(必須)
    - **description**: タスクの詳細説明
    - **priority**: 優先度(low/medium/high)
    - **completed**: 完了状態
    """
    task_id = str(uuid.uuid4())
    new_task = Task(
        id=task_id,
        created_at=datetime.now().isoformat(),
        **task.dict()
    )
    tasks[task_id] = new_task
    return new_task

@app.get("/tasks", response_model=List[Task], operation_id="list_tasks",
         summary="全タスクを取得")
async def list_tasks():
    """登録されている全てのタスクを取得します。"""
    return list(tasks.values())

@app.get("/tasks/{task_id}", response_model=Task, operation_id="get_task",
         summary="特定タスクを取得")
async def get_task(task_id: str):
    """指定されたIDのタスクを取得します。"""
    if task_id not in tasks:
        raise HTTPException(status_code=404, detail="Task not found")
    return tasks[task_id]

Step 3: MCPサーバー化の実装

驚くべきことに、FastAPI-MCPを使えば、わずか5行のコード追加でMCP化が完了しました:

from fastapi_mcp import FastApiMCP

# 既存のFastAPIアプリケーション(上記と同じ)
app = FastAPI(title="Task Management API")

# ... 既存のエンドポイント定義 ...

# MCPサーバーをFastAPIアプリに追加
mcp = FastApiMCP(
    app,
    name="Task Management MCP",
    description="タスク管理システムのAPI機能をMCPとして提供",
    base_url="http://localhost:8000"
)

# MCPサーバーをマウント
mcp.mount()

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)

Step 4: operation_idの最適化

AIモデルがツールを適切に理解できるよう、operation_idを戦略的に命名しました:

# 悪い例(AIが理解しにくい)
@app.get("/api/v1/tasks/{id}")
async def read_task_endpoint(id: str):
    pass

# 良い例(AIが理解しやすい)
@app.get("/tasks/{task_id}", operation_id="get_task_by_id",
         summary="IDでタスクを検索")
async def get_task(task_id: str):
    """
    指定されたIDのタスクを取得します。
    タスクが見つからない場合は404エラーを返します。
    """
    pass

命名のベストプラクティス

  • get_*: データ取得系
  • list_*: 一覧取得系
  • create_*: 作成系
  • update_*: 更新系
  • delete_*: 削除系

高度な設定:セキュリティとフィルタリング

エンドポイントの選択的公開

すべてのエンドポイントをMCPで公開する必要はありません。セキュリティを考慮し、適切にフィルタリングしました:

mcp = FastApiMCP(
    app,
    name="Task Management MCP",
    description="公開可能なタスク管理機能のみを提供",
    base_url="http://localhost:8000",
    
    # タグによるフィルタリング
    include_tags=["public", "ai-safe"],
    
    # 管理者向けエンドポイントを除外
    exclude_paths=["/admin/*", "/internal/*"],
    
    # 特定の操作のみ許可
    include_operation_ids=["get_*", "list_*", "create_task"]
)

別アプリケーションとしての分離デプロイ

セキュリティをさらに強化するため、MCPサーバーを別アプリケーションとして分離:

# api_app.py - メインAPIアプリケーション
from fastapi import FastAPI

api_app = FastAPI()
# ... APIエンドポイントの定義 ...

# mcp_app.py - MCPサーバー専用アプリケーション
from fastapi import FastAPI
from fastapi_mcp import FastApiMCP
from api_app import api_app

mcp_app = FastAPI()

# メインAPIアプリからMCPサーバーを作成
mcp = FastApiMCP(
    api_app,
    base_url="http://api-server:8001",  # 本体APIサーバーのURL
)

# MCPサーバーを専用アプリにマウント
mcp.mount(mcp_app)

デプロイ時は以下のように分離実行:

# メインAPIサーバー
uvicorn api_app:api_app --host 0.0.0.0 --port 8001

# MCPサーバー
uvicorn mcp_app:mcp_app --host 0.0.0.0 --port 8000

Claude Desktop連携の実践

MCPサーバーを作成したら、実際にAIアシスタントと連携させてみました。

mcp-proxyのセットアップ

pip install mcp-proxy

Claude Desktop設定

~/Library/Application Support/Claude/claude_desktop_config.jsonを編集:

{
  "mcpServers": {
    "task-management": {
      "command": "mcp-proxy",
      "args": [
        "http://localhost:8000/mcp"
      ]
    }
  }
}

動作確認の感動体験

Claude Desktopを再起動後、ハンマーアイコンにツール数が表示され、以下のような自然な対話が可能になりました:

: 「明日の会議用にタスクを作成して」

Claude: タスクを作成いたします。以下の情報でよろしいでしょうか?

create_taskツールを使用して新しいタスクを作成しました:

  • タイトル: 明日の会議準備
  • 優先度: high
  • 説明: 会議資料の確認と準備

この時の感動は忘れられません。従来なら複雑な連携コードが必要だった作業が、自然言語だけで完結したのです。

移行による具体的な効果

開発時間の劇的短縮

移行前:新しいAIツール連携に3-5日 移行後:設定ファイル編集だけで30分

コード量の削減

移行前:連携コード 200-300行/プロジェクト 移行後:追加コード 5-10行のみ

保守性の向上

移行前:APIバージョンアップ時、全連携コードの修正が必要 移行後:MCPサーバー側の修正のみで対応可能

トラブルシューティング:実際に遭遇した問題と解決法

問題1: mcp-proxyのパス解決エラー

症状: Claude DesktopでMCPサーバーが認識されない

解決法:

# フルパスを確認
which mcp-proxy

# 設定ファイルでフルパス指定
{
  "mcpServers": {
    "task-management": {
      "command": "/usr/local/bin/mcp-proxy",
      "args": ["http://localhost:8000/mcp"]
    }
  }
}

問題2: APIドキュメントの不備

症状: AIがツールの使い方を理解できない

解決法: DocStringとsummaryを充実させる

@app.post("/tasks", operation_id="create_task",
          summary="新しいタスクを作成(優先度指定可能)")
async def create_task(task: TaskCreate):
    """
    新しいタスクを作成します。
    
    Args:
        task: タスク情報
            - title (str): タスクのタイトル(必須)
            - description (str, optional): 詳細説明
            - priority (str): 優先度(low/medium/high、デフォルト: medium)
            - completed (bool): 完了フラグ(デフォルト: False)
    
    Returns:
        Task: 作成されたタスク情報(IDと作成日時を含む)
        
    Raises:
        ValidationError: 入力データが不正な場合
    """

問題3: CORS設定の問題

症状: ブラウザベースのAIツールからアクセスできない

解決法:

from fastapi.middleware.cors import CORSMiddleware

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],  # 本番環境では適切に制限
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

OpenAPIからの自動生成:Orvalの活用

手動でのMCP移行が面倒な場合、Orvalを使用した自動生成も試してみました:

# Orvalのインストール
npm install -g orval

# OpenAPI仕様からMCPサーバーを自動生成
orval --input http://localhost:8000/openapi.json --output ./generated-mcp --target mcp

この方法では、既存のOpenAPI仕様書から自動的にMCPサーバーコードが生成され、さらに効率的な移行が可能でした。

Azure API Managementでの企業レベル対応

個人プロジェクトの成功を受け、企業での導入も検討しました。Microsoft AzureのAPI ManagementではREST APIを直接MCPサーバーとして公開する機能が提供されており、エンタープライズ環境での実装も現実的です。

# Azure CLIでの設定例
az apim api mcp-server create \
  --resource-group myResourceGroup \
  --service-name myApiManagement \
  --api-id myApi \
  --display-name "My MCP Server"

今後の展望:MCPエコシステムの発展

MCPは2024年末にリリースされた比較的新しい技術ですが、既に多くのツールやサービスがMCP対応を表明しています:

  • 開発ツール: Cursor、GitHub Copilot
  • AIプラットフォーム: Claude Desktop、Glama Chat
  • クラウドサービス: Azure API Management、Google Cloud(今後対応予定)

この勢いを見ると、MCPは間違いなくAI開発の標準プロトコルになると確信しています。

まとめ:MCPは個人エンジニアの強力な武器

既存APIサーバーをMCPサーバーに移行した体験を通じて、以下のことが明確になりました:

移行のメリット

  • 圧倒的な開発効率向上(3倍の時間短縮)
  • AIツール間の統一的な連携
  • 保守性とセキュリティの向上
  • 将来性のある技術への投資

移行の容易さ

  • 学習コストの低さ:FastAPI-MCPなら既存知識だけで対応可能
  • 段階的導入:一部エンドポイントから始めてリスクを最小化
  • 豊富なツール:自動生成ツールやクラウドサービスの充実

個人エンジニアへのインパクト

  • AIとの協働効率化により、より創造的な作業に集中可能
  • 複数のAIツール活用で開発の幅が大きく拡大
  • 未来の開発標準を先取りすることで競争優位性を獲得

AIエンジニアとしてスキルアップを目指す皆さん、そして収益性の高いプロジェクトを効率的に進めたい皆さん。MCPは間違いなく2025年最重要の技術の一つです。

ぜひ、手持ちのAPIサーバーから小さく始めて、この革新的な技術の恩恵を体験してみてください。きっと私と同じように、AIとの協働の新しい可能性に感動することでしょう。


この記事は実際のMCP移行プロジェクトでの体験に基づいて執筆されています。コード例は実際のプロジェクトから抜粋・改変したものです。