MCP服务器栈

一个基于Docker的MCP服务器栈,用于通过Server-Sent Events (SSE)为OpenAI Agents SDK等客户端提供无缝访问。

  • by MOODMNKY-LLC
  • 本地部署
  • 更新于
在 GitHub 查看 moodmnky-llc/moodmnky-mcp-server-stack

使用说明

MoodMNKY MCP服务器堆栈

A. 第一原理 在Docker中运行、公开和集成多个MCP服务器的指南——通过服务器发送事件(SSE)为OpenAI代理SDK和其他客户端实现无缝访问。


目录

  1. 引言

  2. MCP和SSE的第一原理

    1. 什么是MCP?
    2. 为什么选择SSE?
    3. 流媒体与SSE传输
  3. 存储库结构

  4. 先决条件

    1. Docker&Docker编写
    2. Cloudflare隧道(Cloudflared)
    3. 域和DNS设置
    4. OpenAI代理SDK
  5. 环境变量

    1. .env.example
    2. 创建您的 .env
    3. 文件系统MCP默认路径
  6. Docker Compose入门

    1. 克隆存储库
    2. 启动所有MCP服务器
    3. 验证本地 /tools 端点
  7. 通过Cloudflare隧道暴露MCP服务器

    1. 为什么要使用隧道?
    2. 安装和身份验证 cloudflared
    3. 创建隧道和DNS路由
    4. 云雾缭绕 config.yml 示例
    5. 开始 cloudflared 作为一种服务
    6. 验证公共SSE端点
  8. 与OpenAI代理SDK集成

    1. Python代码段示例
    2. 配置 MCPServerSse
  9. SSE与流式HTTP:权衡

  10. 故障排除和最佳实践

    1. 健康检查
    2. 端口冲突
    3. 保护秘密
    4. Redis持久性
    5. 更新MCP版本
  11. 扩展MCP堆栈

  12. 许可证


引言

这 MoodMNKY MCP服务器堆栈 是一个独立的存储库,可以编排各种各样的 模型上下文协议(MCP) 服务器——全部通过Docker容器化——在一个方便的 docker-compose.yml此堆栈支持:

  • 快速部署 许多提供工具的MCP服务器(例如,Notion、Sequential Thinking、Brave Search、Tavily、Firecrawl、Fetch、GitHub、Supabase Dev、Context7、YouTube Transcript、通过Redis的内存等)。
  • 统一配置 通过单一 .env 包含所有主机端口绑定、API密钥和路径的文件。
  • 开箱即用的集成 为了 OpenAI代理SDK (通过苏格兰和南方能源公司)和其他具有苏格兰和南方电力公司能力的客户。
  • 可选曝光 使用 Cloudflare 隧道--保护防火墙安全,同时提供安全的外部访问。

此README需要一个 第一原则方法:它解释了每个步骤背后的“为什么”(而不仅仅是“如何”),这样不熟悉MCP、SSE、Docker或Cloudflare Tunnels的开发人员仍然可以准确地了解正在发生的事情、为什么它很重要,以及如何使其适应未来的需求。


MCP和SSE的第一原理

什么是MCP?

  • MCP(模型上下文协议) 是一个允许人工智能的开源规范 代理 (例如,GPT-4驱动的助手)调用外部“工具”服务。
  • 每个MCP服务器发布一组 工具签名 (名称、参数、描述)通过HTTP端点(通常 /tools).
  • 当代理需要“调用”工具时,它会发送一个JSON编码的POST到 /call,MCP服务器执行该工具(例如,获取网页、查询数据库、运行代码)并将结果流式传输回来。

关键利益:

  1. 关注点分离代理人专注于计划和推理;MCP服务器处理专门的任务。
  2. 语言诊断工具:MCP服务器可以用任何语言(Node、Python、Go等)编写,只要它们讲MCP规范。
  3. 可扩展性:只需将新的MCP服务器添加到堆栈中即可添加新工具;代理在运行时发现它们。

为什么选择SSE?

  • SSE(服务器发送的事件) 是一种基于HTTP的单向流媒体协议,服务器可以通过持久连接将JSON事件推送到客户端。

  • 在MCP环境中,SSE用于两个阶段:

    1. 工具发现(列表):代理向发送GET http://<mcp-url>/tools 并在SSE流上监听描述每个可用工具的JSON。
    2. 刀具调用(CALL):代理向发送POST http://<mcp-url>/call 使用JSON参数。MCP服务器处理请求,然后通过现有的SSE连接将结果流式传输回来。

