Skip to main content
Glama
oines

astral-bridge

by oines

Astral Bridge

Astral Bridge connects QQ, through NapCat's OneBot v11 reverse WebSocket, and optionally Telegram, through the Telegram Bot API, to one long-lived Astral Code app-server session. It also exposes MCP tools so the agent can reply back to chat platforms, send files, mention people, recall/delete messages, and fetch recent conversation context when needed.

This project is intended for self-hosted personal or team automation. It is not affiliated with QQ, Tencent, NapCat, OneBot, Telegram, or Astral Code.

Features

  • Receive QQ private and group messages from NapCat over OneBot v11.

  • Receive Telegram private, group, supergroup, and channel-post messages through long polling.

  • Route every accepted message into one Astral app-server thread, either configured explicitly or auto-created on first startup.

  • Trigger group messages only when the bot is mentioned, replied to, or the chat is configured as always-trigger.

  • Trigger every message from configured private QQ or Telegram users/chats.

  • Store allowed conversation history locally in SQLite for later MCP lookups.

  • Include compact inbound context: platform, chat/group name/id, sender id, nickname, username/card, message id, reply id, trigger kind, unread count, and attachment metadata.

  • Support app-server turn/steer when the current Astral thread already has an active turn.

  • Expose Streamable HTTP or stdio MCP tools for QQ and Telegram replies, history, media, files, mentions, and replies to specific message ids.

  • Accept generic external event webhooks and forward them into the current Astral session.

  • Expose a read-only Web UI for connection status, routing, recent messages, recent conversations, and recent bridge logs.

  • Add a random 3-5 second delay before outbound QQ send actions.

Related MCP server: NapCat MCP Server

Requirements

  • Node.js 26 or newer. The bridge uses node:sqlite.

  • pnpm 10 or newer.

  • A running Astral Code app-server.

  • NapCat configured with OneBot v11 reverse WebSocket.

  • Optional: a Telegram bot token from BotFather if Telegram support is enabled.

Quick Start

pnpm install
cp examples/config.example.json config.json
pnpm dev -- --config ./config.json

Build for production:

pnpm build
pnpm start -- --config ./config.json

Point NapCat's OneBot v11 reverse WebSocket to:

ws://127.0.0.1:6701/onebot/v11/ws

If the bridge is running in Docker or on another host, replace the host and port with the address reachable from NapCat, for example:

ws://bridge:6701/onebot/v11/ws

Configuration

Start from examples/config.example.json:

{
  "onebot": {
    "host": "127.0.0.1",
    "port": 6701,
    "path": "/onebot/v11/ws",
    "accessToken": null,
    "actionTimeoutMs": 10000
  },
  "mcp": {
    "transport": "stdio",
    "host": "127.0.0.1",
    "port": 6710,
    "path": "/mcp"
  },
  "astral": {
    "appServerUrl": "ws://127.0.0.1:4222",
    "authToken": null,
    "threadId": "auto",
    "cwd": null,
    "modelConfigPath": null,
    "modelProvider": null,
    "model": null,
    "includeImageInputs": false,
    "rotateThreadOnStart": false
  },
  "qq": {
    "enabled": true,
    "botUserId": "REPLACE_WITH_BOT_QQ",
    "allowedGroupIds": ["REPLACE_GROUP_ID"],
    "alwaysTriggerGroupIds": [],
    "allowedPrivateUserIds": ["REPLACE_USER_ID"],
    "triggerKeywords": ["astral", "bot"],
    "recordUntriggered": true
  },
  "telegram": {
    "enabled": false,
    "botToken": "REPLACE_WITH_TELEGRAM_BOT_TOKEN",
    "botUsername": "REPLACE_WITH_TELEGRAM_BOT_USERNAME",
    "allowedChatIds": ["REPLACE_TELEGRAM_CHAT_ID"],
    "alwaysTriggerChatIds": [],
    "triggerKeywords": ["astral", "bot"],
    "recordUntriggered": true,
    "pollTimeoutSeconds": 25,
    "pollIntervalMs": 1000,
    "apiBaseUrl": "https://api.telegram.org"
  },
  "tts": {
    "enabled": false,
    "protocol": "openai_speech",
    "apiKey": null,
    "baseUrl": "http://127.0.0.1:8765/v1",
    "model": "mlx-community/Qwen3-TTS-12Hz-0.6B-Base-bf16",
    "voice": null,
    "format": "mp3",
    "language": "Chinese",
    "referenceAudioPath": "/absolute/path/on/tts-server/atri.wav",
    "referenceText": "参考音频中准确说出的文字",
    "timeoutMs": 60000
  },
  "embedding": {
    "enabled": false,
    "baseUrl": "http://127.0.0.1:8766/v1",
    "apiKey": null,
    "model": "qwen3-embedding-0.6b",
    "dimensions": 1024,
    "batchSize": 32,
    "timeoutMs": 60000,
    "queryInstruction": "Given a user query about instant-message history, retrieve messages that answer the query or express the same meaning."
  },
  "externalEvents": {
    "enabled": true,
    "path": "/api/events",
    "authToken": "REPLACE_WITH_EVENT_API_TOKEN",
    "maxBodyBytes": 65536,
    "debounceMs": 2000,
    "maxBatchEvents": 20,
    "maxBatchBodyChars": 6000
  },
  "storage": {
    "dbPath": "./data/astral-bridge.db",
    "mediaDir": "./media",
    "downloadMedia": false
  }
}

