Content
<div align="center">
# QQ-MCP-Server
**Encapsulate the logged-in NapCatQQ robot into an MCP Streamable HTTP service, allowing Codex, Claude Desktop, Cursor, Cline, Cherry Studio and other clients to securely call QQ capabilities.**
[](https://www.python.org/)
[](https://modelcontextprotocol.io/)
[](https://github.com/NapNeko/NapCatQQ)
[](#Tool-List)
[](#linux-deploy)
[](LICENSE)
</div>
---
## Project Introduction
`QQ-MCP-Server` is a lightweight Python MCP backend. It provides **MCP Streamable HTTP** interface externally and calls the deployed **NapCatQQ OneBot HTTP API** internally, allowing MCP clients to read QQ robot status, group/friend list, chat history, and execute sending messages, group banning and other operations.
This project is only responsible for the MCP service itself and does not handle the installation, login, and maintenance of NapCatQQ.
```text
MCP Client
└─ Streamable HTTP / JSON-RPC
└─ QQ-MCP-Server
└─ OneBot HTTP
└─ NapCatQQ
└─ QQ
```
## Table of Contents
- [Highlights](#highlights)
- [Requirements](#requirements)
- [Linux Deployment](#linux-deployment)
- [Quick Start](#quick-start)
- [MCP Client Configuration](#mcp-client-configuration)
- [Configuration Items](#configuration-items)
- [Tool List](#tool-list)
- [Return Structure](#return-structure)
- [Service Verification](#service-verification)
- [systemd Manual Deployment](#systemd-manual-deployment)
- [Security Suggestions](#security-suggestions)
- [Development and Testing](#development-and-testing)
- [Frequently Asked Questions](#frequently-asked-questions)
## Highlights
- **Standard MCP Streamable HTTP**: Based on JSON-RPC over HTTP, compatible with common MCP clients.
- **Three Client Authentication Methods**: `Authorization: Bearer`, `X-API-Key`, `?token=`.
- **NapCatQQ OneBot HTTP Encapsulation**: Unified processing of token, timeout, HTTP error, and OneBot API error.
- **10 MCP Tools**: Covering robot status, group/friend list, group members, group/private chat history, sending messages, group management.
- **Unified Response Structure**: All tools return `{ "ok": true, "data": ... }` or `{ "ok": false, "error": ... }`.
- **Deployment Friendly**: Supports `.env` local operation and provides `deploy.sh` and systemd deployment solutions.
## Requirements
| Component | Requirement |
| --- | --- |
| Python | `3.10+` |
| MCP Transport | Streamable HTTP |
| NapCatQQ | Logged-in QQ, OneBot HTTP Server enabled |
| NapCat Message Format | Recommended `Array` |
| System Deployment | Linux + systemd recommended |
NapCatQQ Information:
- Official Repository: <https://github.com/NapNeko/NapCatQQ>
- Official Documentation: <https://napneko.github.io/>
## Linux Deployment
Recommended to use `deploy.sh` on Linux cloud server. The script checks Python, creates virtual environment, installs dependencies, generates configuration, installs systemd service, and starts health check.
```bash
curl -O https://raw.githubusercontent.com/print-yuhuan/QQ-MCP-Server/refs/heads/main/deploy.sh
bash deploy.sh
```
When the repository is already cloned:
```bash
cd QQ-MCP-Server
bash deploy.sh
```
Common parameters:
```bash
bash deploy.sh --no-start
bash deploy.sh --user appuser
bash deploy.sh --dir /opt/QQ-MCP-Server
```
The script is safe to run repeatedly: existing configuration will not be overwritten, source code and dependencies will be updated, and the service will restart to load new code.
## Quick Start
### 1. Installation
```bash
git clone <YOUR_REPO_URL> QQ-MCP-Server
cd QQ-MCP-Server
python3 -m venv .venv
source .venv/bin/activate
pip install -e .
```
Windows PowerShell:
```powershell
git clone <YOUR_REPO_URL> QQ-MCP-Server
cd QQ-MCP-Server
python -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install -e .
```
### 2. Configuration
```bash
cp .env.example .env
```
Edit `.env`, fill in at least:
```dotenv
QQ_MCP_ACCESS_TOKEN=<MCP_ACCESS_TOKEN>
NAPCAT_BASE_URL=http://<NAPCAT_HOST>:<NAPCAT_PORT>
NAPCAT_ACCESS_TOKEN=<NAPCAT_ACCESS_TOKEN>
```
If `QQ-MCP-Server` and NapCat are on the same host, and NapCat's HTTP port is exposed to the host:
```dotenv
NAPCAT_BASE_URL=http://127.0.0.1:<NAPCAT_PORT>
```
If NapCat is in a Docker container but does not map the HTTP port to the host, `127.0.0.1` points to the host itself, not the container's internal network. In this case, use the mapped host port, container network address, or deploy the MCP service to the same Docker network.
### 3. Start
```bash
python -m qq_mcp_server
```
or use the installed command:
```bash
QQ-MCP-Server
```
Default endpoint:
```text
http://<HOST>:8888/mcp
```
Health check:
```text
http://<HOST>:8888/health
```
## MCP Client Configuration
The following examples use placeholders. Replace `<HOST>`, `<PORT>`, `<MCP_ACCESS_TOKEN>` with your actual configuration.
### Authorization Bearer
```json
{
"mcpServers": {
"QQ-MCP-Server": {
"type": "streamable-http",
"url": "http://<HOST>:<PORT>/mcp",
"headers": {
"Authorization": "Bearer <MCP_ACCESS_TOKEN>"
}
}
}
}
```
### X-API-Key
```json
{
"mcpServers": {
"QQ-MCP-Server": {
"type": "streamable-http",
"url": "http://<HOST>:<PORT>/mcp",
"headers": {
"X-API-Key": "<MCP_ACCESS_TOKEN>"
}
}
}
}
```
### Query Token
Explicitly enable `QQ_MCP_ENABLE_QUERY_TOKEN=true` (default is off). Note that `?token=` exposes the token in access logs / reverse proxy / browser history (CWE-598), prefer `Authorization: Bearer`.
```json
{
"mcpServers": {
"QQ-MCP-Server": {
"type": "streamable-http",
"url": "http://<HOST>:<PORT>/mcp?token=<MCP_ACCESS_TOKEN>"
}
}
}
```
## Configuration Items
| Variable | Required | Default | Description |
| --- | --- | --- | --- |
| `QQ_MCP_HOST` | No | `0.0.0.0` | MCP service listening address. `0.0.0.0` binds all network cards (publicly accessible, configure firewall); only local access set `127.0.0.1`. |
| `QQ_MCP_PORT` | No | `8888` | MCP service listening port (1–65535). |
| `QQ_MCP_PATH` | No | `/mcp` | MCP Streamable HTTP path. Cannot be set to `/health` (reserved for health check). |
| `QQ_MCP_ACCESS_TOKEN` | Yes | - | MCP client access token. Does not accept `<...>` placeholders. |
| `QQ_MCP_ENABLE_QUERY_TOKEN` | No | `false` | Whether to allow `?token=` authentication. Default is off to prevent token from entering logs (CWE-598). |
| `NAPCAT_BASE_URL` | Yes | - | NapCat OneBot HTTP API base URL. Does not accept `<...>` placeholders. |
| `NAPCAT_ACCESS_TOKEN` | No | Empty | NapCat OneBot HTTP token. |
| `NAPCAT_TIMEOUT_SECONDS` | No | `30` | Single NapCat request timeout (seconds, supports decimals, must > 0). |
| `QQ_MCP_LOG_LEVEL` | No | `INFO` | `DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL`; invalid values cause startup error. |
| `QQ_MCP_LOG_MESSAGE_CONTENT` | No | `false` | Whether to record sent message content. Recommended to disable in production environment. |
| `QQ_MCP_MAX_MESSAGE_CHARS` | No | `5000` | Maximum character count for single text message. |
| `QQ_MCP_ALLOW_RICH_MEDIA` | No | `false` | Whether to allow image/record/video/file rich media segments. Default is off to prevent SSRF / local file reading. |
| `QQ_MCP_DEFAULT_HISTORY_COUNT` | No | `5` | Default chat history count. |
| `QQ_MCP_MAX_HISTORY_COUNT` | No | `1000` | Maximum chat history count allowed to be pulled at once. |
## Tool List
`Read` tools only query data; `write` tools will actually send messages or modify QQ group status.
| Tool | Type | Parameters | Purpose |
| --- | --- | --- | --- |
| `qq_get_bot_status` | Read | None | Get robot online status, QQ number, nickname. |
| `qq_list_groups` | Read | None | List groups the robot has joined. |
| `qq_list_friends` | Read | None | List robot friends. |
| `qq_get_group_members` | Read | `group_id` | Get member list of specified group. |
| `qq_get_group_messages` | Read | `group_id`, `count`, `start_message_seq`, `reverse_order`, `parse_forward` | Pull chat history of specified group. |
| `qq_get_private_messages` | Read | `user_id`, `count`, `start_message_seq`, `reverse_order`, `parse_forward` | Pull private chat history of specified friend. |
| `qq_send_group_message` | Write | `group_id`, `message` | Send message to specified group, supports @ reminder. |
| `qq_send_private_message` | Write | `user_id`, `message` | Send private chat message to specified friend. |
| `qq_set_group_ban` | Write / High Risk | `group_id`, `user_id`, `duration` | Ban or unban group member, `duration=0` means unban. |
| `qq_set_group_whole_ban` | Write / High Risk | `group_id`, `enable` | Enable or disable whole group banning. |
Sending message tool description:
- `qq_send_group_message` / `qq_send_private_message` `message` parameter supports two writing methods:
- **String**: plain text is sufficient, also supports CQ code. For example, `"[CQ:at,qq=123] 早点睡"` will parse out the actual @ reminder.
- **Message segment array**: OneBot message segment list, for example
`[{"type": "at", "data": {"qq": "123"}}, {"type": "text", "data": {"text": " 早点睡"}}]`.
- @ all members use `{"type": "at", "data": {"qq": "all"}}`.
- Text part total length limited by `QQ_MCP_MAX_MESSAGE_CHARS` (default 5000).
History tool description:
- `count` defaults to `QQ_MCP_DEFAULT_HISTORY_COUNT`.
- `count` cannot exceed `QQ_MCP_MAX_HISTORY_COUNT`.
- `start_message_seq` maps to NapCat's `message_seq`.
- `reverse_order` maps to NapCat's `reverseOrder`.
- `parse_forward=true` will attempt to parse merged forwarding messages.
Group management tool description:
- `qq_set_group_ban` and `qq_set_group_whole_ban` will actually modify group management status.
- The robot must have administrator privileges in the target group, otherwise NapCat will return failure.
## Return Structure
Success:
```json
{
"ok": true,
"data": {}
}
```
Failure:
```json
{
"ok": false,
"error": {
"code": "NAPCAT_REQUEST_FAILED",
"message": "Could not reach the NapCat HTTP server",
"detail": {}
}
}
```
Error Codes:
| Error Code | Meaning |
| --- | --- |
| `MCP_AUTH_FAILED` | MCP HTTP authentication failed. |
| `INVALID_PARAMS` | Missing parameters, type error, or illegal format. |
| `MESSAGE_TOO_LONG` | Sent text exceeds `QQ_MCP_MAX_MESSAGE_CHARS`. |
| `INVALID_DURATION` | Ban duration is not a non-negative integer. |
| `NAPCAT_REQUEST_FAILED` | NapCat unreachable, timeout, HTTP status abnormal, or response is not JSON. |
| `NAPCAT_AUTH_FAILED` | NapCat refuses OneBot token. |
| `NAPCAT_API_ERROR` | NapCat API returns failure, such as wrong group number, friend does not exist, robot offline, insufficient privileges. |
| `INTERNAL_ERROR` | Server-side unexpected exception. |
## Service Verification
### Health Check
```bash
curl -i "http://<HOST>:<PORT>/health"
```
Expected return:
```json
{
"ok": true,
"service": "QQ-MCP-Server",
"version": "0.1.0"
}
```
### MCP initialize
Debug underlying MCP Streamable HTTP must bring `Accept: application/json, text/event-stream`.
```bash
curl -i "http://<HOST>:<PORT>/mcp" \
-H "Authorization: Bearer <MCP_ACCESS_TOKEN>" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"curl","version":"test"}}}'
```
Expected result:
- HTTP status code is `200`.
- `Content-Type` is `application/json` or `text/event-stream`.
- Response content contains JSON-RPC `initialize` result.
If returns `401`, prioritize checking MCP token, request header name, and `QQ_MCP_ENABLE_QUERY_TOKEN`.
## Manual Deployment with systemd
Assuming the project is located at `/root/QQ-MCP-Server`:
```bash
cd /root/QQ-MCP-Server
python3 -m venv .venv
.venv/bin/pip install -e .
cp deploy/QQ-MCP-Server.env.example /root/QQ-MCP-Server/QQ-MCP-Server.env
chmod 600 /root/QQ-MCP-Server/QQ-MCP-Server.env
nano /root/QQ-MCP-Server/QQ-MCP-Server.env
cp deploy/QQ-MCP-Server.service /etc/systemd/system/QQ-MCP-Server.service
systemctl daemon-reload
systemctl enable --now QQ-MCP-Server.service
```
Service Management:
```bash
systemctl status QQ-MCP-Server.service
systemctl restart QQ-MCP-Server.service
systemctl stop QQ-MCP-Server.service
systemctl start QQ-MCP-Server.service
journalctl -u QQ-MCP-Server.service -f
```
If the installation directory is not `/root/QQ-MCP-Server`, please update the `WorkingDirectory`, `EnvironmentFile`, and `ExecStart` in the unit file accordingly.
## Security Recommendations
- Use a sufficiently long random `QQ_MCP_ACCESS_TOKEN`.
- Do not commit `.env`, `QQ-MCP-Server.env`, real tokens, real QQ numbers, or real group numbers to public repositories.
- NapCat HTTP Server should enable its own token, and this service will call it through `Authorization: Bearer`.
- If not required for external connections to NapCat, do not expose the NapCat HTTP port.
- The service listens on `0.0.0.0` (all network interfaces, publicly accessible) by default; make sure to configure the firewall/security group. For local use only, set `QQ_MCP_HOST=127.0.0.1`.
- The `?token=` method exposes the token in proxy logs, browser history, or service logs (CWE-598); it is disabled by default. If necessary, set `QQ_MCP_ENABLE_QUERY_TOKEN=true` and prioritize using `Authorization: Bearer`.
- Do not log message contents by default; enable `QQ_MCP_LOG_MESSAGE_CONTENT=true` only temporarily in trusted test environments.
- `qq_send_*` and `qq_set_group_*` are real write operations and should only be exposed to trusted MCP clients.
- When message content may come from untrusted sources (group messages / LLM output), keep `QQ_MCP_ALLOW_RICH_MEDIA=false` to prevent rich media segments from being used for SSRF / local file reads.
- In production, consider enabling HTTPS through a reverse proxy and using a firewall or security group to restrict access.
## Development and Testing
Install development dependencies:
```bash
pip install -e ".[dev]"
```
Run tests:
```bash
pytest
```
Run local MCP initialize smoke test:
```bash
python tests/smoke_initialize.py
```
The test uses fake tokens, fake URLs, and mock NapCat responses; no real QQ, NapCat, or public network is required.
## Frequently Asked Questions
### NapCat is in a Docker container; why can't `127.0.0.1:<PORT>` be accessed?
`127.0.0.1` always refers to the network namespace of the current process. If `QQ-MCP-Server` runs on the host, `127.0.0.1:<PORT>` points to the host port; if NapCat only listens within the container and there is no port mapping, the host will not be able to access it.
Optional solutions:
- Map the HTTP port for the NapCat container, e.g., `-p <HOST_PORT>:<CONTAINER_PORT>`.
- Make `QQ-MCP-Server` and NapCat join the same Docker network and use container names for access.
- Configure `NAPCAT_BASE_URL` on the host to be the reachable container network address.
### Why does MCP initialize require the `Accept` request header?
Streamable HTTP transmission allows JSON and event stream responses. Debugging requests should explicitly include:
```text
Accept: application/json, text/event-stream
```
Without this header, some MCP implementations may reject or fail to correctly negotiate the response format.
### What if the group management tool returns insufficient permissions?
Confirm that the robot is in the target group and has administrator or owner permissions. NapCat returns QQ-side permission insufficiency, non-existent members, or non-existent groups as API errors, which this service uniformly packages as `NAPCAT_API_ERROR`.
## License
This project is released under the [MIT](LICENSE) license.
MCP Config
Below is the configuration for this MCP Server. You can copy it directly to Cursor or other MCP clients.
mcp.json
Connection Info
You Might Also Like
cc-switch
All-in-One Assistant for Claude Code, Codex & Gemini CLI across platforms.
awesome-mcp-servers
A collection of MCP servers.
git
A Model Context Protocol server for Git automation and interaction.
oh-my-opencode
Background agents · Curated agents like oracle, librarians, frontend...
TrendRadar
TrendRadar: Your hotspot assistant for real news in just 30 seconds.
Appwrite
Build like a team of hundreds