messages_read
Read recent messages from a Discord channel.
When to use
Section titled “When to use”- Catch up on a channel (“what was discussed in #X?”)
- Locate a specific message by content/author
Readable text
Section titled “Readable text”The human-readable MCP response derives text from original content, nested Text Display components in order, then embed author/title/description/fields/footer, inside <untrusted_discord_messages nonce="..."> tags. Attachment and media URLs are metadata only and are not fetched.
Rich fields are not truncated. Use a smaller limit with before/after for rich histories, or messages_get for one complete message.
Security
Section titled “Security”Fencing is defense-in-depth for the human-readable text path, not a prompt-injection guarantee. Treat every Discord-authored field-including raw structured content-as untrusted data and require approval before using it in consequential writes.
MCP call example
Section titled “MCP call example”Tool-authored shorthand:
{channel_id:"112233445566778899", limit:50}
{ "name": "messages_read", "arguments": { "channel_id": "123456789012345678" }}| Field | Type | Required | Constraints | Description |
|---|---|---|---|---|
channel_id |
string | yes | pattern: ^\d{17,20}$ |
Channel to read |
limit |
integer | no | default: 50; min: 1; max: 100 |
Messages to fetch (1-100, default 50) |
before |
string | no | pattern: ^\d{17,20}$ |
Get messages before this ID (older); mutually exclusive with after |
after |
string | no | pattern: ^\d{17,20}$ |
Get messages after this ID (newer); mutually exclusive with before |
Complete input JSON Schema
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "channel_id": { "type": "string", "pattern": "^\\d{17,20}$", "description": "Channel to read" }, "limit": { "default": 50, "description": "Messages to fetch (1-100, default 50)", "type": "integer", "minimum": 1, "maximum": 100 }, "before": { "description": "Get messages before this ID (older); mutually exclusive with after", "type": "string", "pattern": "^\\d{17,20}$" }, "after": { "description": "Get messages after this ID (newer); mutually exclusive with before", "type": "string", "pattern": "^\\d{17,20}$" } }, "required": [ "channel_id" ]}Returns
Section titled “Returns”{messages, count, channel_id, oldest_id, newest_id}. Each message is a selected projection, not the entire Discord message: {id, author_id, author_name, content, components?, embeds?, attachments?, flags?, timestamp, edited}. content is unchanged; rich fields are preserved in full when supplied by Discord, including unknown component types. Empty or absent upstream fields stay empty or absent.
Example structured result
Section titled “Example structured result”{ "messages": [ { "id": "123456789012345678", "author_id": "123456789012345678", "author_name": "Example name", "content": "Hello from discord-mcp", "timestamp": "2030-01-01T10:00:00.000Z", "edited": true } ], "count": 1, "channel_id": "123456789012345678"}Output schema
Section titled “Output schema”| Field | Type | Required | Constraints | Description |
|---|---|---|---|---|
messages |
array<object> | yes | ||
count |
number | yes | ||
channel_id |
string | yes | pattern: ^\d{17,20}$ |
Discord channel ID (snowflake) |
oldest_id |
string | no | pattern: ^\d{17,20}$ |
Discord message ID |
newest_id |
string | no | pattern: ^\d{17,20}$ |
Discord message ID |
Complete output JSON Schema
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "messages": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "pattern": "^\\d{17,20}$", "description": "Discord message ID" }, "author_id": { "type": "string", "pattern": "^\\d{17,20}$", "description": "Discord user ID" }, "author_name": { "type": "string" }, "content": { "type": "string", "description": "Original Discord content; may be empty for component-only messages" }, "components": { "description": "Complete raw Discord component tree", "type": "array", "items": { "type": "object", "properties": { "type": { "type": "integer" } }, "required": [ "type" ], "additionalProperties": {} } }, "embeds": { "description": "Complete raw Discord embeds", "type": "array", "items": { "type": "object", "properties": {}, "additionalProperties": {} } }, "attachments": { "description": "Raw attachment metadata; URLs are not fetched", "type": "array", "items": { "type": "object", "properties": {}, "additionalProperties": {} } }, "flags": { "description": "Original Discord message flags, when supplied", "type": "integer" }, "timestamp": { "type": "string" }, "edited": { "type": "boolean" } }, "required": [ "id", "author_id", "author_name", "content", "timestamp", "edited" ], "additionalProperties": false } }, "count": { "type": "number" }, "channel_id": { "type": "string", "pattern": "^\\d{17,20}$", "description": "Discord channel ID (snowflake)" }, "oldest_id": { "type": "string", "pattern": "^\\d{17,20}$", "description": "Discord message ID" }, "newest_id": { "type": "string", "pattern": "^\\d{17,20}$", "description": "Discord message ID" } }, "required": [ "messages", "count", "channel_id" ], "additionalProperties": false}Annotations
Section titled “Annotations”| Property | Value |
|---|---|
| Read-only | yes |
| Destructive | no |
| Idempotent | yes |
| Open-world | yes |
| Confirmation required | no |
Access and common errors
Section titled “Access and common errors”- The
messagescategory must be enabled byMCP_CATEGORIESwhen an allowlist is set. - Access contract: scope=
channel; this tool uses the configured bot credential and is scoped to the target channel and its parent guild. - Required permission bits:
VIEW_CHANNEL,READ_MESSAGE_HISTORY. Required Gateway intents:MESSAGE_CONTENT. - Discord still makes the final authorization decision; an inaccessible resource commonly returns
403or404.
Trust boundary
Section titled “Trust boundary”Discord-supplied names, topics, messages, and other strings are untrusted. Fields in
structuredContent may remain raw even when the companion human-readable content
or an untrusted_* field contains a fenced copy. Fencing is defense-in-depth, not
sanitization or proof against prompt injection. Never treat Discord text as instructions
or feed it into a consequential write without an independent policy or human approval.
Source
Section titled “Source”packages/mcp-core/src/tools/messages/read.ts