Environment overrides:

Variable

Description

ASTRAL_BRIDGE_CONFIG

Path to the JSON config file.

ASTRAL_BRIDGE_APP_SERVER_URL

Astral app-server WebSocket URL.

ASTRAL_BRIDGE_APP_SERVER_AUTH_TOKEN

Bearer token for Astral app-server.

ASTRAL_BRIDGE_THREAD_ID

Optional fixed Astral thread/session id. Leave empty or set auto to let bridge create and persist one in its SQLite store.

ASTRAL_BRIDGE_ROTATE_THREAD_ON_START

Auto-managed mode only. Set true once to create a fresh thread on bridge startup, then set it back to false.

ASTRAL_BRIDGE_MODEL_CONFIG_PATH

Optional Astral config.toml path. When set, bridge reads model_provider and model from this file before new turns and syncs the current thread settings.

ASTRAL_BRIDGE_MODEL_PROVIDER

Optional static provider override when modelConfigPath is not set.

ASTRAL_BRIDGE_MODEL

Optional static model override when modelConfigPath is not set.

ASTRAL_BRIDGE_QQ_ENABLED

Enable the QQ/NapCat channel and expose QQ MCP tools.

ASTRAL_BRIDGE_BOT_QQ

Bot QQ user id.

ASTRAL_BRIDGE_ALLOWED_GROUP_IDS

Comma-separated allowed group ids.

ASTRAL_BRIDGE_ALWAYS_TRIGGER_GROUP_IDS

Comma-separated group ids where every non-bot message is forwarded to Astral.

ASTRAL_BRIDGE_ALLOWED_PRIVATE_USER_IDS

Comma-separated allowed private user ids.

ASTRAL_BRIDGE_TRIGGER_KEYWORDS

Comma-separated QQ trigger keywords. Any allowed group/private message containing one keyword, case-insensitively, is forwarded to Astral.

ASTRAL_BRIDGE_TELEGRAM_ENABLED

Enable Telegram long polling.

ASTRAL_BRIDGE_TELEGRAM_BOT_TOKEN

Telegram bot token from BotFather.

ASTRAL_BRIDGE_TELEGRAM_BOT_USERNAME

Optional bot username, without or with @; getMe also discovers it at runtime.

ASTRAL_BRIDGE_TELEGRAM_ALLOWED_CHAT_IDS

Comma-separated Telegram chat.id allowlist. Use /chatid in a chat to retrieve it.

ASTRAL_BRIDGE_TELEGRAM_ALWAYS_TRIGGER_CHAT_IDS

Comma-separated Telegram chat ids where every non-bot message is forwarded to Astral.

ASTRAL_BRIDGE_TELEGRAM_TRIGGER_KEYWORDS

Comma-separated Telegram trigger keywords. Any allowed chat message containing one keyword, case-insensitively, is forwarded to Astral.

ASTRAL_BRIDGE_TELEGRAM_RECORD_UNTRIGGERED

Store non-triggering Telegram messages from allowed chats.

ASTRAL_BRIDGE_TELEGRAM_POLL_TIMEOUT_SECONDS

Telegram getUpdates long-poll timeout.

ASTRAL_BRIDGE_TELEGRAM_POLL_INTERVAL_MS

Delay after a failed Telegram poll before retrying.

ASTRAL_BRIDGE_TTS_ENABLED

Enable TTS-backed QQ/Telegram voice message tools.

ASTRAL_BRIDGE_TTS_PROTOCOL

chat_completions for MiMo-style audio responses or openai_speech for /v1/audio/speech, including MLX-Audio.

ASTRAL_BRIDGE_TTS_API_KEY

Optional API key. Required by chat_completions; local openai_speech servers can leave it empty.

ASTRAL_BRIDGE_TTS_BASE_URL

TTS API base URL, including /v1.

ASTRAL_BRIDGE_TTS_MODEL

TTS model id sent to the configured endpoint.

ASTRAL_BRIDGE_TTS_VOICE

Configured bot voice, hidden from MCP tool schemas.

ASTRAL_BRIDGE_TTS_FORMAT

Audio response format: wav, mp3, ogg, opus, or m4a.

ASTRAL_BRIDGE_TTS_LANGUAGE

Optional language hint sent as lang_code to openai_speech.

ASTRAL_BRIDGE_TTS_REFERENCE_AUDIO_PATH

Optional reference audio path as seen by the TTS server.

ASTRAL_BRIDGE_TTS_REFERENCE_TEXT

Exact transcript of the reference audio; must be configured together with its path.

ASTRAL_BRIDGE_TTS_TIMEOUT_MS

TTS request timeout in milliseconds.

ASTRAL_BRIDGE_EMBEDDING_ENABLED

Enable asynchronous message embeddings and semantic/hybrid query_messages search.

ASTRAL_BRIDGE_EMBEDDING_BASE_URL

OpenAI-compatible embeddings API base URL, including /v1.

ASTRAL_BRIDGE_EMBEDDING_API_KEY

Optional bearer token for the embeddings API.

ASTRAL_BRIDGE_EMBEDDING_MODEL

Embedding model id sent to the configured endpoint.

