discord-py-self-mcp
Bridges an AI assistant with a personal Discord user account via a selfbot, enabling reading and sending messages, managing DMs, channels, threads, roles, permissions, invites, reactions, presence, voice channels, and slash commands/buttons/modals, plus server setup tools such as AutoMod, channels, roles, and bot authorization.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@discord-py-self-mcpcheck my unread DMs and reply to the last one"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Devino Solutions fork. Adds a hardened always-on Windows service: a loopback-only Streamable HTTP endpoint behind a local bearer token, DPAPI-encrypted credentials, an allowlist of reviewed tools with a no-deletion policy, server-setup tools (AutoMod, roles, channels, bot authorization), and an AFK session so the account's phone keeps getting push notifications. See LOCAL_SETUP.md. Upstream: Microck/discord.py-self-mcp.
Automating a user account violates Discord's Terms of Service and can get the account restricted or banned. Use at your own risk.
quick start
this is a local mcp server (stdio transport). your mcp client spawns it as a process, and you provide secrets (like DISCORD_TOKEN) via the client's env/environment config.
manual run:
DISCORD_TOKEN="your_discord_token_here" python3 -m discord_py_self_mcp.mainimportant: automating user accounts is against the Discord ToS. use this at your own risk.
overview
discord-py-self-mcp acts as a bridge between your ai assistant (Claude Code, OpenCode, Codex, etc) and your personal discord account. unlike standard bots, this "selfbot" runs as you; allowing your ai to read your dms, reply to friends, manage your servers, and interact with buttons/menus just like a human user.
built on the discord.py-self library by dolfies.
quick installation
paste this into your llm agent session:
Install and configure discord-selfbot-mcp by following the instructions here:
https://raw.githubusercontent.com/Microck/discord.py-self-mcp/refs/heads/master/INSTALL.mdnpm (recommended)
npm install -g discord-selfbot-mcp
discord-selfbot-mcp-setupmanual installation
prerequisites:
python 3.10+
uv(recommended) orpipvoice support (linux only):
libffi-dev(orlibffi-devel),python-dev(e.g.python3-dev)
install:
uv tool install git+https://github.com/Microck/discord.py-self-mcp.git
# or
pip install git+https://github.com/Microck/discord.py-self-mcp.gitnote: voice dependencies (PyNaCl) are included by default. on linux, ensure system packages are installed first.
npm installation (node.js wrapper)
prerequisites:
node.js 18+
python 3.10+
install:
npm install -g discord-selfbot-mcpthe npm package is a wrapper that uses the underlying python implementation.
how it works (setup wizard)
run the interactive setup script to extract your token and generate the mcp config json (it can also write to common client config files and creates a backup before editing).
# if using npm
discord-selfbot-mcp-setup
# if using python (uv/pip)
python3 -m discord_py_self_mcp.setupextract token: grabs your token from an open browser session (playwright) or via manual entry
generate config: prints the mcp configuration json (and can write it to your client config)
configure: paste the config into your mcp client settings
manual configuration
for the default stdio transport, configure the server as a local command and pass the token via env (not url/headers).
examples:
mcp.example.jsonmcp.python.example.json.env.example
npm wrapper (recommended):
{
"mcpServers": {
"discord-py-self": {
"command": "discord-selfbot-mcp",
"env": {
"DISCORD_TOKEN": "${DISCORD_TOKEN}"
}
}
}
}python (uv tool):
{
"mcpServers": {
"discord-py-self": {
"command": "uv",
"args": ["tool", "run", "discord-py-self-mcp"],
"env": {
"DISCORD_TOKEN": "${DISCORD_TOKEN}"
}
}
}
}python (pip / venv):
{
"mcpServers": {
"discord-py-self": {
"command": "python3",
"args": ["-m", "discord_py_self_mcp.main"],
"env": {
"DISCORD_TOKEN": "${DISCORD_TOKEN}"
}
}
}
}if your client does not expand
${DISCORD_TOKEN}, replace it with the literal token value.
streamable HTTP transport
The default transport is stdio. For clients or local services that need a persistent endpoint, start the same MCP server with Streamable HTTP instead:
python3 -m discord_py_self_mcp.main --transport streamable-http --host 127.0.0.1 --port 7781This exposes the MCP endpoint at http://127.0.0.1:7781/mcp. The listener is
localhost-only by default; place an authenticated reverse proxy or tunnel in
front of it if remote access is required. MCP_TRANSPORT, MCP_HOST, and
MCP_PORT provide equivalent environment-based configuration.
features
powered by the robust discord.py-self library.
category | tools | description |
system | 2 | get_user_info, list_guilds |
messages | 6 | send_message, read_messages, search_messages, edit_message, delete_message, get_message_attachments |
channels | 3 | create_channel, delete_channel, list_channels (bulk and compact summary modes) |
dms | 2 | list_dm_channels, list_unread_dms |
pings | 2 | list_pings, mark_message_read |
voice | 2 | join_voice_channel, leave_voice_channel |
relationships | 4 | list_friends, send_friend_request, add_friend, remove_friend |
presence | 2 | set_status, set_activity |
interactions | 8 | send_slash_command, click_button, select_menu, submit_modal, list_ephemeral_messages, list_application_commands, send_user_command, send_message_command |
threads | 5 | create_thread, send_thread_message, list_active_threads, read_thread_messages, archive_thread |
members | 5 | kick_member, ban_member, unban_member, add_role, remove_role |
roles | 6 | list_roles, get_role, create_role, edit_role, delete_role, reorder_roles |
permissions | 7 | set_role_permissions, get_channel_permissions, set_channel_permissions, patch_channel_permissions, remove_channel_permissions, set_category_permissions, inspect_effective_permissions |
invites | 3 | create_invite, list_invites, delete_invite |
profile | 1 | edit_profile |
server folders | 6 | list_server_folders, create_server_folder, move_server_to_folder, rename_server_folder, reorder_server_folders, apply_server_folder_layout |
server discovery | 3 | get_server_overviews, sample_server_content, analyze_server_sidebar |
reactions | 2 | add_reaction, remove_reaction |
discrawl | 7 | run_discrawl, discrawl_doctor, discrawl_status, discrawl_sync, discrawl_search, discrawl_messages, discrawl_mentions |
roles and permissions
list_roles returns every role as JSON (id, name, color, position, permission
bitfield) sorted highest-first. Run it before any restructuring — position is
guild-wide, so moving one role reindexes the others and the dump is your only
way back.
create_role and edit_role take color as a hex string (#5865F2) or an
integer, and permissions as either a raw bitfield string or a list of flag
names (["manage_roles", "kick_members"]). edit_role only touches the fields
you pass. reorder_roles moves several roles in one call and falls back to
sequential edits when the bulk endpoint is unavailable.
Role edits are bounded by hierarchy: your account cannot change a role at or above your own highest role. Discord answers that with a bare 403, so these tools check position locally first and say which role is blocking. Guild owners are exempt.
set_channel_permissions replaces an overwrite wholesale, so any flag you do
not pass is lost. When an overwrite already exists and you only mean to change
one flag, use patch_channel_permissions — it takes a map of flag to
true/false/null and leaves everything else in that entry untouched. Because a
wholesale write with neither allow nor deny would quietly wipe the entry,
both setters require at least one of the two and reject a flag listed in both;
remove_channel_permissions is the way to drop an overwrite on purpose.
Role moves are checked twice before anything is sent: the role must sit below your own highest role, and so must the position you are moving it to. Both are compared with discord's own role ordering rather than raw position numbers, since positions can tie and are broken by id.
For channel access, set_channel_permissions writes one overwrite and
set_category_permissions writes the category plus, by default, every channel
inside it (sync_children: false to skip). inspect_effective_permissions
resolves a role or member against every channel and reports what they can
actually see — useful for checking a change landed the way you meant.
Flag names are accepted in either spelling on input, but the allowed /
denied lists in JSON output use discord.py-self's canonical names — so
view_channel comes back as read_messages.
direct messages
list_dm_channels enumerates your open 1:1 and group DM channels so you can
discover a channel_id instead of needing to know it in advance. Each row is
<channel_id> - [dm|group] <recipient display> (id=<user_id>) [BOT]. Optional
args: include_groups (default true) and name_contains (case-insensitive
filter on recipient name/handle), e.g. find the DM with a person by name and
feed the id straight into read_messages / send_message.
server discovery and folders
analyze_server_sidebar is the recommended first step when organizing a large
server list. It returns the current folder layout alongside each server's
description, member count, permissions, and a compact channel summary. Set
include_recent_messages: true to sample high-signal channels such as
announcements, general, FAQ, and updates; likely ticket and log channels are
skipped by default.
Use get_server_overviews for selected servers or sample_server_content when
you only need message evidence. list_channels also accepts guild_ids and a
mode: "summary" option, which collapses repeated ticket-style channels unless
include_repetitive is set.
For writes, use apply_server_folder_layout to create, rename, recolor, and
move several folders in one settings update. First call it with dry_run: true;
the response lists each creation, rename, recolor, move, and empty folder that
would be removed. Servers omitted from the request stay in their current place.
The service logs each settings write by operation count and data version, never
message content or account secrets.
slash commands
send_slash_command invokes an application command in a channel or DM. Pass
application_id (the bot's user/application ID) for reliable resolution; in a DM
with a bot it is inferred automatically. The command and any options are
resolved from the application's registered command list
(GET /applications/{id}/commands), which works for ordinary guild-installed
bots whose commands the per-channel / search index does not return. Subcommands
are space-separated in command_name (e.g. "config set"). Example:
{
"channel_id": "123456789012345678",
"command_name": "remind",
"application_id": "987654321098765432",
"options": { "text": "stand up", "when": "in 10 minutes" }
}context menu commands
list_application_commands shows everything a channel offers — slash commands
plus the user and message commands that live in the right-click "Apps" menu:
{ "channel_id": "123456789012345678", "kind": "all" }invoke them with send_user_command (targets a user) or
send_message_command (targets a message):
{
"channel_id": "123456789012345678",
"user_id": "987654321098765432",
"command_name": "Report User"
}a name is only matched within its own kind, so a user command never satisfies
send_message_command. pass application_id when two apps register the same
name.
modals
when a button or slash command opens a modal, click_button reports the
modal's custom_id and its fields instead of a bare "Button clicked". feed
those into submit_modal:
{
"custom_id": "auth_profile:ABC123",
"values": { "profile_username": "your_username" }
}pending modals are held for the session (up to 16 at a time) and are consumed on submit. a modal is put back when the submit is rejected — unknown field ids, missing required fields, or a failed send before anything reached discord — so you can fix the values and retry without clicking the button again. once the answers have been sent the entry stays consumed, because a second attempt would submit the interaction twice. discord expires the underlying interaction after roughly 15 minutes; if that happens, click the button again.
ephemeral replies
most bots answer a click or a slash command with an ephemeral reply — the
private "only you can see this" message. discord never persists those, so
read_messages cannot see them and fetch_message returns 404. they do
arrive over the gateway, so list_ephemeral_messages reads them out of the
cache and click_button / select_menu fall back to the cache when the REST
fetch 404s. that makes multi-step flows reachable:
click_button(panel) -> bot replies ephemerally
list_ephemeral_messages(channel) -> message_id + its buttons
click_button(that message_id, ...) -> next ephemeral steponly replies received while this server was connected are cached.
discrawl integration
Use run_discrawl to execute local discrawl commands directly from MCP.
Use typed tools for common operations (discrawl_sync, discrawl_search, discrawl_messages, etc.) when you want structured params.
By default this MCP uses the Microck fork at ../discrawl-self/bin/discrawl:
https://github.com/Microck/discrawl-self. It does not silently fall back to a
global discrawl from PATH; set DISCRAWL_BIN or the tool binary argument
when you intentionally want another executable.
Example tool call payload:
{
"command": "sync",
"args": ["--guild", "1234567890", "--since", "2026-03-01T00:00:00Z"],
"config_path": "~/.discrawl/config.toml"
}Typed tool payload example:
{
"tool": "discrawl_sync",
"args": {
"guild": "1234567890",
"since": "2026-03-01T00:00:00Z",
"full": true,
"config_path": "~/.discrawl/config.toml"
}
}Optional env var:
DISCRAWL_BIN- custom path to discrawl executable. This overrides the default Microck fork lookup.
attachment access
Use get_message_attachments when a message contains files or images you need to inspect directly.
It returns attachment metadata for the target message and can stream image/file content back through MCP outputs.
comparison
feature | discord-py-self-mcp | discord.py-self (Lib) | Maol-1997 | codebyyassine | elyxlz |
read messages | ✅ | ✅ | ✅ | ✅ | ✅ |
send messages | ✅ | ✅ | ✅ | ✅ | ✅ |
list guilds | ✅ | ✅ | ✅ | ✅ | ✅ |
list channels | ✅ | ✅ | ✅ | ✅ | ✅ |
get user info | ✅ | ✅ | ✅ | ✅ | ❌ |
search messages | ✅ | ✅ | ❌ | ❌ | ❌ |
create channels | ✅ | ✅ | ❌ | ✅ | ❌ |
delete channels | ✅ | ✅ | ❌ | ✅ | ❌ |
edit messages | ✅ | ✅ | ❌ | ❌ | ❌ |
delete messages | ✅ | ✅ | ❌ | ❌ | ❌ |
join voice | ✅ | ✅ | ❌ | ❌ | ❌ |
manage friends | ✅ | ✅ | ❌ | ❌ | ❌ |
manage threads | ✅ | ✅ | ❌ | ❌ | ❌ |
slash commands | ✅ | ✅ | ❌ | ❌ | ❌ |
click buttons | ✅ | ✅ | ❌ | ❌ | ❌ |
select menus | ✅ | ✅ | ❌ | ❌ | ❌ |
submit modals | ✅ | ✅ | ❌ | ❌ | ❌ |
ephemeral replies | ✅ | ✅ | ❌ | ❌ | ❌ |
context menu commands | ✅ | ✅ | ❌ | ❌ | ❌ |
kick/ban | ✅ | ✅ | ❌ | ❌ | ❌ |
invites | ✅ | ✅ | ❌ | ❌ | ❌ |
profile edit | ✅ | ✅ | ❌ | ❌ | ❌ |
setup wizard | ✅ | ❌ | ❌ | ❌ | ❌ |
captcha solver | ✅ | ❌ | ❌ | ❌ | ❌ |
✅ = supported
❌ = not supported
🚧 = planned / in progress
captcha solving (experimental)
automatically solves hCaptchas when encountered (e.g., joining servers, dms). built upon QIN2DIM/hcaptcha-challenger - an AI-powered hCaptcha solver using vision models.
warning: this feature is experimental. use at your own risk.
requirements:
Gemini API Key: Required for AI vision. Get from Google AI Studio. Set
GEMINI_API_KEYin your mcp clientenv.Playwright: Required for browser automation.
playwright install chromium --with-deps
optional:
CAPTCHA_PROXY: proxy url for solving hCaptcha challenges.TEMP_DIR: Directory for temporary model files (default:/tmp/hcaptcha)
rate limiting (recommended)
built-in rate limiting to prevent account bans. configurable via environment variables.
configuration:
variable | default | description |
|
| Enable/disable rate limiting |
|
| Max messages per minute |
|
| Max messages per second |
|
| Max actions (joins, etc.) per minute |
|
| Cooldown duration when limit hit (seconds) |
rate limiting is enabled by default to reduce ban risk. Only disable it if you are deliberately taking responsibility for raw Discord API pacing yourself.
troubleshooting
problem | solution |
token invalid | run the setup script again to extract a fresh one |
missing dependencies | ensure |
playwright error | run |
audioop error | ensure |
camoufox missing | run |
voice error | install |
project structure
discord_py_self_mcp/
├── bot.py
├── main.py
├── setup.py
├── rate_limiter.py
├── tool_utils.py
├── cli_runtime.py
├── logging_utils.py
├── captcha/
│ └── solver.py
└── tools/
├── channels.py
├── dms.py
├── discrawl.py
├── embed.py
├── guilds.py
├── interactions.py
├── invites.py
├── members.py
├── messages.py
├── permissions.py
├── presence.py
├── profile.py
├── reactions.py
├── registry.py
├── relationships.py
├── roles.py
├── threads.py
└── voice.pyskill cli mode (optional)
in addition to the mcp server, this package also provides a skill/cli mode for command-line usage with a persistent daemon. this is useful for scripts or when you need faster execution without the mcp protocol overhead.
quick start:
# install (same package)
npm install -g discord-selfbot-mcp
# create .env file
echo "DISCORD_TOKEN=***" > .env
# use skill mode (from package directory)
python3 scripts/dcli.py send-message --channel 123 --content "Hello!"key commands:
python3 scripts/dcli.py daemon start # start the daemon
python3 scripts/dcli.py daemon status # check daemon status
python3 scripts/dcli.py send-message --channel CHANNEL_ID --content "Hello"
python3 scripts/dcli.py list-guilds
python3 scripts/dcli.py read-messages --channel CHANNEL_ID --limit 20
python3 scripts/dcli.py get-message-attachments --channel CHANNEL_ID --message MESSAGE_ID
python3 scripts/dcli.py get-message-attachments --channel CHANNEL_ID --message MESSAGE_ID --download --output-dir ./attachmentswhen to use skill mode:
command-line scripting
faster execution (persistent connection)
automation tasks
when mcp is not needed
see SKILL.md for detailed documentation.
license
this project is licensed under the mit license.
contributing
issues and pull requests are welcome at github.com/Microck/discord.py-self-mcp.
fork the repository
create a feature branch (
git checkout -b feature/my-feature)commit your changes (
git commit -m 'add my feature')push to the branch (
git push origin feature/my-feature)open a pull request
please ensure tests pass (pytest) before submitting.
This server cannot be deployed
Maintenance
Related MCP Connectors
Remote streamable-HTTP MCP server running on a single Cloudflare Worker. Your assistant gets live Airbnb, Amazon, Booking.com, Google Flights, Maps and Reddit data, social search on X, Instagram and TikTok, the Meta Ad Library, and image/video generation without any keys. Connect your own accounts to let it send WhatsApp or Telegram messages, work an IMAP inbox, manage Meta Ads campaigns and publish to X and LinkedIn. OAuth 2.1 with PKCE; stored credentials are AES-256-GCM encrypted.
Remote Desktop Commander: use files, terminal and processes on your own computers from any AI app.
Operate Linux, macOS and Windows from your LLM. Every action runs through an auditable allowlist.
Give your AI hands. Identity, credential vault, and API gateway for autonomous agents.
Related MCP Servers
- AlicenseNot gradedqualityBmaintenanceEnables web-based AI agents such as claude.ai, ChatGPT and Grok to read and edit files and run allowlisted shell commands on your own machine, plus control Chromium, DevTools, ports, git, SQLite and background tasks. Access is exposed over HTTPS with OAuth 2.1 through a swappable public edge (Tailscale Funnel or a Cloudflare tunnel), with a loopback-only control panel for configuration.MIT
- AlicenseNot gradedqualityBmaintenanceEnables an AI assistant to run tasks on a hosted cloud desktop that belongs to the user, with a browser that stays signed in to their accounts, its own email address, and its own files, so it can fill forms, download and edit documents, and carry out long jobs that outlast a chat reply, returning answers with screenshots and recordings. It also exposes tools for checking current activity, task history, sent mail, interrupting a run, and saving or recalling notes, reached over OAuth-authenticated Streamable HTTP or a stdio bridge.MIT
- AlicenseNot gradedqualityAmaintenanceA local MCP server that lets AI coding tools drive the user's real, already-logged-in Chrome — reading pages, clicking, typing, uploading files, taking screenshots, and inspecting tabs, cookies, console, and network traffic — via 25 browser automation tools that pass bot detection without a debugging port. Requires a companion Chrome extension and stays entirely on the user's machine.3 npmISC
- FlicenseNot gradedqualityAmaintenanceExposes a governed, OAuth-gated suite of 38 tools that let web AI assistants like Claude, ChatGPT, and Grok work directly on your local machine — reading and editing files, running whitelisted shell commands, searching, querying SQLite, driving browsers and DevTools, managing background tasks and localhost services, and controlling Git, clipboard, notifications, and Postman. This lets users build, debug, and maintain projects, inspect databases and local APIs, and check on long-running jobs from a browser or phone without granting unrestricted shell access.-