Conversation
Add the tools/chat-discord adapter specification and operational mappings for contract:chat. Defines read-only interactions over public Discord channels, mapping list_channels(), resolve_user(), and search_messages() verbs onto Discord MCP tools, with explicit enforcement of safety constraints and automatic labeling in .github/labeler.yml. Generated-by: Antigravity
Update docs/labels-and-capabilities.md with tools/chat-discord capability and MCP entries to satisfy capability-sync validation. Synchronize docs/vendor-neutrality.md with the recalculated vendor-neutrality score (11/12 contracts, 92%) reflecting contract:chat's two backend vendors. Generated-by: Antigravity
potiuk
left a comment
There was a problem hiding this comment.
The adapter follows the Slack adapter's shape closely, but two things need fixing first: resolve_user relies on data a Discord bot token cannot read while the adapter is advertised as a complete backend (which flips the published vendor-neutrality score), and the README doesn't say which MCP server provides the discord_* tools or where the token lives. Details inline.
Coverage — resolve_user relies on profile data bots cannot read
partial-read-onlymeans the tool implements a read-only subset of named contract operations, but does not satisfy the complete contract and must not be advertised as a complete/selectable backend.
—docs/labels-and-capabilities.md§ Coverage qualifiers
A bot token can't read another user's connected accounts or their "About Me" bio — connections need the OAuth2 connections scope from that user, and the profile endpoint is user-only — so the confirmed_by: "profile" path never fires for the bot this README asks for. Because vendor-neutrality-score counts any implementation without a **Coverage:** line as a full backend, this PR turns contract:chat green and moves the headline to 11/12. The simplest fix keeps that: the contract allows confirmed_by: null, so drop the profile step and return member-search candidates with confirmed_by: null. The alternative is **Coverage:** partial-read-only and dropping the docs/vendor-neutrality.md change.
(search_messages is fine on this front: Discord documented a bot-accessible Search Guild Messages endpoint in March 2026 — it needs READ_MESSAGE_HISTORY and the Message Content intent.)
Prerequisites — name the MCP server and put the token under $HOME
Any persistent token, API key, OAuth refresh token, or session cookie a framework tool needs goes under a well-known home-directory path —
~/.config/apache-magpie/<tool>for framework-owned tools, or the third-party tool's own convention … New integrations MUST follow the pattern
—AGENTS.md§ Local setup
Slack can leave this out because it uses the claude.ai connector; there is no Discord equivalent, so "Discord MCP (mcp__discord__*)" doesn't point at anything an adopter can install. Please name the server (repo URL and a version that exposes the discord_* tools in operations.md) or give the claude mcp add … -s user recipe, say where the bot token is stored (under $HOME, never in the project tree), list the required permissions and intents (View Channel, Read Message History, and the privileged Message Content intent — without it text comes back empty and search is unavailable), and add the server's source to the MCP table row in docs/labels-and-capabilities.md.
Smaller observations
- See inline:
search_messagesignores thechannelsargument, andlist_channelsfilters on anis_privatefield Discord channels don't have. docs/adapters/authoring.mdstep 5 asks for an eval undertools/skill-evals/evals/; none exists in the stack yet (#1486 adds only a scorer unit test). A community-signals fixture withkind: discordwould cover it.- Stack ordering: this PR flips the neutrality score while
tools/chat/README.mdstill lists Discord asplaceholder | not implementeduntil #1485 — merging the stack together avoids a contradictorymain.
This review was drafted by an AI-assisted tool and
confirmed by an Apache Magpie maintainer. After you've
addressed the points above and pushed an update, an Apache Magpie
maintainer — a real person — will take the next look
at the PR. The findings cite the project's review criteria;
if you think one of them is mis-applied, please reply on the
PR and a maintainer will weigh in.More on how Apache Magpie handles maintainer review:
CONTRIBUTING.md.
| ## `resolve_user(github_handle)` | ||
|
|
||
| 1. Call `mcp__discord__discord_search_members` with `github_handle`, then with the contributor's verified real name when one is known. | ||
| 2. For each candidate member, call `mcp__discord__discord_get_user_profile`: |
There was a problem hiding this comment.
major — A bot token can't read another user's connected accounts or "About Me" bio (connections need the OAuth2 connections scope from that user; the profile endpoint is user-only), so confirmed_by: "profile" never fires for a bot. The contract allows confirmed_by: null — drop this step and return member-search candidates with confirmed_by: null, which keeps the adapter a complete backend. Otherwise declare **Coverage:** partial-read-only and drop the vendor-neutrality score change.
|
|
||
| **Vendor:** Discord | ||
|
|
||
| **MCP:** Discord (mcp__discord__*) |
There was a problem hiding this comment.
major — There's no claude.ai Discord connector, so this doesn't point at anything an adopter can install. Please name the MCP server (repo URL + a version exposing the discord_* tools used in operations.md) or give the claude mcp add … -s user recipe, say where the bot token lives (under $HOME, per AGENTS.md § Local setup — "New integrations MUST follow the pattern"), and list the required permissions/intents: View Channel, Read Message History, and the privileged Message Content intent.
|
|
||
| ## `search_messages(chat_user_id, since, until, channels)` | ||
|
|
||
| 1. Call `mcp__discord__discord_search_messages` with `author_id: chat_user_id` across the public channels returned by `list_channels()`. |
There was a problem hiding this comment.
minor — This ignores the contract's channels argument (tools/chat/README.md: "Empty means every public channel list_channels returned."). Search only the given ids when it's non-empty, as the Slack adapter does with in:<#channel>.
|
|
||
| 1. Call `mcp__discord__discord_list_channels` for the configured server (guild). | ||
| 2. Filter for standard text and announcement channels (guild text, announcements, or public forum threads). | ||
| 3. Drop every channel with `is_private: true`, channels residing under private categories, or channels where `@everyone` permissions deny view access. |
There was a problem hiding this comment.
minor — Discord channel objects have no is_private field; visibility comes from the @everyone VIEW_CHANNEL permission overwrite on the channel and its parent category, so make that the rule. Also, "public forum threads" (step 2) are threads, not channels — name the forum channel type (GUILD_FORUM) and how its posts are searched, or drop it.
Address maintainer review feedback on PR #1484: - In tools/chat-discord/README.md: document concrete MCP server (chrishayuk/discord-mcp), store token under $HOME (~/.config/apache-magpie/discord-token), specify bot permissions (VIEW_CHANNEL, READ_MESSAGE_HISTORY) and privileged intents (MESSAGE_CONTENT, GUILD_MEMBERS). - In tools/chat-discord/operations.md: clarify that bot tokens cannot read OAuth connected accounts or bios, returning confirmed_by: null; check VIEW_CHANNEL permissions on channels and parent categories; honor channels argument in search_messages(). - In docs/labels-and-capabilities.md: update MCP entry to match tool README with Discord MCP (chrishayuk/discord-mcp). Generated-by: Antigravity
potiuk
left a comment
There was a problem hiding this comment.
The resolve_user, channels-argument, and channel-visibility fixes look right — three of the four threads are resolved on my side. Two things still block this, both inline: the README now points at a Discord MCP server (chrishayuk/discord-mcp) whose repository returns 404, and the branch conflicts with main in the generated vendor-neutrality block, so no CI has run.
Smaller observations
- The eval gap from the last review is still open:
docs/adapters/authoring.mdstep 5 asks for one; a community-signals fixture withkind: discordwould cover it. operations.md:27checks the@everyoneoverwrite on the channel and its category but not the guild-level@everyonerole permission. On a server where@everyonelacksVIEW_CHANNELat the guild level, every channel would pass as public. Worth folding the base role permission into the rule.operations.md:45builds message URLs from<guild_id>, butchat.guild_idis optional in the README config — please say where it comes from when unset.- Stack order still applies: this needs to land before #1485, which flips the
discordstatus ontools/chat/README.md.
This review was drafted by an AI-assisted tool and
confirmed by an Apache Magpie maintainer. After you've
addressed the points above and pushed an update, an Apache Magpie
maintainer — a real person — will take the next look
at the PR. The findings cite the project's review criteria;
if you think one of them is mis-applied, please reply on the
PR and a maintainer will weigh in.More on how Apache Magpie handles maintainer review:
CONTRIBUTING.md.
|
|
||
| ## Prerequisites | ||
|
|
||
| - **Runtime:** Node.js 20+ — the backing tool is the Discord MCP server ([`chrishayuk/discord-mcp`](https://github.com/chrishayuk/discord-mcp)), registered at user scope: |
There was a problem hiding this comment.
major — https://github.com/chrishayuk/discord-mcp returns 404, so an adopter can't install the server this adapter depends on, and nothing ties the unpinned npx -y discord-mcp package to it. Please name a Discord MCP server that exists, confirm it exposes the tools operations.md calls (discord_list_channels, discord_search_members, discord_search_messages), and pin the version in the recipe (npx -y <package>@<version>) — unpinned npx -y pulls whatever is latest at run time. If no existing server exposes those tools under those names, rename the calls in operations.md to match the server you pick.
| claude mcp add discord -s user -- npx -y discord-mcp | ||
| ``` | ||
| - **CLIs:** `node` / `npx`. | ||
| - **Credentials / auth:** A Discord bot token stored under `$HOME` at `~/.config/apache-magpie/discord-token` (or in `$DISCORD_BOT_TOKEN`), never in the project tree. The bot application must be authorized for the project's server (guild) with: |
There was a problem hiding this comment.
minor — The claude mcp add discord -s user -- npx -y discord-mcp recipe passes no environment, and nothing reads ~/.config/apache-magpie/discord-token — as written, the server starts without credentials. Please show how the token reaches the server (an explicit -e DISCORD_TOKEN=…, or whatever variable the chosen server reads, sourced from the home-dir file), and whether the clean-env wrapper passes it through.
| <!-- BEGIN vendor-neutrality-score — generated by `uv run --project tools/vendor-neutrality-score vendor-neutrality-score --markdown`; do not edit by hand --> | ||
|
|
||
| **Overall vendor-neutrality score: 10/12 capability contracts (83%).** Generated by [`tools/vendor-neutrality-score`](../tools/vendor-neutrality-score/); re-run it to refresh this section. | ||
| **Overall vendor-neutrality score: 11/12 capability contracts (92%).** Generated by [`tools/vendor-neutrality-score`](../tools/vendor-neutrality-score/); re-run it to refresh this section. |
There was a problem hiding this comment.
major — This generated block conflicts with main, which now reads 10/13 capability contracts (77%); GitHub can't build the merge ref, so no CI has run on this PR. Please rebase onto main and regenerate with uv run --project tools/vendor-neutrality-score vendor-neutrality-score --markdown rather than hand-resolving (should land at 11/13), then prek run --all-files.
Part 1 of 2 in the
contract:chatDiscord adapter stack (next: #1485).Summary
contract:chatundertools/chat-discord/README.md.chrishayuk/discord-mcp), with credentials stored under$HOME(~/.config/apache-magpie/discord-token), specifying bot permissions (VIEW_CHANNEL,READ_MESSAGE_HISTORY) and privileged intents (MESSAGE_CONTENT,GUILD_MEMBERS).mcp__discord__*) intools/chat-discord/operations.mdforlist_channels(),resolve_user(), andsearch_messages():list_channels()checks@everyoneVIEW_CHANNELpermissions across channels and parent categories.resolve_user()notes bot tokens cannot read OAuth accounts/bios, returning candidate members withconfirmed_by: null.search_messages()scopes search to explicitly requested channels when provided.docs/labels-and-capabilities.mdtoDiscord MCP (chrishayuk/discord-mcp).tools/chat-discord/**tocontract:chatin.github/labeler.yml.Type of change
tools/<system>/*.md)prek, workflows, validators)Test plan
tools/chat-discord/README.mdandoperations.mdconform to tool metadata and prerequisite requirements.skill_and_tool_validator.validate_toolsreports 0 violations fortools/chat-discord.vendor_neutrality_score.load_toolssuccessfully detects and loadstools/chat-discordas an implementation forcontract:chat.generate-labeler-config.pyruns cleanly and regenerates.github/labeler.yml.doctocTOC generation and SPDX license validation.RFC-AI-0004 compliance
contract:chatinterface.Linked issues
Refs #1421
🤖 Generated with Antigravity