ASTRAL_BRIDGE_EMBEDDING_DIMENSIONS

Stored vector dimensions. Changing this rebuilds the vector index.

ASTRAL_BRIDGE_EMBEDDING_BATCH_SIZE

Maximum messages embedded in one background request.

ASTRAL_BRIDGE_EMBEDDING_TIMEOUT_MS

Embedding request timeout in milliseconds.

ASTRAL_BRIDGE_EMBEDDING_QUERY_INSTRUCTION

Retrieval instruction prepended to semantic search queries.

ASTRAL_BRIDGE_MCP_TRANSPORT

stdio or http.

ASTRAL_BRIDGE_EVENT_API_ENABLED

Enable or disable the external event API.

ASTRAL_BRIDGE_EVENT_API_PATH

External event API path, default /api/events.

ASTRAL_BRIDGE_EVENT_API_TOKEN

Optional bearer token required by the external event API.

ASTRAL_BRIDGE_EVENT_API_DEBOUNCE_MS

Window used to merge attention-worthy external events before forwarding to Astral.

ASTRAL_BRIDGE_EVENT_API_MAX_BATCH_EVENTS

Maximum external events included in one merged Astral turn. Extra events in the same window are counted and omitted.

ASTRAL_BRIDGE_EVENT_API_MAX_BATCH_BODY_CHARS

Maximum merged event body characters sent to Astral. Longer batches are truncated.

When astral.threadId / ASTRAL_BRIDGE_THREAD_ID is empty or auto, bridge creates one Astral thread on first use and stores the id in SQLite store_meta. To rotate an auto-managed thread manually, call POST /api/astral/thread/rotate with the same bearer token as the external event API. If a turn is currently active, the endpoint returns 409 instead of interrupting it.

recordUntriggered controls whether non-triggering messages from allowed conversations are stored. Keeping it enabled lets the agent fetch surrounding context without forwarding every group message into Astral. For QQ this also stores member-to-member poke notices in allowed groups; only pokes targeting the bot trigger an Astral turn.

Telegram uses long polling. On startup the bridge calls deleteWebhook so Telegram will allow getUpdates. Send /chatid to the bot in a private chat, group, supergroup, or topic to get the exact chat_id; this command works even before the chat is allowlisted. All other Telegram interaction requires the chat id to be present in telegram.allowedChatIds or telegram.alwaysTriggerChatIds.

Web UI

When HTTP MCP is enabled, open:

GET /ui

The dashboard polls GET /api/dashboard/state and shows NapCat/Astral connection status, the active Astral turn id when one is running, configured routing, external event API status, recent conversations, recent stored messages, and recent bridge logs.

Astral MCP Setup

For stdio MCP, build first and point Astral at the compiled entrypoint:

[mcp_servers.bridge]
command = "node"
args = ["/path/to/astral-bridge/dist/index.js", "--config", "/path/to/astral-bridge/config.json"]

Use node directly instead of a package-manager wrapper. stdio MCP requires stdout to contain only JSON-RPC messages.

For container or multi-process deployments, run HTTP MCP:

{
  "mcp": {
    "transport": "http",
    "host": "0.0.0.0",
    "port": 6710,
    "path": "/mcp"
  }
}

Then configure Astral:

[mcp_servers.bridge]
url = "http://bridge:6710/mcp"

The bridge exposes both QQ and Telegram tools from the same MCP endpoint, so register it once. Tool names remain platform-specific, for example mcp__bridge__qq_send_group_message and mcp__bridge__telegram_send_message. QQ tools are registered only when qq.enabled is true, Telegram tools only when telegram.enabled is true, and voice tools only when tts.enabled is true.

MCP Tools

Shared Tool

Purpose

query_messages

Run isolated read-only JavaScript over QQ/TG history with search, messages, context, conversations, sql, and schema; embedding-enabled deployments also expose embed.

query_messages is intended for complex recall and analysis rather than ordinary recent-message lookups. Its code argument is an async JavaScript function body that must return JSON. Each invocation runs in a separate process against a read-only SQLite connection and is terminated after 30 seconds. Helper limit values are defaults rather than hard maxima; Astral applies its normal MCP-output context limit after the bridge returns the result.

return search("电路图", { platform: "qq", context_limit: 2 });

When embeddings are enabled, search() defaults to hybrid FTS5 plus semantic recall. Semantic and hybrid searches are asynchronous, while explicit lexical searches retain the synchronous FTS5 path:

return await search("上次谁说显卡坏了", { mode: "hybrid", platform: "qq", context_limit: 2 });

For custom KNN joins, use await embed(text) and bind the returned float32 vector directly to sql(). The vector is never printed into the tool result:

const vector = await embed("串流画面问题");
return sql(
  "SELECT m.id AS row_id, m.text, e.distance FROM message_embeddings e JOIN messages m ON m.id = e.message_row_id WHERE e.embedding MATCH ? AND e.k = ? ORDER BY e.distance",
  vector,
  20,
);

Message writes and FTS5 updates never wait for the embedding service. New and historical messages are queued in SQLite and indexed in the background. If the local model is unavailable, semantic/hybrid calls return a clear error and mode: "lexical" remains available.

Use schema() from inside the query when exact table fields are needed. Use sql() only for joins, grouping, time buckets, and other shapes not covered naturally by the higher-level helpers.

