mcpField
M
MoodMNKY MCP Server Stack

MoodMNKY MCP Server Stack

本地服务
github.com/MOODMNKY-LLC开发工具074 周前更新

关于 MoodMNKY MCP Server Stack

MoodMNKY MCP Server Stack 是一套通过 Docker Compose 运行和配置多个 MCP 服务的方案。它面向将 MCP 工具接入 OpenAI Agents SDK 或其他支持 SSE 的客户端的开发者,并可选用 Cloudflare Tunnel 对外提供访问。

主要功能

  1. 01通过 Docker Compose 编排多个 MCP 服务
  2. 02用一个 .env 文件配置服务
  3. 03通过 SSE 端点发现和调用工具
  4. 04经由 Cloudflare Tunnel 暴露服务
  5. 05接入 OpenAI Agents SDK

适用场景

  1. 01运行本地 MCP 服务栈
  2. 02通过 SSE 将 OpenAI Agents SDK 接入 MCP 服务
  3. 03通过隧道向远程客户端开放 MCP 端点

MCP 相关

该方案运行多个 MCP 服务,并通过 SSE 端点向客户端提供工具。文档还介绍了使用 Cloudflare Tunnel 为远程客户端开放访问的可选方式。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

暂未收录安装方式

我们还没有获取到这个服务的安装包或远程地址,请按项目 README 中的说明安装。

代码仓库

工具

还没有获取到工具列表

本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。

详细介绍

MoodMNKY MCP 服务栈

一份基于第一性原理的指南,介绍如何在 Docker 中运行、公开和集成多个 MCP 服务——通过服务器发送事件(SSE),让 OpenAI Agents SDK 和其他客户端能够无缝访问。


目录

  1. 简介

  2. MCP 与 SSE 的第一性原理

    1. 什么是 MCP?
    2. 为什么使用 SSE?
    3. 流式传输与 SSE 传输
  3. 代码库结构

  4. 前置条件

    1. Docker 与 Docker Compose
    2. Cloudflare Tunnel(Cloudflared)
    3. 域名与 DNS 设置
    4. OpenAI Agents SDK
  5. 环境变量

    1. .env.example
    2. 创建你的 .env
    3. Filesystem MCP 默认路径
  6. 使用 Docker Compose 入门

    1. 克隆代码库
    2. 启动所有 MCP 服务
    3. 验证本地 /tools 端点
  7. 通过 Cloudflare Tunnel 公开 MCP 服务

    1. 为什么使用隧道?
    2. 安装并验证身份 cloudflared
    3. 创建隧道和 DNS 路由
    4. Cloudflared config.yml 示例
    5. 将 cloudflared 作为服务启动
    6. 验证公开的 SSE 端点
  8. 与 OpenAI Agents SDK 集成

    1. Python 代码片段示例
    2. 配置 MCPServerSse
  9. SSE 与 Streamable HTTP:权衡取舍

  10. 故障排除与最佳实践

    1. 运行状况检查
    2. 端口冲突
    3. 保护密钥
    4. Redis 持久化
    5. 更新 MCP 版本
  11. 扩展 MCP 服务栈

  12. 许可证


简介

MoodMNKY MCP 服务栈是一个独立代码库,通过一个便捷的 docker-compose.yml 编排多种**模型上下文协议(MCP)**服务,并使用 Docker 将它们全部容器化。此服务栈支持:

  • 快速部署大量提供工具的 MCP 服务(例如 Notion、Sequential Thinking、Brave Search、Tavily、Firecrawl、Fetch、GitHub、Supabase-Dev、Context7、YouTube Transcript、通过 Redis 实现的 Memory 等)。
  • 统一配置:通过单个 .env 文件配置所有主机端口绑定、API 密钥和路径。
  • 开箱即用的集成:支持 OpenAI Agents SDK(通过 SSE)和其他支持 SSE 的客户端。
  • 可选的公开访问:使用 Cloudflare Tunnel 通过公共互联网访问各个 MCP 端点,同时保障防火墙安全,并提供安全的外部访问。

