Discord MCP vs Cv MCP Server — MCP Server Comparison | AllMCPs
Side-by-Side Model Context Protocol Comparison
Discord MCP vs Cv MCP Server
In-depth architectural comparison of the Discord MCP and Cv MCP Server MCP servers. Compare execution transports, security boundaries, tool capabilities, quality scores, and ready-to-paste client installation snippets for Claude, Cursor, Windsurf, and VS Code.
At a Glance & Executive Verdict
Discord MCP
Communication · Local stdio
Quality: 67/100 (Great) | Auth: API Key required
Cv MCP Server
Communication · Local stdio
Quality: 65/100 (Great) | Auth: other
Verdict Summary: Choose Discord MCP if you need specialized Communication tools running via a local process. Choose Cv MCP Server if your workspace requires Communication integration with local subprocess execution. Both servers can be configured concurrently in your client's mcpServers manifest.
Which MCP Server Should You Choose?
Choose Discord MCP when:
You need dedicated capabilities in the Communication domain.
You prefer local stdio subprocess transport architecture.
Your security boundary fits: API Key required (Free / Open Source).
You have access to required keys: DISCORD_TOKEN, DISCORD_MESSAGE_CONTENT, DISCORD_GUILD_MEMBERS, DISCORD_MCP_TOOLSETS, DISCORD_ALLOWED_GUILDS.
Lightweight multi-guild Discord MCP server with 60+ tools for messages, channels, roles, forums, webhooks, and moderation.
MCP Server that connects AI Agents to Carbon Voice. Create, manage, and interact with voice messages, conversations, direct messages, folders, voice memos, AI actions and more in Carbon Voice.
List every Discord server (guild) the bot is a member of (id, name, member count, icon). Takes no arguments. Read-only. Start here to discover the guild_id needed by most other tools.
discord_get_guild_info
Get details about one server: name, description, member/channel/role counts, boost tier, owner, and creation date. Read-only. Use discord_get_server_stats for a finer breakdown (humans vs bots, channel types).
discord_list_channels
List all channels in a server, grouped by their parent category and ordered by position. Returns a JSON object keyed by category name. Read-only. Use discord_find_channel_by_name to locate a specific channel.
discord_find_channel_by_name
Find channels whose name contains a substring (case-insensitive). Returns matching channels (id, name, type) as a JSON array. Read-only. Useful for resolving a channel_id when you only know the channel's name.
discord_read_messages
Ready-to-Paste Client Configurations
Paste either (or both) of these JSON server blocks into your client config file (e.g. claude_desktop_config.json or ~/.cursor/mcp.json).
Discord MCP is categorized under Communication and uses a local stdio subprocess. In contrast, Cv MCP Server belongs to Communication using local stdio subprocess. Select Discord MCP when you need capabilities focused on communication and Cv MCP Server when you require tools for communication.
Read messages from a text channel or thread, oldest-to-newest. Page backwards by re-calling with before set to the id of the oldest message you received, which walks a channel past the 100-message per-call cap. Requires the View Channel and Read Message History permissions. Returns { messages: [...] } with id, author, content, timestamp, attachment count, pinned flag. Use discord_search_messages to filter by keyword, or discord_fetch_pinned_messages for pinned messages only.
discord_send_message
Send a plain-text message to a channel or thread. For rich content (title, color, fields, images) use discord_send_embed; to attach a reply reference to an existing message use discord_reply_message. Requires the bot to have the Send Messages permission. Returns the new message ID.
discord_reply_message
Reply to a specific message, attaching a reply reference so clients show it as a threaded reply. Use discord_send_message for a standalone message with no reference. Requires the Send Messages permission. Returns the new reply's message ID.
discord_edit_message
Edit the text content of a message previously sent by this bot. Discord forbids editing other users' messages, so this fails for non-bot messages. Use discord_edit_embed for embed messages. Works in text channels and threads. Returns the edited message ID.
discord_add_reaction
Add a single emoji reaction to a message as the bot. Requires the Add Reactions and Read Message History permissions. Use discord_remove_reactions to undo. Idempotent: re-adding the bot's existing reaction has no effect.
discord_create_thread
Create a thread, either branching from an existing message (pass message_id) or as a standalone thread in a text channel (omit message_id). Standalone creation requires a parent text channel and fails if channel_id is itself a thread. Requires the Create Public Threads permission. Returns the new thread's ID.
discord_bulk_delete_messages
Permanently delete multiple recent messages in one call. IRREVERSIBLE. SAFE BY DEFAULT: dry_run is true unless explicitly set to false, so call it first to preview, then re-call with dry_run:false to actually delete. Discord only allows bulk-deleting messages younger than 14 days; older ones are skipped. Requires the Manage Messages permission. Returns the number deleted.
discord_send_embed
Send a single rich embed (title, description, color, fields, author, footer, images, timestamp). Use discord_send_message for plain text, or discord_send_multiple_embeds to send several embeds at once. Requires the Send Messages and Embed Links permissions. Returns the new message ID.
+87 more tools listed on main page
Cv MCP Server Tools (42)
list_messages
List messages with filtering by date, conversation, folder, workspace, creator or language.
USE WHEN: The general-purpose message reader; full bodies incl. transcript and AI summary. Max date span 183 days. `user_ids` filters by SENDER — for messages exchanged WITH someone, pass `conversation_id` from `list_conversations`. Use presigned URLs as-is.
USE INSTEAD: `get_recent_messages` for a quick look at the latest few (hard-capped at 10, no paging). `search_message_ids` for filters this cannot express — notified state, mentions or labels.
FIRST: `workspace_id` comes from `get_workspaces_basic_info` (field `id`) — call it first if you don't have one.
EXAMPLE: {"workspace_id":"ws-abc","start_date":"2026-09-01T00:00:00Z","size":25}
RETURNS: `{page, size, sort_direction, total, results_count, has_next_page, filters, results: [{id, transcript?, ai_summary?, audio_url?, creator_id, conversation_id?, duration_ms, reply_count, status, type, created_at, ...}]}`. Page on `has_next_page`/`total` — do not guess.
NARROW: pass response_fields ["total","has_next_page","results.id","results.transcript","results.created_at"] unless you need more — the full payload is much larger.
get_message
Get one message by ID, optionally expanded with related records.
USE WHEN: You have a message ID. `fields` ADDS related data (`conversation`, `creator`, `labels`) — it does not narrow the response. Use `response_fields` to narrow.
USE INSTEAD: `list_messages` when you do not have an ID, or need several messages — it already returns full bodies, so fetching each one again is wasted.
FIRST: `id` comes from `list_messages` (field `results[].id`) — call it first if you don't have one.
EXAMPLE: {"id":"msg-abc","fields":"creator"}
RETURNS: `{message: {id, transcript?, ai_summary?, audio_url?, creator_id, duration_ms, status, type, attachments?, created_at, ...}}`.
get_recent_messages
Get up to 10 of the most recent messages, each with its conversation, creator and labels.
USE WHEN: A quick "what just happened" glance. Pre-joined, so no follow-up calls for creator or conversation names.
USE INSTEAD: `list_messages` whenever you need more than 10, any date range, paging, or a filter other than conversation and language — this tool supports none of those.
EXAMPLE: {"conversation_id":"conv-abc"}
RETURNS: `{results: [{message: {...}, conversation: {...}, creator: {...}, labels: [...]}]}`. No total and no paging: the cap of 10 is the whole answer.
create_conversation_message
Post a message into an existing conversation, or reply in a thread.
USE WHEN: You have a `conversation_id`. Pass `parent_id` (a message ID) to reply as a thread. Either `transcript` or `links` is required — the schema marks neither individually, so both param descriptions say so.
USE INSTEAD: `create_direct_message` to reach people who are not already in a conversation. `create_voicememo_message` for a standalone memo.
FIRST: `id` comes from `list_conversations` (field `results[].id`) — call it first if you don't have one.
EXAMPLE: {"id":"conv-abc","transcript":"Agreed, shipping Friday."}
RETURNS: `{message: {id, link, transcript?, status, type, conversation_id, created_at, ...}}`.
ERROR BAD_REQUEST: Neither `transcript` nor `links` was provided. — Pass at least one of them.
create_direct_message
Send a direct message to one or more people, by user ID or email.
USE WHEN: Reaching people outside an existing conversation. Address it with `to.user_ids` or `to.emails`. Requires `transcript` or `links`.
USE INSTEAD: `create_conversation_message` when a conversation already exists — a DM starts a separate thread rather than joining it.
FIRST: `to.user_ids` comes from `search_users` (field `id`) — call it first if you don't have one.
EXAMPLE: {"to":{"user_ids":["user-abc"]},"transcript":"Quick question about the deck."}
RETURNS: `{message: {id, link, transcript?, status, conversation_id, created_at, ...}}`.
ERROR BAD_REQUEST: A user ID is invalid, or neither `transcript` nor `links` was provided. — Resolve people with `search_users` — never pass a display name as a user ID — and include a transcript or links.
create_voicememo_message
Create a voice memo, either from text (spoken via text-to-speech) or from an audio file at a URL.
USE WHEN: Pass `transcript` (2-5000 chars) to have Carbon Voice speak the text, or an https `audio_url` to upload audio, which wins over `transcript`. File it with `folder_id`, whose type must match, or a `workspace_id`.
USE INSTEAD: `create_conversation_message` to post into an existing conversation, or `create_direct_message` to send to specific people. A voice memo is standalone and lives in a folder or workspace.
EXAMPLE: {"transcript":"Reminder to review the pricing deck before Friday."}
RETURNS: `{message: {id, link, transcript?, audio_url?, duration_ms, status, type, created_at, ...}}`. `status` is often `processing` at first.
ERROR INVALID_AUDIO_URL: `audio_url` is not https, unreachable, too large, timed out, embeds credentials, or resolves to a private address. — The message gives the reason. Use a public https URL, or pass `transcript` instead.
ERROR BAD_REQUEST: None of `transcript`, `audio_url` or `links` was provided, or the transcript is outside 2-5000 characters. — Provide one of the three, and keep the transcript within the length limits.
add_attachments_to_message
Attach one or more link URLs to an existing message.
USE WHEN: Adding external links to a message that already exists.
USE INSTEAD: `create_message_share_link` to share a Carbon Voice message outward — that produces a link, this consumes them.
FIRST: `id` comes from `list_messages` (field `results[].id`) — call it first if you don't have one.
EXAMPLE: {"id":"msg-abc","links":["https://example.com/spec"]}
RETURNS: `{...}` confirmation with the resulting attachments.
get_user
Get a user's full profile by ID — names, languages, voice settings, workspace roles.
USE WHEN: You already have a user ID and need complete details.
USE INSTEAD: `search_user` / `search_users` to FIND someone by email, phone or name. `get_current_user` for the caller — this tool needs an explicit ID and will not default to you.
FIRST: `id` comes from `search_users` (field `id`) — call it first if you don't have one.
EXAMPLE: {"id":"user-abc"}
RETURNS: `{id, first_name, last_name?, languages, voice_gender, workspace_ids, workspace_roles, user_type, created_at, ...}`.
NARROW: pass response_fields ["id","first_name","last_name","workspace_ids"] unless you need more — the full payload is much larger.
search_user
Find a single user by email, phone or name.
USE WHEN: Resolving ONE person. Supply exactly one of `email`, `phone` or `name`. Name search only matches your own contacts.
USE INSTEAD: `search_users` for several people in one call — it takes arrays and saves a round trip per person. `get_user` when you already have the ID.
EXAMPLE: {"email":"someone@example.com"}
RETURNS: `{id, full_name, first_name, last_name?, link, image_url?, languages?, ...}`. Use `id` wherever another tool asks for a user ID.
ERROR NOT_FOUND: Nobody matched, or a name search hit a non-contact. — Try an email or phone instead of a name; name search is limited to your contacts.
search_users
Resolve several users at once by emails, phones, IDs or names.
USE WHEN: Turning a list of people into user IDs in one call — the right first step before any tool that takes user IDs. Name search only matches your contacts.
USE INSTEAD: `search_user` for a single lookup. `get_user` for a full profile once you have the ID.
EXAMPLE: {"names":["Brett"]}
RETURNS: Array of `{id, full_name, first_name, last_name?, link, languages?, ...}`. If a name returns more than one candidate, ask which person was meant rather than guessing.
NARROW: pass response_fields ["id","full_name"] unless you need more — the full payload is much larger.
get_current_user
Get the calling user's own identity, workspaces and settings.
USE WHEN: Establishing who you are acting as, or finding the caller’s workspace IDs before a workspace-scoped call. Takes no arguments.
USE INSTEAD: `get_user` for somebody else (it requires an explicit ID). `get_workspaces_basic_info` if you only need workspace IDs and names — it is far smaller than this response.
EXAMPLE: {}
RETURNS: `{success, user: {user_guid, first_name, last_name?, email_txt?, phone_txt?, workspace_guids, identities, entries, environments, lifecycle_events, notification_settings, settings, ...}, settings: {...}}`. This payload is LARGE — several unbounded arrays and an open settings map.
NARROW: pass response_fields ["user.user_guid","user.first_name","user.email_txt","user.workspace_guids"] unless you need more — the full payload is much larger.
list_conversations
List your conversations from the last 6 months, optionally filtered by participants, type and name.
USE WHEN: Finding a `conversation_id`. Filter with `user_ids` plus `match`, `types` and `name` — YOUR DM with someone is `user_ids: ["<their id>"], types: ["directMessage"]`. You are always an implicit participant, so never pass your own ID. Filters AND together; if several match, ask which was meant.
USE INSTEAD: `get_conversation` when you already have an ID and want full detail — this returns only id, name, workspace_id and type.
EXAMPLE: {"user_ids":["user-abc"],"types":["directMessage"]}
RETURNS: `{results_count, results: [{id, name, workspace_id, type}]}` where type is `directMessage` | `customerConversation` | `namedConversation` | `asyncMeeting`. No paging: `results_count` is what is returned, after filtering. `name` adds `unfiltered_count`: rows the name was matched against, AFTER `user_ids`/`types`. ALWAYS check it before saying no such conversation exists. 0 of 47 means none matched that string (misspelt, or >6 months old); 0 of 0 means your other filters left nothing — not that the caller has none. Widen the filters or ask; never report it does not exist.