QQ Tool

Purpose

qq_send_group_message

Send a group message with text, images, ordered parts, mentions, or a reply target.

qq_send_private_message

Send a private message with text, images, ordered parts, or a reply target.

qq_send_group_voice

Generate TTS audio and send it as a real QQ group voice message.

qq_send_private_voice

Generate TTS audio and send it as a real QQ private voice message.

qq_send_group_file

Upload a local file or URL to a QQ group.

qq_send_private_file

Upload a local file or URL to a QQ private chat.

qq_get_unread_messages

Return the unread batch counted by the latest inbound Astral prompt.

qq_get_recent_messages

Return recent stored messages for one group or private conversation.

qq_get_message

Return one stored message by OneBot message_id.

qq_get_forward_messages

Expand every node in one stored, allowlisted QQ merged-forward message without persisting or downloading its contents.

qq_get_conversation_state

Return bridge state and counts for one conversation.

qq_download_media

Download a stored attachment, or one attachment selected by a merged-forward forward_node_path, into the local media cache.

qq_set_reaction

React to a stored QQ group message by OneBot message_id and QQ emoji_id. QQ reactions only work in group chats; the tool description lists common emoji_id values.

qq_group_admin_help

Explain grouped QQ administration tools and actions.

qq_group_member_admin

Kick, mute/unmute, set admin, set card, set special title, or list muted members.

qq_group_request_admin

Read or handle group join/invite requests.

qq_group_settings_admin

Change group name/avatar, whole-group mute, or make the bot leave the group.

qq_group_message_admin

Recall messages, manage essence messages, check @all quota, or mark group read.

qq_group_notice_admin

Send, list, or delete group notices.

qq_group_file_admin

Manage group files and folders.

qq_group_info_admin

Read group, member, and honor information.

Telegram Tool

Purpose

telegram_send_message

Send text with ordered text/mention parts, optional reply target, and optional topic thread id.

telegram_send_rich_message

Send structured rich text with Telegram Rich Message HTML or Markdown.

telegram_send_file

Send a local path, Telegram file_id, or HTTP URL as a document/file. Images intentionally use this tool too.

telegram_send_voice

Generate TTS audio and send it as a real Telegram voice message.

telegram_delete_message

Delete/recall a message when Telegram permissions allow it. Requires confirm:true.

telegram_set_reaction

React to a Telegram group or private message with one standard reaction emoji; the tool description lists the allowed emoji values.

telegram_get_unread_messages

Return the unread batch counted by the latest inbound Astral prompt.

telegram_get_recent_messages

Return recent stored messages for one Telegram chat.

telegram_get_message

Return one stored Telegram message by message_id.

telegram_get_conversation_state

Return bridge state and counts for one Telegram chat.

telegram_download_media

Download a stored Telegram attachment into the local media cache.

Group Administration

Group administration tools are grouped to keep the MCP tool list small. Call qq_group_admin_help to discover action names and required fields. Disbanding groups is intentionally not implemented; leave_group only makes the bot leave the group.

All group-specific administration tools reject group_id values outside qq.allowedGroupIds when that allowlist is configured. Actions that mutate group state require confirm: true; use that only after the user explicitly asks for the operation.

Mentions, Images, and Replies

Use parts when a group message needs exact ordering of text, mentions, and images:

[
  { "type": "text", "text": "请 " },
  { "type": "at", "user_id": "TARGET_QQ" },
  { "type": "text", "text": " 看一下 " },
  { "type": "image", "file": "/workspace/result.png" }
]

Reply to a specific QQ message by passing reply_to_message_id with the OneBot message_id from the inbound prompt or one of the history tools.

Images in outbound messages use OneBot image segments. Non-image files use NapCat-compatible upload_group_file and upload_private_file actions.

QQ merged-forward messages remain opaque in inbound prompts and history until the agent calls qq_get_forward_messages. The tool returns every nested node in depth-first order. To fetch one internal image, file, voice, or video afterward, pass the outer message_id, the returned forward_node_path, and its zero-based attachment_index to qq_download_media. Forwarded children are never added to ordinary history, FTS, or embedding indexes.

Telegram text messages use ordered parts for mentions:

[
  { "type": "text", "text": "请 " },
  { "type": "mention", "username": "alice" },
  { "type": "text", "text": " 看一下;也同步给 " },
  { "type": "mention", "user_id": "123456789", "text": "Bob" }
]

Use telegram_send_rich_message when a Telegram reply needs structured formatting such as headings, lists, tables, collapsible details, code blocks, or formulas. Pass exactly one of html or markdown:

{
  "chat_id": "-1001234567890",
  "html": "<h2>Summary</h2><ul><li>Done</li><li>Next step</li></ul>",
  "reply_to_message_id": "123",
  "message_thread_id": "456"
}

For Telegram files, call telegram_send_file for images and non-images alike. This sends through Telegram sendDocument, preserving the original file quality. Telegram rich message media blocks are intended for HTTP/HTTPS URLs; local /workspace and /app/media files should still be sent with telegram_send_file:

{
  "chat_id": "-1001234567890",
  "file": "/workspace/result.png",
  "caption": "结果图",
  "reply_to_message_id": "123",
  "message_thread_id": "456"
}

Message Routing

