Skip to content

CLI

The discord-mcp binary is the single entry point. Plan 9 split it into four sub-commands routed by commander:

Terminal window
discord-mcp <command> [options]

serve is the default sub-command — running discord-mcp with no command boots the stdio MCP server, equivalent to discord-mcp serve. The other three (doctor, init, migrate) are operator tools.

Source: packages/mcp-server/src/cli.ts.

FlagDescription
--versionPrint the package version and exit.
--helpPrint the help summary for the command.

--help works at every level — discord-mcp --help, discord-mcp doctor --help, etc. Each sub-command has its own option list described below.

Terminal window
discord-mcp serve [--gateway]
discord-mcp [--gateway] # default sub-command

Start the stdio MCP transport. Reads configuration from process.env (see Reference → Environment variables), wires the audit sink, and blocks until the parent agent disconnects.

FlagTypeDefaultDescription
--gatewaybooleanfalseEnable Discord Gateway resource subscriptions. Lazy-imports discord.js so cold-start without this flag stays minimal.
Terminal window
# Bare invocation — equivalent to `discord-mcp serve` (commander default).
discord-mcp
# Explicit serve.
discord-mcp serve
# With Gateway subscriptions enabled.
discord-mcp serve --gateway
# Bare form with the same flag (forwarded to serve through commander's
# default-subcommand passthrough).
discord-mcp --gateway
CodeMeaning
0Process never returns under normal stdio operation. The transport runs until the parent agent disconnects.
1Boot failure — typically invalid config (missing DISCORD_TOKEN, unparseable env). Error message goes to stderr.
Terminal window
discord-mcp doctor [--json] [--online]

Diagnose configuration, token, and connectivity issues. Runs a registry of checks (token format, env-var parse, audit sink, OTel config, etc.) and aggregates results into a single structured report.

FlagTypeDefaultDescription
--jsonbooleanfalseEmit machine-readable JSON instead of pretty TTY output. Use this in CI.
--onlinebooleanfalseRun online checks against Discord (requires a working DISCORD_TOKEN). Without this flag only offline checks run, so doctor stays cheap.
Terminal window
# Quick offline health check (no network calls).
discord-mcp doctor
# Same but JSON for CI.
discord-mcp doctor --json
# Verify the token is accepted by Discord.
DISCORD_TOKEN=Bot.xxx discord-mcp doctor --online
# Full online + JSON report — typical pre-deploy gate.
discord-mcp doctor --online --json | jq .
CodeMeaning
0All checks ok.
1At least one check returned warn, no fails.
2At least one check returned fail (e.g. invalid token, missing env).

The exit-code policy is uniform across doctor, init, and migrate: 0 = success, 1 = success-with-work-left, 2 = couldn’t run.

Terminal window
discord-mcp init [--client <id>] [--token <token>] [--gateway]
[--output <path>] [--force] [--json]

Generate an MCP client config snippet for a supported client. Either prints to stdout or writes to --output <path>.

FlagTypeDefaultDescription
--client <id>stringprompt if TTY, else genericTarget client id. One of claude-desktop, claude-code, cursor, generic.
--token <token>string${env:DISCORD_TOKEN} placeholderDiscord bot token. Warning: writes the value into the snippet unredacted. Omit to leave the env-var interpolation placeholder so users don’t accidentally commit a real secret.
--gatewaybooleanfalseAppend --gateway to the generated snippet so the server enables Gateway subscriptions on boot.
--output <path>string(stdout)Write the snippet to a file instead of stdout.
--forcebooleanfalseOverwrite the --output path if it already exists. Required to overwrite.
--jsonbooleanfalseEmit machine-readable JSON instead of pretty output. The snippet body is delivered under data.content.
Terminal window
# Interactive — prompts for client + token + gateway when stdin is a TTY.
discord-mcp init
# Non-interactive: print a Claude Desktop snippet with the token placeholder.
discord-mcp init --client claude-desktop
# Bake a real token into the snippet (NOT recommended for committed files).
discord-mcp init --client cursor --token "Bot.xxx.yyy.zzz"
# Write directly to Claude Desktop's config (force overwrite).
discord-mcp init --client claude-desktop \
--output ~/Library/Application\ Support/Claude/claude_desktop_config.json \
--force
# JSON for tooling.
discord-mcp init --client generic --json | jq .data.content
CodeMeaning
0Snippet generated (and written, if --output was used).
2Couldn’t run — unknown --client, --output path exists without --force.
Terminal window
discord-mcp migrate [--from <adapter>] [--source <path>] [--json]

Migrate from another Discord MCP setup. Plan 9 Phase E ships one adapter (hubdustry-go-mcp) and the framework is extensible — new adapters land in subsequent plans.

Run without --from to list available adapters and exit.

FlagTypeDefaultDescription
--from <id>string(none)Source adapter id. Run without this flag to list registered adapters.
--source <path>stringcwdPath to the source repo to migrate from. Defaults to the current working directory.
--jsonbooleanfalseEmit machine-readable JSON instead of pretty output.
Terminal window
# List available adapters (exits 2 — no --from given).
discord-mcp migrate
# Migrate from a Hubdustry Go MCP repo at the current directory.
discord-mcp migrate --from hubdustry-go-mcp
# Migrate from a sibling directory.
discord-mcp migrate --from hubdustry-go-mcp --source ../hubdustry-go-mcp
# JSON output for tooling — capture the full migration report.
discord-mcp migrate --from hubdustry-go-mcp --json > migrate-report.json
CodeMeaning
0Adapter ran AND every source tool was mapped cleanly (no unmapped, no manual review).
1Adapter ran but produced unmapped tools or items needing manual review. Successful run with work left — hand-edit the output.
2Couldn’t run — missing/unknown --from, source not detected at --source, IO failure.

doctor, init, and migrate all share the same emitResult(...) envelope. In pretty mode you see a TTY-friendly summary. In --json mode you get a single line of structured JSON with this shape:

{
"ok": true,
"exitCode": 0,
"summary": "<one-line summary>",
"details": ["<line>", "..."],
"warnings": [],
"errors": [],
"data": { /* command-specific payload */ }
}

This is the contract pipelines should consume. data is per-command (doctor’s data.checks array, init’s data.content, migrate’s data.result) and stable across versions within a major.