QQ Mail Reader MCP
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., "@QQ Mail Reader MCPlist my unread QQ Mail messages"
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.
QQ Mail Reader MCP
English | 简体中文
A read-only QQ Mail MCP server for ChatGPT and Codex. It supports both a local single-user mode and a multi-user HTTP mode with OAuth 2.1 and PKCE. Every mail operation uses a read-only QQ Mail IMAP connection.
Portfolio project: a security-first QQ Mail integration built with Node.js, Model Context Protocol, OAuth 2.1/PKCE, and IMAP.
Highlights
Least privilege by design: exposes only five tools for identity, connection status, unread messages, search, and message reading. It cannot send, delete, move, or mark mail as read.
Complete authorization flow: implements OAuth discovery, Dynamic Client Registration, Authorization Code with PKCE S256, token rotation, revocation, and UserInfo.
Credential protection: local mode uses macOS Keychain; HTTP mode encrypts QQ IMAP authorization codes with AES-256-GCM, while OAuth tokens are stored only as SHA-256 hashes.
Prompt-injection boundary: email bodies are explicitly treated as untrusted external content, and the MCP server instructions prohibit executing instructions found in messages.
Two transports: stdio for local Codex integration and Streamable HTTP for ChatGPT or other MCP clients.
Verifiable behavior: includes six automated tests plus a real QQ Mail end-to-end test script.
Related MCP server: Mail Agent MCP
Architecture
flowchart LR
A[ChatGPT / Codex] -->|MCP tools| B[QQ Mail Reader MCP]
B --> C{Runtime mode}
C -->|Local stdio| D[macOS Keychain]
C -->|HTTP + OAuth 2.1| E[Encrypted OAuth Store]
D --> F[QQ Mail IMAP<br/>imap.qq.com:993]
E --> F
B -->|Read-only| FHTTP mode data flow:
MCP Client -> OAuth discovery / DCR / PKCE -> Bearer token -> /mcp
|
v
per-user encrypted credential
|
v
QQ Mail IMAPMCP tools
Tool | Purpose | Changes mailbox state |
| Returns the identity of the connected mailbox | No |
| Checks configuration without returning credentials | No |
| Lists unread message summaries | No |
| Searches by text, sender, subject, date, or read status | No |
| Reads a message body and attachment metadata by mailbox + UID | No |
Every tool declares readOnlyHint: true, destructiveHint: false, and idempotentHint: true.
Quick start
Requirements: Node.js 20+ and a QQ Mail account with IMAP enabled. Use the dedicated IMAP authorization code, not the QQ account password. Never send the authorization code through chat.
Local Codex / MCP client
git clone https://github.com/tqq0531/qq-mail-reader-mcp.git
cd qq-mail-reader-mcp
npm ci
npm run setup
npm startnpm run setup stores the email address and IMAP authorization code in macOS Keychain.
HTTP + OAuth development mode
npm ci
npm run dev:publicThe first run creates a local-only .env.local. Test data is stored in the Git-ignored data/ directory, and QQ IMAP authorization codes are encrypted with AES-256-GCM.
Run the real end-to-end flow in another terminal:
npm run test:manualSee TESTING.md for detailed steps.
Automated tests
npm ci
npm testCurrent coverage includes tool discovery and read-only annotations, encrypted persistence, OAuth discovery, DCR, PKCE, authorization-code exchange, UserInfo, the HTTP 401 challenge, and authenticated MCP calls. Automated tests do not access a real mailbox.
Production deployment
Required container environment variables:
PUBLIC_BASE_URL=https://your-domain.example
MCP_ENCRYPTION_KEY=<32-random-bytes-in-base64>
OAUTH_DB_PATH=/data/oauth-store.json
HOST=0.0.0.0
PORT=8787docker build -t qq-mail-reader-mcp .
docker run --rm -p 8787:8787 --env-file .env.local qq-mail-reader-mcpThe public MCP endpoint is https://your-domain.example/mcp. The deployment environment must allow outbound TCP connections to imap.qq.com:993.
The current JSON persistence layer is intended for single-instance validation. Before a multi-instance production rollout, migrate OAuth clients, accounts, and tokens to PostgreSQL or an equivalent managed database while keeping application-layer encryption for QQ authorization codes.
Current status
✅ Local stdio MCP and macOS Keychain credential loading
✅ Five read-only QQ Mail tools
✅ Multi-user OAuth 2.1 / DCR / PKCE flow
✅ Real QQ IMAP end-to-end validation
✅ Automated tests: 6/6 passing
✅ Dockerfile and Secure MCP Tunnel preflight
🚧 Live ChatGPT Secure MCP Tunnel connection and plugin installation
⏳ PostgreSQL persistence, audit logging, production legal pages, and marketplace submission
See STATUS.md for the detailed milestones and known limitations.
Security
Never commit .env.local, data/, QQ Mail authorization codes, or API keys. See SECURITY.md when reporting a vulnerability, and do not paste credentials into public issues.
License
Available Tools
5 toolsqq_mail_connection_status检查 QQ 邮箱连接配置ARead-onlyIdempotent
检查当前连接是否已配置,只返回邮箱地址和配置状态,绝不返回授权码。
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, idempotentHint=true, destructiveHint=false, and openWorldHint=false. The description adds that it only returns the email address and configuration status, never the authorization code, which is a useful disclosure about output sensitivity.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, front-loaded sentence that states the core action, the returned data, and an explicit exclusion without any filler. Every clause earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the simple read-only nature, the empty input schema, and the rich annotations, the description covers what the tool does and what data it returns. It could optionally clarify what 'configuration status' means (e.g., configured/not configured), but it is adequate.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters, so the baseline for parameter semantics is 4. There are no parameter details to document, and the description appropriately does not discuss inputs.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool checks whether the current connection is configured, using a specific verb '检查' (check) and resource '连接配置' (connection configuration). It distinguishes from sibling tools like qq_mail_read and qq_mail_search, which perform mail operations rather than status checks.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No explicit when-to-use or when-not-to-use guidance is provided, nor are any alternatives mentioned. The description only states what the tool does, not when to invoke it versus the sibling mail tools.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
qq_mail_list_unread列出 QQ 邮箱未读邮件ARead-onlyIdempotent
以只读方式列出 QQ 邮箱的未读邮件摘要,不会将邮件标记为已读。返回 mailbox 和 uid,可用于读取指定邮件。
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | 最多返回的邮件数量 | |
| mailbox | No | 邮箱文件夹,默认 INBOX | INBOX |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint and destructiveHint, but the description adds a genuinely useful behavioral detail beyond them: it will not mark messages as read, which is the key side-effect concern for a mail listing tool. It omits pagination and rate-limit behavior, keeping it below a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single dense sentence that front-loads the read-only guarantee and then the return value; every clause carries information and there is no padding.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description correctly compensates by naming the returned fields (mailbox and uid) and their downstream use. The main remaining gap is any statement about result limits or paging, though limit is covered by the schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so both limit and mailbox are already documented in the schema. The description adds no syntax, format or defaulting information beyond that, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource with scope: '以只读方式列出 QQ 邮箱的未读邮件摘要' (list unread QQ mail summaries read-only). The 'unread' qualifier naturally separates it from qq_mail_read and qq_mail_search, though no sibling is named explicitly, so it falls just short of the top mark.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives a clear usage context and a workflow pointer: the returned mailbox and uid '可用于读取指定邮件', implicitly routing the agent to qq_mail_read. It does not, however, state when to prefer qq_mail_search or any exclusions, so it stops at clear context without explicit routing rules.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
qq_mail_profile查看当前 QQ 邮箱连接ARead-onlyIdempotent
返回当前 OAuth 连接对应的 QQ 邮箱身份,帮助区分多个邮箱连接。不返回授权码。
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare this is a closed-world, read-only, idempotent, non-destructive call, so the bar is low. The description adds a genuine boundary beyond them: it discloses that no authorization code is returned, which prevents an agent from treating this as a credential-fetching tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences, front-loaded with the return subject and followed by the intent and the exclusion. No filler, and the negative constraint is placed where it is most likely to be read.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the burden of signaling what comes back, and it does so at a high level ('identity', explicitly not the auth code). A parameterless read tool with full annotation coverage does not need more, though the exact identity fields remain unspecified.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so there is nothing for the description to disambiguate and the schema is fully self-sufficient. Baseline of 4 applies for a parameterless tool.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific verb and resource: it returns the QQ Mail identity bound to the current OAuth connection, and adds the intent of distinguishing between multiple mailbox connections. It is clear but never names the nearest sibling (qq_mail_connection_status), so an agent must infer the boundary itself.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The clause '帮助区分多个邮箱连接' implies the usage scenario (multiple connections present, identity disambiguation needed) but gives no explicit when-not-to-use rule and names no alternative among qq_mail_connection_status or the read/search siblings. Usage is inferable but not stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
qq_mail_read读取一封 QQ 邮件ARead-onlyIdempotent
使用列表或搜索结果中的 mailbox 和 uid 读取一封邮件的正文与附件元数据,不会下载附件或标记为已读。
| Name | Required | Description | Default |
|---|---|---|---|
| uid | Yes | 邮件 UID,必须来自列表或搜索结果 | |
| mailbox | No | INBOX |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotations already declare the safety profile (readOnlyHint, idempotentHint, destructiveHint=false), and the description adds the genuinely useful behavioral fact that it will not download attachments or mark the message as read — a common ambiguity in mail clients. It stops short of describing error or pagination behavior, but the added context is real.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single sentence that leads with the action, then the data source, then the non-effects. No filler and nothing repeated from the title.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description correctly summarizes the return value (body plus attachment metadata) and the absence of side effects. A 2-parameter read tool with annotations is well covered, missing only failure/empty-result behavior.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is only 50%: mailbox has a default but no description, and uid is already documented as needing to come from list/search results. The description compensates partly by asserting both mailbox and uid originate from list or search results, but adds no format, default, or casing details beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource — reading one QQ mail's body and attachment metadata — and scopes it to a single message, which cleanly separates it from qq_mail_list_unread and qq_mail_search that return collections. An agent can pick this tool over its siblings without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It states that mailbox and uid must come from a list or search result, which effectively tells the agent this is a follow-up call to qq_mail_list_unread or qq_mail_search. That is clear usage context, though there is no explicit statement of when not to use it or what happens if a stale uid is supplied.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
qq_mail_search搜索 QQ 邮箱ARead-onlyIdempotent
按关键词、发件人、主题、日期或未读状态搜索当前已授权的 QQ 邮件,不改变邮件状态。
| Name | Required | Description | Default |
|---|---|---|---|
| from | No | 发件人姓名或地址 | |
| text | No | 在发件人、主题和正文中搜索的关键词 | |
| limit | No | ||
| since | No | 起始日期 YYYY-MM-DD(含) | |
| before | No | 结束日期 YYYY-MM-DD(不含) | |
| unread | No | true 仅未读,false 仅已读 | |
| mailbox | No | INBOX | |
| subject | No | 主题关键词 |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint and destructiveHint=false, so '不改变邮件状态' largely restates structured data rather than adding new behavior. The one genuinely additive detail is the '当前已授权' scoping, which hints at the auth boundary; return format and pagination behavior remain undisclosed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single front-loaded sentence with the verb and resource first, followed by scope dimensions and a safety clause. No filler, nothing buried.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For an 8-parameter search tool with no output schema, the description is workable because annotations cover the safety profile and the schema covers types. However, it does not address result ordering, the limit default/cap, or the INBOX default, leaving real gaps an agent would want when composing a query.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 75%, so the schema already documents most parameters including date patterns and unread semantics. The description mirrors the filter list but adds no syntax, default-value, or interplay detail, and omits mailbox and limit entirely — baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (搜索) and resource (QQ 邮件) with the searchable dimensions enumerated (关键词、发件人、主题、日期、未读状态). It clearly differentiates a filtered search from qq_mail_read, but never names siblings like qq_mail_list_unread, which covers overlapping unread filtering.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied by the enumeration of filter dimensions, but there is no explicit when-to-use or when-not-to-use guidance, and no mention of qq_mail_list_unread as the narrower alternative for unread-only queries. An agent must infer routing from the sibling names.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
5 tool updates
v0.2.0- First observed
qq_mail_connection_status - First observed
qq_mail_list_unread - First observed
qq_mail_profile - First observed
qq_mail_read - First observed
qq_mail_search
TDQS
Scored across 5 tools
Most tools have distinct purposes (read, list unread, search, profile, connection status), but qq_mail_profile and qq_mail_connection_status both essentially report identity/connection info and could be confused, and qq_mail_list_unread overlaps with qq_mail_search which also filters by unread state.
All tools share the consistent qq_mail_ prefix, but suffixes mix verb styles (read, list_unread, search) with noun phrases (profile, connection_status), a minor deviation from a pure verb_noun pattern.
Five tools is a well-scoped set for a focused read-only mail reader, with each tool earning its place without redundancy bloat.
As a read-only reader the core read/list/search flows are covered, but there is no way to list mailboxes/folders or list all (read) mail beyond unread, leaving notable gaps in the browse surface.
Maintenance
Related MCP Connectors
Read-only IMAP email for your AI agent, scoped to the mailboxes you choose, with built-in progress.
Your mailboxes in ChatGPT and Claude: Gmail, iCloud, Fastmail, any IMAP. Passwords stay yours.
Connect any mailbox to Claude, ChatGPT & AI: read, send, reply, schedule & search emails.
Your agent needs a mailbox of its own — to receive, thread, draft and send, with attachments, without borrowing your personal inbox or your company's SMTP. **What you can ask for** • "Create an inbox for this agent and tell me its address." • "Read the new messages in this thread and draft a reply." • "Send this message with the attachment and wait for the response." • "Search this inbox for everything from that domain." • "Show delivery metrics and the events on this inbox." **How to use it** Point any MCP client at https://mcp.aisa.one/mail/mcp and sign in with OAuth — there is no key to create or paste. 49 tools: create and delete inboxes, list and read messages, raw message bodies, attachments, threads, drafts and draft attachments, send and reply, message search, inbox events, metrics, and list entries — reads and writes. **Why this rather than the source** A real inbox an agent owns, rather than an SMTP credential it borrows from a human. **It is also a door to the rest** The same login reaches 26 sources and 580+ operations. Find the contact elsewhere in the catalogue, then write to them from here — without adding a second server. **What it costs** Finding and inspecting an operation is free. Running one is billed per call at API prices, with no seat and no monthly minimum, and every call takes max_price_usd so an agent cannot overspend by accident. **Where else it reaches** https://mcp.aisa.one/sales/mcp finds the person to write to.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceEnables LLMs to read, search, and manage emails via IMAP with secure, read-only access to email accounts.6-
- AlicenseBqualityBmaintenanceEnables AI agents to securely interact with Gmail and QQ Mail, including IMAP search/read/organization, attachments, and preview-confirmed sending.412MIT
- AlicenseNot gradedqualityBmaintenanceEnables AI clients to read, search, manage, and send QQ mailbox emails via IMAP/SMTP, including attachments, drafts, replies, and structured message context for models.53 npmMIT
- AlicenseNot gradedqualityBmaintenanceConnects an IMAP mailbox over OAuth 2.1 so an AI assistant can list and search accounts, folders, messages, attachments, and contacts. Mailboxes stay read-only by default, with optional opt-in write tools for flagging, moving, drafting, and approval-gated sending.MIT