The bridge only forwards messages from configured QQ targets or Telegram chat ids:

  • Group messages: forwarded when the bot is at-mentioned or the message replies to a bot message.

  • Keyword messages: in any allowed QQ/Telegram group or private chat, messages containing any configured trigger keyword are forwarded. Keyword matching is case-insensitive.

  • Always-trigger group messages: for group ids in qq.alwaysTriggerGroupIds, every non-bot message is forwarded, even without an @mention or reply.

  • Private messages: forwarded for every message from configured private users.

  • Other allowed conversation messages: optionally stored when recordUntriggered is true, but not forwarded to Astral.

  • Telegram /chatid: always answered directly so you can discover the current Telegram chat.id before editing the allowlist.

  • Telegram group/supergroup/channel messages: forwarded when the bot is mentioned, the message replies to a bot message, or the chat id is in telegram.alwaysTriggerChatIds.

  • Telegram private messages: forwarded for every message from configured private chat ids.

  • /stop: in any allowed QQ/Telegram group or private chat, interrupts the active Astral turn and replies in the same conversation.

Every forwarded turn includes conversation_unread_count, the number of stored messages in the same group/private conversation since the previous Astral prompt, including the current trigger message. The agent can call qq_get_unread_messages or telegram_get_unread_messages when that context is useful; it does not need to call it for every message.

External Event API

When HTTP MCP is enabled, the same HTTP server can accept generic external events:

GET /api/events/schema

Returns a machine-readable OpenAPI 3.1 schema with examples and curl usage.

POST /api/events
Authorization: Bearer REPLACE_WITH_EVENT_API_TOKEN
Content-Type: application/json
{
  "source": "minecraft:survival-main",
  "event_type": "player_join",
  "title": "Player joined",
  "body": "Steve joined the server",
  "actor": { "id": "uuid", "name": "Steve" },
  "metadata": { "world": "world", "x": 120, "y": 64, "z": -33 }
}

The bridge queues attention-worthy events, merges short bursts into one bounded Astral turn, and submits that merged event to the current Astral thread using the same queue as QQ messages. Set wants_agent_attention to false to validate and accept an event without forwarding it into Astral. Batching is controlled by externalEvents.debounceMs, externalEvents.maxBatchEvents, and externalEvents.maxBatchBodyChars.

Request fields:

Field

Required

Description

source

Yes

System or integration name, such as minecraft:survival-main or monitoring.

event_type / type

No

Event kind. Defaults to event.

title

No

Short title.

body / text

No

Main event text.

severity

No

Severity label. Defaults to info.

actor

No

Entity that caused the event.

metadata

No

Structured event details.

dedupe_key

No

Optional stable key supplied by the caller.

occurred_at

No

ISO timestamp, Unix seconds, or Unix milliseconds.

wants_agent_attention

No

Defaults to true; set false for validation-only events.

id

No

Caller-supplied event id. A UUID is generated when omitted.

Successful requests return 202 Accepted with { ok, accepted_for_astral, event }. Unauthorized requests return 401 when externalEvents.authToken is configured.

Astral App-Server Behavior

The bridge talks to Astral app-server over WebSocket and uses:

  • initialize

  • thread/resume

  • turn/start

  • turn/steer when the current thread already has an active turn

When starting a turn, the bridge requests approvalPolicy = "never" and sandboxPolicy = { type = "dangerFullAccess" }. If you use this mode, isolate Astral at the container, VM, or host level and only mount directories you are willing to expose.

Server approval requests for command execution and file changes are canceled by default. QQ sending should happen through the MCP tools and Astral MCP tool approval settings, not through the bridge approving arbitrary app-server actions.

Docker and OrbStack

The generic bridge image is defined by Dockerfile.

OrbStack deployment templates live under deploy/orbstack. They include:

  • bridge: OneBot reverse WebSocket plus Streamable HTTP MCP.

  • astral-code: an Ubuntu-based Astral app-server runtime with mapped config, binary, source, workspace, and build cache directories.

  • napcat: NapCat Docker service.

Copy deploy/orbstack/.env.example to .env, fill in your local values, and read the Chinese deployment guide at deploy/orbstack/README.md before running the compose stack. It covers required QQ/Telegram/Astral settings, persistent volumes, memory storage, and the memory phase2 sandbox option.

Security Notes

  • Do not commit real QQ ids, app-server tokens, API keys, NapCat WebUI tokens, SQLite databases, downloaded media, or local config files.

  • Bind services to loopback unless you intentionally need LAN access.

  • The app-server danger-full-access mode is powerful. Use a dedicated container or host account and mount only the workspace/config directories needed by the agent.

  • Review allowed groups and private users before exposing the bot to busy chats.

Development

pnpm install
pnpm typecheck
pnpm build

Project layout:

src/                 Bridge source
examples/            Example JSON config
deploy/orbstack/     Self-hosted OrbStack deployment template
data/                Runtime SQLite state, ignored by git
media/               Runtime media cache, ignored by git

Acknowledgements

The design of query_messages was inspired by Obelisk and its agent-first approach to retrieval: give the agent a programmable query surface over a local SQLite index, then let the agent decide how to search, inspect context, and follow the evidence. Thank you for showing how much more capable retrieval becomes when the agent owns the query plan.

License

Licensed under the Apache License, Version 2.0. See LICENSE.

Available Tools