为什么SSE通过WebSocket或轮询?

  • 简洁:SSE基于普通HTTP构建,因此它可以通过大多数代理、防火墙和负载均衡器工作,而无需特殊配置。
  • 自动重新连接:本机重新连接语义处理瞬态网络光点。
  • 低开销:没有WebSocket握手或协议帧,只有基于文本的事件。
  • 单向:代理仍然通过正常的HTTP发送工具调用。SSE仅用于接收流式结果,这与MCP的模型非常吻合。

流媒体与SSE传输

  • 一些MCP服务器实现了单独的“流式HTTP”传输(分块传输编码),而不是SSE。

  • 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编写

  • Docker引擎 (20.10+)和 Docker Compose (v2+)安装在您的主机(Linux、macOS或Windows)上。

  • 确认安装:

    docker --version
    docker-compose --version
    

Cloudflare隧道(Cloudflared)

  • 如果你打算 公开MCP服务器 (例如,远程托管的代理),安装 Cloudflare的 cloudflared 在同一台主机上:

    1. 下载 您的操作系统的最新版本 Cloudflare 隧道 文档。

    2. 安装 (例如,在Ubuntu上):

      curl -LO https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb
      sudo dpkg -i cloudflared-linux-amd64.deb
      
    3. 验证:

      cloudflared version
      

域和DNS设置

  • 你需要一个 注册域名 由Cloudflare管理(例如。, example.com).
  • 对于您希望公开的每个MCP服务器,您将创建一个 别名 Cloudflare DNS仪表板中指向隧道自动配置主机名的记录(例如。, mcp-tunnel.cfargotunnel.com).

OpenAI代理SDK

  • 要集成这些MCP服务器,您需要 Python环境 随着 OpenAI代理SDK 安装:

    pip install openai-agents
    
  • 代理将通过以下方式在代码中引用MCP端点(SSE) MCPServerSse.


环境变量

.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:postgres@127.0.0.1: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将:

    1. 拉取每个图像(例如。, mcp/notion:latest, node:18-alpine, redis:7-alpine).
    2. 创建并启动18个容器,将每个容器端口映射到中设置的主机端口 .env.
    3. 将您的主机目录装载到 filesystem 集装箱在 /mnt/shared.

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

成功的回应是 无限SSE流 描述每个工具的JSON对象(名称、参数、描述)。如果连接立即关闭,请仔细检查您的主机端口是否匹配,以及容器是否已打开。


通过Cloudflare隧道暴露MCP服务器

如果您希望从本地网络外部访问MCP端点,同时保持防火墙锁定,您可以使用 Cloudflare隧道(cloudflared)。本节将介绍一个典型的“每次服务隧道”设置。

为什么要使用隧道?

  • 没有开放的入站端口:您永远不会暴露原始TCP/UDP——Cloudflare处理TLS和持久性。
  • TLS终止:Cloudflare为您的域/子域提供证书。
  • 自动重新连接:如果隧道下降, cloudflared 自动重新连接。
  • 访问控制:可选择与Zero Trust集成,以限制谁可以访问您的MCP服务。

1.安装并验证 cloudflared

  1. 下载并安装 (例如Ubuntu Linux):

    wget https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb
    sudo dpkg -i cloudflared-linux-amd64.deb
    
  2. 登录 (这将打开一个浏览器选项卡进行身份验证):

    cloudflared tunnel login
    
    • 选择您的Cloudflare帐户,然后选择要在其中创建DNS记录的域(例如。, mcp.example.com).
    • 此步骤创建 ~/.cloudflared/cert.pem 文件在您的主机上。

2.创建命名隧道

cloudflared tunnel create mcp-tunnel
  • 这将输出a 隧道ID (例如。, abcd1234-ef56-7890-ghij-klmnopqrstuv).
  • 凭证文件(例如。, ~/.cloudflared/abcd1234-ef56-7890-ghij-klmnopqrstuv.json)是自动创建的。

3.配置DNS路由

对于每个MCP服务,我们将创建一个指向的Cloudflare DNS CNAME记录 <tunnel_id>.cfargotunnel.com子域名示例:

MCP服务 本地端口 所需子域
MCP概念 8100 notion-mcp.example.com
魔术MCP 8101 magic-mcp.example.com
文件系统MCP 8102 filesystem-mcp.example.com
MCP不一致 8103 discord-mcp.example.com
顺序思维MCP 8104 sequential-mcp.example.com
勇敢搜索MCP 8105 brave-mcp.example.com
塔维利MCP 8106 tavily-mcp.example.com
防火墙MCP 8107 firecrawl-mcp.example.com
获取MCP 8108 fetch-mcp.example.com
剧作家MCP 8109 playwright-mcp.example.com
GitHub MCP 8110 github-mcp.example.com
桌面命令器MCP 8111 desktop-mcp.example.com
Supabase开发(Postgres MCP) 8112 supabase-mcp.example.com
上下文7 MCP 8113 context7-mcp.example.com
YouTube转录MCP 8114 yt-transcript-mcp.example.com
存储器MCP 8115 memory-mcp.example.com
@magicuidesign/mcp 8116 magicuidesign-mcp.example.com

