Skip to content

Architecture

Trace a tool call from MCP input to Discord REST. Tools live in a Sapphire-style registry and pass through six middleware stages: telemetry → default guild → validation → category gate → preconditions → audit. The REST adapter adds bulkhead, circuit-breaker, retry, and timeout policies. Optional Gateway mode emits notifications for five URI keys and falls back to REST-only startup when the Gateway connection cannot boot.

graph TD
Client[MCP client] --> Transport[InMemoryTransport / stdio]
Transport --> Server[McpServer]
Server --> MW[Middleware chain]
MW --> Tool[Tool piece]
Tool --> REST[Resilient REST adapter]
REST --> Discord[Discord REST API]
Tool -. optional .-> Sampling[Client LLM via sampling]
Server -. optional .-> Gateway[Gateway client]
Gateway --> DiscordWS[Discord Gateway WebSocket]
  • MCP client sends JSON-RPC tools/call over stdio.
  • Transport owns JSON-RPC framing; production uses stdio, tests use InMemoryTransport.
  • McpServer bridges MCP to the piece registry and hosts the middleware, tool, precondition, and resource stores.
  • Middleware chain applies telemetry, default guild, validation, category gate, preconditions, and audit before execution.
  • Tool piece implements one of the 192 tools, using Discord REST or, for intelligence, MCP sampling back to the client.
  • REST adapter wraps @discordjs/rest in Cockatiel bulkhead, circuit-breaker, retry, and timeout policies.
  • Gateway client is optional under --gateway; it emits notifications for five URI keys but does not add resource list/read handlers.

discord-mcp uses Sapphire’s explicit “piece + store” model. Tool and Precondition classes are registered by server.ts; boot does not scan the filesystem. The stores provide lookup by name, while the container supplies the configured REST client, logger, and config to tool pieces.

This keeps tool construction consistent, but registration is intentionally explicit: adding a tool also requires adding it to server.ts.

packages/
mcp-core/ # Tools, middleware, resilience policy
src/
tools/ # 192 tool definitions
middleware/ # 6 stages + compose
preconditions/ # ConfirmRequired, CategoryEnabled
pieces/ # Tool and Precondition base classes
stores/ # Tool/precondition lookup + resources
rest/ # Cockatiel-wrapped @discordjs/rest
gateway/ # Optional discord.js client
pipeline/ # mcp_pipeline executor
errors/ # Error hierarchy + formatErrorForUser
audit/ # Audit sinks + redaction
telemetry/ # OTel boot + metrics
mcp-server/ # CLI and stdio transport wiring

mcp-core has no transport assumptions. mcp-server is the thin shell that wires it to stdio, OpenTelemetry, and signal handling.

Sources: server.ts, Tool.ts, and ToolStore.ts.

If you’re a contributor, start with the system design above, then jump to the subsystem you’re touching. The deep-dive pages each link to source files via GitHub permalinks so you can read implementation in a tab.

If you’re an operator trying to understand a production behavior, the fastest path is usually:

  1. Look up the env var or error code on the relevant Operations page.
  2. Follow that page’s “Related” links into the architecture deep-dive.
  3. Use the source-map table at the bottom of the architecture page to find the exact file responsible.

The architecture pages assume familiarity with Discord’s API model and basic TypeScript. We do not re-explain MCP itself - see modelcontextprotocol.io for that.

  • Get started - install and run the server.
  • Tools - auto-generated reference for all 192 tools.
  • Recipes - multi-tool workflows that exercise these subsystems.
  • Operations - production-running concerns: telemetry, resilience, audit, client matrix.