10 tools
qq_download_mediaC

Download a stored QQ image/file attachment to the local media cache and return its path.

ParametersJSON Schema
NameRequiredDescriptionDefault
attachment_idNo
message_idNo
attachment_indexNo

TDQS

C2.7/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Without annotations, the description should fully disclose behavioral traits. It mentions downloading to local cache and returning a path, but does not specify side effects (e.g., overwrites), permission needs, or what happens if the attachment does not exist.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, front-loaded sentence with no redundant words. Every part contributes to stating the tool's core action and result, which is ideal for conciseness.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the absence of annotations, output schema, and parameter descriptions, the description is too sparse. It does not cover prerequisites, return value format, or parameter semantics, making it incomplete for secure or correct use.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters1/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 0% schema description coverage, the description was expected to explain the three parameters (attachment_id, message_id, attachment_index). It fails to do so, leaving their roles and constraints entirely undocumented.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the verb 'download' and the resource 'stored QQ image/file attachment', indicating its function. However, it does not explicitly differentiate from sibling tools like qq_send_group_file or qq_get_message, which might also involve attachments.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides no guidance on when to use this tool versus alternatives. It lacks context about prerequisites, such as needing a message_id, or situations where other tools would be more appropriate.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

qq_get_conversation_stateC

Get bridge state for a QQ conversation.

ParametersJSON Schema
NameRequiredDescriptionDefault
target_typeYes
target_idYes

TDQS

C2.9/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description should disclose behavioral traits like whether the tool is read-only, requires authentication, or has side effects. It simply states the operation, leaving the agent unaware of implications.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single sentence, which is concise but lacks essential details. It earns a middling score because while brevity is valued, the content is too sparse.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the lack of output schema and annotations, the description should provide more context about what 'bridge state' entails and how the output can be used. It fails to make the tool self-contained.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema has 0% description coverage, and the description does not explain what 'target_type' or 'target_id' represent beyond their names. The agent gets no additional context to properly populate parameters.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the verb 'Get' and the resource 'bridge state for a QQ conversation', making the tool's purpose unambiguous. It distinguishes from sibling tools like qq_get_message by specifying 'bridge state', which is unique.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides no guidance on when to use this tool versus alternatives, such as when to retrieve conversation state instead of messages. No prerequisites or context hints are given.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

qq_get_messageC

Get one stored QQ message by OneBot message_id.

ParametersJSON Schema
NameRequiredDescriptionDefault
message_idYes
target_typeNo
target_idNo

TDQS

C2.6/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries full burden but only says 'get'. It fails to disclose read-only nature, return structure, error handling, or whether the message must be previously stored by the bot. Minimal transparency.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single concise sentence with no wasted words. It is front-loaded with the verb and object. However, brevity comes at the cost of missing critical details.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given three parameters and no output schema, the description is severely incomplete. It omits return format, optional parameter roles, and any preconditions, leaving the agent underinformed for correct invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters1/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%; the description adds no meaning to parameters. It ignores target_type and target_id, leaving their purpose ambiguous given only message_id is required. The agent has no clue how to use optional params.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states it retrieves a stored QQ message by OneBot message_id, which distinguishes it from sibling tools that list or search messages. However, it could be more specific about the scope (e.g., 'single message').

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No guidance is provided on when to use this tool versus alternatives like qq_search_messages or qq_get_recent_messages. The agent receives no context about prerequisites or preferred scenarios.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

qq_get_recent_messagesC

Get recent stored QQ messages for a group or private conversation.

ParametersJSON Schema
NameRequiredDescriptionDefault
target_typeYes
target_idYes
limitNo
before_message_idNo

TDQS

C2.4/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description must carry the full burden of behavioral disclosure. It only states 'Get recent stored QQ messages' without explaining pagination (using before_message_id), ordering, default limit, or whether media is included. The minimal description leaves critical behavioral traits unspecified.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single sentence with no wasted words, but its brevity comes at the cost of completeness. It does not earn its place because it omits essential information for tool invocation.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness1/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, no annotations, and 0% parameter description coverage, the description is severely incomplete. It fails to explain pagination, error handling, rate limits, or response format, leaving an AI agent underinformed.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters1/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, and the description adds no parameter details. Properties like target_type, target_id, limit, and before_message_id are not explained. The description does not help an agent understand parameter roles beyond their names and types.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

Description clearly states verb ('get'), resource ('recent stored QQ messages'), and context ('group or private conversation'). It matches the target_type enum. However, it does not explicitly differentiate from sibling tools like qq_get_message or qq_get_unread_messages, so clarity is slightly reduced.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No guidance on when to use this tool versus alternatives. For example, it does not mention that this tool fetches stored history while qq_get_unread_messages filters unread, or that qq_search_messages is for searching. The description lacks usage context.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

qq_get_unread_messagesB

Get the current unread batch for a group or private conversation. This returns the messages counted by the latest conversation_unread prompt.

ParametersJSON Schema
NameRequiredDescriptionDefault
target_typeYes
target_idYes
limitNo

TDQS