运行以下命令(替换 <tunnel-id> 使用您的实际隧道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→ 添加记录→ 键入“CNAME”→ 名称=子域→ 目标= <tunnel-id>.cfargotunnel.com).或者,Cloudflare可能会在您运行 route dns 命令。

4.创建 cloudflared 配置

在以下位置创建文件 ~/.cloudflared/config.yml 内容如下。替换 <tunnel-id> 使用您的实际隧道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)

  1. 创建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
    
  2. 重新加载系统d 和 启用/启动 服务:

    sudo systemctl daemon-reload
    sudo systemctl enable cloudflared
    sudo systemctl start cloudflared
    sudo systemctl status cloudflared
    
  3. 确保服务 “活动(运行)”。如果是这样,Cloudflare Tunnel现在正在将您的公共子域转发到localhost。


与OpenAI代理SDK集成

一旦您的MCP服务器在本地运行(并可选择通过Cloudflare隧道公开),您就可以连接 OpenAI代理 通过 MCPServerSse。下面是一个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 指向a Cloudflare‐隧道 URL(例如。, https://notion-mcp.example.com).
  • MCPServerSse 服务器:在引擎盖下, MCPServerSse.connect() 将打开一个持久的HTTP GET http://<url>/tools,解析JSON流,并公开每个工具。当代理人这样做时 CALL <tool>,SDK POST到 http://<url>/call,服务器将结果流式传输回来。

SSE与流式HTTP:权衡

  1. SSE(服务器发送事件)

    • 协议:HTTP GET到 /tools 返回连续的流 data: { ... } 文本/事件流格式的事件。

    • 优点:

      • 本机自动重新连接语义。
      • 通过HTTP/2和大多数代理/负载均衡器工作。
      • 清晰的“事件”框架。
    • 缺点:

      • 仅服务器→ 客户。代理必须使用常规POST发送工具调用。
  2. 流式HTTP(分块响应)

    • 协议:客户端发送GET或POST;服务器以分块传输编码(无显式 event: 框架)。

    • 优点:

      • 在某些语言中实现稍微简单一些。
    • 缺点:

      • 客户端必须手动解析原始块。
      • 没有内置的“重新连接”语义。

为什么选择苏格兰和南方能源公司 对于大多数MCP服务器:

  • 跨参考实现的统一、记录良好的格式。
  • 中断后自动处理重新连接。
  • 代理SDK(例如OpenAI代理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.港口冲突

  • 确保 每 ${*_HOST_PORT} 在你的 .env 是唯一的,不被其他本地服务使用。
  • 使用 ss -tulpn (Linux)或 netstat -anb (Windows)在分配之前验证端口可用性。

3.保密

  • 永不承诺 你的真实 .env 文件。添加到 .gitignore (提供)。

  • 对于 生产,考虑:

    • Docker的秘密:将API密钥存储在Docker的秘密管理中,而不是以纯文本存储。
    • 保险库解决方案: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服务器 或 工具实现 emerge,您可以通过以下方式扩展此堆栈:

  1. 添加新服务 在……里面 docker-compose.yml (或创建一个单独的 Dockerfile 如有必要)。
  2. 添加匹配变量 向 .env.example (然后发送到您当地的 .env).
  3. 测试 当地与 curl -N http://localhost:<NEW_PORT>/tools.
  4. 添加DNS路由 & cloudflared 如果你需要公开曝光,请进行配置。

示例:添加“Slack MCP服务器”

  1. 附加 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}"
    
  2. 更新 .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
    
  3. 拉动更改 (如果你之前克隆过)和 延伸 你的 .env 因此。


许可证

此存储库分布在 MIT许可证。参见 许可证 了解详情。


结论

遵循以下步骤 第一原理 README,您将:

  • 理解 为什么 每个组件(MCP、SSE、Docker、Cloudflare隧道)都存在。
  • 知道 如何 配置、启动和公开MCP服务器。
  • 能够将任何支持SSE的客户端(OpenAI代理SDK、Node/Python脚本等)连接到丰富的工具生态系统。
  • 为添加未来的MCP服务器和集成提供清晰、可扩展的基础。

欢迎来到一个完全容器化、安全和可扩展的MCP服务器世界——在这里,您的代理可以调用他们需要的任何“工具”,您可以完全控制您的环境。