GuildBridge
A remote MCP server for Discord, deployed on Cloudflare Workers.
About · Tools · Access Control · Token Usage · Contributing
关于
虽然没有官方的Discord MCP服务器,但MCP社区中与贡献者的大部分协调都发生在Discord上。GuildBridge为我填补了这一空白——它为MCP客户端提供了对Discord服务器的身份验证、权限感知访问,以便AI代理可以在对话已经发生的地方读取、搜索和发布消息。在一个问题之后,它变得栩栩如生 _我有_ 我通过构建自己的MCP服务器解决了这个问题。
\[!警告\] 此MCP服务器的实际托管版本并不广泛可用(我将其限制在特定的帐户和服务器上),但您也可以在Cloudflare帐户上轻松配置和部署它。
Querying data from the Discord MCP server with Claude
\[!注意\] 托管时,此MCP服务器通过以下方式对用户进行身份验证 Discord OAuth2 并使用 bot令牌基于角色的访问控制(RBAC)是在服务器端实现的,因为Discord自己的身份验证界面在其OAuth实现中无法实现干净的角色分离和与消息传递API的集成。
先决条件
- (v18+)
- A. Cloudflare帐户 (使用免费等级就足够了)
- A. Discord应用程序 与:
- A. 盲目点击者 添加到要访问的服务器 - OAuth2 已配置(客户端ID+机密)
Discord应用程序设置
- 去 Discord开发者门户 并创建(或选择)应用程序。
- 在...之下 机器人,点击“重置令牌”以获取您的 bot令牌。保存它。
- 在...之下 OAuth2,注意 客户端ID 和 客户端密钥.
- 在...之下 OAuth2>重定向,添加您的回调URL:
- 本地开发人员: http://localhost:8788/callback - 生产: https://.workers.dev/callback (稍后将MCP服务器部署到Cloudflare时,您将获得此URI)
- 在...之下 OAuth2>范围,确保
identify和guilds被选中。 - 在...之下 机器人>特权网关意图,启用 消息内容意图 如果你想在搜索结果中看到完整的消息内容。
- 使用OAuth2 URL生成器和
bot范围和这些 权限:View Channels,Read Message History,Send Messages.
本地开发
# Install dependencies
npm install
# Copy the example files and fill in your values
cp wrangler.jsonc.example wrangler.jsonc
cp .dev.vars.example .dev.vars
# Start the dev server
npm run dev服务器运行在 http://localhost:8788The MCP端点 在 /mcp.
.dev.vars
\[!注意\] 您需要在部署之前填写此表,以确保MCP服务器实际上可以与Discord的API通信。
| 变量 | 描述 |
|---|---|
DISCORD_CLIENT_ID | Discord开发者门户中的OAuth2客户端ID |
DISCORD_CLIENT_SECRET | OAuth2客户端机密 |
DISCORD_BOT_TOKEN | 机器人令牌 (用于所有Discord API调用) |
COOKIE_ENCRYPTION_KEY | 用于签名Cookie的随机字符串——使用生成 openssl rand -hex 16 |
CF_ACCESS_TEAM_DOMAIN | Cloudflare Access团队名称——管理面板必需 |
CF_ACCESS_AUD | Cloudflare访问应用程序受众(AUD)标签——管理面板所需 |
DEV_SKIP_CF_ACCESS | 设置为 true 在本地开发中绕过CF Access JWT验证 |
部署到Cloudflare
Worker绑定到三个有状态的Cloudflare资源: KV命名空间 (OAuth状态+满列表),a D1数据库 (审计日志),以及 零信任访问应用程序 (大门 /admin).您可以使用Terraform一次配置所有三个,也可以使用wrangler CLI单独创建它们。
选项A——地形
规定KV、D1和Access应用程序+政策一次完成。需要带有的Cloudflare API令牌 Workers KV Storage:Edit, D1:Edit,以及 Access: Apps and Policies:Edit 范围。
cd terraform
cp terraform.tfvars.example terraform.tfvars
# edit terraform.tfvars — set account ID, worker hostname, admin emails
export CLOUDFLARE_API_TOKEN=...
terraform init
terraform apply将输出连接到您的配置中:
| 输出 | 进入 |
|---|---|
kv_namespace_id | wrangler.jsonc → kv_namespaces[0].id |
d1_database_id | wrangler.jsonc → d1_databases[0].database_id |
d1_database_name | wrangler.jsonc → d1_databases[0].database_name |
cf_access_aud | wrangler secret put CF_ACCESS_AUD |
然后应用D1模式,设置剩余的机密,并部署:
cd ..
npx wrangler d1 migrations apply "$(terraform -chdir=terraform output -raw d1_database_name)" --remote
npx wrangler secret bulk .dev.vars
terraform -chdir=terraform output -raw cf_access_aud | npx wrangler secret put CF_ACCESS_AUD
npm run deploy如果你使用了Terraform,跳过 设置 以下各小节 管理面板 和 可观测性 --这些资源已经存在。
选项B——手动(wrangler CLI)
# Create the KV namespace (https://developers.cloudflare.com/kv/)
npx wrangler kv namespace create OAUTH_KV复制输出 id 进入 wrangler.jsonc 替换 PLACEHOLDER_KV_ID。(D1和访问设置包含在 可观测性 和 管理面板 在......下面)
# Set secrets (https://developers.cloudflare.com/workers/configuration/secrets/)
npx wrangler secret bulk .dev.vars
# Deploy
npm run deploy______________________________________________________________________
在部署之后, 牧马人 将打印您的工作URL(例如。 https://guildbridge..workers.dev).添加 https:///callback 作为Discord开发者门户中的重定向URI。
连接MCP客户端
点任意 MCP兼容客户端 在服务器URL处:
https://.workers.dev/mcp或本地:
http://localhost:8788/mcp用测试 MCP检查员:
npx @modelcontextprotocol/inspector@latest输入上面的URL,完成Discord OAuth流程,工具将可用。
工具
| 工具 | 说明 |
|---|---|
list_guilds | 列出您所在的Discord服务器 |
list_channels | 列出服务器中的频道(可选按类型筛选) |
get_channel_info | 获取频道详细信息(主题、类型等) |
read_messages | 从频道读取消息(带分页) |
search_messages | 在服务器中搜索邮件(按内容、频道、作者) |
send_message | 向频道发送消息 |
reply_to_message | 回复特定消息 |
管理面板
管理面板位于 /admin 允许您在运行时添加和删除允许的Discord用户,而无需重新部署。allowlist存储在KV中,是OAuth回调检查的唯一来源。反对者是 故障关闭 --空列表拒绝所有人,因此您必须通过以下方式为至少一个用户添加种子 /admin 在第一次OAuth登录成功之前。
设置
- 在 Cloudflare零信任仪表板,创建一个 访问应用程序 为了
/admin*. - 配置身份提供程序(电子邮件OTP、谷歌等)。
- 复制 应用程序受众(澳元) 标记并将其设置为
CF_ACCESS_AUD秘密。 - 设置
CF_ACCESS_TEAM_DOMAIN零信任团队名称的秘密。
部署后,请访问 https://.workers.dev/admin 管理排外主义者。
对于本地开发,set DEV_SKIP_CF_ACCESS=true 在 .dev.vars 要绕过CF Access JWT验证,请访问 http://localhost:8788/admin.
可观测性
每个MCP工具调用都经过审核。事件被双重写入 第1天 (有序的审计跟踪,可从管理面板的“活动”选项卡查询)以及 分析引擎 (即发即弃指标,通过Cloudflare仪表板SQL API查询)。
按事件捕获: 时间戳、工具名称、Discord用户ID+用户名、结果(正常/错误)、持续时间, guild_id (当存在时), channel_id (如果存在),已创建 message_id (为 send_message/reply_to_message),错误消息(失败时)。消息内容和搜索查询永远不会被捕获。
设置
# Create the D1 database (one-time)
npx wrangler d1 create guildbridge-audit复制输出 database_id 进入 wrangler.jsonc 替换 PLACEHOLDER_D1_ID,然后应用模式:
# Local dev
npx wrangler d1 migrations apply guildbridge-audit --local
# Production
npx wrangler d1 migrations apply guildbridge-audit --remote分析引擎不需要设置—— TOOL_AUDIT 绑定在 wrangler.jsonc 够了。在本地开发中, writeDataPoint 是一个无操作存根;它只在部署时写入。
查询
管理面板: https://.workers.dev/admin → 活动选项卡。按工具或用户ID筛选。
D1直接:
npx wrangler d1 execute guildbridge-audit --command \
"SELECT * FROM audit_log ORDER BY ts DESC LIMIT 20"分析引擎 (骨料):
npx wrangler analytics-engine sql \
"SELECT blob1 AS tool, count() AS calls, avg(double1) AS avg_ms
FROM guildbridge_tool_calls
WHERE timestamp > now() - INTERVAL '7' DAY
GROUP BY tool"现场映射: indexes[0] =用户ID, blobs = [tool, username, outcome, guildId, channelId, messageId, error], doubles = [durationMs].
访问控制
在接触Discord API之前,每个工具调用都要经过分层访问检查。公会成员资格通过用户的OAuth令牌进行验证,渠道可见性由计算强制执行 Discord的权限算法 从机器人的角度来看。
flowchart TD
A[Tool call] --> B{Channel or guild scoped?}
B -->|Guild scoped| C[assertGuildAccess]
B -->|Channel scoped| D[assertChannelAccess]
C --> E[Fetch user guilds via OAuth token]
E --> F{User is member?}
F -->|No| G[Access denied]
D --> H[Fetch channel info via bot token]
H --> I{Channel in a guild?}
I -->|No| G
I -->|Yes| C
F -->|Yes| J[getGuildPermContext]
J --> K[Fetch guild roles + member roles + guild info]
K --> L{User is guild owner?}
L -->|Yes| M[Access granted]
L -->|No| N[computePermissions]
N --> O[Base: @everyone role perms]
O --> P[OR in member role perms]
P --> Q{ADMINISTRATOR set?}
Q -->|Yes| M
Q -->|No| R[Apply @everyone channel overwrite]
R --> S[Apply matching role channel overwrites]
S --> T[Apply member-specific channel overwrite]
T --> U{VIEW_CHANNEL set?}
U -->|Yes| M
U -->|No| G对于 list_channels 和 search_messages,同样 权限计算 作为后置过滤器应用——用户看不到的频道会从结果中删除。
令牌使用情况
GuildBridge使用两个不同的Discord令牌,它们具有有意分离的角色:
| 令牌 | 存储在 | 用于 |
|---|---|---|
| 机器人令牌 | 服务器端环境变量(DISCORD_BOT_TOKEN) | 所有Discord API调用-读取消息、发送消息、获取频道、角色和成员 |
| 用户OAuth令牌 | MCP访问令牌内加密 | 仅限公会会员验证(/users/@me/guilds) |
机器人令牌永远不会离开服务器。用户的Discord OAuth令牌是在 OAuth2登录流程,嵌入加密的MCP访问令牌中,并返回给MCP客户端。GuildBridge不在服务器端存储用户的令牌——MCP客户端持有加密的令牌,并在每次请求时发送它,在那里对其进行解密以提取OAuth令牌进行公会成员资格检查。
sequenceDiagram
participant Client as MCP Client
participant Server as GuildBridge
participant Discord as Discord API
note over Client,Discord: OAuth Flow (one-time setup)
Client->>Server: Connect to /mcp
Server-->>Client: 401 — authenticate via OAuth
Client->>Server: /authorize
Server->>Discord: Redirect to Discord OAuth
Discord-->>Server: /callback with auth code
Server->>Discord: Exchange code for user OAuth token
Discord-->>Server: User OAuth token
Server-->>Client: Encrypted MCP token (contains user OAuth token)
note over Client,Discord: Tool Calls (ongoing)
Client->>Server: Tool call + MCP token (Bearer)
Server->>Server: Decrypt MCP token → extract user OAuth token
Server->>Discord: Verify guild membership (Bearer user OAuth token)
Discord-->>Server: User's guild list
Server->>Discord: Execute tool action (Bot token from env)
Discord-->>Server: API response
Server-->>Client: Tool result在OAuth流程中,短期会话状态通过以下方式管理:
- CSRF令牌 --仅支持HTTP的cookie,用于验证审批表单的提交(600秒TTL)
- 国家代币 --存储在 Cloudflare KV,跨重定向绑定OAuth请求(600秒TTL)
- 已批准的客户端cookie --HMAC签名,让返回用户跳过审批对话框(30天)