B3.2/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description must fully disclose behavior. It mentions it returns 'messages counted by the latest conversation_unread prompt', which is vague and jargon-heavy. It does not clarify whether the tool is read-only, if it marks messages as read, or any side effects like rate limits or authentication requirements.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is only two sentences, focusing on the core function. However, the second sentence is somewhat redundant and uses unclear phrasing ('conversation_unread prompt'), slightly reducing clarity. Overall, it is concise but could be more efficient.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the complexity of unread message retrieval, no output schema, and sibling tools, the description is incomplete. It does not describe the return format (e.g., list of messages, IDs, or full objects), pagination, or prerequisites. This leaves agents uncertain about how to use the response or how the tool fits with related functionality.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the description must compensate. It relates target_type to group/private conversation and implies target_id identifies the conversation, but it does not explain the limit parameter (its default, meaning, or effect). The description adds minimal value beyond the schema itself, leaving parameter semantics largely unexplained.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states it gets the current unread batch for a group or private conversation, specifying the verb 'get' and resource 'unread messages'. This distinguishes it from siblings like qq_get_recent_messages, which retrieves all recent messages, and qq_get_message, which gets a specific message.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implicitly indicates it is for unread messages, but it does not explicitly state when to use this tool versus alternatives like qq_get_recent_messages or qq_search_messages. No when-not-to-use guidance is provided, leaving the agent to infer usage context.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

qq_search_messagesB

Search stored QQ text messages in a group or private conversation.

ParametersJSON Schema
NameRequiredDescriptionDefault
target_typeYes
target_idYes
queryYes
limitNo

TDQS

B3.1/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries full burden for disclosing behavioral traits. It only states the basic purpose and fails to describe important behaviors such as search algorithm (e.g., exact match, partial match), case sensitivity, handling of no results, authentication requirements, or pagination. This leaves significant uncertainty for an agent.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single sentence of 10 words, extremely concise and front-loaded with the key action and scope. Every word is necessary; there is no superfluous information. It is the model of conciseness.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool has 4 parameters (3 required), no output schema, and no annotations, the description is too terse. It omits critical context such as the format of search results (list of message IDs? full message objects?), error behavior, rate limits, and how the search interacts with QQ's storage (e.g., date range? all history?). Sibling tools like 'qq_get_message' suggest there might be message IDs, but without output schema or further detail, an agent cannot reliably interpret results.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate. It does not explain the semantics of individual parameters: target_id format (e.g., numeric ID or string?), query syntax (free text, exact match?), or limit behavior. It only implies via the description that target_type and target_id specify the conversation, which is already clear from the schema. This adds minimal value beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool searches stored QQ text messages and specifies the scope (group or private conversation). The name 'qq_search_messages' aligns with the action, and it is distinguishable from sibling tools like 'get_message' or 'get_recent_messages' which retrieve specific messages or lists rather than performing a search.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No guidance is provided on when to use this tool vs alternatives. There is no mention of prerequisites, limitations, or when not to use it. The description lacks contextual cues that help an agent decide to invoke this over other message retrieval tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

qq_send_group_fileC

Upload a local file or URL to a QQ group using NapCat's OneBot-compatible file action.

ParametersJSON Schema
NameRequiredDescriptionDefault
group_idYes
fileYes
nameNo

TDQS

C2.7/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Description lacks details on behavioral traits such as authorization requirements, side effects, error handling, or limitations on file size/types. With no annotations, the description should fully disclose these, but it does not.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Single sentence, no redundancy, efficiently states the action. Could be improved by front-loading key constraints, but acceptable.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Tool has 3 parameters, no output schema, and no annotations. Description does not explain return values, error conditions, parameter formats, or operational limitations. Incomplete for effective agent use.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema has 0% coverage, so description must compensate. It implies file can be a local path or URL, but does not specify format for group_id or the name parameter. The optional name is mentioned but not explained. Adds minimal semantic value.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states it uploads a local file or URL to a QQ group, using a specific compatible action. It distinguishes the target (QQ group) from siblings like qq_send_private_file, but does not explicitly contrast with qq_send_group_message.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No guidance on when to use this tool versus alternatives like qq_send_group_message or qq_send_private_file. Missing context for when uploading a file is appropriate.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

qq_send_group_messageB

Send a QQ group message. Supports exact ordered parts for mixed text, @mentions, and images.

ParametersJSON Schema
NameRequiredDescriptionDefault
group_idYes
messageNo
imagesNo
partsNo
reply_to_message_idNo

TDQS

B3.3/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description only discloses that it sends a message and supports ordered parts, but lacks details on mutation behavior, failure handling, auth requirements, or rate limits, leaving significant gaps.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences with no wasted words; the purpose is front-loaded and the feature support is concisely stated.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Despite 5 parameters, no annotations, and no output schema, the description is minimal; it does not explain return values, usage of individual params beyond parts, or prerequisites for sending group messages, making it incomplete for an agent.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema has 0% description coverage; the description adds some meaning to the 'parts' parameter (ordered types) but fails to explain other parameters like group_id, message, images, or reply_to_message_id, so it only partially compensates.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the verb 'Send' and the resource 'QQ group message', and mentions support for mixed text, @mentions, and images, distinguishing it from sibling tools like qq_send_private_message.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage for sending group messages but does not explicitly state when not to use it or provide alternatives; usage guidance is implied but not thorough.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

qq_send_private_fileB

Upload a local file or URL to a QQ private chat using NapCat's OneBot-compatible file action.