本 README 采用第一性原理的方法:解释每个步骤背后的“为什么”(而不只是“怎么做”),让不熟悉 MCP、SSE、Docker 或 Cloudflare Tunnel 的开发者也能理解其中的原理、重要性,以及如何根据未来需求进行调整。


MCP 与 SSE 的第一性原理

什么是 MCP?
  • MCP(Model Context Protocol) 是一项开源规范,允许 AI Agent(例如由 GPT-4 驱动的助手)调用外部“工具”服务。
  • 每个 MCP 服务都会通过 HTTP 端点(通常为 /tools)发布一组工具签名(名称、参数和描述)。
  • 当 Agent 需要“调用”某个工具时,会向 /call 发送经过 JSON 编码的 POST 请求,MCP 服务会执行该工具(例如,获取网页、查询数据库、运行代码),并将结果流式传回。

主要优势:

  1. 关注点分离:Agent 专注于规划和推理;MCP 服务负责处理专门任务。
  2. 语言无关的工具:MCP 服务可以使用任何语言(Node、Python、Go 等)编写,只要遵循 MCP 规范即可。
  3. 可扩展性:只需将新的 MCP 服务添加到技术栈中,即可添加新工具;Agent 会在运行时发现它们。

为什么使用 SSE?
  • SSE(Server-Sent Events) 是一种基于 HTTP 的单向流式传输协议,服务器可以通过持久连接向客户端推送 JSON 事件。

  • 在 MCP 场景中,SSE 用于两个阶段:

    1. 工具发现(LIST):Agent 向 http://<mcp-url>/tools 发送 GET 请求,并监听 SSE 流,获取描述各个可用工具的 JSON。
    2. 工具调用(CALL):Agent 向 http://<mcp-url>/call 发送带有 JSON 参数的 POST 请求。MCP 服务处理请求后,会通过现有 SSE 连接将结果流式传回。

为什么选择 SSE,而不是 WebSocket 或轮询?

  • 简单:SSE 基于普通 HTTP,因此无需特殊配置即可通过大多数代理、防火墙和负载均衡器。
  • 自动重连:原生重连机制可处理短暂的网络中断。
  • 开销低:无需 WebSocket 握手或协议分帧——只使用基于文本的事件。
  • 单向传输:Agent 仍通过普通 HTTP 发送工具调用。SSE 仅用于接收流式结果,这与 MCP 的模型十分契合。

流式传输与 SSE 传输
  • 部分 MCP 服务会实现单独的“streamable-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 Compose
  • 在主机(Linux、macOS 或 Windows)上安装 Docker Engine(20.10+)和 Docker Compose(v2+)。

  • 确认安装:

    docker --version
    docker-compose --version
    
Cloudflare Tunnel(Cloudflared)
  • 如果计划公开 MCP 服务(例如,供远程托管的 Agent 使用),请在同一台主机上安装 Cloudflare 的 cloudflared:

    1. 从 Cloudflare Tunnel 文档下载适用于操作系统的最新版本。

    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 控制面板中创建一条 CNAME 记录,指向隧道自动分配的主机名(例如,mcp-tunnel.cfargotunnel.com)。
OpenAI Agents SDK
  • 要集成这些 MCP 服务,你需要一个安装了 OpenAI Agents SDK 的 Python 环境:

    pip install openai-agents
    
  • Agent 会在代码中通过 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 将会:

    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 Tunnel 暴露 MCP 服务

如果你希望在保持防火墙关闭的同时,让本地网络之外的用户也能访问 MCP 端点,可以使用 Cloudflare Tunnel(cloudflared)。本节将介绍典型的“每个服务一个隧道”配置。

为什么使用隧道?
  • 无需开放入站端口:你无需暴露原始 TCP/UDP 端口,TLS 和持久连接均由 Cloudflare 处理。
  • 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
  • 这会输出一个隧道 ID(例如,abcd1234-ef56-7890-ghij-klmnopqrstuv)。
  • 系统会自动创建凭据文件(例如,~/.cloudflared/abcd1234-ef56-7890-ghij-klmnopqrstuv.json)。
