MoodMNKY MCP Server Stack について
MoodMNKY MCP Server Stackは、複数のMCPサーバーをDocker Composeでまとめて実行・設定する構成です。MCPツールをOpenAI Agents SDKやSSE対応クライアントに接続する開発者向けで、Cloudflare Tunnelによる外部公開にも対応します。
主な機能
- 01Docker Composeで複数のMCPサーバーを管理
- 02単一の.envファイルでサービスを設定
- 03SSEエンドポイントでツールを検出・呼び出し
- 04Cloudflare Tunnel経由でサービスを公開
- 05OpenAI Agents SDKとの連携
活用シーン
- 01ローカルでMCPサービス群を実行
- 02SSE経由でOpenAI Agents SDKをMCPサーバーに接続
- 03トンネル経由でリモートクライアントにMCPエンドポイントを公開
MCP 対応
複数のMCPサーバーを実行し、SSEエンドポイントを通じてクライアントにツールを提供します。Cloudflare Tunnelを使ってリモートクライアントに公開する方法も説明されています。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
このサーバーのパッケージやリモートエンドポイントはまだ取得できていません。プロジェクトの README の手順に従ってください。
ツール
ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。
詳細
MoodMNKY MCP サーバースタック
Docker で複数の MCP サーバーを実行、公開、統合するための第一原理に基づくガイドです。Server-Sent Events(SSE)を介して、OpenAI Agents SDK やその他のクライアントからシームレスにアクセスできるようにします。
目次
はじめに
MoodMNKY MCP サーバースタックは、多様な**Model Context Protocol(MCP)**サーバーを Docker コンテナーとして実行し、1 つの便利な docker-compose.yml の背後でオーケストレーションする、独立したリポジトリです。このスタックにより、次のことが可能になります。
- Notion、Sequential Thinking、Brave Search、Tavily、Firecrawl、Fetch、GitHub、Supabase‐Dev、Context7、YouTube Transcript、Redis を使った Memory など、多数のツール提供型 MCP サーバーを迅速にデプロイできます。
- ホストとポートのバインド、API キー、パスを含む単一の
.envファイルで一元的に設定できます。 - OpenAI Agents SDK(SSE 経由)や、SSE に対応したその他のクライアントとすぐに統合できます。
- Cloudflare Tunnel を使って、各 MCP エンドポイントをパブリックインターネット経由で公開できます(任意)。ファイアウォールの安全性を保ちながら、安全に外部アクセスを提供します。
この README は第一原理に基づくアプローチを採用しています。各手順の「方法」だけでなく、その背景にある「理由」も説明するため、MCP、SSE、Docker、Cloudflare Tunnel に詳しくない開発者でも、何が起きているのか、なぜ重要なのか、今後のニーズに合わせてどう応用すればよいのかを理解できます。
MCP と SSE の第一原理
MCP とは?
- **MCP(Model Context Protocol)**は、AI エージェント(GPT‐4 を搭載したアシスタントなど)が外部の「ツール」サービスを呼び出せるようにする、オープンソースの仕様です。
- 各 MCP サーバーは、HTTP エンドポイント(通常は
/tools)を通じて、ツールのシグネチャ(名前、引数、説明)のセットを公開します。 - エージェントがツールを「呼び出す」必要がある場合、
/callに JSON エンコードされた POST リクエストを送信します。MCP サーバーはツールを実行し(例:ウェブページの取得、データベースへのクエリ、コードの実行)、結果をストリーミングで返します。
主なメリット:
- 関心の分離:エージェントは計画と推論に集中し、MCP サーバーは専門的なタスクを処理します。
- 言語に依存しないツール:MCP サーバーは MCP 仕様に準拠していれば、任意の言語(Node、Python、Go など)で記述できます。
- 拡張性:スタックに新しい MCP サーバーを追加するだけで、新しいツールを追加できます。エージェントは実行時にそれらを検出します。
なぜ SSE なのか?
-
**SSE(Server‐Sent Events)**は HTTP ベースの一方向ストリーミングプロトコルで、サーバーが永続的な接続を通じてクライアントに JSON イベントをプッシュできます。
-
MCP のコンテキストでは、SSE は次の 2 つのフェーズで使用されます。
- ツールの検出(LIST):エージェントは
http://<mcp-url>/toolsに GET リクエストを送信し、利用可能な各ツールを説明する JSON が送られてくる SSE ストリームを受信します。 - ツールの呼び出し(CALL):エージェントは JSON 引数を含む POST リクエストを
http://<mcp-url>/callに送信します。MCP サーバーはリクエストを処理し、既存の SSE 接続を通じて結果をストリーミングで返します。
- ツールの検出(LIST):エージェントは
WebSocket やポーリングではなく SSE を使う理由
- シンプルさ:SSE は通常の HTTP を基盤としているため、特別な設定をしなくても、ほとんどのプロキシ、ファイアウォール、ロードバランサーを通過できます。
- 自動再接続:ネイティブの再接続セマンティクスにより、一時的なネットワーク障害に対応できます。
- 低オーバーヘッド:WebSocket のハンドシェイクやプロトコルのフレーミングは不要で、テキストベースのイベントだけを使用します。
- 一方向通信:エージェントは通常の HTTP を使ってツールの呼び出しを送信します。SSE はストリーミング結果の受信にのみ使用され、MCP のモデルに適しています。
ストリーミングと SSE トランスポート
-
SSE の代わりに、独立した「ストリーミング可能な HTTP」トランスポート(チャンク転送エンコーディング)を実装している MCP サーバーもあります。
-
SSE(ここでは推奨):
- 標準化されたイベント形式(
data: { ... })を使用します。 - 再接続機能を内蔵しています。
- ほとんどの HTTP/2 対応環境で動作します。
- 標準化されたイベント形式(
-
ストリーミング/チャンク化 HTTP:
- 極めて軽量なサーバーでは、よりシンプルに実装できます。
- 「イベント」のフレーミング機能を内蔵していないため、クライアントがチャンクを手動で解析する必要があります。
-
推奨:非常に明確な理由がない限り、SSE を使用してください。このスタックのすべての MCP リファレンスサーバーはデフォルトで SSE を使用し、動作を統一しています。
リポジトリの構成
moodmnky-mcp-server-stack/
├── README.md
├── docker-compose.yml # Orchestrates all MCP services
└── .env.example # Template for environment variables
README.md:(このファイル)セットアップ、使用方法、基本的な設計思想、チュートリアルについて説明します。docker-compose.yml:18 個のサービス(MCP サーバーと Redis)を定義します。それぞれがシークレット、ホスト側のポートバインディング、またはパス用の環境変数を参照します。.env.example:<PLACEHOLDER>値として、必要な変数をすべて記載しています。.envにコピーしてプレースホルダーを実際の値に置き換えてください。実際の.envは決してコミットしないでください。
前提条件
Docker と Docker Compose
-
ホストマシン(Linux、macOS、または Windows)に Docker Engine(20.10 以降)と Docker Compose(v2 以降)がインストールされていること。
-
インストールを確認します。
docker --version docker-compose --version
Cloudflare Tunnel(Cloudflared)
-
MCP サーバーをインターネットに公開する予定がある場合(例:リモートでホストされているエージェントからアクセスする場合)、同じホストに Cloudflare の
cloudflaredをインストールしてください。-
お使いの OS に対応する最新リリースを、Cloudflare Tunnel のドキュメントからダウンロードします。
-
インストールします(例:Ubuntu の場合)。
curl -LO https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb sudo dpkg -i cloudflared-linux-amd64.deb -
確認します。
cloudflared version
-
ドメインと DNS の設定
- Cloudflare で管理している登録済みドメイン(例:
example.com)が必要です。 - 外部に公開する MCP サーバーごとに、Cloudflare の DNS ダッシュボードで、トンネルによって自動的に割り当てられたホスト名(例:
mcp-tunnel.cfargotunnel.com)を指す CNAME レコードを作成します。
OpenAI Agents SDK
-
これらの MCP サーバーを統合するには、OpenAI Agents SDK がインストールされた Python 環境が必要です。
pip install openai-agents -
エージェントはコード内で、
MCPServerSseを使って MCP エンドポイント(SSE)を参照します。
環境変数
.env.example
以下は、プレースホルダー値を含む .env.example ファイルの全内容です。.env という名前のファイルはコミットしないでください。代わりに、このファイルを .env にコピーし、すべてのプレースホルダー(<...>)を実際のキー、ホストポート、パスに置き換えてください。
###############################################
# Rename this to ".env" and fill in your values
###############################################
###############################################
# 1. Notion MCP Server
###############################################
NOTION_MCP_HEADERS={"Authorization":"Bearer <YOUR_NOTION_PAT>","Notion-Version":"2022-06-28"}
NOTION_HOST_PORT=<YOUR_NOTION_HOST_PORT> # e.g., 8100
###############################################
# 2. 21st-Dev Magic MCP Server
###############################################
MAGIC_API_KEY=<YOUR_MAGIC_API_KEY>
MAGIC_HOST_PORT=<YOUR_MAGIC_HOST_PORT> # e.g., 8101
###############################################
# 3. Filesystem MCP Server
###############################################
FILESYSTEM_HOST_PATH=<ABSOLUTE_PATH_TO_SHARE> # e.g., /home/ubuntu/new-wave-protocol
FILESYSTEM_HOST_PORT=<YOUR_FILESYSTEM_HOST_PORT> # e.g., 8102
###############################################
# 4. Discord MCP Server
###############################################
DISCORD_TOKEN=<YOUR_DISCORD_TOKEN>
DISCORD_BOT_PERMISSIONS=<YOUR_DISCORD_BOT_PERMISSIONS>
DISCORD_HOST_PORT=<YOUR_DISCORD_HOST_PORT> # e.g., 8103
###############################################
# 5. Sequential Thinking MCP Server
###############################################
SEQUENTIAL_THINKING_HOST_PORT=<YOUR_SEQUENTIAL_THINKING_HOST_PORT> # e.g., 8104
###############################################
# 6. Brave Search MCP Server
###############################################
BRAVE_API_KEY=<YOUR_BRAVE_API_KEY>
BRAVE_SEARCH_HOST_PORT=<YOUR_BRAVE_SEARCH_HOST_PORT> # e.g., 8105
###############################################
# 7. Tavily Search MCP Server
###############################################
TAVILY_API_KEY=<YOUR_TAVILY_API_KEY>
TAVILY_HOST_PORT=<YOUR_TAVILY_HOST_PORT> # e.g., 8106
###############################################
# 8. Firecrawl MCP Server
###############################################
FIRECRAWL_API_URL=<YOUR_FIRECRAWL_API_URL> # e.g., https://api.firecrawl.dev/v1
FIRECRAWL_RETRY_MAX_ATTEMPTS=<YOUR_FIRECRAWL_RETRY_MAX_ATTEMPTS> # e.g., 5
FIRECRAWL_RETRY_INITIAL_DELAY=<YOUR_FIRECRAWL_RETRY_INITIAL_DELAY> # e.g., 2000
FIRECRAWL_RETRY_MAX_DELAY=<YOUR_FIRECRAWL_RETRY_MAX_DELAY> # e.g., 30000
FIRECRAWL_RETRY_BACKOFF_FACTOR=<YOUR_FIRECRAWL_RETRY_BACKOFF_FACTOR> # e.g., 3
FIRECRAWL_CREDIT_WARNING_THRESHOLD=<YOUR_FIRECRAWL_CREDIT_WARNING_THRESHOLD> # e.g., 2000
FIRECRAWL_CREDIT_CRITICAL_THRESHOLD=<YOUR_FIRECRAWL_CREDIT_CRITICAL_THRESHOLD> # e.g., 500
FIRECRAWL_API_KEY=<YOUR_FIRECRAWL_API_KEY>
FIRECRAWL_HOST_PORT=<YOUR_FIRECRAWL_HOST_PORT> # e.g., 8107
###############################################
# 9. Fetch MCP Server
###############################################
FETCH_HOST_PORT=<YOUR_FETCH_HOST_PORT> # e.g., 8108
###############################################
# 10. Playwright MCP Server
###############################################
PLAYWRIGHT_HOST_PORT=<YOUR_PLAYWRIGHT_HOST_PORT> # e.g., 8109
###############################################
# 11. GitHub MCP Server
###############################################
GITHUB_PERSONAL_ACCESS_TOKEN=<YOUR_GITHUB_PERSONAL_ACCESS_TOKEN>
GITHUB_HOST_PORT=<YOUR_GITHUB_HOST_PORT> # e.g., 8110
###############################################
# 12. Desktop Commander MCP Server
###############################################
DESKTOP_COMMANDER_HOST_PORT=<YOUR_DESKTOP_COMMANDER_HOST_PORT> # e.g., 8111
###############################################
# 13. Supabase-Dev (Postgres MCP) Server
###############################################
SUPABASE_DEV_CONN=<YOUR_SUPABASE_DEV_CONNECTION_URL> # e.g., postgresql://postgres:[email protected]:54322/postgres
SUPABASE_DEV_HOST_PORT=<YOUR_SUPABASE_DEV_HOST_PORT> # e.g., 8112
###############################################
# 14. Context7 MCP Server
###############################################
CONTEXT7_HOST_PORT=<YOUR_CONTEXT7_HOST_PORT> # e.g., 8113
###############################################
# 15. YouTube Transcript MCP Server
###############################################
YOUTUBE_TRANSCRIPT_HOST_PORT=<YOUR_YOUTUBE_TRANSCRIPT_HOST_PORT> # e.g., 8114
###############################################
# 16. Redis (for Memory MCP)
###############################################
REDIS_HOST_PORT=<YOUR_REDIS_HOST_PORT> # e.g., 6379
###############################################
# 17. Memory MCP Server
###############################################
MEMORY_HOST_PORT=<YOUR_MEMORY_HOST_PORT> # e.g., 8115
###############################################
# 18. @magicuidesign/mcp MCP Server
###############################################
MAGICUIDESIGN_HOST_PORT=<YOUR_MAGICUIDESIGN_HOST_PORT> # e.g., 8116
注:実際の
.envに設定する「本番環境対応」の値は、次のものだけです。
- API キーとトークン(Notion PAT、Brave、Tavily、Firecrawl、GitHub、Discord など)。
FILESYSTEM_HOST_PATHの絶対パス(例:/home/moodmnky/new-wave-protocol)。- ホストポートは任意ですが、マシン上の他のサービスと競合しないようにしてください。
Docker Compose での始め方
1. リポジトリをクローンする
git clone https://github.com/<your-org>/moodmnky-mcp-server-stack.git
cd moodmnky-mcp-server-stack
2. .env をコピーして編集する
cp .env.example .env
notepad .env
- 各
<PLACEHOLDER>を実際の値(API キー、ホストポート、パス)に置き換えてください。 - ほかのすべての行はそのままにし、作成した
.envを Git にコミットしないでください。
3. すべての MCP サーバーを起動する
docker-compose up -d
-
Docker Compose は次の処理を行います。
- 各イメージ(例:
mcp/notion:latest、node:18-alpine、redis:7-alpine)をプルします。 - 18 個のコンテナを作成して起動し、各コンテナのポートを
.envで設定したホストポートに割り当てます。 - ホストのディレクトリを
/mnt/sharedにマウントし、filesystemコンテナで使用できるようにします。
- 各イメージ(例:
4. ローカルの /tools エンドポイントを確認する
新しい PowerShell ウィンドウまたはタブを開き、各サービスに対して SSE 形式の curl を実行します。
# Notion MCP
curl.exe -N http://localhost:8100/tools
# Magic MCP
curl.exe -N http://localhost:8101/tools
# Filesystem MCP
curl.exe -N http://localhost:8102/tools
# Discord MCP
curl.exe -N http://localhost:8103/tools
# Sequential Thinking MCP
curl.exe -N http://localhost:8104/tools
# Brave Search MCP
curl.exe -N http://localhost:8105/tools
# Tavily MCP
curl.exe -N http://localhost:8106/tools
# Firecrawl MCP
curl.exe -N http://localhost:8107/tools
# Fetch MCP
curl.exe -N http://localhost:8108/tools
# Playwright MCP
curl.exe -N http://localhost:8109/tools
# GitHub MCP
curl.exe -N http://localhost:8110/tools
# Desktop Commander MCP
curl.exe -N http://localhost:8111/tools
# Supabase-Dev (Postgres MCP)
curl.exe -N http://localhost:8112/tools
# Context7 MCP
curl.exe -N http://localhost:8113/tools
# YouTube Transcript MCP
curl.exe -N http://localhost:8114/tools
# Memory MCP (requires Redis)
curl.exe -N http://localhost:8115/tools
# @magicuidesign/mcp
curl.exe -N http://localhost:8116/tools
成功すると、各ツール(名前、引数、説明)を記述した JSON オブジェクトが流れる 無限の SSE ストリームが返されます。接続がすぐに切れる場合は、ホストポートが一致していることと、コンテナが起動していることを再確認してください。
Cloudflare Tunnel による MCP サーバーの公開
ローカルネットワークの外部から MCP エンドポイントにアクセスできるようにしつつ、ファイアウォールを閉じたままにするには、**Cloudflare Tunnel(cloudflared)**を使用できます。このセクションでは、一般的な「サービスごとにトンネルを作成する」構成について説明します。
トンネルを使用する理由
- インバウンドポートを開放しない:生の TCP/UDP を外部に公開する必要はありません。TLS と接続の維持は Cloudflare が処理します。
- TLS 終端:Cloudflare がドメインやサブドメイン用の証明書を提供します。
- 自動再接続:トンネルが切断されても、
cloudflaredが自動的に再接続します。 - アクセス制御:必要に応じて Zero Trust と統合し、MCP サービスへのアクセスを制限できます。
1. cloudflared のインストールと認証
-
ダウンロードしてインストール(Ubuntu Linux の例):
wget https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb sudo dpkg -i cloudflared-linux-amd64.deb -
ログイン(認証のためにブラウザーのタブが開きます):
cloudflared tunnel login- Cloudflare アカウントを選択し、DNS レコードを作成するドメイン(例:
mcp.example.com)を選択します。 - この手順により、ホスト上に
~/.cloudflared/cert.pemファイルが作成されます。
- Cloudflare アカウントを選択し、DNS レコードを作成するドメイン(例:
2. 名前付きトンネルを作成する
cloudflared tunnel create mcp-tunnel
- これにより Tunnel ID(例:
abcd1234-ef56-7890-ghij-klmnopqrstuv)が出力されます。 - 認証情報ファイル(例:
~/.cloudflared/abcd1234-ef56-7890-ghij-klmnopqrstuv.json)が自動的に作成されます。
3. DNS ルートを設定する
各 MCP サービスについて、<tunnel_id>.cfargotunnel.com を指す Cloudflare DNS CNAME レコードを作成します。サブドメインの例:
| MCP サービス | ローカルポート | 希望するサブドメイン |
|---|---|---|
| Notion MCP | 8100 | notion-mcp.example.com |
| Magic MCP | 8101 | magic-mcp.example.com |
| Filesystem MCP | 8102 | filesystem-mcp.example.com |
| Discord MCP | 8103 | discord-mcp.example.com |
| Sequential Thinking MCP | 8104 | sequential-mcp.example.com |
| Brave Search MCP | 8105 | brave-mcp.example.com |
| Tavily MCP | 8106 | tavily-mcp.example.com |
| Firecrawl MCP | 8107 | firecrawl-mcp.example.com |
| Fetch MCP | 8108 | fetch-mcp.example.com |
| Playwright MCP | 8109 | playwright-mcp.example.com |
| GitHub MCP | 8110 | github-mcp.example.com |
| Desktop Commander MCP | 8111 | desktop-mcp.example.com |
| Supabase-Dev (Postgres MCP) | 8112 | supabase-mcp.example.com |
| Context7 MCP | 8113 | context7-mcp.example.com |
| YouTube Transcript MCP | 8114 | yt-transcript-mcp.example.com |
| Memory MCP | 8115 | memory-mcp.example.com |
| @magicuidesign/mcp | 8116 | magicuidesign-mcp.example.com |
次のコマンドを実行します(<tunnel-id> を実際の Tunnel ID に置き換え、各サブドメインも適宜置き換えてください)。
cloudflared tunnel route dns mcp-tunnel notion-mcp.example.com
cloudflared tunnel route dns mcp-tunnel magic-mcp.example.com
cloudflared tunnel route dns mcp-tunnel filesystem-mcp.example.com
cloudflared tunnel route dns mcp-tunnel discord-mcp.example.com
cloudflared tunnel route dns mcp-tunnel sequential-mcp.example.com
cloudflared tunnel route dns mcp-tunnel brave-mcp.example.com
cloudflared tunnel route dns mcp-tunnel tavily-mcp.example.com
cloudflared tunnel route dns mcp-tunnel firecrawl-mcp.example.com
cloudflared tunnel route dns mcp-tunnel fetch-mcp.example.com
cloudflared tunnel route dns mcp-tunnel playwright-mcp.example.com
cloudflared tunnel route dns mcp-tunnel github-mcp.example.com
cloudflared tunnel route dns mcp-tunnel desktop-mcp.example.com
cloudflared tunnel route dns mcp-tunnel supabase-mcp.example.com
cloudflared tunnel route dns mcp-tunnel context7-mcp.example.com
cloudflared tunnel route dns mcp-tunnel yt-transcript-mcp.example.com
cloudflared tunnel route dns mcp-tunnel memory-mcp.example.com
cloudflared tunnel route dns mcp-tunnel magicuidesign-mcp.example.com
注:最初に Cloudflare のダッシュボード(DNS → Add record → Type “CNAME” → Name = subdomain → target =
<tunnel-id>.cfargotunnel.com)で、対応する CNAME レコードを作成する必要があります。または、route dnsコマンドを実行すると、Cloudflare が自動的に作成する場合があります。
4. cloudflared の設定を作成する
~/.cloudflared/config.yml にファイルを作成し、次の内容を記述します。<tunnel-id> を実際の Tunnel ID に置き換え、hostname の項目を選択したサブドメインに合わせて調整してください。
tunnel: <tunnel-id>
credentials-file: /home/<your-username>/.cloudflared/<tunnel-id>.json
ingress:
- hostname: notion-mcp.example.com
service: http://localhost:8100
- hostname: magic-mcp.example.com
service: http://localhost:8101
- hostname: filesystem-mcp.example.com
service: http://localhost:8102
- hostname: discord-mcp.example.com
service: http://localhost:8103
- hostname: sequential-mcp.example.com
service: http://localhost:8104
- hostname: brave-mcp.example.com
service: http://localhost:8105
- hostname: tavily-mcp.example.com
service: http://localhost:8106
- hostname: firecrawl-mcp.example.com
service: http://localhost:8107
- hostname: fetch-mcp.example.com
service: http://localhost:8108
- hostname: playwright-mcp.example.com
service: http://localhost:8109
- hostname: github-mcp.example.com
service: http://localhost:8110
- hostname: desktop-mcp.example.com
service: http://localhost:8111
- hostname: supabase-mcp.example.com
service: http://localhost:8112
- hostname: context7-mcp.example.com
service: http://localhost:8113
- hostname: yt-transcript-mcp.example.com
service: http://localhost:8114
- hostname: memory-mcp.example.com
service: http://localhost:8115
- hostname: magicuidesign-mcp.example.com
service: http://localhost:8116
# Fallback for any unmatched request
- service: http_status:404
5. cloudflared をシステムサービスとして実行する
Linux の場合(Ubuntu の例)
-
システムの systemd ユニットファイルを作成します。保存先は
/etc/systemd/system/cloudflared.serviceです。sudo tee /etc/systemd/system/cloudflared.service > /dev/null << 'EOF' [Unit] Description=Cloudflare Tunnel After=network.target [Service] Type=notify ExecStart=/usr/local/bin/cloudflared tunnel --config /home/<your-username>/.cloudflared/config.yml run Restart=on-failure RestartSec=5s [Install] WantedBy=multi-user.target EOF -
systemd を再読み込みし、サービスを有効化して起動します。
sudo systemctl daemon-reload sudo systemctl enable cloudflared sudo systemctl start cloudflared sudo systemctl status cloudflared -
サービスが “active (running)” になっていることを確認します。そうなっていれば、Cloudflare Tunnel がパブリックなサブドメインから localhost への転送を開始しています。
OpenAI Agents SDK との統合
MCP サーバーがローカルで稼働したら(必要に応じて Cloudflare Tunnel 経由で公開したら)、MCPServerSse を使用して OpenAI Agent を接続できます。次の Python コード例では、複数の MCP エンドポイントを接続する方法を示します。
import os
import asyncio
from agents import Agent, Runner
from agents.mcp.server import MCPServerSse
# 1. Read MCP SSE URLs (either localhost or public via Cloudflare)
NOTION_MCP_URL = os.getenv("NOTION_SSE_URL", "http://localhost:8100")
MAGIC_MCP_URL = os.getenv("MAGIC_SSE_URL", "http://localhost:8101")
FILESYSTEM_MCP_URL = os.getenv("FILESYSTEM_SSE_URL", "http://localhost:8102")
DISCORD_MCP_URL = os.getenv("DISCORD_SSE_URL", "http://localhost:8103")
SEQUENTIAL_MCP_URL = os.getenv("SEQUENTIAL_SSE_URL", "http://localhost:8104")
BRAVE_MCP_URL = os.getenv("BRAVE_SSE_URL", "http://localhost:8105")
TAVILY_MCP_URL = os.getenv("TAVILY_SSE_URL", "http://localhost:8106")
FIRECRAWL_MCP_URL = os.getenv("FIRECRAWL_SSE_URL", "http://localhost:8107")
FETCH_MCP_URL = os.getenv("FETCH_SSE_URL", "http://localhost:8108")
PLAYWRIGHT_MCP_URL = os.getenv("PLAYWRIGHT_SSE_URL", "http://localhost:8109")
GITHUB_MCP_URL = os.getenv("GITHUB_SSE_URL", "http://localhost:8110")
DESKTOP_MCP_URL = os.getenv("DESKTOP_SSE_URL", "http://localhost:8111")
SUPABASE_MCP_URL = os.getenv("SUPABASE_SSE_URL", "http://localhost:8112")
CONTEXT7_MCP_URL = os.getenv("CONTEXT7_SSE_URL", "http://localhost:8113")
YOUTUBE_MCP_URL = os.getenv("YOUTUBE_SSE_URL", "http://localhost:8114")
MEMORY_MCP_URL = os.getenv("MEMORY_SSE_URL", "http://localhost:8115")
MAGICUIDESIGN_MCP_URL= os.getenv("MAGICUIDESIGN_SSE_URL", "http://localhost:8116")
def make_sse_server(url: str, name: str):
return MCPServerSse(params={"url": url}, name=name)
async def main():
# 2. Instantiate MCP servers
mcp_servers = [
make_sse_server(NOTION_MCP_URL, "NotionMCP"),
make_sse_server(MAGIC_MCP_URL, "MagicMCP"),
make_sse_server(FILESYSTEM_MCP_URL, "FileMCP"),
make_sse_server(DISCORD_MCP_URL, "DiscordMCP"),
make_sse_server(SEQUENTIAL_MCP_URL, "SequentialMCP"),
make_sse_server(BRAVE_MCP_URL, "BraveMCP"),
make_sse_server(TAVILY_MCP_URL, "TavilyMCP"),
make_sse_server(FIRECRAWL_MCP_URL, "FirecrawlMCP"),
make_sse_server(FETCH_MCP_URL, "FetchMCP"),
make_sse_server(PLAYWRIGHT_MCP_URL, "PlaywrightMCP"),
make_sse_server(GITHUB_MCP_URL, "GitHubMCP"),
make_sse_server(DESKTOP_MCP_URL, "DesktopMCP"),
make_sse_server(SUPABASE_MCP_URL, "SupabaseMCP"),
make_sse_server(CONTEXT7_MCP_URL, "Context7MCP"),
make_sse_server(YOUTUBE_MCP_URL, "YouTubeMCP"),
make_sse_server(MEMORY_MCP_URL, "MemoryMCP"),
make_sse_server(MAGICUIDESIGN_MCP_URL,"MagicUIDesignMCP"),
]
# 3. Build an Agent with multiple tool sources
agent = Agent(
name="MoodMNKYUnifiedAgent",
instructions=(
"You have access to multiple MCP servers over SSE. "
"Use NotionMCP to query Notion data, FileMCP to read files, "
"MemoryMCP to store/retrieve memory, etc."
),
tools=[], # No built-in local tools
mcp_servers=mcp_servers
)
# 4. Run a simple example prompt
runner = Runner(agent)
response = await runner.complete(
"List all Notion pages, then fetch the contents of README.md from the filesystem."
)
print(response)
if __name__ == "__main__":
asyncio.run(main())
- 環境変数:各
*_SSE_URLの値を、Cloudflare Tunnel 経由の URL(例:https://notion-mcp.example.com)に変更できます。 - MCPServerSse:内部では、
MCPServerSse.connect()がhttp://<url>/toolsへの永続的な HTTP GET を開始し、JSON ストリームを解析して各ツールを公開します。エージェントがCALL <tool>を実行すると、SDK がhttp://<url>/callに POST リクエストを送信し、サーバーが結果をストリーミングで返します。
SSE と Streamable HTTP:トレードオフ
-
SSE(Server-Sent Events)
-
プロトコル:HTTP GET で
/toolsにアクセスすると、text/event-stream 形式でdata: { ... }イベントの連続ストリームが返されます。 -
メリット:
- 自動再接続の仕組みが標準で備わっています。
- HTTP/2 や、ほとんどのプロキシ/ロードバランサー経由で動作します。
- 「イベント」の区切りが明確です。
-
デメリット:
- サーバーからクライアントへの通信に限られます。エージェントはツール呼び出しの送信に通常の POST を使用する必要があります。
-
-
Streamable HTTP(チャンク化レスポンス)
-
プロトコル:クライアントが GET または POST を送信し、サーバーがチャンク転送エンコーディングを使用して応答します(明示的な
event:による区切りはありません)。 -
メリット:
- 言語によっては、実装がやや簡単です。
-
デメリット:
- クライアントが生のチャンクを手動で解析する必要があります。
- 「再接続」の仕組みは標準で備わっていません。
-
ほとんどの MCP サーバーで SSE が推奨される理由:
- 参照実装で統一された、十分に文書化された形式です。
- 中断後の再接続を自動的に処理します。
- エージェント SDK(例:OpenAI Agents SDK)は SSE をネイティブにサポートしています(
MCPServerSse経由)。
トラブルシューティングとベストプラクティス
1. ヘルスチェック
各サービスにヘルスチェックを追加して、docker-compose.yml 内の /tools がステータス 200 を返すこと(SSE ハンドシェイクが成功すること)を確認します。例:
services:
new-wave-protocol-notion:
# … existing config …
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:${NOTION_HOST_PORT}/tools"]
interval: 30s
timeout: 5s
retries: 3
ほかの重要なサービスについても同様に設定します。
2. ポートの競合
.env内の${*_HOST_PORT}がすべて一意であり、ほかのローカルサービスで使用されていないことを確認します。- ポートを割り当てる前に、
ss -tulpn(Linux)またはnetstat -anb(Windows)を使用して、ポートが利用可能か確認します。
3. シークレットの保護
-
実際の
.envファイルは決してコミットしないでください。.gitignore(提供済み)に追加します。 -
本番環境では、次の方法を検討してください。
- Docker Secrets:API キーは平文ではなく、Docker のシークレット管理に保存します。
- Vault ソリューション:実行時に動的に注入するには、HashiCorp Vault、AWS Secrets Manager、Azure Key Vault を使用します。
4. Redis の永続化
-
redisサービスは、データの永続化に名前付きボリュームredis-dataを使用します。バックアップまたは移行するには、次の手順に従います。- バックアップ:
docker run --rm -v redis-data:/data -v $(pwd):/backup alpine:latest sh -c "cd /data && tar czf /backup/redis-backup.tar.gz ." - 復元:Redis を停止し、
redis-dataを展開済みデータに置き換えてから、再起動します。
- バックアップ:
5. MCP のバージョン更新
-
デフォルトでは、
docker-compose.ymlはmcp/<service>:latestを使用します。安定性を高めるには、特定のタグまたはダイジェストを固定してください。image: mcp/notion:0.2.1 -
MCP の上流リポジトリを監視して、新しいリリースを確認します。
新しいリリースが公開されたら、docker-compose.yml を適宜更新し、ローカルでテストしてから、Git のバージョンを更新します。
MCP スタックの拡張
新しい MCP サーバーやツールの実装が登場したら、次の方法でこのスタックを拡張できます。
docker-compose.ymlに新しいサービスを追加します(必要に応じて、別のDockerfileを作成します)。.env.exampleに対応する変数を追加し(その後、ローカルの.envにも追加します)。curl -N http://localhost:<NEW_PORT>/toolsを使ってローカルでテストします。- 外部公開が必要な場合は、DNS ルートと
cloudflaredの設定を追加します。
例:「Slack MCP Server」の追加
-
docker-compose.ymlに追記します:slack-mcp: image: mcp/slack:latest container_name: mcp-slack restart: unless-stopped ports: - "${SLACK_HOST_PORT}:8080" environment: SLACK_BOT_TOKEN: "${SLACK_BOT_TOKEN}" SLACK_SIGNING_SECRET: "${SLACK_SIGNING_SECRET}" -
.env.exampleを更新します:############################################### # 19. Slack MCP Server ############################################### SLACK_BOT_TOKEN=<YOUR_SLACK_BOT_TOKEN> SLACK_SIGNING_SECRET=<YOUR_SLACK_SIGNING_SECRET> SLACK_HOST_PORT=<YOUR_SLACK_HOST_PORT> # e.g., 8117 -
変更を取得し(以前にクローンした場合)、それに応じて
.envを拡張します。
ライセンス
このリポジトリは MIT License の下で配布されています。詳細は LICENSE を参照してください。
まとめ
このファーストプリンシプルに基づく README に従うことで、次のことができるようになります。
- 各コンポーネント(MCP、SSE、Docker、Cloudflare Tunnel)がなぜ存在するのかを理解できます。
- MCP サーバーの設定、起動、公開の方法がわかります。
- SSE に対応したあらゆるクライアント(OpenAI Agents SDK、Node/Python スクリプトなど)を、豊富なツールのエコシステムに接続できます。
- 将来の MCP サーバーや連携機能を追加するための、明確で拡張性のある基盤を得られます。
完全にコンテナ化された、安全で拡張性のある MCP サーバーの世界へようこそ。エージェントは必要な「ツール」を自由に呼び出せる一方で、環境は常に自分で完全に管理できます。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。