ParametersJSON Schema
NameRequiredDescriptionDefault
user_idYes
fileYes
nameNo

TDQS

B3.2/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description bears full responsibility. It mentions accepting both local files and URLs, which is useful, but lacks details on behavioral traits such as file size limits, whether URL downloads are performed server-side, or whether the operation is idempotent. As an upload action, it likely creates a resource, but this is implicit.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, front-loaded sentence that immediately conveys the primary action and target. It is concise and avoids fluff, though it sacrifices important parameter details. The structure is efficient for the purpose it serves.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the low parameter coverage (0%), no output schema, and no annotations, the description is incomplete for an agent to safely and correctly invoke this tool. Key missing items include return value, error scenarios, prerequisites (e.g., logged-in user), and file path requirements. The description only covers the basic action.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters1/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%. The description does not elaborate on any of the three parameters (user_id, file, name). While 'file' is hinted at via 'local file or URL', there is no explanation of user_id format, the purpose of optional name, or constraints like supported file types. The agent must infer from parameter names alone.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description explicitly states the action ('Upload a local file or URL') and the target resource ('QQ private chat'). It distinguishes from siblings by specifying 'private' as opposed to group file sending, and also mentions the underlying protocol ('NapCat's OneBot-compatible file action'), providing clear purpose.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description clearly indicates use in private chats via the phrase 'to a QQ private chat', which helps differentiate from group file sending (sibling qq_send_group_file). However, it does not provide explicit when-not-to-use guidance or compare with sending private messages (qq_send_private_message), which may cause ambiguity for agents unaware of file vs message distinction.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

qq_send_private_messageB

Send a QQ private message. Supports exact ordered text/image parts and replying to a message id.

ParametersJSON Schema
NameRequiredDescriptionDefault
user_idYes
messageNo
imagesNo
partsNo
reply_to_message_idNo

TDQS

B3.2/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries full burden. It mentions support for ordered parts and replies but omits critical behavioral details like side effects, rate limits, authentication requirements, or what happens if the user is offline. The transparency is minimal beyond basic functionality.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise at two sentences, with the first sentence stating the core purpose. It is front-loaded and contains no redundant information, though a slightly more structured layout could improve readability.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given 5 parameters (one required), 0% schema coverage, and no output schema, the description is insufficient. The tool supports complex features like ordered parts and replies, but the description does not explain how to use the 'parts' array, image formats, or reply functionality in enough detail for an agent to use correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, but the description only references 'parts' and 'reply_to_message_id' indirectly. Required parameter 'user_id' and optional 'message', 'images', and nested 'parts' structure are not explained. The description adds little meaning beyond parameter names.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action 'send' and the resource 'QQ private message', and highlights specific features (ordered text/image parts, replying). It effectively distinguishes from sibling tools like qq_send_group_message and qq_send_private_file.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage for sending private messages with ordered parts or replies, but lacks explicit guidance on when to use this over alternatives, such as qq_send_private_file for file-only messages. No exclusion criteria or prerequisites are mentioned.

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. Dates show when Glama detected each change.

  1. 10 tool updatesv0.1.0
    • First observedqq_download_media
    • First observedqq_get_conversation_state
    • First observedqq_get_message
    • First observedqq_get_recent_messages
    • First observedqq_get_unread_messages
    • First observedqq_search_messages
    • First observedqq_send_group_file
    • First observedqq_send_group_message
    • First observedqq_send_private_file
    • First observedqq_send_private_message

TDQS

B3.3/5.0

Scored across 10 tools

Disambiguation5/5

Each tool targets a distinct operation: download media, retrieve various message types, send messages/files to group/private, and check conversation state. No ambiguity between tools.

Naming Consistency5/5

All tools follow a consistent `qq_verb_noun` snake_case pattern, using clear verbs like download, get, send, search and specific objects like media, message, group_file, private_message.

Tool Count5/5

10 tools is well-scoped for a messaging bridge, covering message retrieval, sending, file uploads, and state queries without superfluous or missing functionality.

Completeness4/5

Core message lifecycle is covered: read, search, send (text/files) for both group and private. Minor gaps like deleting messages or listing conversations exist but are acceptable for a bridge focused on message relay.

Maintenance

ActivityActive
ResponsivenessUnresponsive

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    D
    maintenance
    An MCP server that enables AI clients to send and receive QQ messages through NapCatQQ (OneBot v11) for both private and group chats. It supports message context management, real-time WebSocket listening, and human-like typing simulation.
    7
    25
    MIT
  • F
    license
    Not graded
    quality
    B
    maintenance
    Enables interaction with NapCat QQ bot APIs for group management, messaging, and system operations. Supports HTTP and WebSocket modes with security features like group restrictions and readonly mode.
    4
    -
  • A
    license
    A
    quality
    B
    maintenance
    QQ MCP Server with Auto-Wake, message send/receive, group management, file sharing, and timed tasks. Connects via NapCatQQ (OneBot v11). One-click setup with quickstart.ps1.Based on Amadeus-QQ-MCP.
    33
    3
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    A MCP server that exposes QQ bot capabilities over Streamable HTTP, enabling clients to query bot status, read group and friend info, fetch chat history, and send group/private text messages.
    2
    MIT

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/oines/astral-im-bridge'

If you have feedback or need assistance with the MCP directory API, please join our Discord server