3. 配置 DNS 路由

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

MCP 服务本地端口期望的子域名
Notion MCP8100notion-mcp.example.com
Magic MCP8101magic-mcp.example.com
Filesystem MCP8102filesystem-mcp.example.com
Discord MCP8103discord-mcp.example.com
Sequential Thinking MCP8104sequential-mcp.example.com
Brave Search MCP8105brave-mcp.example.com
Tavily MCP8106tavily-mcp.example.com
Firecrawl MCP8107firecrawl-mcp.example.com
Fetch MCP8108fetch-mcp.example.com
Playwright MCP8109playwright-mcp.example.com
GitHub MCP8110github-mcp.example.com
Desktop Commander MCP8111desktop-mcp.example.com
Supabase-Dev (Postgres MCP)8112supabase-mcp.example.com
Context7 MCP8113context7-mcp.example.com
YouTube Transcript MCP8114yt-transcript-mcp.example.com
Memory MCP8115memory-mcp.example.com
@magicuidesign/mcp8116magicuidesign-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 控制面板中创建相应的 CNAME 记录(DNS → 添加记录 → 类型“CNAME” → 名称 = 子域名 → 目标 = <tunnel-id>.cfargotunnel.com)。或者,运行 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 为例)
  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. 重新加载 systemd,并启用/启动服务:

    sudo systemctl daemon-reload
    sudo systemctl enable cloudflared
    sudo systemctl start cloudflared
    sudo systemctl status cloudflared
    
  3. 确认服务状态为**“active (running)”**。如果是,则 Cloudflare Tunnel 现在已将你的公共子域名转发到 localhost。


与 OpenAI Agents SDK 集成

本地 MCP 服务运行后(也可以选择通过 Cloudflare Tunnels 将其公开),你可以通过 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 隧道 URL 的地址(例如,https://notion-mcp.example.com)。
  • MCPServerSse:在底层,MCPServerSse.connect() 会向 http://<url>/tools 发起持久 HTTP GET 请求,解析 JSON 流并公开每个工具。当 Agent 执行 CALL <tool> 时,SDK 会向 http://<url>/call 发送 POST 请求,服务则会流式返回结果。

SSE 与 Streamable HTTP:权衡

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

    • 协议:向 /tools 发送 HTTP GET 请求,会以 text/event-stream 格式返回连续的 data: { ... } 事件流。

    • 优点:

      • 原生支持自动重新连接语义。
      • 可通过 HTTP/2 以及大多数代理和负载均衡器传输。
      • “事件”分帧清晰。
    • 缺点:

      • 仅支持服务端 → 客户端。Agent 必须使用常规 POST 发送工具调用。
  2. Streamable HTTP(分块响应)

    • 协议:客户端发送 GET 或 POST 请求;服务端使用分块传输编码响应(没有显式的 event: 分帧)。

    • 优点:

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

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

为什么大多数 MCP 服务首选 SSE:

  • 参考实现采用统一且文档完善的格式。
  • 中断后可自动处理重新连接。
  • Agent 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 的密钥管理中,而非明文存储。
    • 密钥保管方案:使用 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 服务或工具实现不断涌现,你可以通过以下方式扩展此技术栈:

  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 许可证分发。详情请参阅 LICENSE。


总结

按照这份基于第一性原理编写的 README,你将:

  • 了解每个组件(MCP、SSE、Docker、Cloudflare Tunnel)为何存在。
  • 知道如何配置、启动并公开你的 MCP 服务。
  • 能够将任何支持 SSE 的客户端(OpenAI Agents SDK、Node/Python 脚本等)连接到丰富的工具生态。
  • 获得清晰且可扩展的基础,以便添加未来的 MCP 服务和集成。

欢迎来到一个完全容器化、安全且可扩展的 MCP 服务世界——在这里,你的 Agent 可以调用所需的任何“工具”,而你始终可以完全掌控自己的环境。

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。