Rocket Cli
FreeNot checkedRocket.Chat bridge with a local SQLite/FTS5 cache — CLI for humans, MCP server for LLM agents.
About
Rocket.Chat bridge with a local SQLite/FTS5 cache — CLI for humans, MCP server for LLM agents.
README
Rocket.Chat bridge with a local SQLite/FTS5 cache — CLI for humans, MCP server for LLM agents.
On first read a room is backfilled (up to 500 messages / 30 days). Subsequent reads hit chat.syncMessages for deltas (60 s TTL), then serve from SQLite — zero network on cache-fresh rooms. Full-text search runs across all cached rooms locally via FTS5; when scoped to a room it falls back to the server and ingests the results into the cache.
graph TB
Agent["LLM Agent\n(Claude · MCP stdio)"]
Human["Human\n(CLI)"]
subgraph Core["Core"]
RD["RoomDirectory"]
SE["SyncEngine"]
SS["SearchService"]
AT["Attention\n(mentions · unread)"]
ED["EmojiDirectory"]
end
subgraph Cache["SQLite cache"]
MSG["messages\n+ FTS5 index"]
META["rooms · emojis"]
end
RC["Rocket.Chat\n(REST API)"]
Agent -->|"MCP tools"| Core
Human -->|"commands"| Core
Core -->|"cache hit: 0 network, sub-ms"| Cache
Core -->|"miss/stale: backfill + syncMessages deltas"| RC
RC -->|"write-through"| Cache
Agent <-->|"open_url / permalinks"| RC
classDef cache fill:#f0f7ff,stroke:#4a90d9,stroke-width:2px
class Cache cache
Architecture at a glance: agents and humans share one Core; the SQLite cache absorbs most reads; the server is only hit on cache miss or write.
Loading philosophy — network follows user value, never ambient
Data is loaded in priority order of what you asked for; the cache accelerates but never blocks, and the tool never fetches history nobody requested:
- Triage is always shallow.
get_unread/get_mentions/get_attentionfetch only the slice after each room's last-read watermark (ts > ls) — usually a handful of messages — not a full backfill. Answering "what's unread?" stays fast even on a cold cache with many unread rooms. - Reading serves instantly, revalidates in the background.
get_messages/list_threadsuse stale-while-revalidate: a cached room is served immediately while a delta sync refreshes it in the background (the response carries"refreshing": truewhen that happens — the data may be seconds stale). A totally-cold room blocks only for one history page (≈100 messages, enough to answer) and then that room's remaining backfill completes in the background — because reading a room is the intent to have its recent history. - Deep history is explicit only. Full backfill happens when you ask for it:
rocket-cli sync [room] | --all(blocking, human choice) or thesync_historyMCP tool (an agent calls it when a task needs history beyond the recent window — e.g. "summarize the last month"). There is no ambient background warmer — the MCP server never progressively fills the database for data nobody asked about.
What needs my attention
The headline feature: one call answers "what did I miss?". get_attention (MCP) / rocket-cli attention (CLI) fuses mentions of you, unread DMs, unread thread replies, and unread channel messages into a single prioritized, deduplicated digest — a message that both mentions you and is unread appears once, in the mentions section, flagged alsoUnread. Every item carries a clickable Rocket.Chat link, and the whole flow is strictly read-only (it never clears a single unread badge). Paste any of those links back to the agent via open_url (or rocket-cli open <url>) and you get the surrounding conversation plus the ids needed to reply — a full triage-to-reply round-trip without leaving the chat.
Install
Requirements: Node >= 20, npm
git clone <repo-url> # or your fork/path
cd rocket-cli
npm install
npm run build
npm link # optional: puts `rocket-cli` on your PATH
After npm link, examples below can use rocket-cli instead of node dist/cli.js.
Get your credentials
- Open Rocket.Chat in your browser → click your avatar (top-left) → My Account → Personal Access Tokens
- If the section is missing: an admin must enable the
API_Enable_Personal_Access_Tokenssetting, and your role needs thecreate-personal-access-tokenspermission - Name the token (e.g.
rocket-cli), check Ignore Two Factor Authentication (without it, API calls may demand TOTP codes the CLI cannot answer), then click Add - Copy both the token and the user ID — they appear together in the same confirmation dialog, and the token is shown only once
- Copy the example env file and fill in your values:
Setcp .env.example .envROCKETCHAT_URL,ROCKETCHAT_TOKEN, andROCKETCHAT_USER_ID. The CLI auto-loads.envfrom the directory you run it in; real environment variables always take precedence.
Quickstart
rocket-cli rooms # lists rooms you're subscribed to — verifies auth
rocket-cli sync --all # initial backfill into the local cache
rocket-cli messages general -n 20
rocket-cli search "deploy"
Cache reset: rm ~/.local/share/rocket-cli/cache.db* — next run re-syncs from the server.
Multiple servers (profiles)
Connect to more than one Rocket.Chat server with named profiles. Each profile carries its own URL, token, user id, and an isolated database — data is never mixed across servers.
Profiles live in ~/.config/rocket-cli/profiles.json (XDG-aware; XDG_CONFIG_HOME honored). The file holds tokens, so it is written chmod 600 (owner read/write only) — keep it that way.
{
"defaultProfile": "test",
"profiles": {
"test": {
"url": "https://test.example.com",
"token": "REPLACE_WITH_TEST_TOKEN",
"userId": "REPLACE_WITH_TEST_USER_ID"
},
"work": {
"url": "https://chat.company.com",
"token": "REPLACE_WITH_WORK_TOKEN",
"userId": "REPLACE_WITH_WORK_USER_ID",
"readOnly": true
}
}
}
Optional per-profile fields: db (explicit database path), readOnly, syncTtlSeconds, backfillLimit, emojiImages.
# List profiles (name, url, db path, read-only, * = default). Tokens never printed.
rocket-cli profiles
# Add a profile (writes profiles.json with mode 600)
rocket-cli profiles --add test --url https://test.example.com --token <t> --user-id <id>
rocket-cli profiles --add work --url https://chat.company.com --token <t> --user-id <id> --read-only
# Set the default profile (used when no --profile / ROCKET_CLI_PROFILE is given)
rocket-cli profiles --default test
# Use a profile for any command
rocket-cli --profile work rooms
rocket-cli --profile work attention
ROCKET_CLI_PROFILE=work rocket-cli rooms # env equivalent (handy for MCP)
Resolution order: an explicit --profile flag (or ROCKET_CLI_PROFILE env) selects a profile → the profile's connection identity (url, token, userId, db) is authoritative — ambient env vars and cwd .env values for those fields are ignored. Tuning knobs (ROCKET_CLI_SYNC_TTL_SECONDS, ROCKET_CLI_BACKFILL_LIMIT, ROCKET_CLI_EMOJI_IMAGES, ROCKET_CLI_READ_ONLY) may still be overridden by env when the profile omits them. With no profile and only env vars, behavior is exactly as before. A defaultProfile applies when nothing is explicitly selected and ROCKETCHAT_URL is not already in the environment (so legacy env-only setups remain untouched).
Per-profile database isolation: a profile's db defaults to ~/.local/share/rocket-cli/<profile>.db (override with the profile's db field). No profile uses the legacy ~/.local/share/rocket-cli/cache.db. A database file is bound on first use to the (server URL, user id) it was synced from — opening it later under a different identity is a hard error (it tells you which profile/db/server mismatched and how to fix it), so cross-profile contamination is impossible.
Read-only mode ("readOnly": true, or --read-only on profiles --add) is the safety mode for production / company servers. It blocks every server write:
- MCP
serveregisters 15 tools instead of 18 —send_message,add_reaction, andupload_fileare not exposed. All reads (includingdownload_attachmentandsync_history, which only write local disk / the local cache) still work. - CLI
send,upload, andwatch --notifyrefuse with a clear error and exit 1. scripts/seed.tsaborts immediately (it writes to the server).
Two MCP registrations for Claude Code
Register one MCP server per profile, each serve with its ROCKET_CLI_PROFILE env — no flags needed. Make work read-only so the agent can read your company server but never post to it:
{
"mcpServers": {
"rocketchat-test": {
"command": "node",
"args": ["/absolute/path/to/rocket-cli/dist/cli.js", "serve"],
"env": { "ROCKET_CLI_PROFILE": "test" }
},
"rocketchat-work": {
"command": "node",
"args": ["/absolute/path/to/rocket-cli/dist/cli.js", "serve"],
"env": { "ROCKET_CLI_PROFILE": "work" }
}
}
}
See .mcp.json.example for a copy-paste starting point.
CLI usage
All commands accept --json for machine-readable output and --profile <name> to select a named connection profile (see Multiple servers).
# List rooms you belong to
node dist/cli.js rooms
node dist/cli.js rooms --type channel
node dist/cli.js rooms --filter infra
# Sync a room or all rooms
node dist/cli.js sync #dev
node dist/cli.js sync --all
node dist/cli.js sync --all --force # bypass TTL, re-fetch everything
# Read messages
node dist/cli.js messages #dev -n 50
node dist/cli.js messages #dev -n 20 --before 2026-06-01T00:00:00.000Z
# Show everything unread since you last read each room (read-only — never clears badges)
node dist/cli.js unread
node dist/cli.js unread --limit 20 --no-threads
# One-call triage: mentions + unread DMs + threads + channels, prioritized & deduplicated
node dist/cli.js attention
node dist/cli.js attention --since-days 2 --limit 20 --all-broadcasts
# Just the messages that mention you, across all cached rooms (read-only)
node dist/cli.js mentions
node dist/cli.js mentions --since-days 14 --all-broadcasts
# Show the conversation around a message id (from search, mentions, or a link)
node dist/cli.js context <message-id>
node dist/cli.js context <message-id> --before 20 --after 10
# Paste any Rocket.Chat web link to open its content + how to reply
node dist/cli.js open "https://chat.example.com/channel/general?msg=<id>"
# Full-text search (cross-room by default)
node dist/cli.js search "deploy error"
node dist/cli.js search "deploy error" --room #dev
node dist/cli.js search "deploy error" --room #dev --author jsmith --limit 10
# Send a message
node dist/cli.js send #dev "Hello team"
node dist/cli.js send #dev "Fixed in the next build" --thread <parent-message-id>
# List threads in a room; show a specific thread
node dist/cli.js threads general -n 10
node dist/cli.js thread <parent-message-id>
# Watch for messages matching a query (local FTS)
node dist/cli.js watch "deploy error" --once
node dist/cli.js watch "incident" --room #ops --interval 30
# Upload a file to a room
node dist/cli.js upload general /path/to/report.pdf --text "Q2 report"
# Download an attachment (use the link from `messages` output: [file] name -> /file-upload/…)
node dist/cli.js download /file-upload/abc123/report.pdf --out /tmp/report.pdf
# List custom emojis registered on the server
node dist/cli.js emojis
node dist/cli.js emojis --filter rocket
node dist/cli.js emojis --sync # force a refresh, ignore TTL
node dist/cli.js emojis --export /tmp/emoji # save every emoji image to a directory
# Start the MCP stdio server (used by Claude Code / Claude Desktop)
node dist/cli.js serve
# Manage named connection profiles (multiple servers)
node dist/cli.js profiles
node dist/cli.js profiles --add work --url https://chat.company.com --token <t> --user-id <id> --read-only
rooms flags
| Flag | Description |
|---|---|
--type <type> |
Filter by type: c / channel, p / group, d / dm |
--filter <substr> |
Case-insensitive name substring filter |
sync flags
| Flag | Description |
|---|---|
[room] |
Room name, #channel, or id |
--all |
Sync every subscribed room sequentially |
--force |
Bypass TTL and re-sync even if cache is fresh |
messages flags
| Flag | Description |
|---|---|
-n, --count <n> |
Number of messages to show (default 30) |
--before <ISO> |
Show messages older than this ISO 8601 timestamp |
--include-system |
Include system messages (joins, topic changes, etc.) |
unread flags
Read-only: lists messages with ts newer than each room's server-side last-read watermark (the marker the UI sets when you open a room). It never calls subscriptions.read and never clears unread badges. Rooms with no read marker fall back to a newest-N approximation, flagged in the output.
Which rooms count as unread mirrors the Rocket.Chat sidebar exactly. A room is surfaced when it has an unread signal (unread count, the alert flag, or unread thread replies) and its "Hide unread counter" room setting (hideUnreadStatus) is off — the same (alert || unread || tunread) && !hideUnreadStatus predicate the sidebar uses (apps/meteor/client/sidebar/hooks/useRoomList.ts). The one exception the UI keeps for a hidden room is an explicit mention: a room with "Hide unread counter" on still appears when you are mentioned in it (userMentions/groupMentions, or a thread reply that mentions you) and "Hide mention" is off, matching getSubscriptionUnreadData.ts. Such a room is labeled hidden room, mentioned in the output and carries hiddenMentioned: true in the JSON report. Use --all to ignore the hide setting and list every room with any unread signal (the pre-parity behavior).
| Flag | Description |
|---|---|
--limit <n> |
Max messages per room (default 50) |
--no-threads |
Skip unread thread replies (threads shown by default) |
--all |
Also include rooms whose "Hide unread counter" setting is on (default matches the UI: hidden rooms appear only when you are mentioned) |
attention flags
Read-only one-call triage. Runs the mentions and unread views, then fuses them into prioritized sections — MENTIONS, DIRECT MESSAGES, THREADS, CHANNELS — deduplicated by message id (a mentioned message that is also unread is shown once, under mentions, flagged also unread). Every item carries a clickable link. Never clears a badge.
| Flag | Description |
|---|---|
--since-days <n> |
How far back to look for mentions, in days (default 7) |
--limit <n> |
Max items per section (default 30) |
--all-broadcasts |
Also include channel-wide @all/@here mentions |
mentions flags
| Flag | Description |
|---|---|
--since-days <n> |
How far back to look, in days (default 7) |
--limit <n> |
Max total mentions to show (default 50) |
--all-broadcasts |
Also include channel-wide @all/@here mentions |
context flags
| Flag | Description |
|---|---|
<messageId> |
The message to center the conversation on |
--before <n> |
Messages to show before the target (0-50, default 10) |
--after <n> |
Messages to show after the target (0-50, default 5) |
open flags
Paste any Rocket.Chat web link — a message, a thread, or a plain channel — and open resolves it, prints the surrounding conversation (target marked →), and shows how to reply.
| Flag | Description |
|---|---|
<url> |
Any Rocket.Chat link: message, thread, or channel |
-n, --count <n> |
Number of messages of context to show (default 20) |
search flags
| Flag | Description |
|---|---|
--room <r> |
Limit to one room and enable server-side fallback |
--author <u> |
Filter by author username |
--limit <n> |
Maximum results (default 20) |
send flags
| Flag | Description |
|---|---|
--thread <id> |
Reply to the thread with this parent message id |
threads flags
| Flag | Description |
|---|---|
-n, --count <n> |
Number of threads to show (default 25) |
--text <filter> |
Filter threads by parent message text |
thread flags
| Flag | Description |
|---|---|
-n, --count <n> |
Number of replies to show (default 50) |
watch flags
| Flag | Description |
|---|---|
--room <r> |
Limit to a specific room (default: all rooms) |
--interval <sec> |
Poll interval in seconds (default 60) |
--once |
Run a single pass over the last 24 h and exit |
--notify <target> |
Post each match to this room or user |
--log <path> |
Append matches as JSON lines to a file |
upload flags
| Flag | Description |
|---|---|
--text <t> |
Caption message for the attachment |
--thread <id> |
Attach inside the thread with this parent message id |
--name <n> |
Override the uploaded file name |
download flags
| Flag | Description |
|---|---|
--out <path> |
Where to save the file (default: ~/Downloads/<name>) |
emojis flags
| Flag | Description |
|---|---|
--filter <substr> |
Case-insensitive name substring filter |
--sync |
Force a refresh, ignoring the cache TTL |
--export <dir> |
Fetch and write each emoji image as <name>.<ext> to a directory |
Image caching can be disabled with ROCKET_CLI_EMOJI_IMAGES=false (metadata only); --export and get_custom_emoji then degrade to names/aliases plus the server image URL.
MCP server for Claude Code
Add to .mcp.json in your project root (or ~/.claude/mcp.json for global):
{
"mcpServers": {
"rocketchat": {
"command": "node",
"args": ["/absolute/path/to/rocket-cli/dist/cli.js", "serve"],
"env": {
"ROCKETCHAT_URL": "${ROCKETCHAT_URL}",
"ROCKETCHAT_TOKEN": "${ROCKETCHAT_TOKEN}",
"ROCKETCHAT_USER_ID": "${ROCKETCHAT_USER_ID}"
}
}
}
}
Use ${VARIABLE} env-expansion so the token is read from your shell environment, not stored literally in the file. Never commit a .mcp.json with a real token.
For Claude Desktop, add an equivalent entry under mcpServers in ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) with the same command/args/env structure.
See .mcp.json.example at the repo root for a copy-paste starting point.
CLI alternative — register with the claude CLI instead of editing .mcp.json manually:
claude mcp add rocketchat \
-e ROCKETCHAT_URL=https://chat.example.com \
-e ROCKETCHAT_TOKEN=your-token \
-e ROCKETCHAT_USER_ID=your-user-id \
-- node /absolute/path/to/rocket-cli/dist/cli.js serve
The -e flag sets env vars scoped to this MCP server; they are not exported to your shell. Run claude mcp add --help for scope and transport options.
MCP tools
Eighteen tools are exposed to the LLM agent (fifteen under a read-only profile — the three write tools send_message, add_reaction, and upload_file are then withheld; see Multiple servers):
| Tool | What it does | Key inputs |
|---|---|---|
list_rooms |
List subscribed channels, groups, and DMs | filter?, type? (channel/group/dm), limit? (default 50) |
get_messages |
Read messages from a room, newest first | room, count? (default 30, max 100), before?, after? (ISO 8601), includeSystem? |
get_attention |
One-call triage of everything needing attention — mentions, unread DMs, unread threads, unread channels, prioritized + deduplicated, every item linked (read-only) | sinceDays? (default 7, max 90), limitPerSection? (default 30, max 100), includeChannelWide? (default false), includeHidden? (default false) |
get_unread |
List everything unread since you last read each room, at sidebar parity — rooms with "Hide unread counter" on are skipped unless you are mentioned (read-only; never clears badges) | limitPerRoom? (default 50, max 100), includeThreads? (default true), includeHidden? (default false) |
get_mentions |
Messages that mention the user (@username) across all cached rooms, each with a link (read-only) | sinceDays? (default 7, max 90), limit? (default 50, max 100), includeChannelWide? (default false) |
get_message_context |
Show the conversation around a message id; thread replies pivot to their whole thread | messageId, before? (0-50, default 10), after? (0-50, default 5) |
open_url |
Open any pasted Rocket.Chat link (message, thread, or channel) and return its content + the ids needed to reply/react | url, count? (1-100, default 20) |
get_thread_messages |
Read a full thread (parent + replies) | threadId (parent message id), count? (default 50) |
list_threads |
List active threads in a room by last activity | room, count? (default 25), text? (filter parent text) |
sync_history |
Load older history for one room into the local cache — use only when a task needs history beyond what get_messages returns; routine triage never needs it (read-only; writes only the local cache) |
room? (omit = most stale unread room), depth? (default backfill limit) |
search_messages |
Full-text search across all cached rooms | query, room? (scopes + enables server fallback), author?, limit? (default 20) |
send_message |
Post to a room or reply in a thread | target (#channel/@user/name/id), text, threadId? |
add_reaction |
Add or remove an emoji reaction on a message | messageId, emoji (colon-wrapping optional), remove? (bool, default false) |
get_user_profile |
Look up a user's profile by username or id | user (username with or without leading @, or user id) |
upload_file |
Attach a local file to a room or thread | room (#channel/@user/name/id), filePath (absolute path), text? (caption), threadId?, fileName? |
download_attachment |
Download a message attachment to local disk | fileUrl (attachment link after ->, e.g. /file-upload/…), savePath? (default: ~/Downloads/<name>) |
list_custom_emojis |
List custom emojis registered on this server (beyond unicode) | filter? (name substring) |
get_custom_emoji |
Show a custom emoji's image (returns image content) | name (with or without colons) |
get_messages and list_threads return an envelope with room, syncedThrough, and coverage so the agent knows the freshness and depth of the cached data, plus "refreshing": true when the answer was served from cache while a background sync revalidates it (data may be seconds stale). Thread parents in get_messages carry a replyCount; pass that message's id as threadId to get_thread_messages.
Attachment links appear in get_messages output as [file] name -> /file-upload/…; pass the part after -> as fileUrl to download_attachment.
Agent skills
skills/ ships six Claude Code skills that teach an agent how to drive rocket-cli (via the MCP tools, or the --json CLI as a fallback):
- rocket-attention — triage "what needs my attention" (mentions, unread DMs/threads/channels).
- rocket-catchup — summarize or recap one specific room or thread.
- rocket-find — full-text search for a known message, link, or file.
- rocket-link — open any pasted Rocket.Chat URL and show how to act on it.
- rocket-send — send/reply/react/upload, with read-only degradation.
- rocket-guide — reference: tool table, cache model, profiles, CLI↔MCP mapping.
Install them with ./scripts/install-skills.sh — it symlinks each skills/<name>/ into ~/.claude/skills/, so edits in this repo propagate live. Re-running is safe; ./scripts/install-skills.sh --uninstall removes only the symlinks that point back into this repo.
Architecture
- Lazy backfill — first access to a room fetches up to 500 messages / 30 days via
channels.history/groups.history/im.history. - Delta sync — subsequent reads call
chat.syncMessages(lastUpdate)(60 s TTL), applying edits and deletions into the local store. - FTS5 search — BM25-ranked full-text search across all cached rooms; if results are thin and a room is specified, falls back to
chat.searchand ingests the server results into the cache. - Write-through sends —
chat.postMessageresponse is upserted into the local DB, so the sent message appears in the nextget_messageswithout a sync round-trip. - Threads on demand —
ensureThreadLoadedcheckstcountvs local reply count and backfills gaps viachat.getThreadMessages.
DB location: ~/.local/share/rocket-cli/cache.db (XDG data home) for the default env-only config; each named profile uses its own ~/.local/share/rocket-cli/<profile>.db (see Multiple servers). Override either with ROCKET_CLI_DB or a profile's db field.
Server load and rate limits
How rocket-cli stays gentle by construction
rocket-cli is designed to minimize server pressure:
| Mechanism | Detail |
|---|---|
| Concurrent requests | Global semaphore caps in-flight API calls at 2 at all times |
| Cache-first reads | Repeat reads hit SQLite — zero network. Sync is TTL-gated (default 60 s). Each profile has its own isolated db |
| Bounded backfills | Initial room backfill is capped at 500 messages / 30 days, fetched in pages of 100 |
| Late-join rooms | Rooms unsynced longer than the backfill window are re-backfilled in the same bounded pages rather than requesting an unbounded delta from the server's last watermark |
watch polling |
Queries the local FTS5 index only — never hits a server-side search endpoint |
Rocket.Chat's built-in rate limiter
Rocket.Chat applies a per-endpoint, per-IP limit out of the box:
| Setting | Default | Admin path |
|---|---|---|
API_Enable_Rate_Limiter_Limit_Calls_Default |
10 calls / 60 s | Admin → Settings → Rate Limiter |
API_Enable_Rate_Limiter_Limit_Time_Default |
60 000 ms | same |
Both values are tunable at runtime without a restart. When rocket-cli receives a 429, it backs off using the server's own reset signal (X-RateLimit-Reset header or details.seconds in the error body). Rocket.Chat does not send a Retry-After header.
Important caveat for admin / bot tokens
Accounts that hold the api-bypass-rate-limit permission are not throttled by the server at all. By default this permission is granted to the admin, bot, and app roles. If you run rocket-cli under an admin Personal Access Token (a common setup), the server-side limiter is effectively off — rocket-cli's own 2-concurrent-request cap is the only brake.
This is fine in practice (see the table above), but worth knowing: the "10 calls/60 s" numbers below do not apply to your session if your token belongs to an admin or bot account.
Practical throughput numbers
| Token type | First sync --all (200 rooms) |
Subsequent runs |
|---|---|---|
| Non-admin (default limits, ≈1 room/6 s per endpoint bucket) | ~20 min | Near-instant — cache hit, 0 network |
| Admin / bot (bypass-rate-limit) | Seconds | Near-instant |
After the first sync the cache absorbs routine reads; typical interactive use generates a handful of delta calls per session regardless of token type.
Environment variables
| Variable | Required | Default | Description |
|---|---|---|---|
ROCKETCHAT_URL |
yes | — | Base URL of your Rocket.Chat server (e.g. https://chat.example.com) |
ROCKETCHAT_TOKEN |
yes | — | Personal Access Token |
ROCKETCHAT_USER_ID |
yes | — | Your Rocket.Chat user id |
ROCKET_CLI_DB |
no | ~/.local/share/rocket-cli/cache.db |
Override the SQLite database path |
ROCKET_CLI_SYNC_TTL_SECONDS |
no | 60 |
How long before a cached room is considered stale |
ROCKET_CLI_BACKFILL_LIMIT |
no | 500 |
Max messages to fetch on initial room backfill |
ROCKET_CLI_EMOJI_IMAGES |
no | true |
Cache custom-emoji image bytes. false/0 caches metadata only (no image fetch/storage) |
ROCKET_CLI_PROFILE |
no | — | Select a named profile from profiles.json (equivalent to --profile); used by MCP registrations |
Validating against your own server
rocket-cli's most important features — unread, mentions, threads, DM unreads — only have meaningful state when other users have generated activity for you. Your own messages never mark your own rooms unread or mention yourself. To exercise the tool end-to-end you need a realistic multi-user workspace.
Two scripts under scripts/ do this against any server where you hold an admin PAT:
scripts/seed.ts— creates four personas (ana.dev,bruno.qa,carla.pm,diego.ops), public channels (#engineering,#random,#incidents), a private group (#leadership), DMs and a multi-party DM to you, then posts a believable conversation fabric as those personas: threads (incl. one mentioning you and a 30+ reply long thread), an edited message, a deleted message, an@all/@herebroadcast, file + image uploads, a custom-emoji reaction, a quote, rich-text and a ~3000-char message, plus negative cases that must stay invisible to you (a#secret-opschannel you are not in, and a persona↔persona DM). It is idempotent: re-running checks-before-creating and will not duplicate content.scripts/validate.ts— the automated true-usage test. It runs the built CLI with an isolated temp cache (ROCKET_CLI_DB), cold-syncs every room, then asserts the seeded state surfaces correctly: attention shows the mentions / DM unreads / unread thread,unreadlists the seeded rooms,mentionsfinds 3+,searchhits thread content,threadreads the long thread fully,openresolves a permalink with reply affordances, the edited text is reflected, the deleted message is gone, and the negative cases never leak. Each assertion prints a pass/fail line; the script exits non-zero on any failure.- Sidebar parity: on a default-config server (
Unread_Count = user_and_group_mentions_only) a plain-chatter channel setsalert: truebutunread: 0; validate asserts such a channel (#random, no@jeanmention) still appears inunread/attention — flaggedactivityOnly— instead of being dropped.
- Sidebar parity: on a default-config server (
[!WARNING] Use a disposable / personal test server only.
seed.tsCREATES users and rooms and posts messages. Never run it against a production or shared workspace. It reads the same.envas the CLI and requires the configured account to be an admin.
# requires: a built CLI (npm run build) + admin PAT in .env
npm run seed # create the multi-user state (idempotent)
npm run validate # cold-sync into a temp cache and assert everything
npm run validate:full # both, back to back
Persona passwords are generated once and stored in scripts/.seed-credentials.json
(gitignored, mode 0600); the path and password are printed to stderr only, never
to stdout. The scripts live outside the src tsconfig rootDir; typecheck them with
npx tsc --noEmit --strict --module NodeNext --moduleResolution NodeNext --target ES2022 --skipLibCheck --types node scripts/*.ts.
Known issues
See docs/KNOWN_ISSUES.md.
Installing Rocket Cli
This server has no published package — it is built from source. Open the repository and follow its README.
▸ github.com/jeanfbrito/rocket-cliFAQ
Is Rocket Cli MCP free?
Yes, Rocket Cli MCP is free — one-click install via Unyly at no cost.
Does Rocket Cli need an API key?
No, Rocket Cli runs without API keys or environment variables.
Is Rocket Cli hosted or self-hosted?
Self-hosted: the server runs locally on your machine via the install command above.
How do I install Rocket Cli in Claude Desktop, Claude Code or Cursor?
Open Rocket Cli on unyly.org, pick your client tab (Claude Desktop, Claude Code, Cursor) and press Install — the config is generated automatically, no JSON editing.
Related MCPs
Gmail
Read, send and search emails from Claude
by GoogleSlack
Send, search and summarize Slack messages
by SlackRunbear
No-code MCP client for team chat platforms, such as Slack, Microsoft Teams, and Discord.
Discord Server
A community discord server dedicated to MCP by [Frank Fiegel](https://github.com/punkpeye)
Compare Rocket Cli with
Not sure what to pick?
Find your stack in 60 seconds
Author?
Embed badge for your README
Browse similar
All communication MCPs
