关于 discord-tools
discord-tools 为编码 Agent 提供 Discord 阅读、搜索、消息、文件、帖子和角色操作。它可作为多个 Agent Harness 的插件或 MCP 服务分发,并通过用户的 Discord 账户和令牌执行操作。
主要功能
- 01读取聊天、消息、成员和服务器
- 02搜索消息并管理收件箱
- 03发送消息和文件
- 04创建和管理帖子
- 05读取和修改角色
- 06附带工具集技能
适用场景
- 01编码工作中搜索 Discord 对话
- 02在 Agent 工作流中发送消息或文件
- 03查看服务器角色并管理分配
MCP 相关
向 MCP 客户端提供 Discord 工具,包括读取、搜索、消息、文件、帖子和角色操作。调用通过用户的 Discord 账户令牌执行;README 提醒自动化用户账户违反 Discord 条款,可能导致账户被终止。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
discord-tools
面向编码 Agent 的 Discord 工具:聊天、消息、搜索、收件箱、用户和服务器、历史记录、文件、发送、线程和角色。
警告
这些工具通过 Web 客户端的 API,使用你自己的 Discord 账号及其令牌执行操作。Discord 的条款禁止自动化用户账号(“self-bots”),违者可能导致账号被终止,即使只是只读使用也不例外。仅在你能接受账号损失的账号上使用,并且只做你自己会做的事,按自己的节奏操作。令牌就是你的账号:持有令牌的人可以以你的身份读取和写入,绕过你的密码和双重验证。
| Harness | Delivery | Pinned by |
|---|---|---|
| OpenCode V2 | 原生插件(npm 包,含技能) | 包中的版本 |
| OpenCode V1 | 原生插件(npm 包,不含技能) | 包中的版本 |
| Claude Code | 插件:MCP 服务和技能 | 发布标签,作为 ref |
| Codex | 插件:MCP 服务和技能 | 发布标签,作为 ref |
| Grok Build | 插件:MCP 服务和技能 | 发布标签,作为 @ref |
| Antigravity | 插件:MCP 服务和技能 | 发布标签的树 URL |
| Hermes Agent | 原生插件(Python,调用命令行) | 发布提交,作为 SHA |
| other MCP host | 来自 npm 的 MCP 服务 | 包中的版本 |
这些工具需要 Node.js 24 或更高版本。通过发布标签固定版本的插件安装可在 macOS(arm64、x64)和 Linux(x64、arm64、glibc)上运行;npm 安装则可在 wreq-js 提供绑定的平台上运行。 docs/conventions.md 介绍了工具的命名方式及其行为。
安装
请从发布版本安装,切勿从默认分支安装:发布版本是一个带有已构建 dist/ 的提交所对应的标签,而默认分支没有。在以下命令中,<version> 是发布版本号(1.2.3),<sha> 是标签所指向的提交:
gh api repos/craft-agent/discord-tools/commits/v<version> --jq .sha
OpenCode
OpenCode V2 在 opencode.json 中指定包及其选项:
{
"plugins": [{ "package": "@craftsamo/discord-tools@<version>", "options": { "read_only": false } }],
"permissions": [{ "action": "discord_*", "resource": "*", "effect": "ask" }]
}
OpenCode V1 可将包指定为字符串,或将其与选项配对指定:
{
"plugin": [["@craftsamo/discord-tools@<version>", { "read_only": false }]],
"permission": { "discord_*": "ask" }
}
OpenCode 允许任何未指定规则名称的操作,因此除非规则设为 ask,否则会默默批准插件的请求。读取工具不会触发询问,因此 discord_* glob 是安全的。
V1 不会注册任何技能。解压该包,并将其中的 skills/* 文件夹复制到 ~/.config/opencode/skills/:
npm pack @craftsamo/discord-tools@<version>
tar -xzf craftsamo-discord-tools-<version>.tgz
mkdir -p ~/.config/opencode/skills
cp -r package/skills/* ~/.config/opencode/skills/
rm -rf package craftsamo-discord-tools-<version>.tgz
Claude Code
claude plugin marketplace add craft-agent/discord-tools#v<version>
claude plugin install discord-tools@craft-agent
Codex
codex plugin marketplace add craft-agent/discord-tools --ref v<version>
codex plugin add discord-tools@craft-agent
Codex 会将服务器名称中的 - 转换为 _,因此工具显示为 mcp__discord_tools__discord_*。它会在插件的安装目录中启动 MCP 服务,且不传递任何 roots;因此,服务会从 Codex 随调用发送的内容中获取每次调用的目录:服务会请求 Codex 提供其沙盒状态,否则使用 Codex 指定的唯一工作区。
该插件声明了 default_tools_approval_mode = "writes":对于每个未标记为只读的工具,Codex 都会事先询问。用户的 [plugins."<plugin>".mcp_servers.<server>] 设置只能进一步收紧这一限制。由于 Codex 认为 auto 和 writes 不可比较,因此将该设置设为 auto 会得到 prompt(读取操作也会触发询问)。
Grok Build
grok plugin install craft-agent/discord-tools@v<version> --trust
Grok 会在会话的工作目录中启动 MCP 服务。
Antigravity
请从发布标签的树安装,切勿从默认分支安装,因为默认分支没有已构建的 dist/;Antigravity 会将该标签克隆到 ~/.gemini/config/plugins/discord-tools。
agy plugin install https://github.com/craft-agent/discord-tools/tree/v<version>
Hermes Agent
Hermes 安装的是一个提交,而不是标签,并且插件安装后处于禁用状态:
hermes plugins install craft-agent/discord-tools --ref <sha>
hermes plugins enable discord-tools
如果 Hermes 网关已在运行,请重启它(hermes gateway restart)以加载插件。
插件会运行 Hermes 启动时找到的 Node。如果版本管理器在 Hermes 运行期间移除了该版本,调用时会再次查找 Node;如果没有找到,请从 node 可以运行的 shell 中重启 Hermes。
如果软件包的写入操作依赖另一个 Hermes 插件,例如一个用于阻止写入、且无人审批的守卫,请在 require_plugins 中列出该插件。即使该插件导入或注册失败,Hermes 仍会继续加载此插件,并将清单中的 requires_plugins 视为建议性配置。启用此设置后,只要列出的插件尚未加载,所有写入操作都会在审批前被拒绝,即使使用 --yolo、approvals.mode: off 或记住的答案也不例外,并会指出缺失的插件。读取操作仍会执行。
plugins:
entries:
discord-tools:
settings:
require_plugins: [write-guard]
其他 MCP 宿主
将服务添加到宿主的 MCP 配置中。标志放在 args 中:
{
"mcpServers": {
"discord-tools": {
"command": "npx",
"args": ["-y", "@craftsamo/discord-tools@<version>", "--read-only"]
}
}
}
工具和技能
每个工具集都附带一项技能,告知 Agent 如何使用其工具。技能会在其 frontmatter 的 metadata 下指定工具集(metadata: { toolset: sends },以块的形式编写)。OpenCode V2 和 Hermes 只有在设置中注册了该工具集的至少一个工具时才会注册该技能,因此,关闭该工具集或移除了该工具集所有工具的配置不会看到该技能;不属于任何工具集的技能则始终会注册。Claude Code、Codex、Grok Build 和 Antigravity 会完整安装技能文件夹,并且只将设置传递给 MCP 服务,因此无论设置选择了什么,它们都会列出所有技能。OpenCode V1 不会注册技能,其复制的技能也会全部列出。
| 工具集 | 工具 | 技能 | 功能 |
|---|---|---|---|
| 账户 | discord_account_read | discord-account | 读取本地账户、令牌和同步状态 |
| 同步 | discord_sync_read | discord-sync | 显示同步列表并建议变更 |
| 同步 | discord_sync_add | discord-sync | 关注服务器或指定频道 |
| 同步 | discord_sync_remove | discord-sync | 取消关注服务器或频道 |
| 聊天 | discord_chat_read | discord-chats | 读取服务器、频道、私信和消息 |
| 搜索 | discord_search_read | discord-search | 搜索镜像或 Discord 的搜索内容 |
| 收件箱 | discord_inbox_read | discord-inbox | 列出提及、待处理聊天和已保存内容 |
| 收件箱 | discord_saved_add | discord-inbox | 保存消息,可选添加提醒 |
| 收件箱 | discord_saved_remove | discord-inbox | 删除已保存内容及其提醒 |
| 收件箱 | discord_read_mark | discord-inbox | 将一个聊天标记为已读,并同步到所有设备 |
| 成员 | discord_people_read | discord-people | 读取好友、备注、个人资料和成员 |
| 成员 | discord_server_read | discord-people | 读取服务器信息、角色、表情符号、活动和邀请 |
| 发送 | discord_message_send | discord-sends | 发送文本,可选作为回复 |
| 发送 | discord_file_send | discord-sends | 发送文件,可选附带文本 |
| 历史 | discord_history_read | discord-history | 按聊天、作者或日期统计消息数量 |
| 历史 | discord_export_create | discord-history | 将聊天记录写入私有文件 |
| 文件 | discord_file_save | discord-files | 将消息中的文件保存到磁盘 |
| 操作 | discord_message_edit | discord-actions | 编辑账户自己的消息 |
| 操作 | discord_message_delete | discord-actions | 删除账户自己的消息 |
| 操作 | discord_reaction_add | discord-actions | 添加账户的回应 |
| 操作 | discord_reaction_remove | discord-actions | 撤回账户的回应 |
| 操作 | discord_pin_add | discord-actions | 置顶消息 |
| 操作 | discord_pin_remove | discord-actions | 取消置顶消息 |
| 线程 | discord_thread_create | discord-threads | 在频道中或从消息创建线程 |
| 线程 | discord_post_create | discord-threads | 在论坛或媒体频道中发布内容 |
| 线程 | discord_file_post | discord-threads | 在论坛或媒体频道中发布文件 |
| 线程 | discord_thread_join | discord-threads | 加入线程 |
| 线程 | discord_thread_leave | discord-threads | 离开线程 |
| 角色 | discord_role_read | discord-roles | 读取角色、权限和角色成员 |
| 角色 | discord_role_assign | discord-roles | 为一名或多名成员分配角色 |
| 角色 | discord_role_unassign | discord-roles | 移除一名成员的角色 |
| 角色 | discord_role_create | discord-roles | 创建带有指定权限的角色 |
| 角色 | discord_role_edit | discord-roles | 更改角色名称、颜色、标记或权限 |
| 角色 | discord_role_delete | discord-roles | 从所有拥有该角色的成员处删除此角色 |
account 默认开启,并可与 read_only 一起使用。使用 {} 调用 | |||
discord_account_read 可按排序列出所有标签,使用 | |||
{"account":"default"} 可查看单个标签;未知标签会返回 not_found。 | |||
| 它会读取本地身份、凭据状态、调度器和镜像元数据, | |||
| 绝不会联系 Discord 或更改服务。结果中的名称是不可信数据, | |||
| 不是指令。 |
token_source 的值为 variable、file 或 null,绝不会返回令牌本身。
token_status: "available" 表示令牌在本地可用,并不表示刚刚完成身份验证。
服务已调度但处于空闲状态属于正常情况;未知的调度器状态会保持为 null。
本地状态健康的条件是 15 分钟内完成一次同步;部分运行需要继续执行。
记录的 running 或 rejected 同步状态并不能证明进程正在运行或当前令牌已被拒绝。
需要处理问题时,action、hint 和 recovery_command 会为用户提供一个下一步操作。
读取操作不会执行该操作。令牌被拒绝后,请使用新令牌登录,然后重新安装服务以恢复其调度,
具体说明见本地账户命令。
sync 默认开启;read_only 仅保留 discord_sync_read。同步列表会列出同步服务关注的服务器,
每个服务器可以整体关注(其中最活跃的 10 个文本频道,减去排除项),也可以按名称指定文本频道和公告频道;
始终关注私信和群聊。最多可关注 10 个服务器和 30 个频道名额,整体关注一个服务器占用 10 个名额。
discord_sync_read的list会显示每个服务器、它关注的频道及各频道是否为最新状态、排除项和已用名额。suggest仅根据镜像,建议账户发过消息的频道、活跃但未关注的频道,以及近期不再活跃的条目;每项都会提供 用于应用建议的工具的确切参数,并说明是否符合名额限制。discord_sync_add会整体关注一个服务器,或关注镜像已知的某个服务器中的指定频道;discord_sync_remove会移除一个服务器、移除指定频道,或将频道从整体关注的服务器中排除。要在整体关注和指定频道之间切换服务器的关注方式,必须先移除现有设置。
这三个工具只会读取或更改本地列表,不会联系 Discord。两项写入操作都会征求确认,因为每个关注的频道都会增加后续每次同步运行的请求数。 更改从下一次运行开始生效;镜像中已有的消息仍可读取。
chats 默认开启,并可与 read_only 一起使用。discord_chat_read 接受一个 method:
| 方法 | 读取内容 |
|---|---|
servers | 账户的服务器,以及同步列表对每个服务器的关注方式 |
channels | 某个服务器按类别划分的频道,以及各频道是否受到关注且为最新状态 |
dms | 私信和群聊,按最新消息从新到旧排列,并支持按名称筛选及查看最后一条消息 |
messages | 某个聊天中两个时间点之间的消息,按从旧到新排列 |
around | 某条消息前后的消息 |
threads | 某个频道中的讨论串或论坛帖子,可按活跃度或创建时间排序,并显示标签 |
pins | 某个聊天中置顶的消息,按置顶时间从新到旧排列 |
backfill | 某个同步服务关注的聊天中的较早历史记录,并写入本地镜像 |
聊天、服务和消息均由 ID 标识,可通过 servers、 | |
channels、dms 和 threads 查找;名称永远不是目标。messages 和 | |
around 会从本地镜像读取同步在 15 分钟内标记为当前的聊天,且只限于同步保存的历史记录;dms | |
使用 15 分钟内读取的 DM 列表,servers 使用 6 小时内读取的列表。其他所有内容,以及 | |
channels、threads 和 pins,始终都会按控制节奏从 Discord 读取并存入镜像。任何读取 | |
| 都不会发送内容、显示账号在线或将聊天标记为已读(按要求调用 | |
discord_read_mark 的 inbox 会执行此操作)。消息 | |
| 文本、嵌入内容、文件名和名称均由其他人撰写:结果会说明这一点,Agent 会将其视为数据,而绝不视为指令。 |
search 默认开启,并始终处于 read_only 模式。
discord_search_read 可按文本、作者、提及对象、has(link、file、image、
video、sound、embed、sticker、poll)、置顶状态和时间范围,按最新优先顺序查找一个聊天、一个服务或所有位置中的消息、链接和文件:
| 方法 | 搜索内容 |
|---|---|
mirror | 本地镜像中的内容,无论当前与否;不发送请求 |
discord | Discord 自带的搜索功能,可搜索一个服务、一个聊天或所有 DM;并保存搜索结果 |
mirror 会匹配字面子串,还会按账号的表情回应、某个表情符号和频道的线程筛选;结果中的每个聊天都会注明上次同步运行将其标记为当前的时间。discord 会涵盖账号在指定范围内可读取的所有内容,但无法一次搜索所有服务;若某个服务仍在建立索引,则会等待一次。两种方式均通过 next_before 分页。
inbox 默认开启;read_only 仅保留 discord_inbox_read,其
method 可以是:
| 方法 | 读取内容 |
|---|---|
mentions | Discord 自带的过去 7 天提及列表,包括角色提及和 @everyone |
waiting | 用户尚未回复其最新消息的聊天,仅从镜像读取 |
saved | 用户保存的消息和提醒,提醒排在前面 |
waiting 表示尚未回复,绝不表示未读。discord_saved_add 可保存镜像中的消息,也可选择设置 remind_at 时间;discord_saved_remove
可移除已保存内容。discord_read_mark 会在所有设备上将一个聊天标记为已读,可标记至某条消息或镜像中最新的消息;它是唯一会将内容标记为已读的工具,且这里的每项写入操作都会先征求同意。此处没有未读计数:Discord 只会在其网关后保留这些计数,而在真实手机上进行的测试显示,即使短暂建立网关会话,也会暂缓手机的推送通知,因此这里不会打开网关。
people 默认开启、只读,并归入 read_only。两个工具每次调用都会逐一实时读取,并使用镜像已知的用户 ID 和服务 ID,而非名称;仅存储返回的用户名。discord_people_read
可读取好友、私人备注、某人的个人资料、带角色名称的成员身份信息,或成员搜索。discord_server_read 可读取服务信息(含大致的成员和在线人数)、角色、自定义表情符号和贴纸、即将举行的活动及感兴趣的用户,或邀请信息。成员搜索和邀请信息需要 Manage Server 权限。邀请代码只会提供给用户;除非用户提出要求,否则绝不会放入消息、文件或其他工具中;备注为私人内容,除非用户提出要求,否则绝不分享。
默认启用 sends;read_only 会将其排除。discord_message_send
会按 ID 向镜像已知的私信、群组私信、服务器频道或帖子串发送一条文本,
且绝不会开启新的私信。文本会原样发送。reply_to
会回复该聊天中镜像的一条消息,但不会提及其作者;
只有启用 mass_mentions 时,@everyone、@here 和角色提及才会通知他人,
而 silent 会静默发送,不触发通知。每次发送都需要确认。
discord_file_send 会以相同方式发送 1 到 10 个文件,也可附带文本。
文件必须位于 send_dirs 允许的文件夹内(默认是
工作目录,绝不会是主目录),且每个文件不得超过 send_max_mb。
凭据、密钥和数据库、程序,以及无法检查的归档文件都会被拒绝;任何一个文件被拒绝,整个发送都会被拒绝。检查时使用的是私有副本,上传的也是该副本;若文件在提示后发生更改,此调用会标记为 stale。文件只会上传到 Discord 的存储空间,
不会附带令牌,并且只有所有文件都上传完成后才会发布任何内容。
每条发送只会发出一次,绝不会重试。发送前,其 nonce 会记录在镜像的发送记录中,
并附上文本哈希,而不是文本本身。返回结果是 Discord 返回的消息,
并存储在镜像中。若发送被拒绝,则返回错误。其他任何情况都属于 uncertain:
消息可能已经发送,details.matches 会列出从该聊天的一次回读中找到的
账号发送的同文本消息。再次发送前,请先检查聊天。
默认关闭 actions,因为它会更改他人已读到的内容;可通过 toolsets 启用
(例如 --toolsets all,或在默认工具集基础上添加 actions)。
read_only 会将其排除。每次调用都必须指定聊天和消息的 ID,
且该消息必须存在于镜像中。每项操作都需要确认。
discord_message_edit会替换账号自己发送的消息文本,并按原样发送;discord_message_delete会删除账号自己的消息,且无法撤销;若 Discord 已没有该消息,则也视为已删除(already)。discord_reaction_add和discord_reaction_remove会在任意消息上添加或移除账号自己的回应:可以是一个 Unicode 表情符号,也可以是该消息上已有的自定义表情符号;绝不使用超级回应。discord_pin_add和discord_pin_remove会置顶或取消置顶任意消息;账号是否有权限由 Discord 决定,每个聊天最多可置顶 250 条消息。
发出请求前,工具会拒绝它能确认有误的操作:为 ID 指定名称、镜像中没有的消息、
编辑或删除他人发送的消息、不可用的表情符号、没有任何更改的编辑、置顶系统消息,
以及移除非账号自己的回应。每项操作只会发送一次,绝不会重试,并会在镜像中跟进。任何可能已到达 Discord 的操作都属于 uncertain:details.applied 会说明对聊天进行一次回读后是否看到新状态(无法确定时为 null)。重复执行操作无害,但请先检查聊天并征求确认。
默认关闭 threads,因为它会创建持久帖子;可通过 toolsets 启用
(例如 --toolsets all,或在默认工具集基础上添加 threads)。
read_only 会将全部五个工具排除,每次调用都需要确认。目标必须是镜像已知的 ID:discord_thread_create 会在文本或公告频道中创建公开或私有帖子串,也可从一条消息创建(仅限公开);discord_post_create 会在论坛或媒体频道中创建文本帖子;
discord_file_post 会创建带文件的帖子,也可附带文本;
discord_thread_join 和 discord_thread_leave 只会更改用户自己的成员身份。标签是 discord_chat_read 的 threads 方法返回的 ID;文件遵循文件发送的目录、大小和安全规则。任何操作都不会重试。创建操作没有 nonce:若结果为 uncertain,请读取 details.read_back,检查频道中的帖子串或帖子,并在重试前征求确认。切勿盲目重复创建;重复加入无害,但再次退出前请先检查。
默认关闭 roles,因为它会改变其他人可以执行的操作;使用 toolsets 启用
它(例如 --toolsets all,或默认工具集加上 roles)。
read_only 只保留 discord_role_read;即使有允许规则,每次写入操作仍
都需要询问。先用方法 list 或 role 读取角色:写入操作需要不超过 15 分钟的
快照;更改用户自己的角色则需要刚读取的快照。目标只能是镜像已知的服务器、角色和用户 ID,不能使用名称。可以授予、收回、创建、编辑或
删除角色;绝不会授予、创建或赋予 administrator,也不会授予用户本身没有的任何角色。审计日志会注明用户,并记录可选的 reason。
不会重试任何操作:若结果为 uncertain,请读取 details.read_back,重新读取角色,
并询问当事人。创建操作返回的候选项只是候选项;切勿盲目重复创建。重复授予或收回没有危害,但请先检查。
默认关闭 history,因为导出会写入文件;使用 toolsets 启用它(例如 --toolsets all,或默认工具集加上 history)。
read_only 只保留 discord_history_read;其方法 counts 会统计镜像中普通消息和回复的数量,可按聊天、作者或日期统计,默认统计过去 30 天,且不会读取文本。总数涵盖整个时间范围;
limit 只会限制行数。日期使用 time_zone,默认为机器的时区。
coverage.partial 和 coverage.not_current 标记的是下限,而非 Discord 的
总数:请回填已关注聊天中的较早缺失记录,或等待下一次同步。
discord_export_create 会将镜像中某个聊天完整保留的历史记录(无论是否为当前记录)导出为 Markdown、JSON 或 JSONL,其中包含完整文本和消息
永久链接。文件会写入 <download_dir>/exports/,并设为私密权限(文件权限为 0600,文件夹权限为
0700),绝不覆盖已有文件;若名称已被占用,则会在名称后加数字。count、current、
left_out、truncated 和 complete_to_start 会说明文件涵盖的内容。
使用 continue.older.before 或 continue.newer.after 继续导出到新文件;
continue.backfill_first 表示在向更早记录继续导出前,先回填已关注的聊天。
每次导出都需要询问。两个工具都不会向 Discord 发出请求。导出内容可能包含私密私信;除非当事人要求,否则绝不要发送、上传或分享。
默认关闭 files,因为它会将文件写入磁盘;使用 toolsets 启用它(例如 --toolsets all,或默认工具集加上 files)。
read_only 不会启用它。discord_file_save 接收聊天和消息 ID(消息必须是镜像中已有的消息),并将其附件、链接预览图片和贴纸保存到
<download_dir>/<channel>-<message>/。每次保存都需要询问。
不会覆盖任何文件:如果同名文件的字节内容相同,则报告为
already;否则文件名会变为 name-2.ext。文件只会从 Discord 自己的
CDN 和媒体代理获取,不使用令牌,也不会从链接指向的网站获取。保留文件前会根据其名称、声明类型和字节内容逐一检查:
无法读取的程序、安装程序、脚本和存档会被标记为 refused,
超过 download_max_mb 的文件会被标记为 too_large。其他文件会继续处理,并各自记录结果。文件不带执行权限位,且在 macOS 上会标记为已下载。
存档(.zip、.tar、.tar.gz、.tgz)会以打包形式保存,并附上其包含内容的列表。
只有在请求时,设置 unpack: true 才会将存档解压到其旁边的新文件夹中;可以解压全部内容,也可以只解压列表中指定的 entries。
文件保存位置和大小限制由 download_dir 和 download_max_mb 设置决定。
授权(grants)
默认关闭。对于无人可以响应的任务,委托有限范围内的写入权限。
| 工具 | 功能 | 类别 |
|---|---|---|
discord_grant_create | 请求某人委托一项工具在限制范围内进行写入 | 管理 |
discord_grant_read | 列出授权及其使用情况,或读取使用日志 | 读取 |
discord_grant_revoke | 撤销授权,阻止后续调用继续使用该授权 | 覆盖 |
每项写入工具都可以针对其目标、每小时调用次数和有效期进行授权。
工具可以通过在其规范中声明 bounds 并提供
measure(args, context) 来增加授权可限制的内容;请参阅
约定。目前此软件包中的工具
均未声明 bounds。
本地账户命令
这些命令供用户使用,并非 Agent 工具。它们会输出纯文本;
list、run 和 target 保留其 JSON 输出。
discord-tools-cli login --account default
discord-tools-cli sync --account default
discord-tools-cli service install --account default
discord-tools-cli service status --account default
discord-tools-cli service uninstall --account default
discord-tools-cli remove --account default
login 会通过 Discord 验证账户。如果其环境中提供了
DISCORD_TOOLS_TOKEN_DEFAULT,则会使用该变量,且不存储令牌。否则,它会从标准输入读取令牌:
在终端中读取一行隐藏输入,或通过 UTF-8 管道读取至 EOF。密钥管理器
可以将其输出直接通过管道传给 discord-tools-cli login --account default。
随后,经过验证的令牌会存储在该标签的私有令牌文件中(模式为 600)。
切勿将令牌作为命令行参数传入。
每条命令都接受 --state-dir <directory>;否则会使用
DISCORD_TOOLS_STATE_DIR 或默认状态目录。状态会区分已计划的
任务和当前正在运行的任务。即使本地状态已被移除,状态查询和卸载命令仍接受显式标签。
sync 会运行一轮有界同步,并输出状态和计数。完整运行或标签已处于忙碌状态时退出码为 0;部分运行时退出码为 1,需要再次运行。
身份验证被拒绝时,会暂停该标签的计划任务,但保留其服务定义。要恢复,请使用新令牌运行 login,然后为该标签运行
service install。
service install 要求标签已登录,并每五分钟调度一次已安装的 CLI:在 macOS 上使用 launchd Agent,在 Linux 上使用 systemd 用户计时器和一次性服务。请确保该 CLI 安装及其 Node 运行时在各自的安装路径下可用;更新其中任一项后,请再次运行
service install。服务定义会记录
运行时、命令、状态目录和 PATH,绝不记录令牌。如果 Node 的路径中包含其版本号(例如使用版本管理器时),service install 会在不含版本号的路径下记录一个 PATH 中的
node,该路径下的 node 会启动同一个 Node;如果找不到这样的路径,则会发出警告。之后,该 node 会运行版本管理器当前设为活动版本的 Node。
安装此版本后,该标签的 service.json 会保留运行时和 CLI 路径;如果任一路径失效,service status
和 discord_account_read 会提示。服务管理器
不会自动继承终端环境:使用
DISCORD_TOOLS_TOKEN_<LABEL> 时,请将其单独提供给计划服务的环境,以及启动 MCP 服务的运行框架。
在 macOS 上,“登录项”会将该服务列为 discord-tools-sync-<label>:Agent 通过该启动脚本运行;service install 会将脚本写入
~/Library/Application Support/io.github.craft-agent.discord-tools/,而
service uninstall 会将其删除。在“登录项”中关闭该项目即可停止同步。
remove 会要求你输入标签。对于非交互式命令,请传入
--yes。该命令会卸载计划任务;如果标签正处于忙碌状态,则会拒绝操作;并删除该标签的本地状态,包括其镜像和令牌文件。
如果前台同步仍在运行,则会保留状态并继续停止计划任务;请先停止该任务,再重试移除。
它既不会删除 Discord 上的任何内容,也不会移除通过环境提供的凭据。其他标签会保留。
添加工具
- 使用
defineTool在src/core/<domain>/<verb>.ts中编写规范:包括 ID<prefix>_<domain>_<verb>、标题和描述、Zod 参数和输出架构、工具集和写入类别,以及execute(args, context)。写入工具还会提供targets(args, context):用于说明调用会写入哪些目标, 权限规则应以此为依据。对于某些调用可能因设置而无法触及的工具,无论用户如何回答,都要提供gate(args, context),并在此处对这类调用抛出异常;这类调用会在询问任何人之前、执行execute之前被拒绝。 - 在规范旁边测试该工具(
<verb>.test.ts),像各入口一样通过invoke调用它。运行程序的工具要针对PATH中该程序的模拟版本进行测试;测试不会访问真实服务。 - 在
src/tools.ts中列出该工具。新的工具集要加入src/project.ts中的toolsets(若默认启用,也加入defaultToolsets);软件包自身的设置要加入options(并在project.py中加入OPTIONS,在plugin.yaml中加入config_schema);工具除设置外读取的变量要加入toolVariables。 - 添加或更新工具集的 skill:
skills/<prefix>-<toolset>/SKILL.md,并在其 frontmatter 的metadata下指定工具集。 - 运行
pnpm run build && pnpm run manifests,将工具列入plugin.yaml,并将其变量列入 Codex 的清单,然后在“工具和技能”下对其进行说明。
docs/conventions.md 列出了每个步骤都必须遵循的规则。
软件包将每个选项声明为 text、boolean、number、list、path
或 paths,也可以声明为带有 type 和可选边界的对象。例如,在 src/project.ts 中:
options: {
notes_dir: "path",
note_limit: { type: "number", integer: true, min: 1, max: 50 },
}
integer: true 要求值为整数;min 和 max 用于限定数字,或限定 list 或
paths 值中的项目数量。仅包含 type 的对象与单独使用该类型的效果相同。Hermes 的 OPTIONS
会将这些声明镜像为单行格式,使用双引号,并在 integer 中使用 Python 的 True:
OPTIONS: dict[str, str | dict[str, object]] = {"notes_dir": "path", "note_limit": {"type": "number", "integer": True, "min": 1, "max": 50}}
读取和写入
每个读取工具都命名为 <prefix>_<domain>_read。读取操作可以在不询问的情况下运行;写入操作会由执行环境确认。
| 执行环境 | 无需询问即可读取 |
|---|---|
| OpenCode | 始终如此;插件只会在写入前询问 |
| Claude Code | ~/.claude/settings.json 中 permissions.allow 下的规则 mcp__plugin_discord-tools_discord-tools__*_read |
| Codex | 始终如此;Codex 会在不询问的情况下运行声明了 readOnlyHint 的工具,读取工具就是如此 |
| Grok Build | grok --allow 'MCPTool(discord-tools__*_read)' --allow 'MCPTool(discord_*_read)'(两条规则;见下文) |
| Antigravity | permissions.allow 下的规则 mcp(discord-tools_discord-tools/<tool id>),每个读取工具各一条 |
| Hermes | 始终如此;插件只会在写入前询问 |
会询问写入的情况,以及不会询问的情况:
- OpenCode 不会因任何规则名称而授权操作,因此除非规则要求确认,否则写入会在不询问的情况下运行:添加 OpenCode 下所示的
discord_*规则。 - Codex 会因插件的审批模式而在每次写入前询问。
在
codex exec下,它会以“需要批准 MCP 工具调用,但批准策略为 never”拒绝操作。对于有界任务,请参阅 无人批准时的写入。 - 在
grok -p下,Grok Build 会拒绝它无法询问的写入,除非事先已允许该写入。 - Grok Build 通过其
use_tool工具调用插件工具,而 Agent 往往会先省略服务器名称来命名工具。Grok 会根据给定的名称检查规则,因此仅有带服务器名称的规则无法匹配首次调用。第二条规则会匹配短名称;但写入仍然不会匹配任何一条规则。 - Antigravity 会在任何 MCP 工具未被规则允许时先询问,包括读取操作;它将插件服务器命名为
discord-tools_discord-tools(先是插件,再是服务器)。agy -p会拒绝无法询问的工具。 - Hermes 的
hermes chat -q会拒绝它无法询问的写入;hermes -z和--yolo会跳过审批,因此写入会在不询问的情况下运行。对于有界任务,请参阅 无人批准时的写入。
如果工具的 gate 拒绝某次调用,该调用就永远不会运行,无论回答是什么。OpenCode 和 Hermes 会在询问前拒绝,因此不会显示提示词;Hermes 会通过工具的错误阻止调用。Claude Code、Codex、Grok Build 和 Antigravity 会在 MCP 服务收到调用前显示各自的提示,因此仍可能询问是否允许该调用;随后服务会拒绝它。
无人批准的写入
授权会将某个任务的写入限制为一个工具,有效期最长为 90 天。其余设置由用户决定:目标(指定目标,或用 * 表示任意目标)、工具声明的限制(未填写的项不受限制),以及每小时的调用次数(未填写则不限次数)。每次使用授权进行的调用都会被记录。授权不会覆盖宿主的权限设置。
约定中说明了相关契约。
- 在有用户应答的会话中,提供设置中所述的密钥,同时启用
grants工具集和任务的工具集,并要求 Agent 委派。它会调用discord_grant_create;提示中会显示工具、目标、频率、天数、工具声明的每项限制(未填写的项显示为no limit)以及原因。 批准一次即可。 - 仅为该任务设置同一密钥和
unattended,例如DISCORD_TOOLS_UNATTENDED=true。否则不会检查授权。 - 按下文所述,让宿主允许本次运行中的写入工具。授权仍会限制每次调用。
- 使用
discord_grant_revoke撤销授权,或使用discord_grant_read列出授权及其使用情况。
当无人应答时,如何让写入操作(例如 discord_message_send)到达程序包:
- OpenCode
opencode run会拒绝所有请求,除非某条允许规则指定了该工具("permission": { "discord_message_send": "allow" }),或运行时带有--auto。 - Claude Code
claude -p需要在--allowedTools中指定该工具,例如mcp__plugin_discord-tools_discord-tools__discord_message_send。 - Codex
codex exec需要在config.toml中插件的 MCP 服务下为该工具设置approval_mode = "approve"([mcp_servers.<server>.tools.<tool>]),因为插件默认会在每次写入前询问。 - Grok Build
grok -p需要同时设置以下两条允许规则:--allow 'MCPTool(discord-tools__discord_message_send)'和--allow 'MCPTool(discord_message_send)',这两个限定名称和短名称见读取和写入。 - Antigravity
agy -p需要在permissions.allow中设置mcp(discord-tools_discord-tools/discord_message_send)。 - Hermes
hermes chat -q在approvals.single_query_mode设置下会拒绝请求,除非已获允许。-z和--yolo会跳过审批并执行写入;此时授权是唯一的限制。
限制
- 如果跳过了所有审批(Hermes
-z或--yolo、始终批准模式、明确允许discord_grant_create,或全局 OpenCode V1allow),则不会显示提示。在这种情况下创建的授权并非用户的批准;其范围可覆盖任意目标、没有调用限制,也没有频率限制,最长有效 90 天:只在运行环境会要求审批时创建授权。 - 不会检测到将较早版本的授权目录整体恢复的情况。最长 90 天的有效期会限制其可恢复的内容。
- 任何能够读取密钥的人都可以签署授权。请将密钥保存在 Agent 的工具无法读取的位置。
- OpenCode V2 插件通过钩子强制要求对
discord_grant_create进行确认;只有提供该钩子的宿主才能运行此功能。
OpenCode V2 服务和 Hermes 网关会保留启动时的环境;修改任务变量前,请参阅设置。
设置
所有入口点都使用相同的设置。命令行标志优先于环境变量;选项或设置也优先于环境变量。
| Setting | Flag | Variable | 含义 |
|---|---|---|---|
toolsets | --toolsets | DISCORD_TOOLS_TOOLSETS | 启用的工具集,或 all;默认为 src/project.ts 中的名称 |
read_only | --read-only | DISCORD_TOOLS_READ_ONLY | 不注册任何会写入的工具;优先级高于其他所有设置 |
unattended | --unattended | DISCORD_TOOLS_UNATTENDED | 无人可以响应:写入操作仅在授权涵盖该操作时才会执行;默认关闭 |
grants_dir | --grants-dir | DISCORD_TOOLS_GRANTS_DIR | 授权及其使用记录的存放位置;默认为 $XDG_STATE_HOME/discord-tools/grants,否则为 ~/.local/state/discord-tools/grants |
tools | --tools | DISCORD_TOOLS_TOOLS | 按 ID 添加单个工具,无论它们属于哪个工具集 |
exclude_tools | --exclude-tools | DISCORD_TOOLS_EXCLUDE_TOOLS | 按 ID 移除单个工具;优先级高于 tools 和 toolsets |
confirm | --confirm | DISCORD_TOOLS_CONFIRM | 仅限 MCP 服务:按约定使用 harness(默认)或 elicitation |
language | --language | DISCORD_TOOLS_LANGUAGE | 仅限原生插件:审批提示词的语言,例如 ja |
emoji | — | — | 仅限 Hermes:按工具集名称设置显示在每个工具集旁的表情符号("" 表示不显示) |
require_plugins | — | — | 仅限 Hermes:必须加载的插件;只要有插件未加载,所有写入操作都会在审批前被拒绝 |
state_dir | --state-dir | DISCORD_TOOLS_STATE_DIR | path:存放每个标签状态的位置;默认为 $XDG_STATE_HOME/discord-tools |
download_dir | --download-dir | DISCORD_TOOLS_DOWNLOAD_DIR | path:接收的文件的保存位置;导出文件存放在其私有的 exports/ 文件夹中;默认为 ~/Downloads/discord-tools |
download_max_mb | --download-max-mb | DISCORD_TOOLS_DOWNLOAD_MAX_MB | 接收文件的最大大小,整数,范围为 1 到 500 MB;默认为 100 |
send_dirs | --send-dirs | DISCORD_TOOLS_SEND_DIRS | paths:允许发送文件的目录,最多 20 个;默认为工作目录 |
send_max_mb | --send-max-mb | DISCORD_TOOLS_SEND_MAX_MB | 发送文件的最大大小,整数,范围为 1 到 500 MB;默认为 10 |
DISCORD_TOOLS_GRANT_KEY 只能作为变量使用,不能作为标志或插件
选项。请使用至少 32 个字符,例如通过 openssl rand -hex 32 生成,
并存放在主机保存机密信息的位置。没有此密钥时,无人值守状态下不会执行
任何写入操作,也无法创建授权。Codex 会连同设置变量一起转发此密钥,
如下所述。
列表在标志或变量中以逗号分隔,send_dirs 也一样。此包自身的设置,从 state_dir 到 send_max_mb,都列在 src/project.ts 的 options 中,并以相同方式读取。path 会先去除首尾空白;~ 和 ~/…(也支持平台分隔符)表示主目录(如果 HOME 是绝对路径,则使用 HOME,否则使用账户的主目录)。之后路径必须是绝对路径,并会以规范化形式传给工具,不会检查文件系统。paths 是此类路径组成的列表,在标志或变量中以逗号分隔,在插件选项中则是字符串数组。空白路径视为未设置,因此会应用默认值;空白列表项会被丢弃,丢弃后为空的列表视为未设置。范围检查只针对已提供的值,不针对未设置的选项。被拒绝的值会返回 invalid_argument,并指出标志、变量或选项的名称以及其必须满足的条件。Hermes 会将路径和列表传给命令行,由命令行检查路径和范围。各个宿主如何读取这些值:
-
OpenCode 使用上文所示的插件
options,其中列表为数组,read_only为布尔值,兆字节限制为数字;未提供时则回退到变量。V2 在后台服务中运行插件,该服务会保留启动时的环境:在opencode run启动时设置的变量,要等到在该环境中重启服务后才会生效(opencode service restart)。V1 在自身进程中运行插件。 -
Hermes 使用
config.yaml中的plugins.entries.discord-tools.settings:plugins: entries: discord-tools: settings: read_only: false exclude_tools: []如果未设置
language,审批卡片会采用 Hermes 自身的display.language(或HERMES_LANGUAGE),也就是其审批按钮所用的语言;如果都没有设置,则使用英语。插件会将自身环境传给它运行的命令行,因此变量也会生效。正在运行的网关会保留启动时的环境; 更改变量后,请重启网关(hermes gateway restart)。 -
Claude Code、Grok Build 和 Antigravity 启动插件服务时不带标志,并将客户端的环境传给它,因此应在宿主运行时所处的环境中设置变量。
-
Codex 只会向插件的 MCP 服务传递少量基本变量(例如
PATH和HOME),以及插件清单中列出的变量,即上述变量:应在 Codex 运行时所处的环境中设置它们。工具读取的其他变量应加入src/project.ts中的toolVariables;pnpm run manifests会在设置所用变量之后,将它添加到清单中。若要传递标志,或向服务提供此包未列出的变量,请改为在 Codex 的config.toml中的[mcp_servers]下添加服务,而不要使用插件:标志放在args中,env_vars用于指定从 Codex 环境转发的变量,env用于设置固定值。[mcp_servers.discord-tools] command = "npx" args = ["-y", "@craftsamo/discord-tools@<version>", "--read-only"] env_vars = ["DISCORD_TOOLS_TOOLSETS"]
账号、令牌和同步服务
- 每个 Discord 账号都有一个标签,由 1 到 24 个小写字母、数字和
_组成(登录时未指定名称则为default);grants保留给授权目录使用。工具的account参数用于选择标签;如果只登录了一个账号,可以省略此参数。 - 每个标签的状态都保存在一个目录中:
<state_dir>/<label>/(权限模式为 700),其中包含已同步消息的镜像、同步列表、令牌文件(如有),以及正在发送或接收的文件副本。 如果XDG_STATE_HOME是绝对路径,state_dir默认为$XDG_STATE_HOME/discord-tools,否则默认为~/.local/state/discord-tools。 镜像中包含你的私人消息,因此请勿将此目录纳入共享备份。 - 令牌来自
DISCORD_TOOLS_TOKEN_<LABEL>(如果已设置) (default对应DISCORD_TOOLS_TOKEN_DEFAULT);否则来自登录时写入的令牌文件。使用环境变量时,此软件包不会存储任何令牌:请通过你使用的密钥管理器,将令牌注入运行环境,供运行环境(其 MCP 服务会读取和写入)和同步服务使用。对于 Codex,请按上述说明在env_vars中列出该变量。 - 同步服务会维护每个标签的镜像,每 5 分钟轮询一次 Discord,每次运行时间较短且有上限:始终同步私信和群组私信;服务器则仅同步列表中指定的服务器(最多 10 个服务器和 30 个频道;可通过
sync工具更改列表)。只有当某个频道在最近 15 分钟内同步过时,读取操作才会使用镜像,否则会直接读取 Discord。服务不会自行发送任何内容:不会更新在线状态、发送正在输入提示或标记已读。 - 令牌被拒绝后,该标签的服务会停止运行,直到提供新令牌;更改 Discord 密码会使令牌失效。
目录结构
src/project.ts— 软件包名称、工具 ID 前缀、设置前缀、工具集、工具选项,以及工具读取的其他变量。src/core/— 工具约定和工具本身,与任何运行环境及项目名称无关。src/tools.ts— 所有工具的列表,每个入口点都会注册这些工具。src/words.ts— 各语言的工具用词翻译,原生插件会在审批提示词中使用这些翻译。src/mcp/— MCP 服务,构建为dist/mcp.js,并由discord-tools运行。src/opencode/— OpenCode 插件,构建为dist/opencode.js。src/cli/— Hermes 插件调用的命令行程序,构建为dist/cli.js,并由discord-tools-cli运行。src/hermes/、plugin.yaml和__init__.py— Hermes 插件。skills/— 每个工具集对应一个技能,位于skills/<name>/SKILL.md;所有支持技能的运行环境都会从软件包或插件根目录加载这些技能;原生插件只会加载已启用工具集对应的技能。.claude-plugin/、.codex-plugin/、.agents/plugins/、.mcp.json、.antigravity-plugin/和mcp_config.json— 其他运行环境的插件清单。Codex 会读取.codex-plugin/plugin.json;根目录中的plugin.json会导致它将插件作为 Agent Plugin 加载,而 Agent Plugin 的工具预算会隐藏超出固定数量限制的工具。根目录中的.mcp.json是 Grok Build 读取的配置(其中包含${CLAUDE_PLUGIN_ROOT},Grok Build 和 Claude Code 都会展开此变量);在 Claude Code 中处理此仓库时,请拒绝它通过该文件提供的项目 MCP 服务。
如何发布请参见 RELEASING.md。
许可证
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。