This Discord MCP server has 7 tools with visible Zod schemas and basic descriptions. However, the implementation exhibits significant quality gaps typical of community servers. Most tool descriptions are under 20 chars (baseline 194 chars for production tools), parameter descriptions are generic or missing, output schemas are not documented, and error handling provides no recovery guidance. The server accepts both names and IDs (good UX), but the parameter design is inconsistent across tools (e.g., 'server' is optional everywhere, creating ambiguity). No tool annotations, no explicit output schema documentation, and no validation of constraints within tool code. The code is readable but patterns from the 54 Agentic Tool Patterns are largely absent.
Create a new message listener with keywords and a predefined response handler
List all available response handlers
List all active message listeners
Read recent messages from a Discord channel
Register slash commands for a Discord bot
Remove an existing message listener
Send a message to a Discord channel
Parameter descriptions are consistently terse (average 35 chars vs. baseline 72 chars). Most lack format constraints, expected ranges, or examples of valid values. Baseline: 100% of A+ tools have descriptions on every param; this server is ~60-70%.
Tool descriptions are all under 50 characters (baseline 194 chars, p90=392). None explain WHEN to use the tool, what happens, or error recovery paths. Pattern says: 'Write descriptions as if prompt-engineering. State WHAT the tool does, WHEN to use it, and any prerequisites.'
Inferred effective spec: <=2025-11-25.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-22 | F | 45 | <=2025-11-25 | v2 |
| 2026-03-09 | F | 45 | - | v1 |
Output schemas are not documented in tool registration. All output is built inside execute() handlers and returned as strings or JSON, but no formal schema is declared to the MCP client. LLMs cannot plan downstream calls without knowing what fields to expect. Pattern: 'Document the output schema. LLMs need to know what fields to expect so they can plan downstream tool calls.'
The 'handlerOptions' parameter in create_listener is z.any() with no schema constraints. This violates pattern:constrained-input: 'When a parameter accepts one of a known set of values, declare it as an enum.' An LLM will struggle to provide valid values without knowing the shape. Either enumerate valid options or document the structure with examples.
Error handling provides no recovery guidance. All errors throw UserError with generic messages like 'Failed to send message: <error>'. Pattern:recovery-guide states: 'Error responses must tell the LLM what to do next.' Examples: if channel not found, suggest 'call list_channels()'; if token invalid, say 'check DISCORD_TOKEN config'; if listener not found, suggest 'call list_listeners() first'.
No tool annotations. MCP spec includes readOnlyHint, destructiveHint, and idempotentHint to help LLMs reason about side effects. read_messages should have readOnlyHint=true; send_message and register_commands should have destructiveHint=true. list_listeners and list_handlers are idempotent. These are part of the current MCP spec (2026-07-28).
Destructive operations (send_message, register_commands, create_listener, remove_listener) have no dry-run, confirmation, or recovery option. Pattern:confirmation-request says: 'Irreversible operations (delete, send, publish) should support a dry-run or confirmation step.' At minimum, add a 'dry_run' boolean param to send_message and register_commands.
The 'server' parameter is optional on almost all tools. Pattern:chat-data-model states: 'Users operate with names, titles, and natural language, not internal IDs.' The current design allows omission of server, but then the tool must reliably resolve to 'the one server the bot is in.' This works for single-server setups but will confuse multi-server agents. Either: (a) make 'server' required and document the resolution order (name first, then ID), or (b) add a 'discover_servers' tool and make server required everywhere.
No batch variants for tools agents may call in loops. If an agent wants to send a message to 10 channels, it must invoke send_message 10 times instead of one send_messages_batch() call. Pattern:composition says: 'Offer batch variants for tools agents call in loops.' This is a lower-severity gap but wastes tokens and latency.